spring的事务传播类型定义在org.springframework.transaction.annotation.Propagation这个枚举类中
类型 | 说明 |
---|---|
REQUIRED | 默认的级别,如果当前事务存在,则加入到当前事务中,否则创建新的事务 |
SUPPORTS | 如果当前事务存在,则加入到当前事务中,否则以非事务的方式执行 |
MANDATORY | 如果当前事务存在,则加入到当前事务中,否则抛出异常 |
REQUIRES_NEW | 创建一个新的事务,如果当前事务存在,则挂起当前事务。挂起操作并不是开箱即用的,只对特定的事务管理器有效 |
NOT_SUPPORTED | 以非事务的方式执行,如果存在当前事务,则挂起当前事务。挂起操作并不是开箱即用的,只对特定的事务管理器有效 |
NEVER | 以非事务的方式执行,如果存在当前事务,则抛出异常 |
NESTED | 如果当前事务存在,则在当前事务中创建一个内嵌的事务。内嵌事务的创建对特定的事务管理器是开箱即用的:工作在JDBC 3.0驱动上的DataSourceTransactionManager |
举例说明:
package com.example.demo.Service;
import com.example.demo.dao.UserMapper;
import com.example.demo.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class TeacherService {
@Autowired
private UserMapper userMapper;
@Autowired
private StudentService studentService;
@Transactional(propagation = Propagation.REQUIRED)
public void insertTeacher() {
System.out.println("我是老师");
User user = new User();
user.setName("哈哈");
user.setAccount("haha");
user.setRoles("1");
user.setStatus(10);
user.setAuthenticateMode(1);
user.setOrganizationId(1);
userMapper.insert(user);
studentService.insertStudent();
throw new NullPointerException();
}
}
和
package com.example.demo.Service;
import com.example.demo.dao.UserMapper;
import com.example.demo.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class StudentService {
@Autowired
private UserMapper userMapper;
@Transactional(propagation = Propagation.REQUIRED)
public void insertStudent() {
System.out.println("我是学生");
User user = new User();
user.setName("黑黑黑黑");
user.setAccount("eieiei");
user.setRoles("1");
user.setStatus(10);
user.setAuthenticateMode(1);
user.setOrganizationId(1);
userMapper.insert(user);
}
}
上述代码中TeacherService.insertTeacher()中调用StudentService.insertStudent()。在insertTeacher传播类型为REQUIRED时我们分析debug日志
当insertStudent传播类型为
REQUIRED
2019-03-08 21:09:43,409 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Creating new transaction with name [com.example.demo.Service.TeacherService.insertTeacher]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2019-03-08 21:09:43,412 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Acquired Connection [HikariProxyConnection@1113620558 wrapping com.mysql.cj.jdbc.ConnectionImpl@6ac6b41f] for JDBC transaction
2019-03-08 21:09:43,414 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Switching JDBC Connection [HikariProxyConnection@1113620558 wrapping com.mysql.cj.jdbc.ConnectionImpl@6ac6b41f] to manual commit
我是老师
2019-03-08 21:09:43,487 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Participating in existing transaction
我是学生
2019-03-08 21:09:43,495 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Initiating transaction commit
2019-03-08 21:09:43,495 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Committing JDBC transaction on Connection [HikariProxyConnection@1113620558 wrapping com.mysql.cj.jdbc.ConnectionImpl@6ac6b41f]
2019-03-08 21:09:43,522 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Releasing JDBC Connection [HikariProxyConnection@1113620558 wrapping com.mysql.cj.jdbc.ConnectionImpl@6ac6b41f] after transaction
流程大致如下:
- 执行insertTeacher时创建事务A
- 执行insertStudent时,insertStudent加入到事务A中
- insertTeacher执行完提交事务A
SUPPORTS
2019-03-08 21:20:43,538 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-6] Creating new transaction with name [com.example.demo.Service.TeacherService.insertTeacher]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2019-03-08 21:20:43,574 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-6] Acquired Connection [HikariProxyConnection@1145965214 wrapping com.mysql.cj.jdbc.ConnectionImpl@20723189] for JDBC transaction
2019-03-08 21:20:43,574 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-6] Switching JDBC Connection [HikariProxyConnection@1145965214 wrapping com.mysql.cj.jdbc.ConnectionImpl@20723189] to manual commit
我是老师
2019-03-08 21:20:43,580 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-6] Participating in existing transaction
我是学生
2019-03-08 21:20:43,588 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-6] Initiating transaction commit
2019-03-08 21:20:43,589 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-6] Committing JDBC transaction on Connection [HikariProxyConnection@1145965214 wrapping com.mysql.cj.jdbc.ConnectionImpl@20723189]
2019-03-08 21:20:43,603 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-6] Releasing JDBC Connection [HikariProxyConnection@1145965214 wrapping com.mysql.cj.jdbc.ConnectionImpl@20723189] after transaction
流程大致如下:
- 执行insertTeacher时创建事务A
- 执行insertStudent时,insertStudent加入到事务A中
- insertTeacher执行完提交事务A
如果单独执行insertStudent,日志如下:
我是学生
2019-03-08 21:24:07,784 DEBUG org.springframework.jdbc.datasource.DataSourceUtils [http-nio-80-exec-3] Fetching JDBC Connection from DataSource
可以看到并没有创建事务
MANDATORY
2019-03-08 21:27:28,670 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-4] Creating new transaction with name [com.example.demo.Service.TeacherService.insertTeacher]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2019-03-08 21:27:28,672 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-4] Acquired Connection [HikariProxyConnection@1977186827 wrapping com.mysql.cj.jdbc.ConnectionImpl@1d2079de] for JDBC transaction
2019-03-08 21:27:28,672 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-4] Switching JDBC Connection [HikariProxyConnection@1977186827 wrapping com.mysql.cj.jdbc.ConnectionImpl@1d2079de] to manual commit
我是老师
2019-03-08 21:27:28,680 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-4] Participating in existing transaction
我是学生
2019-03-08 21:27:28,685 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-4] Initiating transaction commit
2019-03-08 21:27:28,685 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-4] Committing JDBC transaction on Connection [HikariProxyConnection@1977186827 wrapping com.mysql.cj.jdbc.ConnectionImpl@1d2079de]
2019-03-08 21:27:28,705 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-4] Releasing JDBC Connection [HikariProxyConnection@1977186827 wrapping com.mysql.cj.jdbc.ConnectionImpl@1d2079de] after transaction
流程大致如下:
- 执行insertTeacher时创建事务A
- 执行insertStudent时,insertStudent加入到事务A中
- insertTeacher执行完提交事务A
如果单独执行insertStudent,日志如下:
2019-03-08 21:29:27,564 ERROR org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[dispatcherServlet] [http-nio-80-exec-1] Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation ‘mandatory’] with root cause
org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation ‘mandatory’
流程大致如下:
- 抛出IllegalTransactionStateException异常
REQUIRES_NEW
2019-03-08 21:32:20,083 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Creating new transaction with name [com.example.demo.Service.TeacherService.insertTeacher]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2019-03-08 21:32:20,086 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Acquired Connection [HikariProxyConnection@842834947 wrapping com.mysql.cj.jdbc.ConnectionImpl@5f5f8d0b] for JDBC transaction
2019-03-08 21:32:20,088 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Switching JDBC Connection [HikariProxyConnection@842834947 wrapping com.mysql.cj.jdbc.ConnectionImpl@5f5f8d0b] to manual commit
我是老师
2019-03-08 21:32:20,173 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Suspending current transaction, creating new transaction with name [com.example.demo.Service.StudentService.insertStudent]
2019-03-08 21:32:20,176 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Acquired Connection [HikariProxyConnection@1576977912 wrapping com.mysql.cj.jdbc.ConnectionImpl@1b84dc56] for JDBC transaction
2019-03-08 21:32:20,176 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Switching JDBC Connection [HikariProxyConnection@1576977912 wrapping com.mysql.cj.jdbc.ConnectionImpl@1b84dc56] to manual commit
我是学生
2019-03-08 21:32:20,188 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Initiating transaction commit
2019-03-08 21:32:20,188 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Committing JDBC transaction on Connection [HikariProxyConnection@1576977912 wrapping com.mysql.cj.jdbc.ConnectionImpl@1b84dc56]
2019-03-08 21:32:20,212 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Releasing JDBC Connection [HikariProxyConnection@1576977912 wrapping com.mysql.cj.jdbc.ConnectionImpl@1b84dc56] after transaction
2019-03-08 21:32:20,212 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Resuming suspended transaction after completion of inner transaction
2019-03-08 21:32:20,213 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Initiating transaction commit
2019-03-08 21:32:20,213 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Committing JDBC transaction on Connection [HikariProxyConnection@842834947 wrapping com.mysql.cj.jdbc.ConnectionImpl@5f5f8d0b]
2019-03-08 21:32:20,237 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Releasing JDBC Connection [HikariProxyConnection@842834947 wrapping com.mysql.cj.jdbc.ConnectionImpl@5f5f8d0b] after transaction
流程大致如下:
- 执行insertTeacher时创建事务A
- 执行insertStudent时,挂起事务A,然后创建事务B
- insertStudent执行完提交事务B
- insertStudent执行完恢复事务A
- insertTeacher执行完提交事务A
如果单独执行insertStudent,日志如下:
2019-03-08 21:38:26,634 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Creating new transaction with name [com.example.demo.Service.StudentService.insertStudent]: PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT
2019-03-08 21:38:26,635 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Acquired Connection [HikariProxyConnection@1096411465 wrapping com.mysql.cj.jdbc.ConnectionImpl@60d6fd39] for JDBC transaction
2019-03-08 21:38:26,637 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Switching JDBC Connection [HikariProxyConnection@1096411465 wrapping com.mysql.cj.jdbc.ConnectionImpl@60d6fd39] to manual commit
我是学生
2019-03-08 21:38:26,725 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Initiating transaction commit
2019-03-08 21:38:26,725 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Committing JDBC transaction on Connection [HikariProxyConnection@1096411465 wrapping com.mysql.cj.jdbc.ConnectionImpl@60d6fd39]
2019-03-08 21:38:26,740 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Releasing JDBC Connection [HikariProxyConnection@1096411465 wrapping com.mysql.cj.jdbc.ConnectionImpl@60d6fd39] after transaction
流程大致如下:
- 执行insertStudent时创建事务A
- insertStudent执行完提交事务A
NOT_SUPPORTED
2019-03-08 21:43:59,835 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Creating new transaction with name [com.example.demo.Service.TeacherService.insertTeacher]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2019-03-08 21:43:59,839 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Acquired Connection [HikariProxyConnection@514778097 wrapping com.mysql.cj.jdbc.ConnectionImpl@19a9c304] for JDBC transaction
2019-03-08 21:43:59,841 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Switching JDBC Connection [HikariProxyConnection@514778097 wrapping com.mysql.cj.jdbc.ConnectionImpl@19a9c304] to manual commit
我是老师
2019-03-08 21:43:59,921 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Suspending current transaction
我是学生
2019-03-08 21:43:59,924 DEBUG org.springframework.jdbc.datasource.DataSourceUtils [http-nio-80-exec-1] Fetching JDBC Connection from DataSource
2019-03-08 21:43:59,950 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Resuming suspended transaction after completion of inner transaction
2019-03-08 21:43:59,950 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Initiating transaction commit
2019-03-08 21:43:59,951 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Committing JDBC transaction on Connection [HikariProxyConnection@514778097 wrapping com.mysql.cj.jdbc.ConnectionImpl@19a9c304]
2019-03-08 21:43:59,967 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Releasing JDBC Connection [HikariProxyConnection@514778097 wrapping com.mysql.cj.jdbc.ConnectionImpl@19a9c304] after transaction
流程大致如下:
- 执行insertTeacher时创建事务A
- 执行insertStudent时,挂起事务A
- insertStudent执行完
- insertStudent执行完恢复事务A
- insertTeacher执行完提交事务A
如果单独执行insertStudent,日志如下:
我是学生
2019-03-08 21:46:40,719 DEBUG org.springframework.jdbc.datasource.DataSourceUtils [http-nio-80-exec-1] Fetching JDBC Connection from DataSource
流程大致如下:
- 执行insertStudent
NEVER
2019-03-08 21:48:21,439 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-2] Creating new transaction with name [com.example.demo.Service.TeacherService.insertTeacher]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2019-03-08 21:48:21,444 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-2] Acquired Connection [HikariProxyConnection@1284280981 wrapping com.mysql.cj.jdbc.ConnectionImpl@13173907] for JDBC transaction
2019-03-08 21:48:21,446 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-2] Switching JDBC Connection [HikariProxyConnection@1284280981 wrapping com.mysql.cj.jdbc.ConnectionImpl@13173907] to manual commit
我是老师
2019-03-08 21:48:21,526 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-2] Initiating transaction rollback
2019-03-08 21:48:21,526 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-2] Rolling back JDBC transaction on Connection [HikariProxyConnection@1284280981 wrapping com.mysql.cj.jdbc.ConnectionImpl@13173907]
2019-03-08 21:48:21,547 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-2] Releasing JDBC Connection [HikariProxyConnection@1284280981 wrapping com.mysql.cj.jdbc.ConnectionImpl@13173907] after transaction
2019-03-08 21:48:21,563 ERROR org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[dispatcherServlet] [http-nio-80-exec-2] Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation ‘never’] with root cause
org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation ‘never’
流程大致如下:
- 执行insertTeacher时创建事务A
- 执行insertStudent时,抛出异常IllegalTransactionStateException
- 回滚事务A
如果单独执行insertStudent,日志如下:
我是学生
2019-03-08 21:51:50,783 DEBUG org.springframework.jdbc.datasource.DataSourceUtils [http-nio-80-exec-1] Fetching JDBC Connection from DataSource
流程大致如下:
- 执行insertStudent
NESTED
2019-03-08 21:53:22,410 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Creating new transaction with name [com.example.demo.Service.TeacherService.insertTeacher]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2019-03-08 21:53:22,413 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Acquired Connection [HikariProxyConnection@221774154 wrapping com.mysql.cj.jdbc.ConnectionImpl@5bfdaf98] for JDBC transaction
2019-03-08 21:53:22,415 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Switching JDBC Connection [HikariProxyConnection@221774154 wrapping com.mysql.cj.jdbc.ConnectionImpl@5bfdaf98] to manual commit
我是老师
2019-03-08 21:53:22,494 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Creating nested transaction with name [com.example.demo.Service.StudentService.insertStudent]
我是学生
2019-03-08 21:53:22,502 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Releasing transaction savepoint
2019-03-08 21:53:22,503 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Initiating transaction commit
2019-03-08 21:53:22,503 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Committing JDBC transaction on Connection [HikariProxyConnection@221774154 wrapping com.mysql.cj.jdbc.ConnectionImpl@5bfdaf98]
2019-03-08 21:53:22,524 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-1] Releasing JDBC Connection [HikariProxyConnection@221774154 wrapping com.mysql.cj.jdbc.ConnectionImpl@5bfdaf98] after transaction
流程大致如下:
- 执行insertTeacher时创建事务A
- 执行insertStudent时,创建事务B
- 执行完insertStudent
- 执行完insertTeacher
- 提交事务A、B
如果单独执行insertStudent,日志如下:
2019-03-08 22:27:04,133 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-3] Creating new transaction with name [com.example.demo.Service.StudentService.insertStudent]: PROPAGATION_NESTED,ISOLATION_DEFAULT
2019-03-08 22:27:04,136 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-3] Acquired Connection [HikariProxyConnection@1106324228 wrapping com.mysql.cj.jdbc.ConnectionImpl@426fb94d] for JDBC transaction
2019-03-08 22:27:04,139 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-3] Switching JDBC Connection [HikariProxyConnection@1106324228 wrapping com.mysql.cj.jdbc.ConnectionImpl@426fb94d] to manual commit
我是学生
2019-03-08 22:27:04,240 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-3] Initiating transaction commit
2019-03-08 22:27:04,240 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-3] Committing JDBC transaction on Connection [HikariProxyConnection@1106324228 wrapping com.mysql.cj.jdbc.ConnectionImpl@426fb94d]
2019-03-08 22:27:04,256 DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager [http-nio-80-exec-3] Releasing JDBC Connection [HikariProxyConnection@1106324228 wrapping com.mysql.cj.jdbc.ConnectionImpl@426fb94d] after transaction
流程大致如下:
- 执行insertStudent时创建事务A
- 执行完insertStudent
- 提交事务A