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. 一种让运行在CentOS下的.NET CORE的Web项目简单方便易部署的自动更新方案

    一.项目运行环境 项目采用的是.NET5开发的Web系统,独立部署在省内异地多台CentOS服务器上,它们运行在甲方专网环境中(不接触互联网),甲方进行业务运作时(一段时间内)会要求异地服务器开机上线 ...

  2. 还在因为部署 Kubernetes 时,无法拉取 k8s.gcr.io/*** 镜像而头疼吗

    拉取外网 Kubernetes 镜像 还在因为部署 Kubernetes 时,无法拉取 k8s.gcr.io/*** 镜像而头疼吗? 传送门 https://github.com/liamhao/pu ...

  3. Go死锁——当Channel遇上Mutex时

    背景 用metux lock for循环,在for循环中又 向带缓冲的Channel 写数据时,千万要小心死锁! 最近,我在测试ws长链接网关,平均一个星期会遇到一次服务假死问题,因为并不是所有rou ...

  4. idea反编译jar包,jclasslib Bytecode Viewer

    下载 jclasslib Bytecode Viewer https://plugins.jetbrains.com/plugin/9248-jclasslib-bytecode-viewer/ver ...

  5. GET 和 POST 请求的区别与安全性

    超文本传输协议( HTTP )是用于启用客户端与服务器之间的通信,其中 GET 请求和 POST 请求是则是 HTTP 方法中最为常用的两种.那么这 GET 和 POST 的区别到底是什么呢?两者是否 ...

  6. 2022-07-15/16 第一小组 田龙月 管理系统javaSE

    JavaSE小项目(基础语法:二分查找:冒泡排序)--还是存在bug:删除一个数组内一组数据后面只有一组后面数据能向前移位 (YY:使用"方法"应该会好很多,代码架构会清晰一点)未 ...

  7. IDEA快捷键-03

    用了很久的eclipse,换了新的公司,跟着团队的习惯也转到idea上来了.在这里记录下对idea的认识,常用的idea快捷键及使用技巧. 对比eclipse每个workspace打开一个窗口,ide ...

  8. Solution -「CF645F」Cowslip Collections

    设 \(f(i)\) 表示大小为 \(k\),\(\gcd\) 为 \(i\) 的方案数.\(F(i)\) 表示大小为 \(k\),\(\gcd\) 为 \(i\) 的倍数的方案数. 不难看出:\(F ...

  9. DeiT:注意力也能蒸馏

    DeiT:注意力也能蒸馏 <Training data-efficient image transformers & distillation through attention> ...

  10. jdbc 03:注册驱动的方式

    jdbc连接mysql时,注册驱动的方式 package com.examples.jdbc.o3_注册驱动方式; //mysql驱动所在的包 import com.mysql.jdbc.Driver ...