1、事务的基本性质
数据库事务的四个特性——ACID(可通过【acid:酸的】来记忆):
原子性(Atomicity):一系列的操作要么同时成功,要么同时失败;
一致性(Consistency):数据在事务的前后,业务整体一致;
隔离性(Isolation):事务之间互相隔离;
持久性(Durabilily):一旦事务成功,数据的更改是永久性的。
一个事务开始,代表这个事务内的所有操作的在同一个连接里。
2、事务的隔离级别(从小到大)
1)READ UNCOMMITTED(读未提交)
该隔离级别的事务会又脏读现象:指读到其它未提交事务的数据。
2)READ COMMITTED(读提交)
——Oracle 和 SQL Server 的默认隔离级别。
会导致不可重复读现象:指在数据库访问中,一个事务范围内两个相同的查询却返回了不同数据。
3)REPEATABLE READ(可重复读)
—— MySQL 默认的隔离级别
在同一个事务里,查询所得的数据是事务刚开始时的状态,所以读到的结果会是一致的。但会产生幻读现象。MySQL的 InnoDB 引擎可以通过 next-key locks 机制来避免幻读。
4)SERIALIZABLE(序列化)
在该隔离级别下事务都是串行顺序执行的。
MySQL 数据库的 InnoDB 引擎会给读操作隐式加一把读共享锁,从而避免了脏读、不可重读复读和幻读问题。
3、事务的传播行为
1、PROPAGATION_REQUIRED:
如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务;
该设置是最常用的设置。
2、PROPAGATION_SUPPORTS:
支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。
3、PROPAGATION_MANDATORY:
支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
4、PROPAGATION_REQUIRES_NEW:
创建新事务,无论当前存不存在事务,都创建新事务。
5、PROPAGATION_NOT_SUPPORTED:
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
6、PROPAGATION_NEVER:
以非事务方式执行,如果当前存在事务,则抛出异常。
7、PROPAGATION_NESTED:
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED 类似的操作。
4、本地事务失效问题
同一个对象内事务方法互调默认失效,因为这种操作绕过了代理对象。
解决:使用代理对象来调用事务方法
1)引入aop-starter:引入了AspectJ
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2)@EnableAspectJAutoProxy(exposeProxy = true):开启aspectj动态代理功能。对外暴露代理对象。示例:
public class TestService {
//本类方法调用
@Transactional(timeout = 20)
public void a(){
TestService testService = (TestService) AopContext.currentProxy();
testService.b();
testService.c();
}
@Transactional(propagation = Propagation.REQUIRED,timeout = 5)
public void b(){
}
@Transactional(propagation = Propagation.REQUIRES_NEW,timeout = 10)
public void c(){
}
}