JPA事务示例分析

在这个工程中,定义一个名为User的实体:

@Entity
@Data
@NoArgsConstructor
public class User {@Id@GeneratedValueprivate Long id;@Size(max = 5)private String name;@Max(50)private Integer age;public User(String name, Integer age) {this.name = name;this.age = age;}}

这里name设置了长度为5,这样可以通过insert语句中的name超长,让其抛出异常,从而可以测试事务的触发。

另外工程中还包含了Spring Data Jpa的数据访问对象UserRepository,用来实现对User实体的数据操作,这里就不放具体代码了。

问题来了

这里数据库采用MySQL 5.7,存储引擎为InnoDB,使用默认事务级别。

下面来调整下这四个问题吧:

问题一:test1会不会回滚?-- 回滚

@Transactional
public void test1() {userRepository.save(new User("AAA", 10));throw new RuntimeException();
}

问题二:test2会不会回滚?-- 不回滚

@Transactional
public void test2() {userRepository.save(new User("AAA", 10));try {throw new RuntimeException();} catch (Exception e) {log.error("异常捕获:", e);}
}

问题三:test3会不会回滚?(第二句插入name超长)-- 回滚

@Transactional
public void test3() {userRepository.save(new User("AAA", 10));userRepository.save(new User("1234567890", 20));
}

问题四:test4会不会回滚?(第二句插入name超长)-- 回滚

@Transactional
public void test4() {userRepository.save(new User("AAA", 10));try {userRepository.save(new User("1234567890", 20));} catch (Exception e) {log.error("异常捕获:", e);}
}

为什么写了catch,还会回滚

先来看看执行时候报的异常:

javax.validation.ConstraintViolationException: Validation failed for classes [com.didispace.chapter310.User] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[ConstraintViolationImpl{interpolatedMessage='个数必须在0和5之间', propertyPath=name, rootBeanClass=class com.didispace.chapter310.User, messageTemplate='{javax.validation.constraints.Size.message}'}
]at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.validate(BeanValidationEventListener.java:140) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.onPreInsert(BeanValidationEventListener.java:80) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.action.internal.EntityInsertAction.preInsert(EntityInsertAction.java:209) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:83) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:478) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:356) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1454) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:511) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3283) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2479) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:473) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:178) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:39) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:271) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:98) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]

这个异常是这个回滚的关键。这个异常javax.validation.ConstraintViolationException是哪里的呢?还记得以前说的JSR 303不?对的,是Bean Validation中的异常。

有的读者说这个不是RuntimeException,所以不会回滚。很显然,这类判断的都没有实际尝试一下,只要点开源码可以马上发现,这个异常就是属于RunTimeException的。

实际上,之所以会回滚,与这里使用Spring Data JPA以及Hibernate Validator有直接关系。从JPA 2.0开始,就默认支持了这些Bean Validation的实现,它提供了实体生命周期中pre-persistpre-update,pre-remove三个事件发生时来执行校验的功能。而在校验的时候,当校验失败,抛出javax.validation.ConstraintViolationException时,当前事务就会被标记为rollback

源码解析

要想了解,这其中到底发生了什么,跟踪源码是最好的方式。那么源码从哪里开始看呢?从异常日志中找线索吧。

从异常栈中找到最近的一个错误,点开看看。

错误行数在532行tx.commit(),习惯性的加上断点,这样下一次进来的时候可以看看当前情况下的各种参数情况。

同时看到下面还有个catch,既然532行出错了,那这里肯定会进,所以也加个端点,到时候可以进去看看。

执行程序,调用一下test4,执行到532行,然后进入下一步,看看会到哪里?

这个时候,会进入到org.hibernate.engine.transaction.internal.TransactionImpl,具体位置如下:

还是习惯性的,在下面两行重要位置加上断点,以便下次可以快速到这里。

继续按上看的步骤尝试下去,可以来到下图的位置:

可以看到校验异常是从271行出来的,结合278行和280行,是不是清楚这里回滚的原因了呢?

为什么加了@Transactional注解,事务没有回滚?

@Transactional注解不生效,是Spring使用者非常常见的一类问题,上面我们讲了一种,其他还有一些可能的原因,这里作为扩展阅读一并列出。

如果你当前碰到的原因不是上面的情况,那就看看下面这几种情况是否存在:

1.@Transactional注解修饰的函数中catch了异常,并没有往方法外抛。不过,也有一写复杂场景可能不一样,比如我这里出的四个题中的test4:我来出个题:这个事务会不会回滚?

2.@Transactional注解修饰的函数不是public类型

3.异常类型错误,如果有通过rollbackFor指定回滚的异常类型,那么抛出的异常与指定的是否一致。

4.数据源没有配置事务管理器

5.在一个类中调用自己的方法。建议分开写,互相调用。

6.对应数据库使用的存储引擎不支持事务,比如:MyISAM。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/497476.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

智能零售来了!Amazon Go无人商店周一正式对公众开放

来源:网络大数据概要:经过近 14 个月只对亚马逊公司员工开放的试运行,周一这家标着 Amazon Go 标志的店面将公开亮相,这是亚马逊近年来投入最多努力的项目之一,旨在重塑实体购物的体验。据《西雅图时报》报道&#xff…

看懂GE Predix ,就看懂了工业互联网

来源:小黑羊JoinWings概要:Predix是GE推出的针对整个工业领域的基础性系统平台,这是一个开放的平台,它可以应用在工业制造、能源、医疗等各个领域。Predix是GE推出的针对整个工业领域的基础性系统平台,这是一个开放的平…

JPA和事务管理

1 事务 1.1事务管理方式 spring支持编程式事务管理和声明式事务管理两种方式。 编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。 声明式事务管理建立在AOP之上的…

纽约大学Gary Marcus发文指出AlphaZero「被夸大」,强调重视人工智能「先天因素」

原文来源:arXiv作者:Gary Marcus「雷克世界」编译:嗯~是阿童木呀纽约大学Gary Marcus教授一直是深度学习的反对者,他认为深度学习并没有主动学习能力,且鲁棒性较差。同时,他始终认为人工智能应该多在“先天…

oracle10g新建数据,Oracle10g手工创建数据库

【注:本文中所有$表示在oracle用户中操作的命令、SQL>表示所有SQL语句】手工建库步骤:1、删除原有的数据库,如TEST命令:SQL> shutdown immediate;SQL> startup mount;SQL> alter system enable restricted session;SQ…

展望:模型驱动的深度学习

来源:《国家科学评论》概要:近年来,深度学习在人工智能领域一系列困难问题上取得了突破性成功应用。模型驱动的深度学习方法近年来,深度学习在人工智能领域一系列困难问题上取得了突破性成功应用。例如用于人脸识别已高于人的正确…

JPA架构

JPA(Java持久性API)是存储业务实体关联的实体的来源。它显示了如何定义一个面向普通Java对象(POJO)作为一个实体,以及如何与管理关系实体。 类级别架构 下图显示了JPA的类的层次结构。它显示核心类和JPA接口。 下表描述了每个在上述架构的显示单元。 单元描述Ent…

Amazon Go开门营业,号称无需现金、无需排队结账,现场究竟体验如何?

来源:36氪概要:无人零售的鼻祖Amazon Go姗姗来迟,那么体验究竟如何呢?无人零售的鼻祖Amazon Go姗姗来迟,那么体验究竟如何呢?当地时间周一(1月22日),位于西雅图亚马逊总部…

哪些是Linux内核的同步机制,Linux内核的同步机制(1)

Linux内核的同步机制(1)yanqin | 2009-04-16 14:51:09 阅读:791发布文章一、 引言%A%A 在现代操作系统里,同一时间可能有多个内核执行流在执行,因此内核其实象多进程多线程编程一样也需要一些同步机制来同步各执行单元对共享数据的访问。尤…

量子机器学习入门科普:解读量子力学和机器学习的共生关系

原作:Reena Shaw安妮 编译自 KDnuggets量子位 出品 | 公众号 QbitAI量子机器学习(Quantum ML)是量子力学和机器学习的一门交叉学科。两者间像一种共生关系,我们可以利用量子计算的力量生成机器学习算法的量子版本,并应…

RedissonClient 缓存Bug

引入背景 期望RedissonClient 能定期更新&#xff0c;避免网络不稳定导致 Redis 连接失效&#xff0c;只能重启服务&#xff1f; 使用了Caffeine 缓存&#xff0c;自动 2 小时失效剔除RedissonClient /*** 本地缓存.*/private static final Cache<String, RedissonClient&g…

人工智能重构下的金融场景

来源&#xff1a;亿欧概要&#xff1a;从金融领域来看&#xff0c;国际银行业对人工智能的主要应用集中在资本运营、市场分析、客户营销、风险监管等方面。智能客服、智能投顾、智能量化交易……人工智能在金融领域存在巨大的发展空间&#xff0c;但其也使监管更加复杂。近年来…

linux中写脚本不能写中文,Linux系统中Sublime Text无法输入中文怎么办?

Sublime Text是一个代码编辑器&#xff0c;拥有强大的功能&#xff0c;但Sublime Text 在Linux下运行的时候存在无法输入中文的问题&#xff0c;遇到该问题该如何解决呢&#xff1f;下面小编就给大家介绍下Linux下Sublime Text 无法输入中文的解决方法。1.保存下面的代码为subl…

深度学习引擎的终极形态是什么?

来源&#xff1a;微软研究院AI头条概要&#xff1a;1月17日&#xff0c;院友袁进辉博士回到微软亚洲研究院做了题为《打造最强深度学习引擎》的报告&#xff0c;分享了深度学习框架方面的技术进展。1月17日&#xff0c;院友袁进辉博士回到微软亚洲研究院做了题为《打造最强深度…

linux进程映像由哪些构成,Linux编程开发进程映像类型分析

进程与线程问题是程序员在学习编程开发语言需要重点掌握的编程知识之一&#xff0c;而今天我们就一起来了解一下&#xff0c;Linux编程开发中进程映像的执行标准。什么是进程映像呢?进程映像是执行程序时所需要的可执行文件&#xff0c;通常会包括下面这些东西代码段(codesegm…

AI芯片之争白热化的当下,如何设计一款真正适用于终端的AI芯片?

来源&#xff1a;36氪概要&#xff1a;2017年&#xff0c;人工智能最火的风口一定是AI芯片。2017年&#xff0c;人工智能最火的风口一定是AI芯片。AI芯片的出现&#xff0c;与深度学习技术的成熟及应用密不可分。深度学习的过程可以简化理解为利用大量标注的数据进行训练&#…

李开复:AI巨头是有史以来最难以打破的垄断

来源&#xff1a;凤凰网概要&#xff1a;李开复认为目前最需要的是小的AI公司&#xff0c;甚至于打破巨头垄断局面的“破局者”也会是这些由小变大的AI公司。当地时间周二(1月23日)&#xff0c;世界经济论坛在瑞士达沃斯小镇正式举行&#xff0c;各国政要、企业家、学者云集。创…

杨立昆辞Facebook人工智能实验室主任,任首席科学家

来源&#xff1a;澎湃新闻概要&#xff1a;他将不再担任Facebook 人工智能实验室主任一职&#xff0c;改任Facebook首席人工智能科学家&#xff0c;从而能更加专注于带领科学研究与AI策略。当地时间1月23日&#xff0c;执掌Facebook人工智能实验室&#xff08;FAIR&#xff09;…

Redis系列一、redis介绍与安装

一、Redis介绍 redis是一种基于键值对&#xff08;key-value&#xff09;数据库&#xff0c;其中value可以为string、hash、list、set、sorted set等多种数据结构&#xff0c;可以满足很多应用场景。还提供了键过期&#xff0c;发布订阅&#xff0c;事务&#xff0c;流水线&am…

redhat6.3的linux内核版本,1-6-RHEL6.3-内核升级(Red Hat Enterprise Linux Server6.3)@树袋飘零...

本节介绍内容&#xff1a;1、内核的概述2、源码编译安装文件系统中的ntfs内核模块案例分析1、内核的概述Linux操作系统是用来跟硬件和用户程序互联的支撑平台&#xff0c;设备的驱动程序完全可以访问硬件&#xff0c;而设备的驱动程序以模块化的形式设置&#xff0c;可以进行安…