Spring 声明式事务

    <!--基于xml的事务配置;需要aop和tx名称空间  -->
     <!-- transactionManager事务切面 -->
     <!-- aop配置切面 -->
     <aop:config>
        <!-- 指定事务管理器要切入哪些方法进行事务控制 -->
         <aop:pointcut expression="execution(* com.lamsey.service.*.*(..))" id="txPoint"/>
         <!-- aop:advisor,建议:pointcut-ref:使用指定的切入点表达式切入事务 -->
         <aop:advisor advice-ref="myTxAdvice" pointcut-ref="txPoint"/>
     </aop:config>
     <!-- 使用tx名称空间和配置(事务建议,事务属性,事务增强) ,事务方法怎么执行
     id="myTxAdvice"自己进行命名,方便其它引用
     transaction-manager="transactionManager":指定配置哪个事务管理器
     -->
     <tx:advice id="myTxAdvice" transaction-manager="transactionManager">
         <tx:attributes>
             <!-- 指定事务方法 :代表所有方法是事务方法-->
             <tx:method name="*"/> 
             <tx:method name="checkout" rollback-for="java.lang.Exception"/>
             <tx:method name="updatePrice" propagation="REQUIRES_NEW"/>
             <!-- 所有以get开头的方法,认为其可以优化,所以 -->
             <tx:method name="get*" read-only="true"/>
         </tx:attributes>
     </tx:advice>

 

 

1、事务的概述:

在JavaEE企业级开发的应用领域,为了保证数据的完整性一致性,必须引入数据库事务的概念,所以事务管理是企业级应用程序开发中必不可少的技术。

●事务就是一组由于逻辑上紧密关联而合并成一个整体(工作单元)的多个数据库操作,这些操作要么都执行要么都不执行

四个特性:

原子性、一致性、隔离性、持久性

2、Spring事务管理

2.1编程式事务

1)获取连接

2)设置为非自动提交

3)提交

4)执行失败就回滚

5)关闭相关资源

可以将事务控制做成一个事务切面

2.2声明式事务

大多数情况下声明式事务比编程式事务管理更好:它将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。

事务管理代码的固定模式作为一种横切关注点,可以通过AOP方法模块化,进而借助Spring AOP框架实现声明式事务管理

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

2.3     Spring提供的事务管理器

2.4事务管理器:

Spring的核心事务管理抽象是PlatformTransactionManager(接口)

2.5事务管理器的主要实现

①DataSourceTransactionManager:在应用程序中只需要处理一个数据源,而且通过JDBC存取。

②JtaTransactionManager:在JavaEE应用服务器上用JTA(Java Transaction API)进行事务管理

③HibernateTransactionManager:用Hibernate框架存取数据库

 

3、快速的进行事务控制;
1)、搭建事务的基础环境
          1、导包
          2、写配置;
          3、创建对应的测试表
2)、如何快速进行事务控制;
          1、在xml中配置事务切面
 
<!--3、配置事务切面;控制住连接池  -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="comboPooledDataSource"></property>
    </bean>
          2、配置开启基于注解的事务控制
<tx:annotation-driven/>
          3、给事务方法上加注解
@Transactional
 
事务控制细节

 @Transactional的属性

 @Transactional(noRollbackForClassName="java.lang.ArithmeticException")

* 1、控制异常回滚机制的;
     * noRollbackFor:指定哪些异常可以不回滚;
     * 运行时异常本来是都回滚的;
     * 写法:noRollbackFor=ArithmeticException.class
     *
     * noRollbackForClassName
     * 写法:noRollbackForClassName="java.lang.ArithmeticException"
     *
     *
     *
     * rollbackFor:指定哪些异常回滚;
     * 默认哪些异常回滚?
     *      运行时异常:(不受检异常);默认都回滚
     *      编译时异常:(受检异常);(必须处理,要么try-catch,要么在方法上throws)默认都不回滚;
     *              
     * 效果:数学异常回滚了,文件没找到异常不回滚
     * 写法:
     *      多个异常:rollbackFor={FileNotFoundException.class,NullPointerException.class}
     *      单个异常:rollbackFor=FileNotFoundException.class 
     * rollbackForClassName:
     * 写法:rollbackForClassName={"java.io.FileNotFoundException"}
     *
     *
     *
     *
     * readOnly:只读;
     * true:代表当前事务是一个只读事务;查询就可以进行优化,加快速度;
     *      如果某个事务真的是只读的,再加这个否则报错
     *
     * false:默认,代表当前事务读写操作都会有,不会有只读优化;
     *
     *
     *
     * timeout:超时;指就是从事务开始操作,到事务dao最后一次完成
     * 我们可以控制这个事务必须在多少秒内完成,如果没有完成,自动中断事务,回滚到之前状态
     * timeout=3;
事务控制的两个重点问题
1、隔离级别
  1. 事务的隔离级别
    1. 数据库事务并发问题
假设现在有两个事务:Transaction01Transaction02并发执行。
脏读
      [1]Transaction01将某条记录的AGE值从20修改为30
      [2]Transaction02读取了Transaction01更新后的值:30
      [3]Transaction01回滚,AGE值恢复到了20
      [4]Transaction02读取到的30就是一个无效的值。
不可重复读
      [1]Transaction01读取了AGE值为20
      [2]Transaction02AGE值修改为30
      [3]Transaction01再次读取AGE值为30,和第一次读取不一致。
幻读
      [1]Transaction01读取了STUDENT表中的一部分数据。
      [2]Transaction02STUDENT表中插入了新的行。
      [3]Transaction01读取了STUDENT表时,多出了一些行。
    1. 隔离级别
数据库系统必须具有隔离并发运行各个事务的能力,使它们不会相互影响,避免各种并发问题。一个事务与其他事务隔离的程度称为隔离级别SQL标准中规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性就越好,但并发性越弱。
读未提交READ UNCOMMITTED
允许Transaction01读取Transaction02未提交的修改。
读已提交READ COMMITTED
         要求Transaction01只能读取Transaction02已提交的修改。
可重复读REPEATABLE READ
         确保Transaction01可以多次从一个字段中读取到相同的值,即Transaction01执行期间禁止其它事务对这个字段进行更新。
串行化SERIALIZABLE
         确保Transaction01可以多次从一个表中读取到相同的行,在Transaction01执行期间,禁止其它事务对这个表进行添加、更新、删除操作。可以避免任何并发问题,但性能十分低下。
⑤各个隔离级别解决并发问题的能力见下表
 
脏读
不可重复读
幻读
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ
SERIALIZABLE
⑥各种数据库产品对事务隔离级别的支持程度
 
Oracle
MySQL
READ UNCOMMITTED
×
READ COMMITTED
REPEATABLE READ
×
(默认)
SERIALIZABLE
 
 

 

 

修改MySQL隔离级别
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}

如:SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

查询MySQL的隔离级别
SELECT @@global.tx_isolation; //查询全局隔离级别
SELECT @@session.tx_isolation;//查询当前会话隔离级别 
SELECT @@tx_isolation;//同上


事务操作
开启事务  start transaction;
提交事务  commit;
回滚事务  rollback;

4、 事务的传播行为

当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。

事务的传播行为可以由传播属性指定。 

事务传播属性可以在@Transactional注解的propagation属性中定义。

 

传播:在共用一个事务的情况下大事务的属性配置会传播给小事务。

 注解式事务声明步骤:

1)、配置事务切面,控制住连接池。

2)、配置开启基于注解的事务控制 

3)、在业务方法中加注解

<!-- 配置事务切面,控制住连接池 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 2、配置开启基于注解的事务控制 -->
    <!--transaction-manager定义事务管理的对象-->
    <tx:annotation-driven transaction-manager="transactionManager"/> 

5、基于XML的事务配置(重点)

 

 

posted @ 2017-07-26 17:00  lamsey16  阅读(152)  评论(0编辑  收藏  举报