JPA和事务管理

1 事务

1.1事务管理方式

spring支持编程式事务管理和声明式事务管理两种方式。

编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。

声明式事务管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。

显然声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式。声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要加上注解就可以获得完全的事务支持。和编程式事务相比,声明式事务唯一不足地方是,后者的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等。

声明式事务管理也有两种常用的方式,一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解。显然基于注解的方式更简单易用,更清爽。

1.2自动提交(AutoCommit)与连接关闭时的是否自动提交

默认情况下,数据库处于自动提交模式。每一条语句处于一个单独的事务中,在这条语句执行完毕时,如果执行成功则隐式的提交事务,如果执行失败则隐式的回滚事务。对于正常的事务管理,是一组相关的操作处于一个事务之中,因此必须关闭数据库的自动提交模式。不过,spring会将底层连接的自动提交特性设置为false。

当一个连接关闭时,如果有未提交的事务应该如何处理?JDBC规范没有提及,C3P0默认的策略是回滚任何未提交的事务。这是一个正确的策略,但JDBC驱动提供商之间对此问题并没有达成一致。

1.3事务隔离级别

隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量:

1、TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是TransactionDefinition.ISOLATION_READ_COMMITTED

2、TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别。比如PostgreSQL实际上并没有此级别。

3、TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。

4、TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。该级别可以防止脏读和不可重复读。

5、TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

注:

MYSQL: 默认为REPEATABLE_READ级别
SQLSERVER: 默认为READ_COMMITTED

脏读 :一个事务读取到另一事务未提交的更新数据
不可重复读 :在同一事务中, 多次读取同一数据返回的结果有所不同, 换句话说, 
后续读取可以读到另一事务已提交的更新数据. 相反, "可重复读"在同一事务中多次
读取数据时, 能够保证所读数据一样, 也就是后续读取不能读到另一事务已提交的更新数据

幻读 :一个事务读到另一个事务已提交的insert数据。

1.4事务传播行为

所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:

1、TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。

2、TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。

3、TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。

4、TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。

5、TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。

6、TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。

7、TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED

例如:@Transactional(propagation=Propagation.REQUIRED) 

1.5事务超时

所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。

默认设置为底层事务系统的超时值,如果底层数据库事务系统没有设置超时值,那么就是none,没有超时限制。@Transactional(timeout=30) //默认是30秒

1.6事务只读属性

只读事务用于客户代码只读但不修改数据的情形,只读事务用于特定情景下的优化,比如使用Hibernate的时候。默认为读写事务。

@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)

只读标志只在事务启动时应用,否则即使配置也会被忽略。启动事务会增加线程开销,数据库因共享读取而锁定(具体跟数据库类型和事务隔离级别有关)。通常情况下,仅是读取数据时,不必设置只读事务而增加额外的系统开销。

1.7 spring事务回滚规则

指示spring事务管理器回滚一个事务的推荐方法是在当前事务的上下文内抛出异常。spring事务管理器会捕捉任何未处理的异常,然后依据规则决定是否回滚抛出异常的事务。

默认配置下,spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚),而抛出checked异常(编译器会检查到的异常叫受检查异常)则不会导致事务回滚。
可以明确的配置在抛出那些异常时回滚事务,包括checked异常。也可以明确定义那些异常抛出时不回滚事务。如: @Transactional(notRollbackFor=RunTimeException.class)、@Transactional(rollbackFor=Exception.class)

还可以编程性的通过setRollbackOnly()方法来指示一个事务必须回滚,在调用setRollbackOnly()后你所能执行的唯一操作就是回滚。

1.8 @Transactional注解

@Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。

虽然 @Transactional 注解可以作用于接口、接口方法、类以及类方法上,但是 Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效,因为注解是不能继承的,这就意味着如果你正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装(将被确认为严重的)。另外, @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。

默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰。

2  关于UnexpectedRollbackException异常。


因为在被spring事务代理方法中, 被代理的方法(dosomething())内部有异常抛出,事务会标记为回滚,并在最外层调用那(service里的callB中)回滚。 这种情况下transaction会正常的rollback。

 
这个时候,我们再调用ServiceA的callB。程序会抛出org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only这样一个异常信息.因为在ServiceA和ServiceB中的@Transactional propagation都采用的默认值:REQUREID。根据我们前面讲过的REQUIRED特性,当ServiceA调用ServiceB的时候,他们是处于同一个transaction中。当ServiceB中抛出了一个异常以后,ServiceB会把当前的transaction标记为需要rollback(设置rollBackOnly状态),继续执行到serviceA, 可是被serviceA中的方法捕获了并进行了处理,也就不回滚了,一直执行到最后commit。在commit时spring会判断回滚标志(rollBackOnly状态),若有回滚标记,回滚并抛出UnexpectedRollbackException异常(因为出现了前后不一致)。


此时,程序可以正常的退出了,也没有抛出UnexpectedRollbackException。原因是因为当ServiceA调用ServiceB时,serviceB的doSomething是在一个新的transaction中执行的。当doSomething抛出异常以后,仅仅是把新创建的transaction rollback了,而不会影响到ServiceA的transaction。ServiceA就可以正常的进行commit。

3  访问多个数据源或者多个数据库

利用@Transactional 的value属性定不同的事务管理器。主要用来满足:在同一个系统中存在不同的事务管理器时,可以用此参数来根据需要指定特定的transactionManager(配置文件中qualifier元素定义的名称)。比如:在同一个系统中,需要访问多个数据源或者多个数据库时,则必然会配置多个事务管理器。

类或方法上添加注解:@Transactional(value= "system"),或简写为@Transactional("system"),即显式的要求spring用id="system"的事务管理器来管理事务。该属性亦可省略(省略的话用容器中缺省的事务管理器),

注:spring容器缺省事务管理器:以加载顺序,首先加载的作为缺省。例如如果

<tx:annotation-driven transaction-manager="transactionManagerX" /><tx:annotation-driven transaction-manager="transactionManagerY" />

定义在同一个文件中,则第一个transactionManagerX作为缺省。定义在不同文件,则按文件的加载顺序,首先加载的作为缺省。

4  transaction和EntityManager

(1)、关于persistence context(持久化上下文)和database transaction(事务)

@Transactional本身定义了单个事务的范围。这个事务在persistence context的范围内。JPA中的持久化上下文是EntityManager,内部实现使用了Hibernate Session(使用Hibernate作为持久化provider)。持久化上下文仅仅是一个同步对象,它记录了有限集合的Java对象的状态,并且保证这些对象的变化最终持久化到数据库。这是与单个事务非常不同的概念。一个Entity Manager可以跨越多个事务使用,而且的确是这样使用的。EntityManager何时跨越多个事务?最常见的情况是应用使用Open Session In View模式处理懒初始化异常时。这种情况下视图层运行的多个查询处于独立的事务中,而不是单事务的业务逻辑,但这些查询由相同的entity manager管理。另一种情况是开发人员将持久化上下文标记为PersistenceContextType.EXTENDED,这表示它能够响应多个请求。

如何定义EntityManager和Transaction之间的关系?这由应用开发者来选择,但是JPA Entity Manager最常用的方式是“Entity Manager per application transaction”(每个事务都有自己的实体管理器)模式。entity manager注入的常用方法是:
@PersistenceContext
private EntityManager em;
这里默认为“Entity Manager per transaction”模式。这种模式下如果在@Transactional方法内部使用该Entity Manager,那么该方法将在单一事务中运行。EntityManager是一个接口,注入到spring bean中的不是entity manager本身,而是在运行时代理具体entity manager的context aware proxy(上下文感知代理)。

(2)、事务的实现

实现了EntityManager接口的持久化上下文代理并不是声明式事务管理的唯一部分,事实上包含三个组成部分:

EntityManager Proxy本身、事务的切面、事务管理器
这三部分以及它们之间的相互作用如下:。

1、事务的切面

事务的切面是一个“around(环绕)”切面,在注解的业务方法前后都可以被调用。实现切面的具体类是TransactionInterceptor。

事务的切面有两个主要职责:

在’before’时,切面提供一个调用点,来决定被调用业务方法应该在正在进行事务的范围内运行,还是开始一个新的独立事务。
在’after’时,切面需要确定事务被提交,回滚或者继续运行。
在’before’时,事务切面自身不包含任何决策逻辑,是否开始新事务的决策委派给事务管理器完成。

2、事务管理器

事务管理器需要解决下面两个问题:

新的Entity Manager是否应该被创建?是否应该开始新的事务?这些需要事务切面’before’逻辑被调用时决定。事务管理器的决策基于以下两点:

事务是否正在进行
事务方法的propagation属性(比如REQUIRES_NEW总要开始新事务)
如果事务管理器确定要创建新事务,那么将创建一个新的entity manager,entity manager绑定到当前线程,从数据库连接池中获取连接,将连接绑定到当前线程,使用ThreadLocal变量将entity manager和数据库连接都绑定到当前线程。事务运行时他们存储在线程中,当它们不再被使用时,事务管理器决定是否将他们清除。程序的任何部分如果需要当前的entity manager和数据库连接都可以从线程中获取。

3、EntityManager proxy

当业务方法调用entityManager.persist()时,这不是由entity manager直接调用的。而是业务方法调用代理,代理从线程获取当前的entity manager,事务管理器将entity manager绑定到线程。
 

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

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

相关文章

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

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

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

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

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

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

JPA架构

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

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

来源&#xff1a;36氪概要&#xff1a;无人零售的鼻祖Amazon Go姗姗来迟&#xff0c;那么体验究竟如何呢&#xff1f;无人零售的鼻祖Amazon Go姗姗来迟&#xff0c;那么体验究竟如何呢&#xff1f;当地时间周一&#xff08;1月22日&#xff09;&#xff0c;位于西雅图亚马逊总部…

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

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

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

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

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;可以进行安…

MIT人工突触芯片新突破:指甲大小的芯片有望媲美超算

原作 Jennifer ChuRoot 编译自 MIT News量子位 出品 | 公众号 QbitAI论传递信息的能力&#xff0c;计算机的二进制目前还比不上人脑。因为大脑神经元之间传递的信号形式远多过0或1两种&#xff1a;根据突触&#xff08;神经元之间的结构&#xff09;间不同的神经递质&#xff0…

Redis系列二、redis的五种数据结构和相关指令之String

redis是一种基于键值对&#xff08;key-value&#xff09;的内存数据库&#xff0c;redis数据结构可以分为string、hash、list、set、sorted set。本节中将介绍Redis支持的主要数据结构中的string&#xff0c;以及相关的常用Redis命令。 redis的五种数据结构和相关指令之Strin…

体积最小桌面linux,Tiny Core Linux - 体积最小的精简 Linux 操作系统发行版之一 (仅10多MB) - 蓝月网络...

Tiny Core Linux (TCL) 是一款极体积极小且高度可扩展的微型 Linux 发行版&#xff0c;它将一个 Linux 操作系统精简到仅有 10 多 MB 左右的大小&#xff0c;似乎小巧得有点让人叹为观止&#xff01;要知道无论是常见的 Ubuntu、CentOS、Debian 的体积动辄就是几百MB甚至要上GB…