spring事务

一、核心3个接口
1.TransactionDefinition定义事务管理的属性包括传播行为和隔离级别

public interface TransactionDefinition {
//事务的传播行为
     int PROPAGATION_REQUIRED = 0;
     int PROPAGATION_SUPPORTS = 1;
     int PROPAGATION_MANDATORY = 2;
     int PROPAGATION_REQUIRES_NEW = 3;
     int PROPAGATION_NOT_SUPPORTED = 4;
     int PROPAGATION_NEVER = 5;
     int PROPAGATION_NESTED = 6;
//事务的隔离级别
     int ISOLATION_DEFAULT = -1;
     int ISOLATION_READ_UNCOMMITTED = 1;
     int ISOLATION_READ_COMMITTED = 2;
     int ISOLATION_REPEATABLE_READ = 4;
     int ISOLATION_SERIALIZABLE = 8;
     int TIMEOUT_DEFAULT = -1;
     int getPropagationBehavior();//获得事务的传播行为
     int getIsolationLevel();//获得事务的隔离级别
     int getTimeout();//获得事务超时时间
     boolean isReadOnly();//是否只读
     String getName();//事务名称
 }

默认实现类是 DefaultTransactionDefinitioin
2.PlatformTransactionManager负责执行具体的事务,默认实现类是 AbstractPlatformTransactionManager
//在spring中配置事务管理器时可根据需要配置一个该接口的实现类,比如jdbc管理事务的类 DataSourceTransactionManager
PlatFormTransactionManager的类图
在这里插入图片描述

public interface PlatformTransactionManager {
//这里将事务定义传入当参数,获得一个事务状态的实例
    TransactionStatus getTransaction(TransactionDefinition var1) throws TransactionException;
    void commit(TransactionStatus var1) throws TransactionException; //提交
    void rollback(TransactionStatus var1) throws TransactionException;//回滚
}

3.TransactionStatus提供控制和查询事务状态的方法

public interface TransactionStatus extends SavepointManager, Flushable {
     boolean isNewTransaction();//是否一个新的事务
     boolean hasSavepoint();//是否有存储点,嵌套事务会有存储点
     void setRollbackOnly();//将事务设置为只能回滚,不允许提交
     boolean isRollbackOnly();//查询事务是否已有回滚标志
     void flush();
     boolean isCompleted();//查询事务是否结束
 }

4.spring事务管理工作运行图,分析下过程
在这里插入图片描述
描述:(1)transactionDefinition传递给getTransaction,得到transactionStatus
(2**)提交事务时 plateformTransactionManager.commit/rollback方法里传参tansactionSstatus**
5.https://www.cnblogs.com/fjdingsd/p/5632949.html.事务的属性
参考 https://www.cnblogs.com/yixianyixian/p/8372832.html
参考 https://segmentfault.com/a/1190000011910376

6.spring事务的基本流程
在这里插入图片描述
**过程描述:**调用transactionInterceptor中的invoke()
1.invoke 中调用invokeWithinTransaction,判断是编程式事务还是声明式事务
(1).调用transactionAspectSupport的createTransactionIfNecessary创建TransactionInfo
1)AbstractPlatformTransactionManager中的getTransaction
i. 调用AbstractPlatformTransactionManager中可继承方法doGetTransaction,JDBC的话就是datasourceTransactionManager中的doGetTransaction
ii.判断当前事务外围是否已经存在事务,通过当前线程的threadLocal中是否存在connectionHolder,如果有则处理iii,否则处理iv
AbstractPlatformTransactionManager 中可继承方法isExistingTransaction,JDBC的话就是datasourceTransactionManager中的isExistingTransaction
iii.AbstractPlatformTransactionManager 中调用handleExistingTransaction处理外围事务存在的情况;
iv. 调用 AbstractPlatformTransactionManager中可继承方法doBegin,JDBC的话就是datasourceTransactionManager中的doBegin(),
该方法中主要是获得连接,事务与线程同步,将connection自动提交设置false,即交给spring的事务对象
(2) 调用TransactionINtercepter中的proceedWithInvocation()处理拦截链中的方法,这里其实就是代理模式中invoke调用代理方法之后,再调用目标方法
(3)异常抛出的话则调用transactionAspectSupport的completeTransactionAfterThrowing进行回滚
1)掉用abstractPlatFormTransactionManager中的processRollBack
i,调用AbstractPlatformTransactionManager中可继承方法dorollback, JDBC的话就是datasourceTransactionManager中的dorollback
ii.dorollback中直接调用connection.rollback
(4)如果不抛异常的话则直接调用提交方法TransactionAspectSupport中的commitTransactionAfterReturning
1). 调用AbstractPlatformTransactionManager 中 的commit()判断是否isGlobalRollbackOnly为true
i 如果有则调用processRollback进行回滚并抛出异常
ii否则调用AbstractPlatformTransactionManager 的processcommit提交
iii.ii中又调用了AbstractPlatFormTransactionManager方法中的抽象方法doCommit(), JDBC的话就是datasourceTransactionManager中的docommit,进行connection的commit

7.连接池泄露的问题最大的可能就是连接未关闭,spring框架中,基本就是spring事务没有生效,目前发现有两种原因,交给spring的bean在其他地方被new了一个,二是xml文件中没有配置事务
8.事务和try/catch的关系总结
(1)嵌套事务的讲解
https://blog.csdn.net/f641385712/article/details/80445912;
嵌套常见错误 rollback-only原因
**如果某个子方法(不同实例间方法的调用)有异常,spring将该事务标志为rollback only。**如果这个子方法没有将异常往上整个方法抛出或整个方法未往上抛出,那么改异常就不会触发事务进行回滚,事务就会在整个方法执行完后就会提交,这时就会造成Transaction rolled back because it has been marked as rollback-only的异常。简单说就是跨实例调用方法时,内部方法被catch住了 没有将异常抛出,spring没能捕获住异常,外层事务直接提交,这是发现内部方法被标记为rollback-only则报错

(2)事务不生效的几种情况:https://blog.csdn.net/f641385712/article/details/80445933
如@transactional只能在public上,默认只对对runtimeException及子类回滚起作用,配置文件等等
(3)this调用方法时无事务的情况
事务仅仅在方法上,方法A无事务,方法B有事务,方法A中调用方法B,不管B前面加不加this,其实生成的class文件都是通过this调用的B,那么当通过bean调用方法A时,整体上线程是跟没有事务绑定的,也就是这种调用没有事务环境,B报错时并不会回滚,也没有create newtransaction的日志打印;
但是通过bean直接调用B时,是有事务环境的
原因是this是直接调用的目标类的方法,不会走事务增强

//同一个类
   @Override
    public void save(TestUser user) {
  /*  jdbcTemplate.update("insert into t_mytest (fid, fname, fpwd) values (?, ?, ?)",
            new Object[]{user.getId(),user.getName(),null});*/
     save1( user);

    }
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor=Throwable.class)
    @Override
    public void save1(TestUser user) {
        jdbcTemplate.update("insert into t_mytest (fid, fname, fpwd) values (?, ?, ?)",
                new Object[]{user.getId(),user.getName(),null});

        throw  new RuntimeException();
    }
//不同类中oerations抛异常,在controller中捕获了也没事,同样会回滚,因为异常已经跳出了对应事务
     try {
            operations.deleteData(id);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return  "deleteSuccess";
    }

(4)不是只要加了try catch就一定不会回滚,得看catch能否捕获对应异常,比如sql异常,缺捕获的runtime,那还是会回滚的
(5)如果非要catch则catch后一般做完操作后直接再抛一个runtime异常
(6)spring框架下的sql异常都被重写成了runtime异常,事务也会回滚,异常分类
https://www.cnblogs.com/qcq0703/p/8793707.html
(7)一般在service中不要try catch ,主要是做事务处理的,如果捕获,则必须跑出runtime异常,才不影响事务dao和service
异常应该一直往上抛,到controller层处理
https://4876391520.iteye.com/blog/2300772
9.事务隔离级别propagation = Propagation.REQUIRES_NEW的使用应该是跨实例生效的,另外它有两点作用:
1.内层新事务报错会触发外层事务回滚(如果不想外层回滚,且内层仍然能事务生效即能回滚,则在外层方法调用内层时catch住,总之内层不能抛异常出来
2.外层事务报错,内层事务不受影响
以上两点的原理是new级别的隔离会在调用内层方法时,先将外层事务挂起,然后重新创建一个新事务,再内层提交之后再将外层事务复位,通过日志可以看出,有创建新事务和恢复之前事务的日志

https://blog.csdn.net/mawenshu316143866/article/details/81281443
在这里插入图片描述
在这里插入图片描述
10.spring所有的事务传播行为都必须是跨实例调用方法才会生效,因为事务是在产生实例的代理类时生效的,在调用目标类方法时其实没有事务处理,如果同一个实例方法之间的调用其实相当于目标类内部调用,始终用的最开始AOP产生代理类时的事务,跨实例调用则是在用代理类,
简单说,要使用事务,则必须使用spring代理类,而目标对象内部的自我调用将无法实施切面中的增强。
https://blog.csdn.net/hepei120/article/details/78058468
在这里插入图片描述
11.并非由spring创建的bean都会存在事务,只有那些被@transactional注解了的bean才会在生成代理对象的时候走AOP加上事务,如上面的过程,而且类事务是紧跟实例的,可以在非事务的方法里调用含有事务的实例(很废话,,)
如这个方法在todobo里被调用了todobo是加了类事务的 这个方法由于没有事务,会被外层事务囊括进去,导致回滚,如果加not_suppoted可以解决,注解会将这个方法外层加的事务挂起,但是它里面调用的todobo.listtodobytaskids这个方法事务又是生效的,因为todobo有事务,notsupported只会影响外围事务,方法里的事务仍起作用

    @Transactional(propagation=Propagation.NOT_SUPPORTED)
public void startNextTask(String todoTaskId,ExceptionHandleFlowService exc){
    Set<String> set = new HashSet();
    set.add(todoTaskId);
    List<ToDo> todos = todobo.listToDoByTaskIds(set);

    }
    

12.嵌套事务的源码分析
handleExistingTransaction如果已经存在事务,则嵌套事务的处理是创建存储点,而非创建新事务,相当于还是用的外围事务,只是在外围事务上创建 另一个存储点

  if (definition.getPropagationBehavior() == 6) {
                    } else {
                        if (this.useSavepointForNestedTransaction()) {
                            DefaultTransactionStatus status = this.prepareTransactionStatus(definition, transaction, false, false, debugEnabled, (Object)null);
                            status.createAndHoldSavepoint();//创建存储掉
                            return status;
                        } else {
                            newSynchronization = this.getTransactionSynchronization() != 2;
                            DefaultTransactionStatus status = this.newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, (Object)null);
                            this.doBegin(transaction, definition);
                            this.prepareSynchronization(status, definition);
                            return status;
                        }
                    }
//提交时
processCommit中nested嵌套事务,提交的时候释放掉存储点
   if (status.hasSavepoint()) {
                    if (status.isDebug()) {
                        this.logger.debug("Releasing transaction savepoint");
                    }
//释放存储点
                    status.releaseHeldSavepoint();
}//但是未提交

//回滚时,回滚到存储点,不影响外围事务的提交
 private void processRollback(DefaultTransactionStatus status) {
        try {
            try {
  
                if (status.hasSavepoint()) {
                   status.rollbackToHeldSavepoint();
                   }



嵌套事务:跟随外围事务一起提交,外围事务异常时,会导致内部嵌套事务回滚,因为是同一个事务
Execute within a nested transaction if a current transaction exists,
behave like PROPAGATION_REQUIRED else 外部有事务的话则作为嵌套事务执行,否则跟required一样

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值