事务有关笔记
事务基础的ACID:原子性、一致性、隔离性和持久性(不做解释了)
1.同一service中不同方法调用,spring事务无效的问题
示例代码:
public class ServiceAImpl implements ServiceA
@AutoWird
private UserDao userDao;
public void methodA(){
//调用B
methodB();
}
@Transcation
@Override
public void methodB(){
userDao.deleteAll();
}
}
调用methodA(),事务不会生效:
原因:
这时候直接调用methodA方法,是不会开启事务的,虽然methodA里面调用了有事务的methodB,这时候调用methodB是当前对象调用的,没有走ServiceA的代理类去调用
解析:
srping事务就是springAOP的体现,事务可以认为对方法本身的一种加强,那么要开启这种加强,就要代理对象,那么大家看上述代码,methodA()中methodB被谁调用呢?是this!!(同类中不同方法的调用默认就是this)也就是目标对象,并不是代理对象,也就不能使用AOP代理,自然就开启不了事务,所以这就是常说的:要想开启事务,需要不同service方法调用才行
总结:
在一个Service内部,事务方法之间的嵌套调用,普通方法和事务方法之间的嵌套调用,都不会开启新的事务.
spring注解事务怎样生产:
spring 在扫描bean的时候会扫描方法上是否包含@Transactional注解,如果包含,spring会为这个bean动态地生成一个子类(即代理类,proxy),代理类是继承原来那个bean的。此时,当这个有注解的方法被调用的时候,实际上是由代理类来调用的,代理类在调用之前就会启动transaction。
2.事务7种传播行为
1.propagation-required: 支持当前事务,如果有就加入当前事务中;如果当前方法没有事务,就新建一个事务;(默认值)
2.propagation-supports: 支持当前事务,如果有就加入当前事务中;如果当前方法没有事务,就以非事务的方式执行;
3.propagation-mandatory: 支持当前事务,如果有就加入当前事务中;如果当前没有事务,就抛出异常;
4.propagation-requires_new: 新建事务,如果当前存在事务,就把当前事务挂起;如果当前方法没有事务,就新建事务;
5.propagation-not-supported: 以非事务方式执行,如果当前方法存在事务就挂起当前事务;如果当前方法不存在事务,就以非事务方式执行;
6.propagation-never: 以非事务方式执行,如果当前方法存在事务就抛出异常;如果当前方法不存在事务,就以非事务方式执行;
7.propagation-nested: 如果当前方法有事务,则在嵌套事务内执行;如果当前方法没有事务,则与required操作类似;
前六个策略类似于EJB CMT,第七个(PROPAGATION_NESTED)是Spring所提供的一个特殊变量。
它要求事务管理器或者使用JDBC 3.0 Savepoint API提供嵌套事务行为(如Spring的DataSourceTransactionManager)
3.事务4种隔离级别
由低到高分别为Read uncommitted 、Read committed(默认) 、Repeatable read 、Serializable
1、Serializable :最严格的级别,事务串行执行,资源消耗最大;
2、REPEATABLE READ :保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了“脏读取”和“不可重复读取”的情况,但是带来了更多的性能损失。
3、READ COMMITTED :大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”。该级别适用于大多数系统。
4、Read Uncommitted :保证了读取过程中不会读取到非法数据。
不可重复读的重点是修改 :
同样的条件 , 你读取过的数据 , 再次读取出来发现值不一样了
幻读的重点在于新增或者删除
同样的条件 , 第 1 次和第 2 次读出来的记录数不一样