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(); } }
위 내용은 Spring 트랜잭션 원칙에 대한 자세한 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!