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. 基于Vue2.x的前端架构,我们是这么做的

    通过Vue CLI可以方便的创建一个Vue项目,但是对于实际项目来说还是不够的,所以一般都会根据业务的情况来在其基础上添加一些共性能力,减少创建新项目时的一些重复操作,本着学习和分享的目的,本文会介绍 ...

  2. NewApiDay03_File类

    File类创建一个新文件 File类的每一个实例可以表示硬盘(文件系统)中的一个文件或目录(实际上表示的是一个抽象路径) 使用File可以做到: 1:访问其表示的文件或目录的属性信息,例如:名字,大小 ...

  3. Eclipse 安装配置和 Git 创建代码库 教程

    1. Eclipse 安装 http://www.eclipse.org/downloads/ 这是eclipse的官网,进入下载,步骤如下图: 选择Download或者下面的 [Select Ano ...

  4. Jenkins性能优化

    jenkins性能优化 1.评估安装插件,插件数量过多,会导致界面加载慢: 2.添加slave节点: 01.禁止在master上构建性能耗费大的任务,可以使用标签的方式使其在slave上构建: 02. ...

  5. rust里的内存对齐

    内存对齐主要遵循下面三个原则: 结构体变量的起始地址能够被其最宽的成员大小整除 结构体每个成员相对于起始地址的偏移能够被其自身大小整除,如果不能则在前一个成员后面补充字节 结构体总体大小能够被最宽的成 ...

  6. Object类的toString方法和equals方法

    Object类 概述 java.long.Object 类是java语言中的根类,即所有类的父类.它中描述的所有方法子类都可以使用.在对象实例化的时候,最终的父类就是Object 类Object是类层 ...

  7. python在执行命令时添加环境变量或指定执行路径

    cwd: 命令的执行路径,相当于os.chdir('/home')提前切换到对应路径 env: 环境变量,某些执行路径需要添加必须的环境变量,例如fastboot依赖与adb路径下的环境变量 impo ...

  8. DBPack SQL Tracing 功能及数据加密功能详解

    上周,我们正式发布了 DBPack SQL Tracing 功能和数据加密功能,现对这两个功能做如下说明. SQL Tracing 通过 DBPack 代理开启的全局事务,会自动在 http head ...

  9. SpringBoot 集成 FreeMarker 导出 Word 模板文件(底部附源码)

    思路解说 word 模板文件(doc 或 docx 文件)另存为 xml 文件 将后缀 xml 改成 html:大部分文档会改成 ftl(FreeMarker 的后缀名),因为 word 文件另存为 ...

  10. you need to load the kernel first

    背景:在用第三方软件备份win10系统时,提示you need to load the kernel first 1.进BIOS把硬盘AHCI 模式调整成 SATA. 2.检查硬盘数据线是否插紧.主板 ...