Spring使用篇(十一)—— Spring与MyBatis事务管理

1、搭建开发测试环境

  在名为Spring_Demo的项目中创建名为“Transaction”的普通Java模块,并在该模块中创建名为“lib”的包用于存放该模块所需的所有jar包。在该开发环境中与前一篇所需的开发环境一致,jar包参考前篇博客《Spring使用篇(十)—— Spring与MyBatis整合》

  在该模块中创建如下图所示的包结构,其中:
config包: 用于存放Java配置类;
controller包: 用于存放控制器类;
mapper包: 用于存放数据库操作接口;
pojo包: 用于存放POJO类;
service包: 用于存放业务接口;
service.impl包: 用于存放业务接口的实现类;
sql包: 用于存放MyBatis框架所需的数据库映射Mapper文件;
test包: 用于存放测试类
database-config.properties属性文件: 用于存储数据库四要素属性值;
log4j.properties: 为日志配置属性文件;
spring-config.xml: 为Spring框架配置文件;
SqlMapConfig.xml: 为MyBatis框架的核心配置文件。
在这里插入图片描述
  其余开发环境包括数据库的创建,数据表的创建,POJO类的创建,Mapper接口的定义,数据库映射文件的编写以及Java配置类的基础配置,均与上一篇博客(《Spring使用篇(十)—— Spring与MyBatis整合》)相同。

2、配置Spring数据库事务

  在Spring中数据库事务是通过PlatformTransactionManager接口进行管理的。在Spring中,有多种事务管理器,由于目前在持久层常用MyBatis框架,因此常用的事务管理器是DataSourceTransactionManager(org.springframework.jdbc.datasource.DataSourceTransactionManager),它继承抽象事务管理器AbstractPlatformTransactionManager,而AbstractPlatformTransactionManager又实现了PlatformTransactionManager接口。

  因此在Spring的XML配置文件中加入对事务管理器的配置,同时还需要加入XML的事务命名空间,spring-config.xml具体的配置修改如下:

<?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"
       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/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
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <!--加载属性文件-->
    <context:property-placeholder location="database-config.properties" ignore-resource-not-found="true" />

    <!-- 数据库连接池 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="${jdbc.database.driver}" />
        <property name="url" value="${jdbc.database.url}" />
        <property name="username" value="${jdbc.database.username}" />
        <property name="password" value="${jdbc.database.password}" />
        <!--连接池的最大数据库连接数 -->
        <property name="maxActive" value="255" />
        <!--最大等待连接中的数量 -->
        <property name="maxIdle" value="5" />
        <!--最大等待毫秒数 -->
        <property name="maxWait" value="10000" />
    </bean>

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" value="classpath:sqlMapConfig.xml" />
    </bean>

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.ccff.spring.transaction.mapper" />
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
        <!-- 使用sqlSessionTemplateBeanName将覆盖sqlSessionFactoryBeanName的配置 -->
        <!-- <property name="sqlSessionTemplateBeanName" value="sqlSessionFactory"/> -->
        <!-- 指定标注才扫描成为Mapper -->
        <property name="annotationClass" value="org.springframework.stereotype.Repository" />
    </bean>

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

</beans>

  在配置DataSourceTransactionManager事务管理器时注入了数据库连接池,这样Spring就知道此事已经将数据库事务委托给了事务管理器transactionManager管理了。

3、数据库隔离级别与传播行为

  数据库事务的管理一定会涉及对数据库,尤其是数据库事务的知识,但本系列博客主要是对框架使用的学习,因此在这里只做简单说明。

3.1 数据库隔离级别

  并行事务的四大问题:第一,更新丢失:和别的事务读到相同的东西,各自写,自己的写被覆盖了。(谁写的快谁的更新就丢失了)。第二,脏读:读到别的事务未提交的数据。(万一回滚,数据就是脏的无效的了)。第三,不可重复读:两次读之间有别的事务修改。第四,幻读:两次读之间有别的事务增删。

  数据的隔离级别主要有:读未提交、读已提交、可重复读和可序列化。对应的隔离级别分别为:READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ和SERIALIZABLE。各类隔离级别和产生的现象如下表所示:

隔离级别 脏读 不可重复读 幻读
读未提交 可能 可能 可能
读已提交 不可能 可能 可能
可重复读 不可能 不可能 可能
可序列化 不可能 不可能 不可能

  而选取隔离级别的出发点在于两点:性能和数据一致性。数据库的隔离级别从读未提交到可序列化,系统性能直线下降。在实际工作中,注解@Transactional隔离级别的默认值为Isolation.DEFAULT,其含义是默认的,随数据库默认值的变化而变化。因为对不同的数据库而言,隔离级别的支持是不一样的。在MySQL中可支持4种隔离级别,而默认的是可重复读的隔离级别。而在Oracle中只支持读已提交和可序列化两种隔离级别,默认值是读已提交。

3.2 Spring的7种传播行为

  在Spring中传播行为的类型,是通过一个枚举类型去定义的,这个枚举类是org.springframework.transaction.annotation.Propagation,它定义了如下表所示的7种传播类型。

传播行为 含义 备注
REQUIRED 当方法调用时,如果不存在当前事务,那么就创建事务;如果之前的方法已经存在事务了,那么就沿用之前的事务 这是Spring默认的传播行为
SUPPORTS 当方法调用时,如果不存在当前事务,那么不启用事务;如果存在当前事务,那么就沿用当前事务 ——
MANDATORY 方法必须在事务内运行 如果不存在当前事务,那么就抛出异常
REQUIRES_NEW 无论是否存在当前事务,方法都会在新的事务中运行 也就是事务管理器会打开新的事务运行该方法
NOT_SUPPORTED 不支持事务,如果不存在当前事务也不会创建事务;如果存在当前事务,则挂起它,纸质该方法结束后才恢复当前事务 适用于那些不需要事务的SQL
NEVER 不支持事务,只有在没有事务的环境中才能运行它 如果存在当前事务,那么就抛出异常
NESTED 嵌套事务,也就是调用方法如果抛出异常只回滚自己内部执行的SQL,而不回滚主方法的SQL 它的实现存在两种情况,如果当前数据库支持保存点(savepoint),那么它就会在当前事务上使用保存点技术;如果发生异常则将方法内执行的SQL回滚到保存点上,而不是全部回滚,否则就等同于REQUIRES_NEW创建新的事务运行方法代码

  7种传播行为中,最常用的是REQUIRED,也是默认的传播行为。对于那些不支持事务的方法我们使用得不多,一般而言,我们还比较关注的是REQUIRES_NEW和NESTED。

4、声明式事务

4.1 声明式事务概述

  在Spring中可以使用编程式事务与声明式事务。如今,编程式事务几乎不用了,因为它会产生荣誉,代码可读性差,因此这里只介绍声明式事务。声明式事务又可以分为XML配置和注解事务,但XML方式也已经不常用了,目前主流方法是注解@Transactional,因此本篇仅介绍使用注解@Transactional。

  声明式事务是一种约定型的事务,在大部分情况下,当使用数据库事务时,大部分的场景是在代码中发生了异常时,需要回滚事务,而不发生异常时则是提交事务,从而保证数据库数据的一致性。从这点出发,Spring给了一个约定,如果使用的是声明式事务,那么当你的业务方法不发生异常(或者发生异常,但该异常也被配置信息允许提交事务)时,Spring就会让事务管理器提交事务,而发生异常(并且该异常不被你的配置信息所允许提交事务)时,则让事务管理器回滚事务。

4.2 注解@Transactional配置项

  声明式事务允许自定义事务接口——TransactionDefinition,它可以由XML或者注解@Transactional进行配置,本篇主要讨论注解@Transactional,其配置项如下表所示:

配置项 含义 备注
value 定义事务管理器 它是Spring IoC容器里的一个Bean id,这个Bean需要实现接口PlatformTransactionManager
transactionManager 同上 同上
isolation 隔离级别 这是一个数据库在多个事务同时存在时的概念,默认值取数据库默认的隔离级别
propagation 传播行为 传播行为是方法之间调用的问题,默认值为Propagation.REQUIRED
timeout 超时时间 单位为秒,当超时时,会引发异常,默认会导致事务回滚
readOnly 是否开启只读事务 默认值为false
rollbackFor 回滚事务的异常类定义 也就是只有当方法产生所定义异常时,才回滚事务,否则就提交事务
rollbackForClassName 回滚事务的异常类名定义 同rollbackFor,只是使用类名称定义
noRollbackFor 当产生哪些异常不回滚事务 当产生所定义的异常时,Spring会继续提交事务
noRollbackForClassName 同noRollbackFor 同noRollbackFor,只是使用类的名称定义

  当了解了注解@Transactional的配置项后,有两种方式开启该注解。第一种是在Spring的配置XML文件spring-config.xml中通过如下配置开启,就可以使用注解@Transactional配置事务了,具体修改如下:

<?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"
       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/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
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <!--加载属性文件-->
    <context:property-placeholder location="database-config.properties" ignore-resource-not-found="true" />

    <!-- 数据库连接池 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="${jdbc.database.driver}" />
        <property name="url" value="${jdbc.database.url}" />
        <property name="username" value="${jdbc.database.username}" />
        <property name="password" value="${jdbc.database.password}" />
        <!--连接池的最大数据库连接数 -->
        <property name="maxActive" value="255" />
        <!--最大等待连接中的数量 -->
        <property name="maxIdle" value="5" />
        <!--最大等待毫秒数 -->
        <property name="maxWait" value="10000" />
    </bean>

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" value="classpath:sqlMapConfig.xml" />
    </bean>

    
  • 9
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值