事务管理器

我们知道关系型数据库具有事务和事务隔离级别的概念,我们的Java程序一般都是通过JDBC操作数据库,比如开启事务、提交事务、设置隔离级别等,在JDBC接口中也有这些概念的定义。如果直接使用JDBC操作数据库,那么我们就需要调用相关的API,手动处理这些操作。

在Spring框架中,提供了事务管理器TransactionManager功能。我们在配置文件中配置好事务管理器,当ORM框架从数据源中获取JDBC的Connection对象并进行一些操作时,Spring会自动通过AOP拦截管理事务操作,这样能大大简化我们代码的编写。

相关概念

事务隔离级别:关系型数据库的事务具有隔离级别这一概念,JDBC作为一个通用的抽象接口,也定义了相关隔离级别的常量值,这部分源码可以在java.sql.Connection类中找到。

事务隔离级别 说明
TRANSACTION_NONE 代表JDBC驱动不支持事务,一般不会用到该项。
TRANSACTION_READ_UNCOMMITTED 允许脏读,不可重复读和幻读。
TRANSACTION_READ_COMMITTED 不可脏读,但允许不可重复读和幻读。
TRANSACTION_REPEATABLE_READ 不可脏读和不可重复读,但允许幻读。
TRANSACTION_SERIALIZABLE 不可脏读,不可重复读,幻读。

注:MySQL数据库默认的事务隔离级别为REPEATABLE_READ,但JDBC驱动中默认设置了READ_COMMITTED,大多数数据库也是此隔离级别,这是历史原因造成的。

事务传播属性:Spring框架中的事务管理器支持该配置,用于在多个声明了事务的方法互相调用时,事务如何在方法间传播。

事务传播属性 说明
PROPAGATION_REQUIRED 支持当前事务,如果当前没有事务就新建,最常用,默认。
PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY 支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。

配置事务管理器

下面例子来自MyBatis相关章节,其中定义了一个默认的事务管理器,并配置了声明式事务@Transactional注解的扫描。Hibernate等框架也是类似,这里仅仅是以MyBatis为例。

<!-- 配置事务管理器 -->
<bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

<!-- 声明式事务注解扫描 -->
<tx:annotation-driven/>

<!-- 配置MyBatis的SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="configLocation" value="classpath:mybatis-config.xml"/>
    <property name="mapperLocations" value="classpath*:mapper/*Mapper.xml"/>
</bean>

<!-- 配置MyBatis的Mapper扫描 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.gacfox.**.mapper"/>
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>

我们可以看到,事务管理器对象引用了数据源对象dataSource,事务管理器的相关功能就会在该数据源上生效。

使用声明式事务

Spring中最常用的就是声明式事务,用法如下:

@Service("testService")
@Transactional(rollbackFor = Exception.class)
public class TestServiceImpl implements TestService {
    // ... 具体实现相关代码
}

代码中,我们使用了@Transactional标注了一个类,这标明其方法执行时,默认就会以声明的事务隔离级别和传播属性执行。rollbackFor = Exception.class指定抛出任何异常时,即回滚事务。

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。
Copyright © 2017-2024 Gacfox All Rights Reserved.
Build with NextJS | Sitemap