Spring - 事务

来源:互联网 发布:战争程序员白濑 编辑:程序博客网 时间:2024/06/17 10:15

【1】事务

事务的四个关键属性(ACID)

  • 原子性(atomicity):
    事务是一个原子操作, 由一系列动作组成. 事务的原子性确保动作要么全部完成要么完全不起作用.
  • 一致性(consistency):
    一旦所有事务动作完成, 事务就被提交. 数据和资源就处于一种满足业务规则的一致性状态中.
  • 隔离性(isolation):
    可能有许多事务会同时处理相同的数据, 因此每个事物都应该与其他事务隔离开来, 防止数据损坏.
  • 持久性(durability):
    一旦事务完成, 无论发生什么系统错误, 它的结果都不应该受到影响. 通常情况下, 事务的结果被写到持久化存储器中.

【2】Spring-事务

Spring 既支持编程式事务管理, 也支持声明式的事务管理.

  • 编程式事务管理:

将事务管理代码嵌入到业务方法中来控制事务的提交和回滚. 在编程式管理事务时, 必须在每个事务操作中包含额外的事务管理代码.

  • 声明式事务管理:

大多数情况下比编程式事务管理更好用.
它将事务管理代码从业务方法中分离出来, 以声明的方式来实现事务管理. 事务管理作为一种横切关注点, 可以通过 AOP 方法模块化. Spring 通过 Spring AOP 框架支持声明式事务管理.

  • Spring的核心事务管理对象:

Interface Platform TransactionManager


  • Spring 中的事务管理器的不同实现
1.Class DataSourceTransactionManager:在应用程序中只需要处理一个数据源,而且通过JDBC存取。
    <bean id="transactionManager"        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">        <property name="dataSource" ref="dataSource" />    </bean>
2.Class JtaTransactionManager:在JAVAEE应用服务器上用JTA(Java Transaction API)进行事务管理。3.Class HibernateTransactionManager:用Hibernate框架存取数据库。

【3】用事务通知声明式地管理事务

事务管理是一种横切关注点 !!!

1.<tx:advice> 元素定义

为了在 Spring 2.x 中启用声明式事务管理, 可以通过 tx Schema 中定义的 <tx:advice> 元素声明事务通知, 为此必须事先将这个 Schema 定义添加到 <beans> 根元素中去.

 <tx:advice id="txadvice" transaction-manager="transactionManager" >        <tx:attributes>            <!-- 根据方法名指定事务的属性 -->            <tx:method name="purchase" propagation="REQUIRES_NEW" isolation="READ_COMMITTED"  />            <tx:method name="*"/>        </tx:attributes>    </tx:advice>

2.声明了事务通知后, 就需要将它与切入点关联起来.

由于事务通知是在 <aop:config> 元素外部声明的, 所以它无法直接与切入点产生关联. 所以必须在<aop:config> 元素中声明一个增强器通知与切入点关联起来.

<aop:advisor advice-ref="txadvice" pointcut-ref="txPointCut" />

3.由于 Spring AOP 是基于代理的方法, 所以只能增强公共方法. 因此, 只有公有方法才能通过 Spring AOP 进行事务管理.

【4】事务的传播属性

即当前的事务方法被另外一个事务方法调用时如何使用事务,默认取值为required,即使用调用方法的事务。

    • 七种属性,如下图所示:

这里写图片描述

其中,最常使用的是 REQUIRED 、REQUIRED_NEW。

【5】事务的隔离级别

五种隔离级别:

1.DEFAULT:

这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.
另外四个与JDBC的隔离级别相对应。大部分数据库的默认级别都是READ_COMMITTED

2.READ_UNCOMMITTED:
(读取未提交)
这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据。
这种隔离级别会产生脏读,不可重复读和幻像读。

3.READ_COMMITTED:
(读取已提交)
保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。
可以避免脏读,但不可重复读和幻读的现象仍然可能出现。

4.REPEATABLE_READ:
(可重复读)
这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。
它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。

5.SERIALIZABLE :
(可串行化)
这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。
除了防止脏读,不可重复读外,还避免了幻像读。但性能十分低下!

脏读: 对于两个事物 T1, T2, T1  读取了已经被 T2 更新但 还没有被提交的字段. 之后, 若 T2 回滚, T1读取的内容就是临时且无效的.不可重复读:对于两个事物 T1, T2, T1  读取了一个字段, 然后 T2 更新了该字段. 之后, T1再次读取同一个字段, 值就不同了.幻读:对于两个事物 T1, T2, T1  从一个表中读取了一个字段, 然后 T2 在该表中插入了一些新的行. 之后, 如果 T1 再次读取同一个表, 就会多出几行.

事务的隔离级别要得到底层数据库引擎的支持, 而不是应用程序或者框架的支持.

Oracle 支持的 2 种事务隔离级别:READ_COMMITED , SERIALIZABLE

Mysql 支持 后4 种事务隔离级别.


【6】事务的其他属性

6.1事务的回滚属性

默认情况下只有未检查异常(RuntimeException和Error类型的异常)会导致事务回滚. 而受检查异常不会.

事务的回滚规则可以通过 rollbackFor 和 noRollbackFor 属性来定义. 这两个属性被声明为 Class[] 类型的, 因此可以为这两个属性指定多个异常类.

rollbackFor:  遇到时必须进行回滚noRollbackFor: 一组异常类,遇到时必须不回滚
rollbackFor={UserAccountException.class},noRollbackFor={ArithMeticException.class}

6.2事务的超时和只读属性

由于事务可以在行和表上获得锁, 因此长事务会占用资源, 并对整体性能产生影响.
如果一个事物只读取数据但不做修改, 数据库引擎可以对这个事务进行优化.

  • 超时事务属性: ( timeout=millons )事务在强制回滚之前可以保持多久. 这样可以防止长期运行的事务占用资源.

  • 只读事务属性:(readOnly=true/false) 表示这个事务只读取数据但不更新数据, 这样可以帮助数据库引擎优化事务.

【7】使用注解配置事务

@Transactional(propagation=Propagation.REQUIRES_NEW,            isolation=Isolation.READ_COMMITTED,            rollbackFor={UserAccountException.class},            readOnly=false,            timeout=3)    public void purchase(String userName, int isbn) {    }

【8】使用xml配置事务

<!-- *************1.配置事务管理器******************* -->    <bean id="transactionManager"         class="org.springframework.jdbc.datasource.DataSourceTransactionManager">        <property name="dataSource" ref="dataSource" />    </bean>    <!-- *************2.配置事务属性 *********************-->    <tx:advice id="txadvice" transaction-manager="transactionManager" >        <tx:attributes>            <!-- 根据方法名指定事务的属性 -->            <tx:method name="purchase" propagation="REQUIRES_NEW" isolation="READ_COMMITTED"  />            <tx:method name="checkout" propagation="REQUIRED" isolation="READ_COMMITTED"  />            <tx:method name="get*" read-only="true"/>            <tx:method name="find*" read-only="true"/>            <tx:method name="*"/>        </tx:attributes>    </tx:advice>    <!-- ***3.配置事务切入点,以及把事务切入点和事务属性关联起来 -->    <aop:config>        <aop:pointcut expression="execution(* com.web.xml.service.*.*(..))" id="txPointCut"/>        <!--  配置增强通知,关联advice与pointcut  -->        <aop:advisor advice-ref="txadvice" pointcut-ref="txPointCut" />    </aop:config>
0 0
原创粉丝点击