Spring事务的使用、事务的基本属性、事务的隔离级别、事务的传播特性学习总结


本篇旨在记录和分享对于Spring的@Transactional的学习和理解,也希望本篇可以对正在学习的小伙伴有一定的帮助

要想使用Spring的事务,首先要在配置文件中添加事务管理器

<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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans  
                           http://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">
                           
	<context:component-scan base-package="com.gavin" />
    <context:property-placeholder location="classpath:db.properties" />

	<!--配置德鲁伊数据源-->
	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="driverClassName" value="${jdbc.driverName}"/>
    </bean>

    <!--将jdbcTemplate注册为bean对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--配置事务管理器的bean对象-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
    <!--开启基于注解的事务管理器的配置-->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

配置好之后,我们就可以通过 在方法代码的上部添加@Transactional注解的方式来使用Spring为我们提供的事务控制了

接下来介绍一下@Transactional注解的几个简单的属性

1、timeout:超时时间

表示事务执行的最长时间
@Transactional(timeout = 4)//即事务执行超过4秒则事务回滚

2、readonly:只读事务

如果配置了只读事务,那么在事务运行期间,不允许对数据进行修改,否则抛出异常;如果一个事务中含有多条查询
语句,没有其他修改、新增、删除的操作,那么建议将此事务设置为只读事务,可以防止其它事务对数据源进行了修
改
@Transactional(readOnly = true)
@Transactional(readOnly = false)

3、noRollBackFor:指定忽略回滚

通过异常类的Class对象来指定哪些异常不会回滚数据
@Transactional(noRollbackFor = Exception.class)//这里可以指定具体的异常类;比如:NullPointException等

4、noRollBackForClassName:指定忽略回滚

与noRollbackFor 一样的功能,但是它是通过异常类的完全限定名来指定哪些异常不会回滚数据
@Transactional(noRollbackForClassName = "java.lang.Exception")

5、rollBackFor:指定回滚

通过异常类的Class对象来指定哪些异常需要回滚数据
@Transactional(rollbackFor = Exception.class)

6、rollBackForClassName:指定回滚

通过异常类的完全限定名来指定哪些异常需要回滚数据

@Transactional(rollbackForClassName = "java.io.FileNotFoundException")

OK,以上几个是Spring的事务中比较简单的几个属性

接下来介绍Spring事务中另外两个重要的两个属性

1、isolation——Spring事务的隔离级别

Spring事务的隔离级别本质上是调用了数据库的事务隔离级别,而数据库的事务隔离级别则是使用数据库锁的方式来进行控制;因此,我们在使用Spring事务的时候,就相当于使用了数据库锁。

Spring事务只有捕获到异常才会终止或回滚,如果你在程序中视同try/catch后自己处理了异常而没有throw,那么事务将不会终止或回滚,那么Spring事务也就不会生效,白瞎了

Spring事务有以下五种隔离级别

	1.1:DEFAULT(默认的):会匹配数据库,使用对应数据库(如:MySQL、Oracle等)的事务隔离级别
@Transactional(isolation = Isolation.DEFAULT)
	1.2:READ_UNCOMMITTED(读未提交):
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
	1.3:READ_COMMITTED(读已提交):
@Transactional(isolation = Isolation.READ_COMMITTED)
	1.4:REPEATABLE_READ(可重复读):
@Transactional(isolation = Isolation.REPEATABLE_READ)
	1.5:SERIALIZABLE(序列化):
@Transactional(isolation = Isolation.SERIALIZABLE)

事务的隔离级别主要是为了解决事务并发时出现的各种问题的,事务并发主要有:脏读、不可重复读、幻读三种,这里就不一一赘述了,接下来看一下这些事务并发问题的不同的隔离级别

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

2、propagation:Spring事务的传播特性

所谓事务的传播特性,指的是不同事务之间的执行时的关系以及效果,即:当一个事务被另一个事务进行调用的时候,这个事务应该如何进行

propagation属性主要有三个关键词:加入、挂起、异常
加入:指一个A事务方法在被另一个B事务方法调用的时候,A事务方法当成一个普通方法加入到B事务中,于B事务方法一起执行,共享同样的事务隔离级别,类似于Thread.join()方法;
挂起:指A事务方法在被B事务方法调用的时候,B事务方法就会暂停执行,等待A事务方法执行结束,然后继续执行;
异常:指抛出异常
有以下七个值:

2.1:PROPAGATION_REQUIRED 	如果有事务正在运行,当前的方法就在这个事务内运行(加入);如果没有,就
启动一个新的事务,并在自己的事务内运行
@Transactional(propagation = Propagation.REQUIRED)
2.2:RROPAGATION_REQUIRES_NEW 	当前方法必须创建新的事务,并在它自己的事务内运行;如果有事务正在运行
,它就会被挂起(挂起)
@Transactional(propagation = Propagation.REQUIRES_NEW)
2.3:PROPAGATION_NESTED 	如果有事务正在运行,当前的方法就应该在这个事务的嵌套事务内运行(嵌套);
否则,创建一个新的事务,并在自己的事务内运行;这里要严格注意的是其与以上两种状态的不同之处主要是在于A事
务在被B事务调用的时候,A事务有没有对自己的异常进行捕获,如果捕获了,那么B事务就相当于是2.2的执行效果,
即B事务的执行结果不会回滚;否则,A事务的异常没有捕获,那么B事务的执行结果会一同回滚
@Transactional(propagation = Propagation.NESTED)
2.4:PROPAGATION_SUPPORTS 	如果有事务正在运行,当前事务就会在该事务中运行(加入);如果没有,那么
它可以不运行在该事务中
@Transactional(propagation = Propagation.SUPPORTS)
2.5:PROPAGATION_NOT_SUPPORTED 	当前的方法不应该运行在事务中;如果有事务正在运行,将它挂起(挂起)
@Transactional(propagation = Propagation.NOT_SUPPORTED)
2.6:PROPAGATION_NEVER 	当前方法不应该运行在事务中;如果有事务正在运行,就抛出异常(异常)
@Transactional(propagation = Propagation.NEVER)
2.7:PROPAGATION_MANDATORY 	当前方法必须运行在事务中,如果没有正在运行的事务,就会抛出异常(异常)
@Transactional(propagation = Propagation.MANDATORY)

以上的传播特性主要指的是在不同的类中事务方法相互调用或嵌套时Spring事务的传播特性,如果是在同一个类中调用不同的事务方法的话,那么就相当于是普通的方法调用,不会有传播特性,而是相当于一个整体的事务;因为Spring的事务管理实际上是通过Spring AOP面向切面拦截的方法来实现的,在同一个类中调用不同的事务,并不会涉及到AOP的动态代理,只是普通的内部调用。

最后在介绍一下Spring事务的另一种使用方式:即通过配置文件来使用

<?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:context="http://www.springframework.org/schema/context"
       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.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/tx
       https://www.springframework.org/schema/tx/spring-tx.xsd
">
    <context:component-scan base-package="com.gavin"></context:component-scan>
    <context:property-placeholder location="classpath:dbconfig.properties"></context:property-placeholder>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="driverClassName" value="${jdbc.driverClassName}"></property>
    </bean>
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
    </bean>
    <bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
        <constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
    </bean>
    <!--事务控制-->
    <!--配置事务管理器的bean-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--
    基于xml配置的事务:依赖tx名称空间和aop名称空间
        1、spring中提供事务管理器(切面),配置这个事务管理器
        2、配置出事务方法
        3、告诉spring哪些方法是事务方法(事务切面按照我们的切入点表达式去切入事务方法)
    -->
    <bean id="goodsService" class="com.gavin.service.GoodsService"></bean>
    <aop:config>
        <aop:pointcut id="txPoint" expression="execution(* com.gavin.service.*.*(..))"/>
        <!--事务建议:advice-ref:指向事务管理器的配置-->
        <aop:advisor advice-ref="myAdvice" pointcut-ref="txPoint"></aop:advisor>
    </aop:config>
    <tx:advice id="myAdvice" transaction-manager="transactionManager">
        <!--事务属性-->
        <tx:attributes>
            <!--指明哪些方法是事务方法-->
            <tx:method name="*"/>
            <tx:method name="buyGoods" propagation="REQUIRED"/>
            <tx:method name="get*" read-only="true"></tx:method>
        </tx:attributes>
    </tx:advice>
</beans>

这种方式比较麻烦,一般在公司的项目中大家还是使用注解的方式来使用Spring的事务比较方便


以上就是本人对于Spring事务的一些学习总结,如果能够对读到本篇的小伙伴起到一下帮助,是在下的荣幸

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值