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. React中setState方法说明

    setState跟新数据是同步还是异步? setState跟新数据是异步的. 如何用代码表现出来是异步的. 点击按钮更新数据,然后去打印这个值看一下 setState跟新数据是异步的 class Fa ...

  2. sql-DDL-约束

    约束 对表中的数据进行限定,保证数据的正确性.有效性和完整性. 6个约束 1. 主键约束Primary Key: 唯一,不能为null -- 主键约束.和唯一约束不能同时设置 1. 含义:非空且唯一 ...

  3. 在.NET 6.0上使用Kestrel配置和自定义HTTPS

    大家好,我是张飞洪,感谢您的阅读,我会不定期和你分享学习心得,希望我的文章能成为你成长路上的垫脚石,让我们一起精进. 本章是<定制ASP NET 6.0框架系列文章>的第四篇.在本章,我们 ...

  4. Redis入门到精通01

    Redis入门到精通 目录 Redis入门到精通 一.Redis缓存框架基本介绍 1.1Redis的应用场景 二.Redis的安装方式 2.1Windows操作系统安装Redis 2.2Linux操作 ...

  5. k8s之有状态服务部署基石(基础知识)

    PV&PVC&HeadlessService 4.1.什么是无状态/有状态服务? 无状态服务: 1.没有实时的数据需要存储 (即使有,也是静态数据) 2.服务集群网络中,拿掉一个服务后 ...

  6. mysql实现两个字段合并成一个字段查询

    [需求]实现国际化I18N语言切换功能,例如菜单列表.字典等. 主要是个辅助表进行管理语言的配置: 单个字段很简单,直接通过字典配置的数据标签(key)- 表名, 数据键值(value)-表字段名[默 ...

  7. led的进化

    1.一个led亮100ns,灭400ns,循环 2.一个led亮2500ns,灭5000ns,亮7500ns,灭10000ns循环 3.以2500ns为变化周期,20000ns为一个循环,每个周期的亮 ...

  8. 第十一天python3 递归函数

    递归Recursion 函数直接或者间接调用自身就是递归: 递归需要有边界条件,递归前进段.递归返回段: 递归一定要有边界条件: 当边界条件不满足的时候,递归前进: 当边界条件满足的时候,递归返回: ...

  9. break和continue语句的使用

    break break关键字的用法有常见的两种: 1.可以用在switch语句当中,一旦执行整个switch语句like结束. 2.还可以用在循环语句当中,一旦执行,整个循环语句立刻结束,打断循环 关 ...

  10. python 链表、堆、栈

    简介 很多开发在开发中并没有过多的关注数据结构,当然我也是,因此,我写这篇文章就是想要带大家了解一下这些分别是什么东西. 链表 概念:数据随机存储,并且通过指针表示数据之间的逻辑关系的存储结构. 链表 ...