Spring事务大致流程
当我们在某个方法上加了@Transactional注解后,就表示该方法在调用时会开启Spring事 务,而这个方法所在的类所对应的Bean对象会是该类的代理对象。
Spring事务的代理对象执行某个方法时的步骤:
- 判断当前执行的方法是否存在@Transactional注解
- 如果存在,则利用事务管理器(TransactionMananger)新建一个数据库连接
- 修改数据库连接的autocommit为false
- 执行target.test(),执行程序员所写的业务逻辑代码,也就是执行sql
- 执行完了之后如果没有出现异常,则提交,否则回滚 Spring事务是否会失效的判断标准:某个加了@Transactional注解的方法被调用时,要判 断到底是不是直接被代理对象调用的,如果是则事务会生效,如果不是则失效
- 如果没有抛异常,则提交
- 如果抛了异常,则回滚
Spring事务传播机制
Spring事务大致流程
当我们在某个方法上加了@Transactional注解后,就表示该方法在调用时会开启Spring事 务,而这个方法所在的类所对应的Bean对象会是该类的代理对象。
Spring事务的代理对象执行某个方法时的步骤:
- 判断当前执行的方法是否存在@Transactional注解
- 如果存在,则利用事务管理器(TransactionMananger)新建一个数据库连接
- 修改数据库连接的autocommit为false
- 执行target.test(),执行程序员所写的业务逻辑代码,也就是执行sql
- 执行完了之后如果没有出现异常,则提交,否则回滚 Spring事务是否会失效的判断标准:某个加了@Transactional注解的方法被调用时,要判 断到底是不是直接被代理对象调用的,如果是则事务会生效,如果不是则失效
- 如果没有抛异常,则提交
- 如果抛了异常,则回滚
Spring事务传播机制
默认情况下传播机制为REQUIRED,表示当前如果没有事务则新建一个事务,如果有事务则在当前事 务中执行。
也可以手动设置为REQUIRED_NEW,将ThreadLocal中已有的conn移除,并放入一个挂起对象资源中。
场景一:
typescript
@Component
public class UserService {
@Autowired
private UserService userService;
@Transactional
public void a() {
// sql
userService.b();
}
@Transactional
public void b() {
// sql
}
}
执行流程:
- 事务管理器创建数据库连接conn
- 将autocommit设置为false
- 将数据库连接放置到ThreadLocal中
- 执行a中的sql
- 执行b中的sql
- 执行conn的方法commit提交
场景二:
typescript
@Component
public class UserService {
@Autowired
private UserService userService;
@Transactional
public void a() {
// sql
userService.b();
}
@Transactional
public void b() {
// sql
int i = 100/0;
}
}
执行流程:
1、事务管理器建立数据库连接conn
2、将autocommit设置成false
3、将conn放入ThreadLocal
4、执行方法a中的sql
5、执行方法b中的sql
6、异常报错
7、执行conn中的rollback回滚方法,两个方法中的事务都会回滚掉
场景三:
typescript
@Component
public class UserService {
@Autowired
private UserService userService;
@Transactional
public void a() {
// sql
userService.b();
int i = 100/0;
}
@Transactional
public void b() {
// sql
}
}
执行流程:
1、事务管理器创建一个数据库连接conn
2、将autocommit设置为false
3、执行方法a中的sql
4、执行b中的方法
5、报异常
6、调用conn的rollback方法,两个方法的事务都会回滚
场景四:
typescript
@Component
public class UserService {
@Autowired
private UserService userService;
@Transactional
public void a() {
// sql
userService.b();
}
@Transactional(Propagation=propagation.REQUIRES_NEW)
public void b() {
// sql
}
}
执行流程:
1、事务管理器创建一个数据库连接conn
2、将autocommit设置为false
3、执行方法a中的sql
4、将ThreadLocal中a方法的conn移除,挂起到资源对象中
5、事务管理器创建一个数据库连接conn2(方法b的)
6、 执行b方法的sql
7、conn2调用commit方法提交事务
8、然后再把挂起资源对象中的coon(方法a的)恢复到ThreadLocal中
9、a执行完后,conn调用commit方法提交事务
场景五:
java
@Component
public class UserService {
@Autowired
private UserService userService;
@Transactional
public void a() {
// sql
userService.b();
int i = 100/0;
}
@Transactional(Propagation=propagation.REQUIRES_NEW)
public void b() {
// sql
}
}
执行流程:
1、事务管理器创建一个数据库连接conn
2、将autocommit设置为false
3、执行方法a中的sql
4、将conn从ThreadLocal中移除,存入挂起资源中
5、事务管理器新建一个conn2存放到ThreadLocal中
6、报异常
7、两个事务都得回滚(因为事务a中调用了事务b,事务a报异常回滚了,事务b也得回滚)
场景六:
java
@Component
public class UserService {
@Autowired
private UserService userService;
@Transactional
public void a() {
// sql
userService.b();
}
@Transactional(Propagation=propagation.REQUIRES_NEW)
public void b() {
// sql
int i = 100/0;
}
}
执行流程:
1、事务管理器创建一个数据库连接conn
2、设置autocommit为false
3、执行方法a的sql
4、将conn从ThreadLocal中移除,并存入挂起资源对象中
5、方法b新建一个连接conn2
6、异常报错
7、conn2调用rollback回滚事务
8、继续抛异常,对于test()方法而言,它会接收到一个异常,然后抛出
9、执行conn的rollback()方法进行回滚,最终还是两个方法中的sql都回滚了
Spring事务强制回滚
正常情况下,a()调用b()方法时,如果b()方法抛了异常,但是在a()方法捕获了,那么a()的事务还是会正常提交的,但是你b()方法都执行异常并抛出了,还继续执行干什么,所以我们通常可以有在a()方法中捕获异常并将异常友好的提示出去:
java
@Component
public class UserService {
@Autowired
private UserService userService;
@Transactional
public void a() {
// sql
try{
userService.b();
}catch{
// 构造友好的错误信息返回
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
@Transactional(Propagation=propagation.REQUIRES_NEW)
public void b() throws Exception{
// sql
int i = 100/0;
}
}
TransactionSynchronization
Spring事务有可能会 提交,回滚、挂起、恢复,所以Spring事务提供了一种机制,可以让程序员来监 听当前Spring事务所处于的状态。
typescript
@Component
public class UserService {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private UserService userService;
@Transactional
public void test(){
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void suspend() {
System.out.println("test被挂起了"); }
@Override
public void resume() {
System.out.println("test被恢复了"); }
@Override
public void beforeCommit(boolean readOnly) {
System.out.println("test准备要提交了"); }
@Override
public void beforeCompletion() {
System.out.println("test准备要提交或回滚了"); }
@Override
public void afterCommit() {
System.out.println("test提交成功了"); }
@Override
public void afterCompletion(int status) {
System.out.println("test提交或回滚成功了");}};
//方法test()的sql
}