spring 事务

spring事务的五个参数来控制管理事务:传播行为、隔离级别、只读提示、超时间隔、回滚规则。

(1)Spring 事务的传播行为:控制调用方和被调用方的事务边界

传播行为回答的问题:一个新事务是应该被启动还是被挂起,以及一个方法是否应该在事务的上下文中运行。

Propagation-required :支持当前事务,如果当前没有事务,则新建一个事务;

Propagation-supports :支持当前事务,如果当前没有事务,则以非事务方式执行;

Propagation-mandatory :支持当前事务,如果当前没有事务,则抛出异常;

Propagation-requires_new :新建事务,如果当前有事务,把当前事务挂起;

Propagation-not_supported :以非事务方式执行,如果当前有事务,把当前事务挂起;

Propagation-never :以非事务方式执行,如果当前有事务,则抛出异常。

PROPAGATION_NESTED:在一个嵌入的事物中执行,否则同PROPAGATION_REQUIRED

(2)隔离级别:定义一个事务受其他并发事务影响的程度。

首先了解并发操作可能导致的问题:

Dirty read -- 脏读,(修改且未提交引起)

张三的工资为5000,事务A中把他的工资改为8000,但事务A尚未提交。与此同时,事务B正在读取张三的工资,读取到张三的工资为8000。随后,事务A发生异常,而回滚了事务。张三的工资又回滚为5000。最后,事务B读取到的张三工资为8000的数据即为脏数据,事务B做了一次脏读。

(大部分数据库缺省的事物隔离级别都不会出现这种状况)

Norepeatable read --- 不可重复读 ,(修改引起)

在事务A中,读取到张三的工资为5000,操作没有完成,事务还没提交。

与此同时,事务B把张三的工资改为8000,并提交了事务。随后,在事务A中,再次读取张三的工资,此时工资变为8000。在一个事务中前后两次读取的结果并不致,导致了不可重复读。

(大部分数据库缺省的事物隔离级别都不会出现这种状况) .

Phantom read -- 幻读,(添加新记录引起)

A目前工资为5000的员工有10人,事务A读取所有工资为5000的人数为10人。此时,事务B插入一条工资也为5000的记录。这是,事务A再次读取工资为5000的员工,记录为11人。此时产生了幻读。

(大部分数据库缺省的事物隔离级别都会出现这种状况,此种事物隔离级别将带来表级锁)

说明 :Oracle数据库缺省的事物隔离级别已经保证了避免脏读和不可重复读。但可能会幻读,避免幻读需要加表级锁,Oracle缺省行级锁。在基于Spring的事物配置中一定要慎重使用ISOLATION_SERIALIZABLE的事物隔离级别。这种配置会使用表级锁,对性能影响巨大。一般没有特殊需要的话,配置为使用数据库缺省的事物隔离级别便可。

隔离级别:

Isolation_default:使用数据库默认的隔离级别;

Isolation_read_uncommitted :允许读未提交的更改,可导致脏读、不可重复读、幻读。

Isolation_read_committed :保证一个事务提交后的数据才能被另一个事务读取,可避免脏读,不能避免不可重复读、幻读。

Isolation_repeatable_read:对相同自动的多次读取结果是一致的。可避免脏读、不可重复读,不能避免幻读。

Isolation_serializable :事务处理为顺序执行。

(3)只读提示:

如果一个事务只对后端数据库执行读操作,那么数据库可以利用事务只读特性,采用优化措施。由此可见,只读的优化措施是在一个事务启动时由后端数据库实施的。

因此只读可能启动一个新事务的的传播行为(required,requires_new,NESTED)有效。

(4)事务超时

设置事务执行的最长时间,超时后事务会回滚。

因为超时时针在事务开始时启动,所以事务超时只对启动一个新事务的的传播行为(required,requires_new,NESTED)有效。

(5)回滚规则

定义哪些异常会引起回滚,哪些不会。默认下为:事务只有在出现运行时异常(runtime exception,也就是 unchecked exception)时回滚,而出现受阻异常(checked exception)时不回滚。不够可以在声明事务时设置。

spring申明式事务配置:1、xml声明事务;2、注释驱动事务

1、xml声明事务:

第一步:定义一个事务AOP通知:

<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
        <tx:method name="search*" propagation="SUPPORTS" read-only="true"/>
        <tx:method name="check*" propagation="SUPPORTS" read-only="true"/>
        <tx:method name="save*" propagation="REQUIRED"
            rollback-for="cn.com.base.exception.OperationException" />
        <tx:method name="update*" propagation="REQUIRED"
            rollback-for="cn.com.base.exception.OperationException" />                
        <tx:method name="delete*" propagation="REQUIRED" rollback-for="cn.com.base.exception.OperationException" />
        <tx:method name="*" propagation="REQUIRED" />
    </tx:attributes>
</tx:advice>

tx:method 属性包括:isolation ,no_rollbacke_for ,propagation,read_only,rollback_for,timeout

第二步:定义一个事务切面,即应该在哪些类哪些方法上进行事务切入

<aop:config>
    <aop:pointcut id="point-service"
        expression="execution(* cn.com.staff.*.service.*.*(..))" />
    <aop:advisor advice-ref="txAdvice" pointcut-ref="point-service" />
</aop:config>

2、注释驱动事务

第一步:xml配置文件中增加配置,

<tx:annotation-driven transaction-manager="transactionManager"/>

<tx:annotation-driven>配置元素告诉spring在类层面或方法层面检查应用程序上下文的所以bean,并且寻找标注了@Transactional的bean,对于标注了@Transactional 的所以bean,<tx-annotation-driven>将自动把事务通知的内容通知给它。这个通知的事务参数将由@Transactional注释的参数来定义

第二步:@Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上

Spring团队的建议是你在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上

@Service
 @Transactional(rollbackFor=Exception.class)   //对当前类的所有方法起作用
 @SuppressWarnings("serial")
 public class ButtonBo extends GlobalBo {
  ....
  @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true) //具体方法上
    public Button findButton(String buttonid) throws BaseException {
     return hibernateEntityDao.get(Button.class, buttonid);
   }
 }
原文地址:https://www.cnblogs.com/mains/p/3390865.html