Spring4学习:Spring的事务管理

一、数据库事务知识

1、数据库锁机制

按锁定的对象的不同,可分为表锁定和行锁定。表锁定对整张表进行锁定,而行锁定对表中的特定行进行锁定。从并发事务锁定的关系上看,可以分为共享锁定和独占锁定。共享锁定会防止独占锁定,但允许其他的共享锁定。而独占锁定既防止其他的独占锁定,也防止其他的共享锁定。更新数据时,数据库必须在进行更改的行上施加行独占锁定,insert、update、delete和select for update语句都会隐式采用必要的行锁定。Oracle数据库常用的5种锁定,如下:

行共享锁定:不防止对数据行进行更改操作,但防止其他会话获取独占性数据表锁定。允许进行多个并发的行共享和行独占锁定,还允许进行数据表的共享或者采用共享行独占锁定。

行独占锁定:可以防止其他会话获取一个共享锁定、共享行独占锁定或独占锁定。

表共享锁定:可以防止其他会话获取行独占锁定,或者防止其他表共享行独占锁定或表独占锁定,但允许在表中拥有多个行共享和表共享锁定。该锁定可以让会话具有对表事务级一致性访问,因为其他会话在用户提交或者回滚该事务并释放对该表的锁定之前不能更改这种被锁定的表。

表共享行独占锁定:可以防止其他会话获取一个表共享、行独占或者表独占锁定,但允许其他行共享锁定。

表独占锁定:可以防止其他会话对该表的任何其他锁定。

2、事务隔离级别


事务的隔离级别和数据库并发性是对立的。一般来说,使用READ UNCONMMITED隔离级别的数据库拥有最高的并发性和吞吐量,而使用SERIALIZABLE隔离级别的数据库并发性最低。

3、JDBC对事务的支持

并不是所有的数据库都支持事务,即使支持事务的数据库也并非支持所有的事务隔离级别。用户可以通过Connection#getMetaData()方法获取DatabaseMetaData对象,并通过该对象的supportsTransactions()、supportsTransactionIsolationLevel(int level)方法查看底层数据库的事务支持情况。

Connection默认情况下是自动提交的,即每天执行的SQL语句都对应一个事务。为了将多条SQL语句当成一个事务执行,必须先通过Connection#setAutoCommit(false)阻止Connection自动提交,并通过Connection#setTransactionIsolationLevel()设置事务的隔离级别。

二、Spring使用ThreadLocal解决线程安全问题

使用模板类访问底层数据,根据持久化技术的不同,模板类需要绑定数据连接或会话的资源。但这些资源本身是非线程安全的,也就是说它们不能在同一时刻被多个线程共享。虽然模板类通过资源池获取数据连接或会话,但资源池本身解决的是数据连接或会话的缓存问题,并非数据连接或会话的线程安全问题。

ThreadLocal可以保存线程本地化对象的容器。当运行与多线程环境的某个对象使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程分配一个独立的变量副本。所以每个线程都可以独立地改变自己的副本,而不会影响其他线程所对应的副本。

三、Spring对事务管理的支持

Spring为事务管理提供了一致的编程模板,在高层次建立了统一的事务抽象。不管选择Spring JDBC、Hibernate、JPA还是选择MyBatis,Spring都可以让用户用统一的编程模型进行事务管理。

通过TransactionTemplate并配合使用事务回调TransactionCallback指定具体的持久化操作,就可以通过编程方式实现事务管理,而无须关注资源获取、复用、释放、事务同步和异常处理等操作。

Spring事务管理的亮点在于声明式事务管理。Spring允许通过声明方式,在IoC配置中指定事务的边界和事务属性,Spring自动在指定的事务边界上应用事务属性。

1、事务管理关键抽象

在Spring事务管理的抽象层主要包括3个接口,它们的关系如下:


(1)TransactionDefinition

TransactionDefinition用于描述事物的隔离级别、超时时间、是否为只读事务和事务传播规则等控制事务具体行为的事务属性,这些事务属性可以通过XML配置或注解描述提供,也可以用手工编程的方式设置。

事务隔离:当前事务和其他事务的隔离程度。在该接口中定义了4个隔离级别:ISOLATION_READ_UNCOMMITTED、ISOLATION_READ_COMMITTED、ISOLATION_REPEATABLE_READ和ISOLATION_SERIALIZABLE,还定义了默认的隔离级别ISOLATION_DEFAULT,表示使用底层数据库的隔离级别。

事务传播:通常在一个事务中执行的所有代码都会运行于同一事物的上下文中。

事务超时:事务在超时前能运行多久,超过时间后,事务被回滚。

只读状态:只读事务不修改任何数据。

(2)TransactionStatus

TransactionStatus代表一个事务的具体运行状态。事务管理器可以通过该接口获取事务运行期的状态信息,也可以通过该接口间接地回滚事务。该接口继承于SavepointManager接口,SavepointManager接口基于JDBC3.0保存点的分段事务控制能力提供了嵌套事务的机制。

(3)PlatformTransactionManager

PlatformTransactionManager根据TransactionDefinition提供的事务属性配置信息创建事务,并用TransactionStatus描述这个激活事务的状态。该接口定义了3个方法:

TransactionStatus getTransaction(TransactionDefinition definition):该方法根据事务定义信息从事务环境中返回一个已存在的事务,或者创建一个新的事务,并用TransactionStatus描述这个事务的状态。

commit(TransactionStatus status):根据事务的状态提交事务。如果事务状态已经被标识为rollback-only,则该方法将执行一个回滚事务的操作。

rollback(TransactionStatus status):将事务回滚。当commit方法抛出异常时,rollback方法被隐式调用。

2、Spring的事务管理器实现类

要实现事务管理,首先要在Spring中配置好相应的事务管理器,为事务管理器指定数据资源以及一些其他事务管理控制属性。

(1)Spring JDBC和MyBatis的配置

Spring JDBC和MyBatis都是基于数据源的Connection访问数据库,所以可以使用DataSourceTransactionManager,DataSourceTransactionManager使用DataSource中Connection的commit()、rollback()等方法管理事务,配置如下:


(2)Hibernate的配置

大部分ORM框架都拥有自己事务管理的API,它们对DataSource和Connection进行了封装。Hibernate使用org.hibernate.Session封装Connection,所以需要一个能够创建Session的SessionFactory。


3、事务同步管理器

Spring将JDBC的Connection、Hibernate的Session等访问数据库的连接或会话对象统称为资源,这些资源在同一时刻是不能多线程共享的。Spring的事务同步管理器TransactionSynchronizationManager使用ThreadLocal为不同事务线程提供独立的资源副本,同时维护事务配置的属性和运行状态信息。

Spring框架为不同的持久化技术提供了一套从TransactionSynchronizationManager中获取对应线程绑定资源的工具类,SpringJDBC和Mybatis使用的工具类是DataSourceUtils,Hibernate使用的工具类是SessionFactoryUtils。这些工具类都提供了静态的方法,通过这些方法可以获取和当前线程绑定的资源。当需要脱离模板类,手工操作底层持久化技术的原生API时,就需要通过这些工具类获取线程绑定的资源,而不应该直接从DataSource或SessionFactory中获取。

4、事务传播行为

Spring通过事务传播行为控制当前的事务如何传播到被嵌套调用的目标服务接口方法中。Spring在TransactionDefinition接口中规定了7种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播。如下所示:


四、使用XML配置声明式事务

Spring的声明式事务管理是通过Spring AOP实现的,通过事务的声明性信息,Spring负责将事务管理增强逻辑动态织入业务方法的相应连接点中。这些逻辑包括获取线程绑定资源、开始事务、提交/回滚事务、进行异常转换和处理等工作。

Spring在基于Schema的配置中添加了一个tx命名空间,在配置文件中以明确结构化的方式定义事务属性,配合aop命名空间所提供的切面定义,业务类方法事务配置得到了极大的简化。如下代码:

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

    <import resource="classpath:applicationContext-dao.xml"/>
	<!--事务管理器-->
    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
          p:dataSource-ref="dataSource"/>
	<!--使用切点表达式定义目标方法-->
    <aop:config>
        <aop:pointcut id="serviceMethod"
                      expression="execution(* com.smart.service.*Forum.*(..))"/>
        <aop:advisor pointcut-ref="serviceMethod"
                     advice-ref="txAdvice"/>
    </aop:config>
	<!--事务增强-->
    <tx:advice id="txAdvice">
        <tx:attributes>
            <tx:method name="get*" read-only="false"/>
            <tx:method name="add*" rollback-for="PessimisticLockingFailureException"/>
            <tx:method name="update*"/>
        </tx:attributes>
    </tx:advice>
</beans>

五、使用注解配置声明式事务

通过@Transactional对需要事务增强的Bean接口、实现类或方法进行标注,在容器中配置基于注解的事务增强驱动,即可启用基于注解的声明式事务。

@Service
@Transactional
public class BbtForum {
    public ForumDao forumDao;

    public TopicDao topicDao;

    public PostDao postDao;

    public void addTopic(Topic topic) throws Exception {
        topicDao.addTopic(topic);
//		if(true) throw new PessimisticLockingFailureException("fail");
        postDao.addPost(topic.getPost());
    }


    @Transactional(readOnly = true)
    public Forum getForum(int forumId) {
        return forumDao.getForum(forumId);
    }
}
还需要在Spring配置文件中通知Spring容器对标注@Transactional注解的Bean进行加工处理

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="com.smart"/>
    <import resource="classpath:applicationContext-dao.xml"/>

    <bean id="bbtForum"
          class="com.smart.service.BbtForum"
          p:forumDao-ref="forumDao"
          p:topicDao-ref="topicDao"
          p:postDao-ref="postDao"/>

    <bean id="txManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
          p:dataSource-ref="dataSource"/>

    <tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>
</beans>
默认情况下,<tx:annotation-driven>会自动使用名为“transactionManager”的事务管理器。如果事务管理器id为“transactionManager”,可以将配置简化为<tx:annotation-driven/>

<tx:annotation-driven>还有属性:

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

order:如果业务类除事务切面外,还需织入其他的切面,则通过该属性可以控制事务切面在目标连接点的织入顺序。

(1)@Transactional的属性

默认属性有:

事务传播行为:PROPAGATION_REQUIRED

事务隔离级别:ISOLATION_DEFAULT

读写事务属性:读/写事务

超时时间:底层事务系统的默认值

回滚设置:任何运行期异常引发回滚,任何检查型异常不会引发回滚。

(2)@Transactional注解标注的地方

Spring建议在具体业务类上使用@Transactional注解。在方法处注解会覆盖类定义处的注解。如果有些方法需要使用特殊的事务属性,则可以在类注解的基础上使用方法注解。










  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值