Spring 事务管理

事务的基础知识

将Spring中的事务之前,先介绍一点事务的基本知识,方便后续对Spring中事务管理的理解

什么是事务?为什么要使用事务?

事务就是用来控制对数据资源进行访问的一组操作,保证事务前后,数字资源的状态都是正确的,举个例子,A转账给B 300元,此时需要从A的账户里扣除300元,然后给B的账户添加300元,此时要是给A扣款成功了,但是!给B添加300的操作失败了,那么现在A的账户被扣掉了300元,而B账户却没有增加300元,那么这个操作显然是不正确的,所以此时必须使用事务,来确保,就算B收款失败,而这300元也应该退还给A

事务4大特性
特性说明
原子性一个事物中的所有操作看成1个原子操作,同时成功,或同时失败
一致性事务操作对象的前后状态应该一致
持久性一旦事务提交操作,对数据做的操作无法更改
隔离性规定各种事务之间的相互影响程度
隔离级别
隔离级别说明
ReadUncommitted(读未提交)隔离级别最低,会产生脏读,不可重复读,幻读不可避免
ReadCommitted(读已提交)可避免脏读 但不可重复读,幻读不可避免,数据库的默认级别
RepeatedRead(重复读)
Serializable(串行读取)隔离级别最高,可以避免脏读,不可重复读,幻读,但是执行效率太低,一般不考虑
脏读,幻读,不可重复读
脏读:事务A读取到了事务B中尚未提交的数据,但是加入B回滚了,那么A读取到的B中的数据就是脏数据

不可重复读:同一个事务在整个过程中,前后两次读取同一数据,前后不一致问题

幻读:同一个事务在多次查询过程中,针对的总记录数量不同,比如第一次读取大于30岁的员工有100,同一事务过程中第二次读,发现大于30岁的员工只有25个了,这前后记录总数不一致就导致了幻读
Spring事务管理
Spring事务的设计理念

事务管理的关注点 和 数据访问关注点 分离

JDBC的局部事务控制是由JDBC的Connection来完成的,也就是,必须使用同一个Connection来进行数据操作,才能实现局部事务。在事务开始前获取一个Connection,然后将该Connection绑定到当前线程,之后的数据访问对象都使用该同一Connection进行操作

事务的传播行为
传播行为说明
Requried(常用)当前存在事务,就加入,不存在事务就创建一个事务
Support存在事务就加入,不存在就直接执行
RequiredNew(常用)不管当前是否存在事务,都创建一个新事务
Never永远不需要当前事务,当前有事务就抛出异常
Nested当前存在事务,则在当前存在事务的一个嵌套事务种执行

A方法调用了B方法和C方法,当B方法传播行为被设置成 Required的时候,B方法会直接加入到A方法的事务种,设置C的传播行为为RequiredNew,就是不管A是否有开启事务,B都重新开启一个新事务

Spring种对事务做了统一支持:
  PlatformTransactionManager:核心类,所有事务处理的顶级父类,每种事务的实现方式都是该类的实现类
  TransactionDefinition:可以用来指定事务属性,可以指定的属性有:
     1.事务的隔离级别
     2.事务的传播行为
     3.事务的过期时间
     4.是否为只读(设置为true会对查询语句进行优化提高效率,不能有insert,update,delete类型语句)
  TransactionTemplate:Spring提供的针对于编程式事务管理的模板方法类
  TransactionAttribute:针对AOP进行声明式事务管理的场合,继承自 TransactionDefinition,提供了一个rollbackOn(Throwable ex),可以通过声明的方式,指定业务出现某些错误的情况下回滚事务。
  TransactionStatus: 定义事务处理中的事务状态,在编程式事务中使用

PlatformTransactionManager的子类DatasourceTransactionManager:

了解几个概念:    
    tansaction object,承载当前事务的必要信息,DatasourceTransactionManager会根据transaction object来处理当前事务
    TransactionSynchronization,可以注册到事务处理中的回调接口,可以当作式事务的监听器
    TransactionSynchronizationManager,管理TransactionSynchronization,Spring中会将具体的事务资源,比如Connection绑定到该类

编程式事务

使用PlatformTransactionManager不同的实现类,就可以直接用编程的方式来实现事务,使用TransactionTemplate类来对PlatformTransactionManager进行模板化封装,可以将事务操作中很多相同的步骤同一封装。

直接使用PlatformTransactionManager进行事务管理

 PlatformTransactionManager transactionManager = new DataSourceTransactionManager();
   public void testPlatformTransaction(){
       DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
       definition.setTimeout(20);
       //还可以设置其他属性
       TransactionStatus status = transactionManager.getTransaction(definition);
       try{
       }catch (RuntimeException e){
           transactionManager.rollback(status);	//回滚
       }
   }

使用TransactionTemplate进行事务管理

TransactionTemplate template = new TransactionTemplate();
    Object result = template.execute(new TransactionCallback<Object>() {
        @Override
        public Object doInTransaction(TransactionStatus transactionStatus) {
            Object result = null;
            //这里可以写事务处理逻辑...
            return result;
        }
    });
声明式事务

声明式事务才是Spring事务管理的核心精髓,也是使用最多的,声明式事务管理于SpirngAOP进行结合,只需要少量的编码就可以完成事务管理相关工作,虽然事务处理的粒度没有编程式事务那么细,但是声明式事务完全不依赖于业务代码,对业务代码没有任何入侵

有XML声明式和注解声明式,这里只将注解声明式,只需要是用@Transactional,对所需要进行事务管理的方法或类进行注解,如果注解的对象级别,那么对象中的方法将会继承对象级别上的事务,也就是所有方法都会加上事务,建议不要这么做,因为这样会拖慢执行效率,只在有必要的方法上加上@Transactional才是更推荐的写法。@Transactional只是一个声明,具体的事务实现需要通过反射读取所有需要被@Transactional表明的方法,并根据这些信息,才能使事务声明有效

使用@Transactional的方法

@Transactional(propagation = Propagation.REQUIRED,readOnly = true,timeout = 20)
    public void testTransactional(){
        //直接写数据处理逻辑即可
    }

根据反射获取注解,并加入事务处理的伪代码

 public void getAllMarkedByTransactional() {
        try {
            Method method = new Demo1().getClass().getDeclaredMethod("testTransactional",null);
            //判断是否为Transactional注解
            boolean isMarked = method.isAnnotationPresent(Transactional.class);
            if(!isMarked){
                //没有被@Transaction注解,直接执行方法即可
            }

            Transactional info = method.getAnnotation(Transactional.class);
            TransactionTemplate transactionTemplate = new TransactionTemplate();
            //设置事务传播行为
            transactionTemplate.setTransactionManager(transactionManager);
            transactionTemplate.setPropagationBehavior(info.propagation().value());
            transactionTemplate.setReadOnly(info.readOnly());
            transactionTemplate.execute(new TransactionCallback<Object>() {
                @Override
                public Object doInTransaction(TransactionStatus transactionStatus) {
                    Object result = null;
                    //这里可以写事务处理逻辑...
                    return result;
                }
            });
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } finally {
        }
    }

其实上面的代码根本不用我们自己写,Spring已经提供好了

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值