spring事务管理

事务回顾

1、事务的特性:

①原子性:事务是不可分割的,要么都成功,要么都失败

②一致性:事务发生前和事务发生后,事件的总数状态不变。(例如:转账操作)

③隔离性:多个事务在执行时可能会收到彼此的影响,所以采用了不同的隔离级别来避免这种影响

④持久性:事务一旦提交,它对数据的改变就是永久性的,即使数据库发生故障也不应该有什么影响。

2、多个事务造成的影响

①脏读:一个事务读取到了另一个事务还没有提交的数据(脏数据),导致了查询数据不一致的效果

②不可重复读:在同一个事务中,读取到了已经提交事务的数据,导致数据查询结果不一致。

③幻读:一个事务读取到了另一个事务提交的insert数据,导致查询出原来没有的数据。

3、幻读和不可重复读的区别

幻读是指读到了其他已经提交事务的新增数据,不可重复读是指读到了已经提交事务的更改数据(更改或者删除)

4、解决不可重复读的幻读的策略

》防止不可重复读到更改数据,只需要对操作的数据添加行级锁,阻止操作重的数据发生变化;

》防止读到新增数据,往往需要添加表级锁(将整张表锁定),防止新增数据(orcale使用多版本数据的方式实现)

 

Spring事务管理

spring提供了两种事务管理方式,一种是编程式事务,另一种是基于AOP的声明式事务,可以让程序从事务代码中解放出来。

不仅如此,Spring为事务管理提供了一致的编程模板,在高层次建立了统一的事务抽象。也就是说,不管是选择Spring JDBC、Hibernate还是MyBatis,Spring都可以让用户用统一的编程模型进行事务管理。

1、事务管理的抽象接口

Spring事务管理高层抽象主要包括3个接口,如下图所示:

①PlatformTransactionManager(平台事务管理器)

事务管理器是真正用来管理事务的,比如说事务的提交、回滚。对于不同的持久化框架,Spring提供了不同的平台事务管理器,当然最长用的就是spring Jdbc的TransactionManager。

②TransactionDefinition(事务定义信息)

描述事务的隔离级别、超时时间、是否为只读事务和事务传播规则等控制事务具体行为的事务属性,这些属性可以通过xml配置或者注解描述提供,也可通过手工编程设置。

》Isolation(隔离级别)

  • default: :使用底层数据库默认的隔离级别
  • read_uncommited :允许读取还未提交的并发事务还没提交的数据
  • read_commited :允许读取并发事务提交后的数据
  • repetable_read: :对相同事务的读取保证是一致的。
  • serializeable :事务串行进行,安全但是慢。

》propagation(传播行为)

主要解决业务层方法之间的相互调用问题,到底使用那个方法中的事务,事务是如何进行传递问题。

  • propagation_required:必须有事务,如果没有,就新建一个
  • propagation_supports:事务可有可没有,如果没有,则在非事务的环境中执行
  • propagation_mandatory:使用当前的事务,如果当前没有事务,抛出异常
  • propagation_required_new:不管有没有事务,都会新进一个事务,原先的会被挂起。
  • propagation_not_supported:如果当前存在事务,就把当前事务挂起
  • propagation_never:以非事务执行,如果当前存在事务,则抛出异常
  • propagation_nested:如果当前存在事务,则在嵌套事务内执行,如果当前没有事务,则
  • 与porpagation_required类似。

》read-only(只读事务)

只读事务不修改任何数据,也就是说不能有update、delete、insert

》timeout(事务超时)

事务在超时前能运行多久。超时时间后,事务回滚。

③TransactionStatus(事务运行状态)

代表了一个事务的具体运行状态。事务管理器可以通过该接口获取事务运行期的状态信息,也可以通过该接口间接地回滚事务。该接口继承与SavepointManager接口,该接口下有如下方法:

  • createSavepoint():创建一个保存点对象。
  • realseSavepoint():释放一个保存点。如果事务提交,所有保存点将会自动释放。
  • rollbackSavepoint():将事务回滚到特定的保存点上,被回滚的保存点将会自动释放

 

这三个接口的关系

Spring在进行事务管理的时候,会首先查看事务定义的信息(比如,使用了什么隔离级别,什么传播行为),然后通过平台事务管理器真正的去管理事务,在进行事务的管理的过程中,将产生相应的状态保存在了TransactionStatus中

 

Spring支持两种方式事务管理

1、编程式的事务管理

Spring提供了TransactionTemplate模板类来支持编程式事务,TransactionTemplate和那些持久化模板类一样是线程安全的,所以可以在多个业务类中共享TransactionTemplate实例来进行事务管理

如下,已一个简单的转账案例作为说明,如果转账过程中抛出异常,转账操作将不会完成

<!--基于数据源的事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>

<!--声明事务模板类-->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
    <property name="transactionManager" ref="transactionManager"/>
</bean>
/**
 * 编程式的事务管理
 * @return void
 */
public void transforAccount(final String out, final String in , final Double money){
    transactionTemplate.execute(new TransactionCallbackWithoutResult() {
        @Override
        protected void doInTransactionWithoutResult(TransactionStatus status) {
            accountDao.outMoney(out,money);
            int i=1/0;
            accountDao.inMoeny(in,money);
        }
    });
}

2、使用xml配置声明式事务管理

Spring是通过AOP实现的。对代码的侵入性最小,可以让事务管理代码完全从业务代码中移除,非常符合非侵入式轻量级容器的理念。Spring在基于schema的配置中添加了一个tx命令空间,在配置文件中以明确结构化的方式定义事务属性,配合切面工具,使得业务类方法事务的配置得到极大的简化

<!-- 事务增强 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <!-- 对那些方法进行增强 -->
        <tx:method name="save*" propagation="REQUIRED"  />
        <tx:method name="insert*" propagation="REQUIRED" />
        <tx:method name="add*" propagation="REQUIRED" />
        <tx:method name="create*" propagation="REQUIRED" />
        <tx:method name="delete*" propagation="REQUIRED" />
        <tx:method name="update*" propagation="REQUIRED" />
        <tx:method name="find*" propagation="SUPPORTS" read-only="true" />
        <tx:method name="select*" propagation="SUPPORTS" read-only="true" />
        <tx:method name="get*" propagation="SUPPORTS" read-only="true" />
    </tx:attributes>
</tx:advice>

<!-- 使用切点表达式定义目标方法 -->
<aop:config>
    <!--通过aop定义事务增强切面,并引入事务增强-->
    <aop:advisor advice-ref="txAdvice" pointcut="execution(* cn.*.service..*.*(..))" />
</aop:config>
@Service
public class AccountService {
    @Autowired
    private AccountDao accountDao;

    public void updateAccount(final String out, final String in , final Double money){
        accountDao.outMoney(out,money);
        int i=1/0;
        accountDao.inMoeny(in,money);
    }
}

3、使用注解配置声明式事务(@Transaction)

Spring还提供了基于 注解的事务配置,只需要在同期总配置基于注解的事务增强驱动,即可启动基于注解的声明式事务。

<!--基于数据源的事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>

<!--开启注解事务,对标注@Transaction注解的Bean进行加工处理,织入事务管理切面-->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="false" order="1"/>
@Transactional
@Repository
public class AccountDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
   
    public void outMoney(String out,Double money){
        String sql="update account set money=money - ? where name = ?";
        jdbcTemplate.update(sql,money,out);
    }
    
    public void inMoeny(String in,Double money){
        String sql="update account set money=money + ? where name = ?";
        jdbcTemplate.update(sql,money,in);
    }
}

①<tx:annotation-driven>注解驱动属性说明

transaction-manager:引用指定的事务管理器

proxy-target-class:为true,表示通过cglib创建子类的方式来代理业务类;为false,表示使用jdk动态代理的方式。

order:如果业务类除事务切面外,还需要织入其他的切面,可以通过该属性来空值目标连接点的织入顺序。

② @Transaction注解的作用位置:

可被应用于接口定义和接口方法、类定义和类的public方法上。但是注解是不能继承的,所以在接口中添加的注解是不会被业务实现类继承的,所以一般添加在具体的业务实现类上。

  • 类级别的注解只对public的方法起作用。

Spring的事务管理是基于接口管理或动态字节码技术的。对于基于动态代理的AOP事务来说,代理的方法只能是public或public final修饰的,不能使用static修饰。对于基于CGLIB字节码动态代理的方案,由于final、static、private修饰符的方法子类都不能覆盖,所以无法实施AOP 增强。

  • 方法上的注解会覆盖类上的注解

 

③ @Transaction注解的默认属性:

事务隔离级别:isolation_default

事务传播行为:propagation_required

读写事务属性:读/写事务

超时时间: 依赖于底层的事务系统的默认值

回滚设置: 任何运行期异常引发回滚,任何检查性异常不会引发回滚

总结:

  • Spring默认的事务回滚规则为:“运行期异常回滚,检查性异常不会滚”。
  • Spring的事务管理是Spring AOP技术的典型应用。事务管理作为切面织入目标业务方法的周围,使得业务方法完全从事务代码中解脱出来,代码的复杂度大大降低。
  • Spring的事务配置相对来说比较简单,主要提供两方面的信息:第一,切点的信息,用于定位实施事务切面的业务类方法;其二,控制事务行为的事务属性,这些属性包括隔离级别、事务的传播行为等
  • Spring的传播机制可以很好的应对事务方法嵌套调用的情况。
  • 因为单例对象不存在线程安全问题,所以经过事务管理增强的单实例Bean可以很好的工作在多线程环境中
  • Spring AOP事务增强有两个方案:一个是基于接口的动态代理,另一个是基于CGLIB董改生成子类的代理。注意有些特殊的方法不能被Spring AOP代理,所以无法享受事务增强
  • 在使用Spring JDBC如何直接获取Connection,可能会造成连接泄露。应尽量使用DataSourceUtils获取数据连接
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值