SpringJdbc控制事务

一、事务的四大特性

1、原子性:多个修改操作,一起成功执行,或者一起执行失败;

2、一致性:对不同事物操作前后,保证事物的状态一致性,即我增加的数量等于你减少的数量

3、隔离性:是说事务之间操作时彼此不受影响的,即多个角色对同一事物操作,减少彼此受到的影响,

  事务的隔离级别分为:

    读未提交,read-uncommite,会因此脏读,幻读和不可重复度

    读已提交,read-commite,避免了脏读

    重复度,repeatable-read,避免了脏读和幻读

    串行化,serializable,最严格的隔离级别,再次模式下所有的事务按照顺序依次执行,避免以上所有情况。

4、持久性:数据在数据库保存。

 

二、spring事务管理有许多细节需要注意,对整个事务框架接口的整体了解有助于我们理解事务,下面通过了解spring的事务接口来理解spring管理实务的策略

1、其实spring是开放PlatformTranctionManger接口给操作数据库的框架的事务来实现的,他并不直接管理事务,而是提供各种各样对应的事务管理器;具体看下图:

 

 

 

2、PlatformTranctionManger接口提供了三个抽象方法,获取tranctionStatus对象的、事务提交操作和事务回滚方法。从这里可以看出spring并不关系事务的及具体实现方式,只是给你们提供相同的事务处理模型。

 

 

    下面分贝说一下,各个持久层框架具体的事务实现方式

 

一、先从各持久框架的持久成实现类说起

1、sprinJdbc:使用springJdbc进行持久化,事务管理需要使用DataSourceTranctionManger,接下使用xml方式把它装配到应用程序的上下文中:如下

  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
  </bean>
实际上DataSourceTranctionManger是通过调用java.sql.Connection对象来管理事务的,其中Connection通过datasource获去,然后通过connection的commit和rollback方法进行提交或者回滚。
  其实其他持久成框架实现策略都基本相同,不信接着往下看。

2、Hibernate:使用Hibernate进行持久化操作,事务需要使用HibernateTranctionManger,具体引入到程序上下文环境的xml配置为:

  <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
     </bean>
其中HiberanateTranctionManger是通过调用org.hiberanate.Tranction来管理的,然后Tranction是通过HibernateSession获得,最后调用Tranction的commit和rollBack方法来实现。
似曾相识的感觉,
3、springJpa相似,使用JpaTransactionManager来管理事务,下面说下xml引入方式:
  <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
  </bean>
接着JpaTranctionManger需要装配一个Jpa实体管理工厂(javax.persistence.EntityMangerFactory接口的任一实现),然后JpaTranctionManger需要使用工厂产生的JPA EntityManger来构建事务。
4、如果应用程序没有使用以上所述的事务管理,或者是跨越了多个事务管理源(比如两个或者是多个不同的数据源),
此时需要使用 JtaTransactionManager:
  <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="transactionManagerName" value="java:/TransactionManager" />
  </bean>
JtaTransactionManager 将事务管理的责任委托给 javax.transaction.UserTransaction 和javax.transaction.TransactionManager 对象,其中事务成功完成通过UserTransaction.commit() 方法提交,事务失败通过 UserTransaction.rollback() 方法回滚。
三、下面说一下说一下项目中具体的事务配置,一般存在两种方式,配置xml和注解
  前言:

Spring 事务配置
1. 添加事务和AOP的命名空间
2. 开启AOP代理
3. 配置事务管理器
4. 配置事务通知
5. 配置AOP

1、springJdbc
  事务的注解配置:
    <!-- spring 注解式事务声明 -->
    <!-- 事务管理器定义 -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      <property name="dataSource" ref="dataSource"></property>
    </bean> 
    配置注解支持
    <tx:annotation-driven transaction-manager="txManager"/>
    方法上加入事务注解
    Service 方法上在需要添加事务的方法上加入事务注解 
@Override
@Transactional(propagation=Propagation.REQUIRED)
public void saveUser(String userName,String userPwd){
   User user1=new User();
   user1.setUserName(userName);
   user1.setUserPwd(userPwd);
   userDao.saveUser(user1);
   userDao.delUserById(2);
}
备注:默认 spring 事务只在发生未被捕获的 runtimeexcetpion 时才回滚。
spring aop 异常捕获原理:
被拦截的方法需显式抛出异常,并不能经任何处理,这样aop 代理才能捕获到方法的异常,才能进行回滚,默认情况
下 aop 只捕获 runtimeexception 的异常,但可以通过配置来捕获特定的异常并回滚换句话说在 service 的方法中
不使用 try catch 或者在 catch 中最后加上 throw new RunTimeexcetpion(),这样程序异常时才能被 aop 捕获
进而回滚。
 
  事务的xml配置:
  I、
    在spring.xml中配置事务的命名空间
      xmlns:tx="http://www.springframework.org/schema/tx"
      http://www.springframework.org/schema/tx
      http://www.springframework.org/schema/tx/spring-tx.xsd
    配置AOP的命名空间     
      xmlns:aop="http://www.springframework.org/schema/aop"
      http://www.springframework.org/schema/aop
      http://www.springframework.org/schema/aop/spring-aop.xsd
    配置如下:   
      <beans xmlns="http://www.springframework.org/schema/beans"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:context="http://www.springframework.org/schema/context"
            xmlns:tx="http://www.springframework.org/schema/tx"
            xmlns:aop="http://www.springframework.org/schema/aop"
            xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/tx
            http://www.springframework.org/schema/tx/spring-tx.xsd
            http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop.xsd">
  II、设置AOP代理  
    <!-- 开启AOP代理 -->
    <aop:aspectj-autoproxy />
  III、配置事务管理器   
    <!-- 事务管理器定义 -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
         <!--数据源 -->
         <property name="dataSource" ref="dataSource"></property>
    </bean>
  III、配置事务相关通知   
    一般来说增删改方法 propagation=Required,对于查询方法使用 read-only="true"
 
<!-- 配置事务通知   transaction-manager属性表示这个事务通知是哪个事务管理器管理的-->
<!--
   tx:method的属性:
      name是必须的,表示与事务属性关联的方法名(业务方法名),对切入点进行细化。通配符(*)可以用来指定一批关联到相同的事务属性的方法。
      如:'get*'、'handle*'、'on*Event'等等.
      propagation不是必须的,默认值是REQUIRED表示事务传播行为, 包括:
  REQUIRED,SUPPORTS,MANDATORY,NEVER
  REQUIRES_NEW,NOT_SUPPORTED,NESTED
      isolation  不是必须的,默认值DEFAULT,表示事务隔离级别(数据库的隔离级别)
      timeout不是必须的,默认值-1(永不超时),表示事务超时的时间(以秒为单位)
      read-only不是必须的,默认值false不是只读的,表示事务是否只读
      rollback-for不是必须的,表示将被触发进行回滚的 Exception(s);以逗号分开。
          如:'com.foo.MyBusinessException,ServletException'
      no-rollback-for不是必须的, 表示不被触发进行回滚的 Exception(s);以逗号分开。
          如:'com.foo.MyBusinessException,ServletException',任何 RuntimeException 将触发事务回滚
   -->
<tx:advice id="txAdvice" transaction-manager="txManager">
   <!--对以add update delete query开头的所有方法进行事务处理-->
   <tx:attributes>
       <!--定义什么方法需要使用事务 name代表的是方法名(或方法匹配)-->
       <!-- 匹配以 add 开头的所有方法均加入事务 -->
       <tx:method name="add*" propagation="REQUIRED" />
       <!-- 匹配以 update 开头的所有方法均加入事务 -->
       <tx:method name="update*" propagation="REQUIRED" />
       <!-- 匹配以 delete 开头的所有方法均加入事务 -->
       <tx:method name="delete*" propagation="REQUIRED" />
       <!-- 匹配以 query 开头的所有方法均加入事务 --> 
     <tx:method name="query*" read-only="true" />
   </tx:attributes>
</tx:advice>
事务传播行为介绍:
   @Transactional(propagation=Propagation.REQUIRED)
       如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)
   @Transactional(propagation=Propagation.NOT_SUPPORTED)
       容器不为这个方法开启事务
   @Transactional(propagation=Propagation.REQUIRES_NEW)
       不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务
   @Transactional(propagation=Propagation.MANDATORY)
       必须在一个已有的事务中执行,否则抛出异常
   @Transactional(propagation=Propagation.NEVER)
       必须在一个没有的事务中执行,否则抛出异常(与 Propagation.MANDATORY 相反)
   @Transactional(propagation=Propagation.SUPPORTS)
       如果其他 bean 调用这个方法,在其他 bean 中声明事务,那就用事务.
       如果其他 bean 没有声明事务,那就不用事务.
   @Transactional(propagation=Propagation.NESTED)        
    支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。
IIII、配置AOP:
  <!-- aop 切面定义 (切入点和通知) -->
  <aop:config>
     <!-- 设置切入点 设置需要被拦截的方法 -->
  <aop:pointcut expression="execution(* com.xxxx.service..*.*(..) )" id="cut" />
     <!-- 设置通知 事务通知 -->
     <aop:advisor advice-ref="txAdvice" pointcut-ref="cut"/>
     <aop:advisor 
  
posted @ 2020-10-16 17:17  StoBe  阅读(181)  评论(0)    收藏  举报