事务的四大特性:
- 原子性
- 一致性
- 隔离性
- 持久性
事务隔离级别 isolation
使用方式举例: @Transactional(isolation=Isolation.DEFAULT)
isolation参数有以下五种:
- Isolation.DEFAULT:数据源默认隔离级别,对于大部分数据源来说此级别就是Isolation.READ_COMMITTED
- Isolation.READ_UNCOMMITTED:读未提交,该隔离级别可以读取其它事务已修改未提交的数据,该级别不能防止脏读、不可重复度和幻读。
- Isolation.READ_COMMITTED:读提交,该级别只能读取其它事务已经提交的数据,该级别可以防止脏读,但不能防止不可重复度和幻读。
- Isolation.REPEATABLE_READ:可重复读,改隔离级别内多次读取同一条数据结果是一致的,该级别可以防止脏读和不可重复读,但不能防止幻读。
- Isolation.SERIALIZABLE:可序列化,该级别中所有事务按顺序执行,该级别可以防止脏读、不可重复读和幻读,但该级别将严重影响性能。
名词解释:
- 脏读:指读取了另一个事务未提交的数据。例如,事务1修改了数据但还没有提交,然后事务2读取了这条数据,接下来事务1回滚了事务,数据的修改被撤销了,那么此时事务2读取的这条数据就是脏数据。
- 不可重复读:指在一个事务中前后两次(或多次)读取的同一条数据不一样。例如,事务2读取了一条数据,事务1修改了这条数据然后提交了,此时事务2又一次读取这条数据,发现这条数据和第一次读取的不一样,此时就发生了不可重复读。
- 幻读:指读取时这条数据还不存在,但操作时发现已经存在了这条数据。例如,事务1要插入一条id为1的数据,先检查id为1的数据是否存在,不存在才插入,事务1读取后发现id为1的数据不存在,然后准备执行插入操作,此时事务2插入了一条id为1的数据,然后事务1插入数据出错了,发现此时已经有id为1的数据了,之前的读取好像发生了幻觉一样。幻读和不可重复读的区别就是修改和新增的区别,可重复读的隔离级别并不会禁止其它事务的插入操作。
自动回滚条件 rollbackFor 和 rollbackForClassName
使用方式举例:
@Transactional(rollbackFor = Exception.class)
@Transactional(rollbackFor = {NullPointerException.class, SQLException.class})
@Transactional(rollbackForClassName = “Exception”)
@Transactional(rollbackForClassName = {“NullPointerException”, “SQLException”})
如果不指定这两个属性中的一个的话,默认的回滚异常是 RuntimeException。
不自动回滚条件 noRollbackFor 和 noRollbackForClassName
被指定的异常发生时不会自动回滚事务。使用方式和自动回滚一样
事务传播 propagation
使用方式举例: @Transactional(propagation = Propagation.REQUIRED)
propagation 参数有以下7种:
- Propagation.REQUIRED:表明该方法必须在一个事务中执行,如果事务存在就加入,如果不存在就新建事务。此属性也是默认属性。
- Propagation.SUPPORTS:该方法可以在事务中执行,如果事务存在就加入,如果不存在就以非事务执行。
- Propagation.MANDATORY:必须在当前事务中执行,如果当前没有事务就抛出异常。
- Propagation.REQUIRES_NEW:必须在自己的事务里执行,新建事务,如果当前已经存在事务,则把已存在的事务挂起,直到当前方法执行完毕。
- Propagation.NOT_SUPPORTED:不在事务里执行,如果存在事务,则把已存在的事务挂起,直到当前方法执行完毕。
- Propagation.NEVER:不在事务里执行,如果存在事务,则抛出异常。
- Propagation.NESTED:表示此方法在一个嵌套的事务里运行,如果没有事务,则其表现和 Propagation.REQUIRED 方式相同。嵌套事务可以单独回滚,当父事务提交时嵌套事务将一起提交,当其回滚时,父事务可以选择是否跟随回滚。
事务超时 timeout
使用方式举例: @Transactional(timeout = -1)
设置事务的超时时间,默认为-1 永不超时。
超时的回滚机制:
如果超过了设置的超时时间,并且后面还有对数据库的操作就会回滚。
如果超过了设置的超时时间,但是后面的代码已经不涉及数据库的操作了,就不会回滚。