2010-12-15 9 views
28

JDBC API가 자동 커밋 모드 (java.sql.Connection.setAutocommit())를 제공하는 이유에 대해 오랫동안 궁금해했습니다. 사람들을 곤경에 빠지게하는 매력적인 성가신 것 같습니다. 내 이론은 JDBC를 사용하여 SQL을 편집하고 실행하기위한 도구를 만들고 싶어하는 공급 업체의 생활을 단순화하기 위해 JDBC에 추가 된 것입니다. 자동 커밋을 설정하는 다른 이유가 있습니까? 아니면 항상 실수입니까?왜 Autocommit을 true로 설정합니까?

답변

11

자동 커밋 사용은 데이터베이스와 관련이 있습니다 (트랜잭션 동작처럼). 전 세계적으로 프로그래밍 방식의 트랜잭션 전략이 없다면 모든 사람이 트랜잭션을 적절히 닫고 롤백하기를 바라는 것보다 자동 커밋이 더 나을 것 같습니다.

MySQL의 경우, 기본적으로 autocommit = true로 설정하면 트랜잭션을 시작할 때 자동으로 해제됩니다. autocommit = false를 설정하는 유일한 이유는 누군가가 BEGIN없이 트랜잭션을 시작하려고 시도하는 경우 오류를 강제 실행하려는 경우입니다.

오늘날 일반적인 Java + MySQL 응용 프로그램에서 간단하게하기 위해 자동 커밋 설정을 무시하고 개방형 세션보기 패턴을 사용하고이를 훌륭하게 호출합니다.

명시 적 RDBMS 행 잠금을 강력히 권장하지 않고 대신 낙관적 잠금을 사용합니다. Hibernate는 낙관적 인 잠금을위한 내장 된 지원을 제공하지만 손으로 ​​직접 코드를 사용하는 경우에도 쉬운 패턴이며 더 나은 성능을 제공합니다.

+2

일반적인 Ja va + MySQL 응용 프로그램 : auto-commit을 true로 설정합니다. 들어오는 요청 (웹 페이지 또는 REST/JSON)이 시작될 때 세션을 열고 트랜잭션을 시작하십시오. 요청이 정상적으로 처리되면 요청 처리가 끝나면 트랜잭션을 커밋하십시오. 그런 다음 요청에 대한 500 페이지 렌더링에 롤백을 추가하십시오. 이것은 기본적으로 Play Framework에서 어떻게 일을 처리하는지입니다. 사용자와 개발자에게는 직관적입니다. –

+0

이것은 좋은 대답입니다. "웹 요청"은 웹 응용 프로그램의 "DB 트랜잭션"과 매우 관련이 있어야합니다. 따라서 우리는 DB 잠금이 아닌 낙관적 인 방법에 의존 할 필요가 있습니다. OpenSessionInView를 사용하면 뷰 렌더링을 포함한 전체 요청을 통해 세션을 열어 놓은 다음 요청이 끝날 때 플러시/커밋 할 수 있습니다. –

+0

전형적인 자바 + MySQL 애플리케이션이 "몇 주 동안의 프로젝트"이상의 것이면 세션 개방형 뷰를 반 패턴으로 간주하는 것이 제 생각에는 좋은 대답이 아닙니다. 애플리케이션에서 어떤 일이 일어나고 있는지 신속하게 제어 할 수 없으며, 성능이나 동시성 문제에 대한 확실한 추진력을 얻을 수 있습니다. 자동 커밋은 "일반적인 요청 처리 시간 초과"로 작동하는 트랜잭션 시간 초과 또는 트랜잭션 시간 초과없이 당신을 떠날 것입니다. 나는 90 % 이상의 경우에 웹 트랜잭션에서 상관 관계가없는 웹 요청을 말합니다. –

5

커밋 모드는 DB가 잠금을 유지하는 방식을 변경합니다.

트랜잭션 모드에서만 자동 커밋 모드를 비활성화하는 것이 좋습니다. 이렇게하면 여러 문에 대한 데이터베이스 잠금을 유지하지 않아도되므로 다른 사용자와의 충돌 가능성이 높아집니다.

...

트랜잭션 동안 충돌을 방지하려면, DBMS의 트랜잭션에 의해 액세스되는 데이터에 대한 다른 사람의 액세스를 차단하기위한 잠금 메커니즘을 사용합니다. (각 문은 트랜잭션입니다 자동 위탁 모드에서, 잠금 장치가 하나의 문 개최합니다.)

http://download.oracle.com/javase/tutorial/jdbc/basics/transactions.html

+0

요즘 MySQL과 DB2조차도 멀티 버전입니다.이 튜토리얼은 약간 시대 착오적이되고 있습니다. :( – Affe

+0

스냅 샷 격리 수준이 무료로 제공되지 않음 : http://blogs.msdn.com/b/sqlserverstorageengine/archive/2008/03/30/overhead-of-row-versioning.aspx 스냅 샷 격리로 동시성 확보 오버 헤드를 추가 할 수 있습니다. – hythlodayr

+0

잠금을 획득하는 방법을 이해하는 것은 항상 관련이 있습니다. –

18

하기 만 내가 볼 수있는 합리적인 이유는 connection.commit() 및 제거하는 것입니다 connection.rollback() 작은 응용 프로그램에서 간단한 단일 쿼리 트랜잭션의 상용구. 원시 형식의 JDBC는 자체적으로 이미 많은 상용구가 필요합니다. 모든 행을 줄이면 JDBC를 처음부터 덜 겁내게 만듭니다.

3

내가 작업중인 코드베이스의 95 %는 자동 업데이트가 필요한 곳에서 완벽하게 합리적인 단일 업데이트를 포함합니다. 그래서, 우리는 그것을 기본값으로 사용합니다. 트랜잭션이 필요한 코드 섹션을 수행 할 수있을만큼 오랫동안 끄기 만하면 자동 커밋이 바로 시작됩니다.

+0

트랜잭션은 트랜잭션 관리자로부터 트랜잭션 시간 초과를 제공 할 수 있음을 명심하십시오. 각 쿼리에서 시간 제한을 설정합니까? –

8

거의 항상 autocommit = true로 실행됩니다. 시간의 99 %, 내 업데이 트가 원자입니다. 물론, 차변을 기입 한 다음 롤백하려는 크레딧을 쓰지 못하는 경우가 있습니다. 그러나 제 경험상, 이것들은 비교적 드뭅니다. 보통 내가 쓰는 각 레코드는 독자적으로 나타납니다. 이 경우 각 쓰기 후에 커밋을 수행하는 것을 귀찮게 할 필요가 없습니다. 그것은 여기 저기에 코드 줄을 저장합니다. 프로그램의 구조를 감안할 때 추가 try/catch 블록이 필요하지 않거나 함수간에 연결 객체를 전달할 필요가 없다는 것을 의미하면 그 이상을 절약 할 수 있습니다. 누군가가 커밋을 잊어 버린 성가신 버그를 저장합니다.

"문제가 생긴 사람을 유인 할 수있는"유일한 방법은 자동 커밋을 해제하고 커밋 또는 롤백을하는 것이 너무 어려워서 트랜잭션 내에서 개별적으로 업데이트해야한다고 결정하는 것입니다. 그런 다음 트랜잭션을 중단해야하는 상황이 발생하지 않는 한 모든 것이 제대로 작동합니다. 테스트 시나리오가 부적절한 경우, 이것이 생산에 미끄러지는 것을 상상할 수 있습니다.

하지만 언어의 거의 모든 기능에 관해서도 똑같이 말할 수 있습니다. 예를 들어 시간의 90 %가 길어질 수있는 숫자를 처리하는 프로그램을 작성한다고 가정 해 봅시다.하지만 지금은 더 커질 수도 있습니다. 이러한 상황에 직면하면 할 일은 BigInteger를 사용하거나 더 큰 수를 처리 할 수있는 새로운 클래스를 만드는 것입니다. 게으른 프로그래머라면 일반적으로 작동하고 다른 대안은 너무 많은 문제가 있기 때문에 long을 사용하게 될 것입니다. Java가 long (또는 int)을 포함하면 안된다고 결론 내릴 수 있습니까? 왜냐하면 누군가가 적절하지 않을 때 Java를 사용하도록 유혹 당할 수 있기 때문입니다.

프로그램에서 대부분의 업데이트를 트랜잭션 컨텍스트 내에서 수행해야하는 경우 자동 커밋을 해제하십시오. 그 존재는 당신을 해치지 않습니다. 그것은 편리한 때를위한 것이지만, 그렇지 않은 경우에는 끌 수 있습니다.

+1

JDBC 3 스펙 이래로 "자동 커밋"모드의 연결은 둘 이상의 명령문을 열 수 없습니다. 따라서 중첩 된 UPDATE 나 외부 SELECT 루프 내의 SELECT가 문제를 일으킬 수 있습니다. –

+0

그것은 원 자성 일뿐만 아니라 트랜잭션 관리자가 트랜잭션을 지원하면 트랜잭션도 시간 초과가 할당 될 수 있습니다. 자동 커밋 & no query timeout을 사용하면 탐지되지 않은 SQL 성능 문제가 발생할 수 있습니다. 무거운 쿼리 등이 걸릴 수 있습니다. –

+0

저는 몇 년 동안 Javaland에서 벗어 났으므로 아마도 최신 Java 버전이 다를 수도 있고 그냥 잘못 처리 한 것일 수도 있습니다. 그러나 나는 자동 커밋 (autocommit)으로 질의를 수행 할 때 SQL 타임 아웃이 발생했다. 나는 개발 환경에서 발견 된 쿼리에 대해 많은 추억을 가지고 있지만 시간이 많이 걸린다. 어쩌면 기본값이 다를 지 모릅니다. 어쨌든 성능 문제가 있음을 알려주는 제한 시간에 의존하는 것은 매우 무딘 도구입니다. – Jay

6

자동 커밋이 편리합니다. 그러나 JDBC 3 스펙의 변경으로 인해 유용성이 줄어 들었습니다.

"자동 커밋"모드의 JDBC 3 연결은 둘 이상의 명령문을 열 수 없습니다. 다른 명령문을 실행하면 ResultSet을 포함하여 첫 번째 명령문을 닫습니다.

따라서 SELECT 내에서 루핑하고 UPDATE (또는 중첩 된 SELECT)를 발행하는 것은 실패하는 경향이 있습니다. 분명히 그것은 범죄입니다. 실제로는 에 뭔가를하십시오. 바깥 쪽 SELECT 결과가입니다!


어쨌든, 특정 드라이버 & 버전에 따라 달라집니다 .. 그러나 일반적으로 JDBC 3 사양이 도움이되지 않는 행동을 의무화 것으로 보인다. 또한 드라이버를 업그레이드하면이 동작을 '발견'할 수 있습니다.

왜 자동 커밋을 사용합니까? 원래 편리했습니다 & 도움이되었다. 다른 답변이 말하는 것처럼, JDBC는 .. JDBC 정말 잘 설계된 API :(


요즘, 당신은 더 나은 것 절전 모드 또는 Spring의 JdbcTemplate을 사용하지 않을 것입니다 제대로 호출하는 시시한 이야기와 취급의 풍부한 양을 필요로한다. . 그리고 서블릿/웹 애플리케이션을 사용하는 경우 "사용자 요청"경계에서 트랜잭션 관리 (시작/종료) 또는 최대 절전 모드 세션 (스레드 로컬에 바인딩)을 배치하십시오.

예 : get ServletRequest의 시작 부분에 연결/트랜잭션을 바인드하여 끝에 리턴하십시오.

javax.servlet.Filter 또는 유사한 것을 사용하여 바인드 할 수 있습니다 스레드 지역에 정적 도우미 그것을 얻을 수 있도록 또는 등,에게 그것을 요구

음이 글로벌 수준에서 "자동 위탁"가능하게하고있는 동안 조심 모양을 필요로 특정 조건이 있습니다
+0

웹 요청 ANTI 패턴에 연결된 연결/트랜잭션/세션을 권장하지 마십시오.요청 처리, 멀티 캐스트 업로드 처리, 느린 연결로 클라이언트에게 바디를 전송하면 그렇게 할 수 있지만 거의 모든 경우에 아주 나쁜 생각이라고 말할 수 있습니다. –

+0

감사합니다. @ PiotrMüller - 추론이나 참고 자료가 있습니까? 나는 거의 모든 패턴에 대해 0.001 % 나쁜 케이스를 생각해 낼 수있을 것이라고 기대할 수 있지만, "고립 된 문제가있는 코너 케이스가 가능합니다"를 "거의 모든 경우"와 구별하는 것이 더 낫습니다. - 그리고이 추천을 준 시점에 (2012), 좋은 조언이라고 생각합니다. 사용자 요청 영역은 HTTP 서비스 응용 프로그램에서 가장 기본적이고 중요한 경계입니다. 그렇기 때문에 디자인 할 강력하고 분명한 후보자입니다. 다른 대안은 더 복잡 할 것입니다. –

+0

웹 응용 프로그램에서 언급 한 대부분의 "나쁜 경우"가 적용됩니다 (일반적인 웹 응용 프로그램의 경우). 보기에서 세션을 사용하도록 설정하면 즉시 처리 할 수있는 많은 기술적 측면을 확보해야합니다. 응답 버퍼링 : 트랜잭션 및 SQL 연결이 클라이언트 연결의 전체 시간 동안 응답을 끌어 오지 않는지 확인하십시오 (클라이언트가 대역폭이 부족한 경우 SQL 연결을 오래 유지해야하는 이유). 매우 빠른 속도로 설계/성능 문제가 발생합니다 자라. 빨리, 몇 주간의 소규모 프로젝트를 위해 해결책이 될 수도 있지만, 큰 것으로 추천하지는 않겠습니다. –

2

:

은 a.) 쿼리 수준에서의 트랜잭션 관리는 사용자에게 맡겨 질 것입니다. 하나의 쿼리가 성공하거나 실패 할 경우 BEGIN 및 트랜잭션을 래핑해야합니다.

b.) "자동 커밋"을 사용하는 경우 롤백 할 필요가 없습니다.

c.) 또한 모든 트랜잭션을 작성 (커밋)하는 오버 헤드가 있습니다.

d. 읽기 전용 쿼리의 경우 "자동 커밋"이 필요하지 않지만 "자동 커밋"을 사용하면 모든 쿼리에 대해 자동으로 적용됩니다.

테이블 잠금이 자동 커밋을 활성화하는 유일한 문제인 경우 좋은 생각이 아니라 오히려 잠금 시간 제한을 낮추는 것이 좋습니다.

관련 문제