Spring事务管理中的配置文件(三)
在开发中,遇到了sql语句报错,但是并没有回滚的情况。
经过几天的排查,终于找到了事务没有回滚的原因。
原来的项目用的是informix的数据库,原来针对事务回滚的机制都是好用的。我本地用的是mysql数据库。
先将程序代码与spring-mybatis.xml配置文件拿过来:
1、程序代码:
这个问题是在验证增删改查返回值时发现的。
两个操作,删除时,因为关联了外键,所以会报错,此时正常情况更新的语句也会回滚,但是并没有。
/**
*@Author: Administrator on 2020/3/12 15:15
*@param:
*@return:
*@Description:查询同步情况
*/
@Override
public PageInfo getSyncstatusPages(Syncstatus vo, int pageNo, int pageSize) {
PageHelper.startPage(pageNo, pageSize); /* //查看增删改查的返回值
//1新增:返回值自己定义,可以是void,int
//1-1新增一条数据:插入成功,返回值为1
int insert_success1 = yylfHttpServletMapper.insert("8", "2", "1");
//1-2新增多条数据:插入成功,返回值为插入的数据条数,当有一条数据错误时,所有数据都会插入失败
int insert_success2 = yylfHttpServletMapper.insert_duotiao("7");
String insert_success3 = yylfHttpServletMapper.insert_duotiao_String("7");//不支持返回值为String类型
//1-3新增一条数据:插入失败:主键冲突,会直接报异常
int insert_failed = yylfHttpServletMapper.insert("1", "2", "1");
//1-4插入null:属性为null,如果表中所有字段允许为null,插入一条所有值均为null的数据
Syncstatus syncstatus1 = null;
yylfHttpServletMapper.insertSyncstatus(syncstatus1);
//1-5插入一个没有赋值的对象:属性为null,如果表中所有字段允许为null,插入一条所有值均为null的数据
Syncstatus syncstatus2 = new Syncstatus();
yylfHttpServletMapper.insertSyncstatus(syncstatus2);*/ /*//2删除:返回值自己定义,可以是void,int
//2-1删除成功:没有数据:返回值为0
int delete_success1 = yylfHttpServletMapper.delete("0");
//2-2删除成功:有多条数据:返回值为删除的数据条数
int delete_success2 = yylfHttpServletMapper.delete_systemcode("2");*/
//2-3删除失败:例如有外键:报异常 //3更新:返回值自己定义,可以是void,int
//3-1更新成功:没有数据,返回值为0
//int update_no = yylfHttpServletMapper.update_no("0");
//3-2更新成功:有多条数据,返回更新的数据条数
int update_duotiao = yylfHttpServletMapper.update_duotiao_systemcode("2");
int delete_fail = yylfHttpServletMapper.delete("1");
//3-3更新失败:例如有外键,报异常
//int update_fail = yylfHttpServletMapper.update_fail("1"); //4查询
//4-1 没数:String 类型返回null
//Object object = yylfHttpServletMapper.select("0");
//4-1 没数:集合 类型返回[]空集合
//Syncstatus syncstatus3 = new Syncstatus();
//syncstatus3.setStatus("7");
//List<Syncstatus> page0 = yylfHttpServletMapper.getSyncstatusList(syncstatus3);
//4-1 没数:int 类型返回null,如果定义为int会报错。因为没数时返回null,可以将返回类型改为String
//String i = yylfHttpServletMapper.select_int(0);
//4-1:当返回值为对象时,若返回值为空,则返回null
//4-2 有数
List<Syncstatus> pages = yylfHttpServletMapper.getSyncstatusList(vo);
return new PageInfo<Syncstatus>(pages);
}
2、对数据库的操作:
<update id="update_duotiao_systemcode">
UPDATE aaa SET systemcode = '3' WHERE systemcode = #{systemcode,jdbcType=VARCHAR}
</update> <delete id="delete">
delete from aaa where uuid = #{uuid,jdbcType=VARCHAR}
</delete>
3、配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <bean id="dataSource" class="com.p6spy.engine.spy.P6DataSource">
<constructor-arg ref="dataSourceTarget"/>
</bean> <!-- 定义使用dbcp2连接池的数据源
此处使用自定义的数据源,将用户名与密码解密处理
-->
<bean id="dataSourceTarget" class="com.asd.common.jdbc.MyBasicDataSource" >
<property name="url" value="${jdbc.url}"> </property>
<property name="username" value="${jdbc.username}"> </property>
<property name="password" value="${jdbc.password}"> </property>
<property name="driverClassName" value="${jdbc.driverClassName}"> </property>
<!-- informix-->
<!--<property name="validationQuery" value="select count(*) from systables"> </property>-->
<!-- mysql检测方式 -->
<property name="validationQuery" value="select 1"> </property>
<!-- oracle检测方式
<property name="validationQuery" value="select 1 from dual"> </property> -->
</bean> <!-- 配置SqlSessionFactoryBean -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注入数据源 相关信息看源码 -->
<property name="dataSource" ref="dataSource" />
<!-- 扫描的实体所在的包-->
<property name="configLocation" value="classpath:mybatis.xml"/>
<!-- mapper和resultmap配置路径 -->
<property name="mapperLocations">
<list>
<value>classpath:mybatis/*Mapper.xml</value>
</list>
</property>
</bean> <!-- 自动扫描mapper接口,注入sqlsessionfactory -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.asd.modules.dao"/>
</bean> <!-- 启用类扫描机制,通过元数据配置Service -->
<context:component-scan base-package="com.asd">
<context:include-filter type="regex"
expression="com\.asd\.modules\.sevice\.impl\.*ServiceImpl" />
</context:component-scan> <!-- mybatis事物配置 --> <context:annotation-config />
<!-- ================================事务相关控制================================================= --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean> <tx:advice id="reinsAdvice" transaction-manager="transactionManager">
<tx:attributes> <tx:method name="delete*" propagation="REQUIRED" read-only="false"
rollback-for="java.lang.Exception" no-rollback-for="java.lang.RuntimeException" /> <tx:method name="insert*" propagation="REQUIRED" read-only="false"
rollback-for="java.lang.RuntimeException" />
<tx:method name="save*" propagation="REQUIRED" read-only="false"
rollback-for="java.lang.RuntimeException" /> <tx:method name="update*" propagation="REQUIRED" read-only="false"
rollback-for="java.lang.Exception" /> <tx:method name="find*" propagation="SUPPORTS" />
<tx:method name="get*" propagation="SUPPORTS" />
<tx:method name="select*" propagation="SUPPORTS" />
<tx:method name="*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
</tx:attributes>
</tx:advice> <aop:config>
<!-- 把事务控制在Service层 -->
<aop:pointcut id="reinsPointCut"
expression="execution(* com.asd.modules.service.impl.*ServiceImpl.*(..))" />
<aop:advisor pointcut-ref="reinsPointCut"
advice-ref="reinsAdvice" />
</aop:config> </beans>
4、数据库语句:
-- 创建aaa表用来验证增删改查的返回值
CREATE TABLE `reserve`.`aaa` (
`uuid` char(36) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`systemcode` varchar(8) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`status` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, PRIMARY KEY (`uuid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- 创建bbb表用来关联aaa的uuid作外键
CREATE TABLE `reserve`.`bbb` (
`uuid` char(36) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`systemcode` varchar(8) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`status` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, PRIMARY KEY (`uuid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; alter table bbb add constraint FK_T_POSITI_REFERENCE_T_COMPAN foreign key (uuid)references
aaa (uuid); insert into bbb (uuid,systemcode,status)value ('1','2','2'); -- 验证事支持
DELETE from aaa where uuid != '1';
insert into aaa (uuid,systemcode,status)value ('2','2','2');
SELECT * FROM aaa;
排查过程共查找了下述方面:
1、排除数据库原因:

查看mysql数据库是支持事务的;而且用informix数据库进行了验证,同样没有回滚。
2、验证了impl的类型等均为问题。
3、查看了事务的配置信息也正确好用。
4、验证了系统其它的一些方法,发现是支持事务的。
5、将这两个语句放到其它方法里也好用。
6、事务是在service层处理的,在控制层也加了异常捕获(这个操作并不会影响事务回滚,即使不catch,也会回滚的)
最终锁定问题原因:是因为方法名称的问题。
当将方法名改成其它的,不以get开头,不报错。
这个问题很坑,因为本以为为配置文件中的get*,会使这个方法的事务起作用,谁知道恰恰get*的这个配置虽然起作用了,但是结果却是事务不回滚,在将该配置改为
<tx:method name="get*" propagation="SUPPORTS" rollback-for="java.lang.Exception"/>
也没有用,最后将其注释掉,事务回滚。走了下面的配置:
<tx:method name="*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
需要注意的是 tx:method 的name属性指的是方法名。
将SUPPORTS改为REQUIRED后,事务也进行回滚。最终得到原因:是因为propagation的配置信息不正确。
拓展:
一、在声明式的事务处理中,要配置一个切面,其中就用到了propagation,表示打算对这些方法怎么使用事务,是用还是不用,其中propagation有七种配置,REQUIRED、SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER、NESTED。默认是REQUIRED。
二、Spring中七种Propagation类的事务属性详解:
REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。
三、注意.
这个配置将影响数据存储,必须根据情况选择。
问题往往出现在你忽略的地方。
还是对spring的各种配置不太熟悉。
花费了太多时间。
Spring事务管理中的配置文件(三)的更多相关文章
- ThreadLocal在Spring事务管理中的应用
ThreadLocal是用来处理多线程并发问题的一种解决方案.ThreadLocal是的作用是提供线程的局部变量,在多线程并发环境下,提供了与其他线程隔离的局部变量.通常这样的设计的情况是因为这个局部 ...
- spring事务管理及相关知识
最近在项目中遇到了spring事务的注解及相关知识,突然间感觉自己对于这部分知识只停留在表面的理解层次上,于是乎花些时间上网搜索了一些文章,以及对于源码的解读,整理如下: 一.既然谈到事务,那就先搞清 ...
- Spring 事务管理原理探究
此处先粘贴出Spring事务需要的配置内容: 1.Spring事务管理器的配置文件: 2.一个普通的JPA框架(此处是mybatis)的配置文件: <bean id="sqlSessi ...
- Spring事务管理——其他的事务属性
之前我们说过Spring事务管理中的事务的传播行为的属性.下面我们来说一下它的其他属性. 一.事务的隔离级别 1 .数据库事务并发问题.假设现在有两个事务:Transaction01和Transact ...
- SSM(spring mvc+spring+mybatis)学习路径——1-2、spring事务管理
目录 1-2 Spring事务管理 概念介绍 事务回顾 事务的API介绍 Spring 事务管理 转账案例 编程式事务管理 声明式事务管理 使用XML配置声明式事务 基于tx/aop 使用注解配置声明 ...
- Spring事务管理——回滚(rollback-for)控制
探讨Spring事务控制中,异常触发事务回滚原理.文章进行了6种情况下的Spring事务是否回滚. 以下代码都是基于Spring与Mybatis整合,使用Spring声明式事务配置事务方法. 1.不捕 ...
- 【Java EE 学习 52】【Spring学习第四天】【Spring与JDBC】【JdbcTemplate创建的三种方式】【Spring事务管理】【事务中使用dbutils则回滚失败!!!??】
一.JDBC编程特点 静态代码+动态变量=JDBC编程. 静态代码:比如所有的数据库连接池 都实现了DataSource接口,都实现了Connection接口. 动态变量:用户名.密码.连接的数据库. ...
- Spring事务管理的三种方式
一 .第一种:全注解声明式事务 Xml代码 复制代码 收藏代码 .<?xml version="1.0" encoding="UTF-8"?> .& ...
- Spring事务管理(编码式、配置文件方式、注解方式)
1.事务(https://www.cnblogs.com/zhai1997/p/11710082.html) (1)事务的特性:acdi (2)事务的并发问题:丢失修改,脏读,不可重复读 (3)事务的 ...
随机推荐
- jquery给动态生成的元素绑定事件,on函数
首先先解释一下什么是动态生成的元素:动态生成的元素即我们用jquery的内部插入函数append()所生成的html代码.相对的也有静态生成的元素:即直接编写在页面的html代码. 下面通过例子来讲解 ...
- springboot——重定向解决刷新浏览器造成表单重复提交的问题(超详细)
原因:造成表单重复提交的原因是当我们刷新浏览器的时候,浏览器会发送上一次提交的请求.由于上一次提交的请求方式为post,刷新浏览器就会重新发送这个post请求,造成表单重复提交. 解决办法: 将请求当 ...
- 692. 前K个高频单词
2021-05-20 LeetCode每日一题 链接:https://leetcode-cn.com/problems/top-k-frequent-words/ 标签:堆.字典序.哈希表 题目 给一 ...
- Padavan安装使用ZeroTier实现组建虚拟局域网的方法
首先到这个网站ZeroTier – Global Area Networking注册登陆,注册及创建网络的过程可以参考网上及其他UP主的教程,我就不重复了. 本篇主要讲述的是hiboy大佬编译的固件在 ...
- 一、DNS服务器的搭建
一.介绍 DNS服务:域名解析 将域名解析ip地址 DNS服务器的功能– 正向解析:根据注册的域名查找其对应的IP地址– 反向解析:根据IP地址查找对应的注册域名,不常用 所有完整的域名都要以点结 ...
- Centos acme.sh 申请 LetsEncrypt 通配证书
1. 安装 acme.sh 注意:如果需要使用 Standalone Mode请先安装socat# yum intall socat It is recommended to install soca ...
- Reactor3 中文文档(用户手册)
文章很长,建议收藏起来,慢慢读! 疯狂创客圈为小伙伴奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : <Netty Zookeeper Redis 高并发实战> 面试必备 + 大厂必备 ...
- UNREFERENCED_PARAMETER的用处
UNREFERENCED_PARAMETER的用处 作用:告诉编译器,已经使用了该变量,不必检测警告! 在VC编译器下,如果您用最高级别进行编译,编译器就会很苛刻地指出您的非常细小的警告.当你生命了一 ...
- 温故而知新--day5
温故而知新--day5 ip地址 IP是英文Internet Protocol的缩写,意思是"网络之间互连的协议",也就是为计算机网络相互连接进行通信而设计的协议.当多个设备要进行 ...
- DOS命令行(8)——netsh-网络配置命令行工具
netsh 介绍与语法 netsh(Network Shell) 是一个windows系统本身提供的功能强大的网络配置命令行工具,可用来显示与修改当前正在运行的计算机的网络配置(如:IP地址.网关.D ...