Spring 트랜잭션의 본질은 실제로 데이터베이스의 트랜잭션 지원이 없으면 Spring에서는 트랜잭션 기능을 제공할 수 없습니다. 순수 JDBC 운영 데이터베이스의 경우 트랜잭션을 사용하려면 다음 단계를 수행하면 됩니다.
연결 가져오기 Connection con = DriverManager.getConnection()
트랜잭션 열기 con.setAutoCommit(true/false);
CRUD 실행
커밋 트랜잭션/롤백 트랜잭션 con.commit () / con.rollback();
연결을 닫습니다. conn.close();
Spring의 트랜잭션 관리 기능을 사용한 후, 그런 다음 2단계와 4단계의 코드를 작성하면 Spirng 그러면 Spring은 우리가 작성한 CRUD 전후에 어떻게 트랜잭션을 열고 닫을 수 있을까요? 이 문제를 해결하기 위해 Spring의 트랜잭션 관리 구현 원리를 전체적으로 이해할 수 있습니다 . <.>
주석 활성화Driver, @Transactional 주석
으로 관련 클래스 및 메서드 표시 Spring은 시작 시 관련 Bean을 구문 분석하고 생성하며 관련 주석이 있는 클래스와 메서드를 확인하고 이러한 클래스와 메서드에 대한 프록시를 생성하며 @Transaction의 관련 매개변수에 따라 관련 구성을 주입합니다. , 에이전트가 관련 트랜잭션을 처리하도록 합니다(일반 트랜잭션 제출 및 예외 롤백 활성화)상수 이름 | 상수 설명 |
PROPAGATION_REQUIRED | 현재 트랜잭션을 지원합니다. 현재 트랜잭션이 없으면 새 트랜잭션을 생성하세요. . 이것은 가장 일반적인 선택이며 Spring의 기본 트랜잭션 전파입니다. |
PROPAGATION_REQUIRES_NEW | 새 거래(현재 있는 경우) 거래, 현재 거래를 일시 중단합니다. 새로 생성된 트랜잭션은 일시 중단된 트랜잭션과 아무런 관련이 없습니다. 이는 두 개의 독립적인 트랜잭션입니다. 외부 트랜잭션이 실패하고 롤백된 후에는 내부 트랜잭션 실행 결과를 롤백할 수 없습니다. 예외를 발생시킵니다, 외부 트랜잭션에 의해 캡처되거나 롤백 작업을 처리하지 않습니다 |
PROPAGATION_SUPPORTS | 현재 거래가 없는 경우 현재 거래를 지원합니다. , 비트랜잭션 방식으로 실행됩니다. |
PROPAGATION_MANDATORY | 현재 거래가 없는 경우 지원합니다. 현재 트랜잭션에서는 예외가 발생합니다. |
PROPAGATION_NOT_SUPPORTED | 비트랜잭션 방식으로 작업 수행 if 현재 트랜잭션이 있는 경우 현재 트랜잭션이 일시 중지됩니다. |
PROPAGATION_NEVER | 다음의 경우 비트랜잭션 모드에서 실행합니다. 현재 트랜잭션이 존재하는 경우 예외가 발생합니다. |
PROPAGATION_NESTED | 활성 트랜잭션이 있으면 중첩된 트랜잭션에서 실행됩니다. 활성 트랜잭션이 없으면 REQUIRED 속성이 실행됩니다. 롤백할 수 있는 여러 저장점이 있는 단일 트랜잭션을 사용합니다. 내부 트랜잭션 롤백은 외부 트랜잭션에 영향을 미치지 않습니다. DataSourceTransactionManager 트랜잭션 관리자에서만 작동합니다. |
隔离级别 | 隔离级别的值 | 导致的问题 |
Read-Uncommitted | 0 | 导致脏读 |
Read-Committed | 1 | 避免脏读,允许不可重复读和幻读 |
Repeatable-Read | 2 | 避免脏读,不可重复读,允许幻读 |
Serializable | 3 | 串行化读,事务只能一个一个执行,避免了脏读、不可重复读、幻读。执行效率慢,使用时慎重 |
더티 읽기(Dirty read): 하나의 트랜잭션이 데이터를 추가, 삭제 또는 수정했지만 제출되지 않았습니다. 커밋되지 않은 데이터를 읽을 수 있습니다. 이때 첫 번째 트랜잭션이 롤백되면 두 번째 트랜잭션에서 더티 데이터를 읽게 됩니다.
반복 불가능한 읽기: 한 트랜잭션에서 두 번의 읽기 작업이 발생했습니다. 첫 번째 읽기 작업과 두 번째 작업 사이에 다른 트랜잭션이 데이터를 수정했습니다. 이때 두 번 읽은 데이터가 일치하지 않습니다.
팬텀 읽기: 첫 번째 트랜잭션은 특정 범위의 데이터에 대한 수정을 일괄 처리하고 두 번째 트랜잭션은 이 범위에 데이터 조각을 추가합니다. 이때 첫 번째 트랜잭션은 새로 추가된 데이터의 수정 사항을 잃게 됩니다. .
요약:
격리 수준이 높을수록 데이터의 완전성과 일관성이 보장되지만 동시성 성능에 미치는 영향은 더 커집니다.
SqlServer, Oracle과 같은 대부분의 데이터베이스의 기본 격리 수준은 Read Commited입니다.
일부 데이터베이스의 기본 격리 수준은 다음과 같습니다. MySQL과 같은 반복 읽기 InnoDB
常量 | 解释 |
ISOLATION_DEFAULT | 这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。另外四个与 JDBC 的隔离级别相对应。 |
ISOLATION_READ_UNCOMMITTED | 这是事务最低的隔离级别,它充许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。 |
ISOLATION_READ_COMMITTED | 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。 |
ISOLATION_REPEATABLE_READ | 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。 |
ISOLATION_SERIALIZABLE | 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。 |
위의 이론적 지식을 통해 데이터베이스 트랜잭션과 스프링 트랜잭션의 일부 속성과 특성을 대략적으로 이해했습니다. 다음으로 몇 가지 중첩 트랜잭션 시나리오를 분석하여 스프링 트랜잭션 전파 메커니즘.
외부 트랜잭션 서비스 A의 메서드 A()가 내부 서비스 B의 메서드 B()를 호출한다고 가정합니다.
PROPAGATION_REQUIRED(봄 기본값)
If ServiceB.methodB()의 트랜잭션 수준이 PROPAGATION_REQUIRED로 정의되어 있으면 ServiceA.methodA()를 실행할 때 Spring이 이미 트랜잭션을 시작했으며 이때 ServiceB.methodB()가 호출되고 ServiceB.methodB()가 이를 확인합니다. ServiceA에서 이미 실행 중입니다. methodA() 트랜잭션 내에서는 새 트랜잭션이 시작되지 않습니다.
ServiceB.methodB()가 실행 중일 때 트랜잭션에 없는 것을 발견하면 자체적으로 트랜잭션을 할당합니다.
이런 방식으로 ServiceA.methodA() 또는 ServiceB.methodB() 내 어디에서나 예외가 발생하면 트랜잭션이 롤백됩니다.
PROPAGATION_REQUIRES_NEW
예를 들어 ServiceA.methodA()의 트랜잭션 수준은 PROPAGATION_REQUIRED로, ServiceB.methodB()의 트랜잭션 수준은 PROPAGATION_REQUIRES_NEW로 설계합니다. .
그런 다음 ServiceB.methodB()가 실행되면 ServiceA.methodA()가 있는 트랜잭션이 일시 중지되고 ServiceB.methodB()는 ServiceB.methodB()를 기다리면서 새 트랜잭션을 시작합니다. 트랜잭션이 완료되면 실행이 계속됩니다.
PROPAGATION_REQUIRED와 차이점은 트랜잭션 롤백 정도입니다. ServiceB.methodB()가 새 트랜잭션을 시작하기 때문에 두 가지 다른 트랜잭션이 있습니다. ServiceB.methodB()가 제출된 경우 ServiceA.methodA()는 실패하고 롤백되지만 ServiceB.methodB()는 롤백되지 않습니다. ServiceB.methodB()가 롤백에 실패하고 발생한 예외가 ServiceA.methodA()에 의해 포착되면 ServiceA.methodA() 트랜잭션이 계속 제출될 수 있습니다. 이는 주로 B에서 발생한 예외가 다음과 같은 예외인지 여부에 따라 달라집니다. A는 롤백됩니다).
PROPAGATION_SUPPORTS
ServiceB.methodB()의 트랜잭션 수준이 PROPAGATION_SUPPORTS라고 가정하고 ServiceB.methodB()가 실행될 때 ServiceA가 발견되면. methodA()가 열려 있으면 현재 트랜잭션에 참여합니다. ServiceA.methodA()가 트랜잭션을 열지 않는 것으로 확인되면 트랜잭션 자체를 열지 않습니다. 이때 내부 메소드의 트랜잭션성은 가장 외부 트랜잭션에 전적으로 의존합니다.
PROPAGATION_NESTED
이제 상황은 더욱 복잡해집니다. ServiceB.methodB()의 트랜잭션 속성은 PROPAGATION_NESTED로 구성됩니다. ? ServiceB#methodB 롤백되는 경우 내부 트랜잭션(예: ServiceB#methodB)은 실행되기 전에 SavePoint로 롤백되는 반면, 외부 트랜잭션(예: ServiceA#methodA)은 다음 두 가지 방법으로 처리될 수 있습니다. 🎜>
a. 예외 캡처 및 예외 분기 논리 실행void methodA() { try { ServiceB.methodB(); } catch (SomeException) { // 执行其他业务, 如 ServiceC.methodC(); } }이 메서드는 중첩 트랜잭션의 가장 중요한 부분이기도 합니다. ServiceB.methodB가 실패하면 ServiceC를 실행합니다. .methodC( ) 및 ServiceB.methodB는 실행되기 전에 SavePoint로 롤백되었으므로 더티 데이터가 생성되지 않습니다(이 메서드는 절대 실행되지 않는 것과 동일). 이 기능은 일부 특수 비즈니스에서 사용할 수 있으며 PROPAGATION_REQUIRED 및 PROPAGATION_REQUIRES_NEW 이를 수행할 수 있는 방법이 없습니다. b. 외부 트랜잭션 롤백/커밋 코드는 수정되지 않으며, 내부 트랜잭션(ServiceB#methodB)이 롤백되면 먼저 ServiceB.methodB가 실행되기 전에 SavePoint로 롤백됩니다. 이 경우) 외부 트랜잭션(예: ServiceA#methodA)은 특정 구성에 따라 커밋할지 롤백할지 결정합니다다른 세 가지 트랜잭션 전파 속성은 기본적으로 사용되지 않으므로 여기서는 분석하지 않습니다. 6. 요약 프로젝트에서 트랜잭션을 사용해야 하는 경우 개발자는 여전히 spring의 TransactionCallback 인터페이스를 사용하여 트랜잭션을 구현하는 것이 좋습니다. Note를 사용해야 하며, Spring 트랜잭션 전파 메커니즘과 격리 수준을 자세히 이해해야 합니다. 그렇지 않으면 예상치 못한 효과가 발생할 수 있습니다.
위 내용은 Spring 트랜잭션 원칙에 대한 자세한 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!