Spring事务处理方式

方式1:注解式事务

  • 使用@Transactional注解完成事务控制,此注解可添加到类上,则对类中所有方法执行事务的设定,注解添加到方法上,则对该方法执行事务处理

  • @Transactional(...)注解参数说明:

    • propagation = Propagation.REQUIRED:设置事务的传播特性,例如当多个事务叠加时,谁起主导作用等
    • noRollbackForClassName = "异常名称":指定发生什么异常不回滚,使用的是异常的名称
    • noRollbackFor = 异常.class:指定发生什么异常不回滚,使用的是异常的类型
    • rollbackForClassName = "异常名称":指定发生什么异常必须回滚,使用的是异常的名称
    • rollbackFor = 异常.class:指定发生什么异常必须回滚,使用的是异常的类型:
    • timeout = -1:连接超时设置,默认值是-1,表示永不超时
    • readOnly = false:默认为false,如果是查询操作,必须设置为true
    • isolation = Isolation.DEFAULT:使用的数据库的默认隔离级别
  • 注意:当一个类中有较多方法时,对方法进行一对一的注解式事务管理太多繁琐,简单演示事务特性时可以使用注解式事务,在实际项目中不常用

方式2:声明式事务

  • 在配置文件中添加一次,整个项目遵循该事务的设定,是Spring常用的,也是非常有名的事务处理方式

  • 要求项目中的方法命名有规范,例如:

  • 添加操作包含:add,save,insert,set等

  • 更新操作包含:update,change,modify等

  • 删除操作包含:delete,drop,remove,clear等

  • 查询操作包含:select,find,search,get等

  • 配置事务切面时,可以使用通配符来匹配满足通配条件的方法

声明式事务案例

applicationContext_trans.xml

  • 在src/main/resources目录下新建applicationContext_trans.xml,注意:这里如果使用idea默认的xml头信息,< tx >标签的属性显示不出来,可以使用下面的头信息
<!-- 此配置文件和applicationContext_service.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: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/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <!-- 导入applicationContext_mapper.xml -->
<import resource="applicationContext_mapper.xml"/> <!-- 添加包扫描 -->
<context:component-scan base-package="com.example.service.impl"/> <!-- 添加事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean> <!-- 配置事务切面 -->
<tx:advice id="myadvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*select*" read-only="true"/>
<tx:method name="*search*" read-only="true"/>
<tx:method name="*find*" read-only="true"/>
<tx:method name="*get*" read-only="true"/>
<tx:method name="*update*" propagation="REQUIRED"/>
<tx:method name="*save*" propagation="REQUIRED"/>
<tx:method name="*modify*" propagation="REQUIRED"/>
<tx:method name="*set*" propagation="REQUIRED"/>
<tx:method name="*insert*" propagation="REQUIRED"/>
<tx:method name="*delete*" propagation="REQUIRED"/>
<tx:method name="*remove*" propagation="REQUIRED"/>
<tx:method name="*clear*" propagation="REQUIRED"/>
<tx:method name="*" propagation="SUPPORTS"/>
</tx:attributes>
</tx:advice> <!-- 绑定切面和切入点 -->
<aop:config>
<!-- 定义切入点表达式 -->
<aop:pointcut id="mycut" expression="execution(* com.example.service.impl.*.*(..))"/> <!-- 将切面和切入点表达式绑定,为目标业务实现类中的业务方法提供对应的事务切面功能 -->
<aop:advisor advice-ref="myadvice" pointcut-ref="mycut"/>
</aop:config>
</beans>

业务实现类

  • 修改UserServiceImpl:持有Account业务逻辑层的接口类型的变量,在User业务逻辑中嵌套调用Account业务
package com.example.service.impl;

import com.example.mapper.UserMapper;
import com.example.pojo.Account;
import com.example.pojo.User;
import com.example.service.AccountService;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; /**
* 业务实现类
*/
@Service
public class UserServiceImpl implements UserService {
//业务逻辑层实现类持有数据访问层的接口类型的变量
@Autowired
UserMapper userMapper; //持有Account业务逻辑层的接口类型的变量
@Autowired
AccountService accountService; @Override
public int insert(User user) {
int num = userMapper.insert(user);
if(num == 1){
System.out.println("用户导入成功!");
}else{
System.out.println("用户导入失败!");
} //嵌套调用账户的业务逻辑功能
accountService.save(new Account(25, "荷包蛋6","富婆的账户6"));
return num;
}
}

测试

package com.example.test;

import com.example.pojo.User;
import com.example.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestUserAndAccount {
@Test
public void testUserAndAccount(){
//创建Spring容器
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext_trans.xml");
//获取用户的业务逻辑层对象
UserService userService = (UserService) ac.getBean("userServiceImpl");
//调用业务功能
userService.insert(new User(2, "荷包蛋2", "hanzhanghan2"));
}
}

测试输出

  • 从控制台看出两个业务的sql语句都执行成功,程序在出错后终止

  • 在上述事务配置下,用户业务和账户业务都被添加事务,从用户表和账户表可以看出,在内部嵌套的业务执行失败后,两个事务都被撤销,两条记录都未成功导入

修改aplicationContext_trans.xml

  • 对下述两个标签添加新的标签属性,对于某些指定异常不回滚
<tx:method name="*save*" propagation="REQUIRED" no-rollback-for="ArithmeticException"/>
<tx:method name="*insert*" propagation="REQUIRED" no-rollback-for="ArithmeticException"/>

测试输出

  • 这时对于算术异常不进行事务回滚,再次测试,两条记录成功导入数据表并有效保存

注意

如果当声明式注解所规划的事务管理和某个业务层的业务方法对事务的个性化需求相冲突时,可以再另外开启注解式事务并设置两种事务的优先级,达到优先使用注解式事务的目的。当order属性的值越大,事务的优先级越高

  • 在applicationContext_trans.xml中增加注解式事务驱动并设置事务优先级
        <!-- 添加注解式事务驱动-->
<tx:annotation-driven order="10" transaction-manager="transactionManager"/>
  • 为applicationContext_trans.xml中的< aop:advisor / >标签设置事务级别,此时如果某业务逻辑层的业务方法使用了注解式事务,则该业务方法的事务遵循注解式事务
 <aop:advisor order="1" advice-ref="myadvice" pointcut-ref="mycut"/>

Spring事务的传播特性

  • 多个事务之间的合并,互斥等都可以通过设置事务的传播特性来解决
  • 常用特性:
  • PROPAGATION_REQUIRED:必被包含事务(增删改必用)
  • PROPAGATION_REQUIRES_NEW:自己开启新事务,不管之前是否有事务
  • PROPAGATION_SUPPORTS:支持事务,如果加入的方法有事务,则遵循该事务,如果没有,不单开事务
  • PROPAGATION_NEVER:不能运行在事务中,如果被包在事务中,抛异常
  • PROPAGATION_NOT_SUPPORTED:不支持事务,运行在非事务环境中
  • 不常用特性:
  • PROPAGATION_MANDATORY:必须包在事务中,没有事务则抛出异常
  • PROPAGATION_NESTED:嵌套事务
  • 注意:
  • 事务必须声明在业务逻辑层
  • 事务传播特性的部分组合结果:下表列出了在User业务实现类中嵌套调用Account业务实现类,当内外层出现不同事务特性组合时,是分别能对users表和accounts表起到数据修改作用还是被事务回滚

Spring事务的隔离原则

  • 未提交读:允许脏读,可能读到其他会话中未提交事务所修改的数据,例如,读取数据后,发生数据回滚,则前面读到的数据就是脏读,读取到了未真实提交的数据
  • 提交读:只能读取到已经提交的数据。oracle等多数数据库默认都是该级别,即读已提交(不重复读)
  • 可重复读:在同一个事务内的查询都是与事务开始时刻一致,是InnoDB数据库引擎的默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是存在幻象读,但InnoDB解决了幻读
  • 串行读:完全串行化的读,每次读都需要获取表级共享锁,读写相互都会阻塞
  • 注意:mysql默认事务处理级别为:可重复读。oracel支持读已提交和串行读两种隔离级别,但是其默认事务隔离级别是:读已提交

添加事务管理器的原因

  • 不同技术对事务提交和回滚的实现简单列举如下,可见不同的技术使用的数据库操作对象不同

    • JDBC:Connection con.commit(); con.rollback();

    • MyBatis:SqlSession sqlSession.commit(); sqlSession.rollback();

    • Hibernate:Session session.commit(); session.rollback();

  • 使用事务管理器,目的就是为了生成相应技术下的数据库连接 + 执行语句的对象

  • 如果使用MyBatis框架,必须使用DataSourceTransactionManager类完成处理

    <!-- 添加事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 由于事务管理必然要涉及到数据库的操作,例如数据回滚等等,所以必须添加数据源配置 -->
<property name="dataSource" ref="dataSource"/>
</bean>

Spring 16: SM(Spring + MyBatis) 注解式事务 与 声明式事务的更多相关文章

  1. spring事务管理——编程式事务、声明式事务

    本教程将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. 先决条件 本教程假定您已经掌握了 ...

  2. 事务之三:编程式事务、声明式事务(XML配置事务、注解实现事务)

    Spring2.0框架的事务处理有两大类: JdbcTemplate操作采用的是JDBC默认的AutoCommit模式,也就是说我们还无法保证数据操作的原子性(要么全部生效,要么全部无效),如: Jd ...

  3. Spring注解驱动开发之声明式事务

    前言:现今SpringBoot.SpringCloud技术非常火热,作为Spring之上的框架,他们大量使用到了Spring的一些底层注解.原理,比如@Conditional.@Import.@Ena ...

  4. spring整合mybatis,ioc容器及声明式事务配置

    步骤: 1.创建jdbc.properties文件,用来管理存放连接数据库的相关信息 jdbc.properties:jdbc.user=root jdbc.password=123456 jdbc. ...

  5. Spring事务管理的实现方式:编程式事务与声明式事务

    1.上篇文章讲解了Spring事务的传播级别与隔离级别,以及分布式事务的简单配置,点击回看上篇文章 2.编程式事务:编码方式实现事务管理(代码演示为JDBC事务管理) Spring实现编程式事务,依赖 ...

  6. Spring事务管理的实现方式之编程式事务与声明式事务详解

    原创说明:本博文为原创作品,绝非他处转载,转载请联系博主 1.上篇文章讲解了Spring事务的传播级别与隔离级别,以及分布式事务的简单配置,点击回看上篇文章 2.编程式事务:编码方式实现事务管理(代码 ...

  7. Spring事务管理实现方式之编程式事务与声明式事务详解(转)

    原文:https://blog.csdn.net/liaohaojian/article/details/70139151 编程式事务 编码方式实现事务管理(代码演示为JDBC事务管理) Spring ...

  8. 使用SpringAOP实现事务(声明式事务管理、零配置)

    前言: 声明式事务管理建立在AOP之上的.其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务.声明式事务最大的优点就是不需要通过编 ...

  9. Spring声明式事务管理基于@Transactional注解

    概述:我们已知道Spring声明式事务管理有两种常用的方式,一种是基于tx/aop命名空间的xml配置文件,另一种则是基于@Transactional 注解.         第一种方式我已在上文为大 ...

随机推荐

  1. JS:函数的几种写法1

    1.构造函数: var fn = new function(); 2.声明式: function fn(){}; 3.匿名函数(又称自调用函数): (function(){})(); 4.表达式: v ...

  2. RPA应用场景-海关报关

    场景概述海关报关 所涉系统名称海关页面,业务核心系统 人工操作(时间/次) 10 分钟 所涉人工数量 3 操作频率实时 场景流程 1.每日接收报关申请邮件: 2.根据邮件信息进入业务核心系统查询相关数 ...

  3. 从Hadder看蛋白质分子中的加氢算法

    技术背景 PDB(Protein Data Bank)是一种最常用于存储蛋白质结构的文件.而我们在研究蛋白质构象时,往往更多的是考虑其骨架,因此在很多pdb文件中直接去掉了氢原子.但是在我们构建蛋白质 ...

  4. 深入理解 volatile 关键字

    volatile 关键字是 Java 语言的高级特性,但要弄清楚其工作原理,需要先弄懂 Java 内存模型.如果你之前没了解过 Java 内存模型,那可以先看看之前我写过的一篇「深入理解 Java 内 ...

  5. Codeforces Round #790 (Div. 4) A-H

    Codeforces Round #790 (Div. 4) A-H A 题目 https://codeforces.com/contest/1676/problem/A 题解 思路 知识点:模拟. ...

  6. Django【执行查询】(二)

    官方Django3.2 文档:https://docs.djangoproject.com/en/3.2/topics/db/queries/ 本文大部分内容参考官方3.2版本文档撰写,仅供学习使用 ...

  7. PTA(BasicLevel)-1014 福尔摩斯的约会

    一.问题描述 大侦探福尔摩斯接到一张奇怪的字条:我们约会吧! 3485djDkxh4hhGE 2984akDfkkkkggEdsb s&hgsfdk d&Hyscvnm.大侦探很快就明 ...

  8. YYYYMMdd和yyyyMMdd的区别

    YYYYMMdd的 YYYY 是表示:当天所在的周属于的年份,一周从周日开始,周六结束,只要本周跨年,那么这周就算入下一年.比如今天是2021-12-29 星期三,然后本周六是2022-01-01,存 ...

  9. 2022-07-21 第四组 java之继承

    目录 一.继承 1.概念 2.语法 3.父类成员访问 3.1 子类访问父类的成员变量 3.1.1 子类和父类中不存在同名的成员变量 3.1.2 子类和父类中不存在同名的成员变量 3.2 子类中访问父类 ...

  10. CentOS7桥接模式上不了外网的配置

    电脑VM10装了CentOS7后用NAT模式可以上网,但我想要的是桥接模式,因为我要用Xshell5进行远程访问.所以要 ifconfig 找到ip .那么为什么桥接模式上不了外网呢? 首先参考了 h ...