Springboot 事务

1. 打印SQL 日志的两种配置方式

[1]通过配置包的log等级来打印SQL日志,但这种不会打印出事务日志

logging.level.com.grady.mybatisdemo.mapper=DEBUG

[2] 配置mybatis的logImpl属性,好处是会输出事务日志

mybatis.configuration.logImpl=org.apache.ibatis.logging.stdout.StdOutImpl

PS:rollbackFor默认是非受检异常回滚,配置rollbackFor = Exception.class改成所有异常回滚

2 成功和失败的日志信息

[1]. 一次查询成功的日志

代码

    @Transactional(rollbackFor = Exception.class)
@PostMapping("/allUser")
public PageInfo<User> allUser() {
PageHelper.startPage(2,3);
List<User> users = userMapper.findAllUser();
PageInfo<User> pageInfo = new PageInfo<>(users);
return pageInfo;
}
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7580f2b1]
Cache Hit Ratio [SQL_CACHE]: 0.5
JDBC Connection [HikariProxyConnection@2138610113 wrapping com.mysql.cj.jdbc.ConnectionImpl@55855042] will be managed by Spring
==> Preparing: SELECT count(0) FROM user_copy
==> Parameters:
<== Columns: count(0)
<== Row: 5
<== Total: 1
==> Preparing: SELECT * FROM user_copy LIMIT ?, ?
==> Parameters: 3(Integer), 3(Integer)
<== Columns: user_id, name, password, token, ownapps, role_id
<== Row: 4, testUser4, 4, a, 2, 4
<== Row: 5, testUser5, 5, a, 4, 5
<== Total: 2
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7580f2b1]
Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7580f2b1]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7580f2b1]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7580f2b1]

[2]. 一次抛异常回滚的日志

代码:

    @Transactional(rollbackFor = Exception.class)
@Override
public Integer insertUser(User user) throws BusinessException {
try {
List<User> users = userMapper.findAllUser();
Integer result = userMapper.insert(user);
if (true) {
int i = 1 / 0; //这里抛RuntimeException异常
}
return result;
} catch (Exception e) {
e.printStackTrace();
throw new BusinessException("访问数据库失败", 1001);// 被我catch然后改为受检异常抛出
}
}
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e775383]
JDBC Connection [HikariProxyConnection@1016081606 wrapping com.mysql.cj.jdbc.ConnectionImpl@3560cd99] will be managed by Spring
==> Preparing: SELECT * FROM user_copy
==> Parameters:
<== Columns: user_id, name, password, token, ownapps, role_id
<== Row: 1, testUser1, 1, a, 2, 1
<== Row: 2, testUser2, 2, a, 2, 2
<== Row: 3, testUser3, 3, a, 2, 3
<== Row: 4, testUser4, 4, a, 2, 4
<== Row: 5, testUser5, 5, a, 4, 5
<== Total: 5
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e775383]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e775383] from current transaction
==> Preparing: INSERT INTO user_copy ( name, password, token, ownapps, role_id ) VALUES ( ?, ?, ?, ?, ? )
==> Parameters: jiang(String), zhongjin(String), abcd(String), o(String), 2(Long)
<== Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e775383]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e775383]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e775383]

ps:此异常从被Transactional注解的方法中抛出后就立即回滚并关闭SQLSession了

总结1:SpringBoot使用事务就是这么容易,只要在对应的方法上加上注解就可以了

3. 事务冲突问题

当使用事务增强来为一些匹配的方法加上事务,如果在这些方法调用其他被@Transactional绑定的方法时,会抛出事务异常,但对数据不会有影响**

比如:

事务增强加在了Controller上,controller调用Manager的方法,而Manager方式使用了@Transactional注解,这是会抛一下错误(经测试如果加载controller自己上没有问题,在调用链上才有问题)

抛出的异常是

org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:873) ~[spring-tx-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:710) ~[spring-tx-5.1.9.RELEASE.jar:5.1.9.RELEASE]
[1] 使用事务增强的两种方式

①XML 方式(然后使用@ImportResource("classpath:transaction.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: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/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" ></property>
</bean>
<tx:advice id="cftxAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="query*" propagation="SUPPORTS" read-only="true" ></tx:method>
<tx:method name="get*" propagation="SUPPORTS" read-only="true" ></tx:method>
<tx:method name="select*" propagation="SUPPORTS" read-only="true" ></tx:method>
<tx:method name="*" propagation="REQUIRED" rollback-for="Exception" ></tx:method>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="allManagerMethod" expression="execution (* com.grady.mybatisdemo..controller.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="allManagerMethod" order="0" />
</aop:config>
</beans>

// read-only="true" 表示这个方法只能读数据库,写会报错

这个增强表示,controller下的所有方法都在范围内,如果满足tx:method 的条件则加上事务

②代码配置方式

@Configuration
public class TransactionAdviceConfig { private static final String AOP_POINTCUT_EXPRESSION = "execution (* com.grady.mybatisdemo..controller.*.*(..))"; @Autowired
private PlatformTransactionManager transactionManager; @Bean(name = "txAdvice")
public TransactionInterceptor txAdvice() {
Properties properties = new Properties();
// readOnly 表示这个方法只能读数据库,写会报错
properties.setProperty("get*", "PROPAGATION_REQUIRED,-Exception,readOnly");
properties.setProperty("add*", "PROPAGATION_REQUIRED,-Exception");
properties.setProperty("save*", "PROPAGATION_REQUIRED,-Exception");
properties.setProperty("update*", "PROPAGATION_REQUIRED,-Exception");
properties.setProperty("delete*", "PROPAGATION_REQUIRED,-Exception");
//"PROPAGATION_REQUIRED, -Exception"这里有空格不要紧
properties.setProperty("insert*", "PROPAGATION_REQUIRED,-Exception");
TransactionInterceptor transactionInterceptor = new TransactionInterceptor(transactionManager, properties);
return transactionInterceptor;
} @Bean
public Advisor txAdviceAdvisor() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
return new DefaultPointcutAdvisor(pointcut, txAdvice());
}
}

经测试 properties.setProperty("insert*", "PROPAGATION_REQUIRED,-Exception"); "PROPAGATION_REQUIRED,-Exception" 每个关键字的两侧有空格不要紧,加载前会自动trim

代码的方式要更加优雅,可以利用到编译器在编译期做检查,XML只有运行时才能知道是对是错,代码的方式相对会更好一些

总结:

  1. 建议不要使用事务增强,因为你还得去记哪些方法名会被加事务,哪些不会,也会影响到你对方法的命名,一个表意的函数名是非常重要的,我觉得这种方式是得不偿失的。

  2. 建议直接使用@Transactional 来为方法加事务,这样一眼就可以知道当前方法有没有事务。

  3. 最好不要用了事务增强,又用@Transactional,因为如果两个方法加在了同一个方法链上,一旦抛异常回滚是会报UnexpectedRollbackException异常错误的

  4. 如果在调用链很后的地方抛出的异常,到被事务增强的函数时,此时一定要接着抛出,否则不会回滚,因为内部消化的异常等于正常操作,不会回滚

SpringBoot_事务总结的更多相关文章

  1. Spring基于AOP的事务管理

                                  Spring基于AOP的事务管理 事务 事务是一系列动作,这一系列动作综合在一起组成一个完整的工作单元,如果有任何一个动作执行失败,那么事务 ...

  2. SQLServer事务同步下如何收缩日志

    事务同步是SQLServer做读写分离的一种常用的方式. 随着业务数据的不断增长,数据库积攒了大量的日志,为了腾出硬盘空间,需要对数据库日志进行清理 订阅数据库的日志清理 因为订阅数据库所有的数据都来 ...

  3. 事务日志已满,原因为“ACTIVE_TRANSACTION”

    汇总篇:http://www.cnblogs.com/dunitian/p/4822808.html#tsql 异常处理汇总-数据库系列  http://www.cnblogs.com/dunitia ...

  4. Mysql事务探索及其在Django中的实践(二)

    继上一篇<Mysql事务探索及其在Django中的实践(一)>交代完问题的背景和Mysql事务基础后,这一篇主要想介绍一下事务在Django中的使用以及实际应用给我们带来的效率提升. 首先 ...

  5. Mysql事务探索及其在Django中的实践(一)

    前言 很早就有想开始写博客的想法,一方面是对自己近期所学知识的一些总结.沉淀,方便以后对过去的知识进行梳理.追溯,一方面也希望能通过博客来认识更多相同技术圈的朋友.所幸近期通过了博客园的申请,那么今天 ...

  6. CRL快速开发框架系列教程七(使用事务)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  7. 玩转spring boot——结合JPA事务

    接着上篇 一.准备工作 修改pom.xml文件 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi=&q ...

  8. MySQL 系列(三)你不知道的 视图、触发器、存储过程、函数、事务、索引、语句

    第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 你不知道的数据库操作 第三篇:MySQL 系列(三)你不知道的 视图.触发器.存储过程.函数 ...

  9. PHP中PDO事务的使用方法

    事务 (Transaction) 是操作数据库中很重要的一个功能, 它可以让你预定一条, 或者一系列 SQL 语句, 然后一起执行. 在执行的过程中, 如果其中的某条执行失败, 可以回滚所有已更改的操 ...

随机推荐

  1. 一文读懂数仓中的pg_stat

    摘要:GaussDB(DWS)在SQL执行过程中,会记录表增删改查相关的运行时统计信息,并在事务提交或回滚后记录到共享的内存中.这些信息可以通过 "pg_stat_all_tables视图& ...

  2. labview从入门到出家6(进阶篇)--移位寄存器的使用

    前面介绍了如何熟悉和使用Labview自带的库函数以及调试方式,大家后期基本可以凭借这两个方式从入门到出家了,哈哈,后面就靠各位同仁99%的努力了.这篇为啥要讲移位寄存器呢,主要是之前做的项目和经验告 ...

  3. Object类和toString方法 --和Object类的equals方法

    一,Object类概述:Object是类层次结构的根,每个类都可以将Object作为超类,所有类都直接或者间接的继承自该类构造方法:pulic Object()在面向对象中,子类要访问父类的无参构造方 ...

  4. 如何编写测试团队通用的Jmeter脚本

    平时学习.工作过程中,编写的一些jmeter脚本,相信大多数都遇到过这个问题.那就是:如果换一台电脑运行,文件路径不一样,会导致运行失败. 前不久,自己就真真切切遇到过一回,A同学写了个脚本用于压测, ...

  5. nexus org.sonatype.nexus.bootstrap.jetty.JettyServer - Start failed

    INFO [jetty-main-1] *SYSTEM org.sonatype.nexus.bootstrap.jetty.JettyServer - Runningjvm 1 | 2020-04- ...

  6. 解决Windows10、Windows11文件名无法大写的问题

    问题描述: 同一目录下的不同文件有些可以用大写字母做文件名,有些输入大写字母完成后自动变成小写. 甚至同一文件的文件名中的相同字母也会有这种情况,例如:文件名为"bu人BU"的文件 ...

  7. logrotate command in Linux

    背景 在生产过程中,由于磁盘空间.保留周期等因素,会对系统.应用等日志提出要求,要求系统日志定期进行轮转.压缩和删除,从而减少开销,而系统自带的logrotate  则是一个简单又实用的小工具,下面着 ...

  8. JAVA基础-11-Java Number 类--九五小庞

    问题:一直有疑惑,为什么java中学习了基本数据类型,而不使用,使用的是封装的对象. 解答: 一般地,当需要使用数字的时候,我们通常使用内置数据类型,如:byte.int.long.double 等. ...

  9. 有事务冲突时节点怎么加入MGR集群

    GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 目录 1. 问题场景描述 2. 如何修复 2.1 找出事务差异点 2.2 决定如何处理 3. 小结 文章推荐: 关于 Gr ...

  10. [极客大挑战 2019]HardSQL-1

    1.打开之后万能密码等均被过滤,那就先确定下过滤的内容,采用brup抓包进行爆破,发现对union进行了过滤,因此这里就没法使用联合注入,结果如下: 爆破得字典: ^ & && ...