定义
逻辑上的一组操作,要么全部执行,要么全部不执行。
特性(ACID)
- 原子性:一组操作,要么全部执行,要么全部不执行。
- 一致性:执行事务前后,数据保持一致。
- 隔离性:各事务之间相互隔离,不会相互干扰。
- 持久性:一个事务提交后,对数据库中的数据改变是持久的。
事务传播行为
解决业务层方法之间相互调用的事务问题
事务传播行为 | |
---|---|
REQUIRED(默认) | 如果存在事务,则加入事务; 如果不存在事务,则创建事务。 |
REQUIRS_NEW | 创建一个新事物,如果事物存在,则挂起事务。 |
SUPPORTS | 如果存在事务,则加入事务; 如果不存在事务,则以非事务的方式执行。 |
NOT_SUPPORTED | 以非事务方式执行操作,如果存在事务,则挂起事务 |
MANDATORY | 如果存在事务则加入事务; 如果没有事务,则抛出异常。(必须有事务) |
NEVER | 以非事务方式执行操作,如果存在事务,则抛出异常。(必须没事务) |
事务隔离级别
事务失效及解决方案
1.未捕获异常
2. 方法为非public方法
3.方法用final、static修饰
4.this调用类内部方法
5.数据库不支持
6.多线程调用
-
未捕获异常
默认情况只会回滚RuntimeException(运行时异常)和Error(错误),如果一个事务方法中发生了未捕获异常,并且异常未被处理或传播到事务边界之外,事务失效。
-
方法为非公开方法
如果@Transactional注解标注在私有方法上或非public方法上,事务失效。
-
方法用final、static修饰
Spring事务的实现是基于动态代理的,使用final、static修饰后,无法重写改方法,所以事务失效。
-
调用类内部的事务方法
因为Spirng事务是通过代理对象来控制的,使用this直接调用,绕过了Spring的代理机制,不会应用事务设置。
@Service public class UserService{ public void save(User user){ queryData(); save(user); updateStatus(user); //this调用类内部方法 } @Transactional public void updateStatus(User user){ update(user); } }
解决:
-
创建一个Service方法
@Service public class UserService{ @Autowired ServiceA service public void save(User user){ queryData(); save(user); service.updateStatus(user); } } @Service public class ServiceA{ @Transactional public void updateStatus(User user){ update(user); } }
-
注入自己
@Service public class UserService{ @Autowired UserService userService; public void save(User user){ queryData(); save(user); userService.updateStatus(user); } @Transactional public void updateStatus(User user){ update(user); } }
自己注入自己回导致循环依赖,但是Spring内部的三级缓存机制解决了该循环依赖的问题。
-
通过AopContext类获取代理对象
@Service public class UserService{ public void save(User user){ queryData(); save(user); ((UserService)AopContext.currentProxy()).updateStatus(user); //获取代理对象 } @Transactional public void updateStatus(User user){ update(user); } }
-
-
数据库不支持事务
比如MySql使用了MyISAM引擎,它本身是不支持事务的,在这种情况下,即使添加了@Transactional主机诶,事务也不会生效。
-
多线程调用
两个事务方法不在同一个线程中,获取到的数据库连接不一样,从而是两个不同的事务。如果抛出了异常,也不会正确回滚。