后端与数据库产生交互时,我们只能单一的一次一次去实现数据库的增,删,改,查询的功能,并不能在多个增,删,改,查询操作同时进行时,对其操作进行控制管理。所以我们需要事务管理来解决这种问题。
1.什么是事务?
service层的同一个业务逻辑下执行的所有操作,要么完全执行,要么都不执行,这种并发控制,就叫做事务。
- 事务的四大属性:
A:原子性(Atomicity)
事务中的操作要么都不做,要么就全做。
C:一致性(Consistency)
事务执行的结果必须是从数据库从一个一致性状态转换到另一个一致性状态。
I:隔离性(Isolation)
一个事务的执行不能被其他事务干扰
D:持久性(Durability)
一个事务一旦提交,它对数据库中数据的改变就应该是永久性的
2.通过案例分析事务
转账案例中,在一个账户转账到另一个账户时,一旦在转账业务逻辑中出现异常,若在转出之后,转进之前出现异常则会造成转账出现不一致现象(转出账户金额减少,转进账户却没增加)。
2.1分析在spring容器中实现案例,产生上述bug的原因
1)分析业务逻辑代码
通过分析我们发现,在每次调用dao层的方法与操作数据库时,我们都会从Spring容器中调用一个datasource数据池注入dao获取一个数据库的连接,这样就会导致每一次的调用方法都不是在同一个线程中,所以无法在同一时间控制不同的方法进行提交或者关闭。
2)解决问题逻辑
既然是因为每一次调用时获取了不同的连接,所以我们可以创建一个工具类,专门来获取数据库的连接Connection。
在ConnectionUtils类添加一个remove方法,为conection和线程实现解绑(线程的remove方法,移除存放在此线程里的connection)
public void removeConnectin(){
t1.remove();
}
2.2开始创建事务管理类
获取到了Connection类后,我们就可以通过Connection来管理事务,事务管理分别有:开启事务,提交事务,回滚事务,释放连接。
- 开启事务
- 提交事务
- 回滚事务
- 释放连接
2.3更新Service类
1)添加事务管理类
2)测试管理事务
只要代码产生异常,执行操作时,每个操作都是使用的同一个线程中的Connection,所以凡是存在事务当中的操作都无法成功执行,就会使数据库更新一致。
但是这样添加事务我们会发现,Service层的每个方法都需要添加事务,就会使代码重复性增强,变得臃肿。于是我们引入aop的理念,让Spring来进行事务控制。
3.aop配置事务
- 在spring容器中配置Cooection类与TransactionManager类
- 配置aop
4.配置aop声明式事务步骤
以上配置我们使用的都是自己创建的事务管理器类,其实spring中有自己的事务管理器类,所以我们可以利用spring中的事务管理器进行配置。
4.1基于xml配置
1)配置事务管理器;
2)配置事务通知,添加事务名称空间与约束;
3)配置aop中的通用切入点表达式;
4)建立事务通知和切入点表达式的对应关系。
5)添加事务属性(事务隔离级别,事务传播行为等)
4.2基于注解配置
- 配置所有需要扫描类的包,在类上添加相应的注解。
- 配置事务管理器(与xml文件一样,注入一个datasource到事务管理器里)
- 添加spring对注解事务的支持
- 在需要事务的service类或方法上添加注解@Transactional(在注解后添加属性)