Spring---事务管理

一.数据库事务基础知识

1.何为数据库事务

事务必须同时满足四个特性(ACID):原子性、一致性、隔离性和持久性。

原子性:表示组成一个事务的所有数据操作是一个不可分割的原子单元,只有所有操作都执行成功,整个事务才会提交。

一致性:事务操作成功后,数据库所处的状态和它的业务规则是一致的,即数据不会被破坏。

隔离性:在并发数据操作时,不同的事务拥有各自的数据空间,他们的操作不会对对方产生干扰。

持久性:一旦事务提交成功后,事务中所有的数据操作都必须持久化到数据库中。

2.数据并发的问题

数据并发导致的问题有:脏读、不可重复读、幻象读、第一类丢失更新、第二类丢失更新。

脏读、不可重复读、幻读三个问题都是由于事务A对数据进行修改、增加,事务B总是在做读操作。而丢失更新问题则是由于两事务都在对数据进行修改。

3.数据库锁机制

数据库通过锁的机制解决并发访问问题。按锁定的对象的不同,可分为表锁定和行锁定;从并发事务锁定的关系上看,可以分为共享锁定和独占锁定。

1)表共享锁定:通过 lock table in share mode 语句显示获得

2)行共享锁定:通过 lock table in row share mode 语句显示获得,或者通过 select for update 

3)表独占锁定:通过 lock table in exclusive  mode 语句显示获得 

4)行独占锁定:通过 lock table in row exclusive mode 语句显示获得,或者通过 insert、update、delete

5)表共享行独占锁定:通过 lock table in share row exclusive  mode 语句显示获得  

4.事务隔离级别

虽然数据库为用户提供了锁的DML操作方式,但直接使用锁管理师非常麻烦的,因此数据库为用户提供了自动锁机制,只要用户指定会话的事务隔离级别,数据库就会分析事务中的SQL语句,然后自动为事务操作的数据资源添加合适的锁。

 ANNSI/ISO SQL 92标准定义了4个等级的事务隔离级别。read uncommitted  <  read committed<   repeatable read <   serializale

 

注意:并不是所有的数据库都支持事务,即使数据库支持事务,也并非支持所有的事务隔离级别。

二.Spring为不同的持久化框架提供了不同的事务管理器实现类。

持久层技术                                                            事务管理器类实现类

Spring JDBC 和 iBatis                                           DataSourceTransactionManager

JPA                                                                       JpaTransactionManager

Hibernate                                                              HibernateTransactionManager

JTA                                                                       JtaTransactionManager---------具有多个数据源的全局事务使用该事务管理器

JDO                                                                      org.springframework.orm.jdo.IdoTransactionManager   不常用

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

编程式事务管理:通过代码控制事务的提交和回滚。

声明式事务管理:将事务管理代码从业务方法中分离出来,通过配置来实现事务管理。核心基于AOP实现。

1.编程式的事务管理

jdbc代码:conn.setAutoCommite(false);

Hibernate代码:session.beginTransaction();//开启事务

2.使用xml配置声明式事务

实现步骤:
1.引入spring-sop相关的4个jar文件
2.引入aop名称空间(xml配置方式需要引入)
3.引入tx名称空间(事务方式必须引入)

例如,我们想通过spring的声明事务来让以下接口的delete()和update()方法拥有写事务的能力,而其他方法只拥有读事务的能力。

package com.testMyBatis.service;
public class BookService { private BookDao bookdao; public List<Book> getAllBooks() { return bookdao.getAllBooks(); } public Book getBookById(int id) { return bookdao.getBookById(id); }

public int delete(int id) { return bookdao.delete(id); }

public int update(Book entity) { return bookdao.update(entity); } }

 Spring基本配置

    <!--配置事务管理器(不同的持久类对应不同的事物管理器实现类) -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource"></property>
    </bean>   

1)使用原始的TransactionProxyFactoryBean

    <!--1.需要实现事务增强的目标业务Bean-->
    <bean id="BookServiceTarget"  class="com.testMyBatis.service.BookService">
        <property name="bookdao" ref="bookdao"></property>
    </bean>
    <!--2.使用事务代理工厂类为目标业务Bean提供事务增强-->
    <bean id="BookService"  class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="transactionManager" ref="transactionManager"></property>
        <property name="target" ref="BookServiceTarget"></property>
        <property name="transactionAttribubutes" >
             <props>
                  <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop><!--以get为前缀的方法拥有只读事务属性-->
                  <prop key="*">PROPAGATION_REQUIRED</prop><!--目标bean中所有方法拥有可写事务属性-->
             </props>
        </property>
    </bean>

2)基于tx/aop命名空间的配置

   <!--配置事务增强(如何管理事务?)-->    
<tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="get*" read-only="true"/> <tx:method name="delete" rollback-for="Exception"/> <tx:method name="update" /> </tx:attributes> </tx:advice>

<!--AOP配置,拦截那些方法(切入点表示式)+应用上面的事务增强配置-->
<aop:config> <aop:pointcut id="serviceMethod" expression="execution("com.testMyBatis.service.BookService.*(..)")"/> <aop:advisor advice-ref="serviceMethod" advice-ref="txAdvice"/> </aop:config>

 注意:<tx:method>元素属性有:

             name:必须属性,与事务属性关联的方法,可使用通配符*

             propagation:非必需元素,事务传播行为,默认值是REQUIRED

             isolation:非必需元素,事务隔离级别,默认值是DEFAULT

             timeout:非必需元素,超时,默认值是-1

             read-only:非必需元素,读写事务,默认值是false

             rollback-for:非必需元素,回滚,默认值是所有运行期异常都回滚

             no-rollback-for:非必需元素,默认值是所有检查型异常不回滚

3.使用注解配置声明式事务

1.在需要添加事务控制的地方,即业务类使用@Transactional注解

注意:@Transactional的8个属性:

             propagation:非必需元素,事务传播行为,默认值是Propagation_REQUIRED

             isolation:非必需元素,事务隔离级别,默认值是Isolation_DEFAULT

             timeout:非必需元素,超时,int型,以秒为单位

             readOnly:非必需元素,读写事务,默认值是false

             rollbackFor:非必需元素,回滚,默认为{},类型为Class[],例如{SQLException.calss},多个异常之间用逗号分隔

             noRollbackFor:非必需元素,默认为{}         

             rollbackForClassName:非必需元素,回滚,默认为{},类型为String[]

             noRollbackForClassName:非必需元素,默认为{}

2.基于aop/tx命名空间的配置

    <!--支持注解驱动的事务管理,指定事务管理器(@Transactional使事务注解生效) -->
    <tx:annotation-driven transaction-manager="transactionManager" />

注意:<tx:annotation-driven >具有三个属性

           1)transaction-manager:如果用户事务管理器id为transactionManager,可简化为<tx:annotation-driven />

           2)proxy-target-class:如果为true,Spring将通过创建子类来代理业务类,如果为false,则使用基于接口的代理

           3)order:如果业务类除事务切面外,还需要织入其他的切面,通过该属性可以控制织入顺序

注意事项:1.Spring建议在具体业务上使用@Transactional注解,这样,不管<tx:annotation-driven >的proxy-target-class的属性配置是哪个,业务类都会启用事务机制。

                 2.方法上的注解会覆盖类定义处的注解

                 3.如果一个应用具有多个事务管理器,如果我们希望不同的地方使用不同的事务管理器,只需像下面配置,为事务管理器标志一个名字

    <bean id="transactionManager1"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource"></property>
<qualifier value="tm1"/> </bean>

然后,用上注解@Transactional(tm1)

 

Spring的事务管理

posted on 2018-01-08 11:24  米虫爱喝咖啡  阅读(230)  评论(0编辑  收藏  举报

导航