Spring 学习(五)--- 事务(未完成)
问题 :
- Spring 事务传播机制是怎么样的,在什么应用场景使用
- 事务是什么
- 我们使用的框架可能是
Hibernate/JPA或者是Mybatis,都知道的底层是需要一个session/connection对象来帮我们执行操作的。要保证事务的完整性,我们需要多组数据库操作要使用同一个session/connection对象,而我们又知道Spring IOC所管理的对象默认都是单例的,这为啥我们在使用的时候不会引发线程安全问题呢?内部Spring到底干了什么?
概述
事务指逻辑上的一组操作,组成这组操作的各个单元,要不全部成功,要不全部不成功。 使用Spring 事务的优势有 :
- 一致的事务编程接口对应不同的事务API
- 声明式事务
- 提供简单的编程式事务API
- 与 Spring DATA 对接
Spring 事务可以通过两种方式实现事务,一种是 declarative transaction management(声明式事务) ,一种是program-matic transaction management (编程式事务),前者又可以通过两种形式来实现 XML 或是 javaConfig。
本文将会使用 @Transctional 注解的形式来解释Spring 事务。
Spring 事务
声明式事务
declarative transctional 事务主要运用到了AOP 的知识。
The most important concepts to grasp with regard to the Spring Framework’s declarative transaction support are that this support is enabled via AOP proxies and that the transactional advice is driven by metadata (currently XML- or annotation-based). The combination of AOP with transactional metadata yields an AOP proxy that uses a
TransactionInterceptorin conjunction with an appropriatePlatformTransactionManagerimplementation to drive transactions around method invocations.关于Spring Framework的声明式事务支持,最重要的概念是通过AOP代理启用此支持,并且事务性建议由元数据(当前基于XML或基于注释)驱动。 AOP与事务元数据的组合产生一个AOP代理,该代理使用TransactionInterceptor和适当的PlatformTransactionManager实现来驱动围绕方法调用的事务。
这里所说的与AOP相关,可以通过官方文档的这张图来理解 :

平时要是我们在使用spring事务的时候也可以通过Log看到代理的影子。
PlatformTransactionManager 又是什么呢?为什么它可以驱动底层的数据完成调用事务的动作。我们可以从下图来了解Spring 事务的内部结构。

可以看到Spring 事务管理接口提供了多种底层实现,由 PlatformTransactionManager 平台事务管理者来管理。下面讲一下使用,再通过使用来介绍知识点。
使用
例子中使用的是Spring MVC框架 ,以下是一个Service 的方法实现,mStudentDao 进行的操作都是与数据库相关的。
@Transactional(propagation= Propagation.REQUIRED,isolation= Isolation.DEFAULT,readOnly = true)
@Service
public class BeanTestServiceImpl implements BeanTestService {
@Autowired
private StudentDao mStudentDao; @Transactional(propagation= Propagation.REQUIRED,isolation= Isolation.DEFAULT,readOnly = false)
@Override
public void updateStuName(int id, String name) throws Exception {
mStudentDao.updateStuName(id,"pig");
int i = 5/0;
mStudentDao.updateStuName(id,"dog"); }
}
方法中的第二句明显会抛出异常,查看我们的数据库会发现第一句的更新语句发生了回退(rollback),示例很简单。我们看一下@Transcational 中的三个属性 : propagation , isolation , readOnly .
使用了AOP ,那么注解应该就要在应用在public 的方法上上,假如注解不是运用在public(例如protected或是private)上,
When you use proxies, you should apply the
@Transactionalannotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the@Transactionalannotation, no error is raised, but the annotated method does not exhibit the configured transactional settings. If you need to annotate non-public methods, consider using AspectJ (described later).
默认的@Transaction 设置如下 :
The propagation setting is
PROPAGATION_REQUIRED.The isolation level is
ISOLATION_DEFAULT.The transaction is read-write.
The transaction timeout defaults to the default timeout of the underlying transaction system, or to none if timeouts are not supported.
Any
RuntimeExceptiontriggers rollback, and any checkedExceptiondoes not.
其中propagation setting 和 isolation level 后面会进一步解释。我们看一下这个还有哪些属性可以设置。

后面几个属性和rollback有关,指定在什么情况下回退。
事务的隔离级别
这是 propagation 的选项。
- PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。
- PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。
- PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
- PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。
- PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
- PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
- PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
下面我们学习这几个选项。
Understanding PROPAGATION_REQUIRED(默认)
需要注意的地方:默认情况下,一个新的事务加入外部作用域,默认忽略会本地隔离级别,超时值或只读标志(如果有)。这样的场景就是当前的事务是read-only,新来了一个外部的事务是 read-write 的。
By default, a participating transaction joins the characteristics of the outer scope, silently ignoring the local isolation level, timeout value, or read-only flag (if any). Consider switching the
validateExistingTransactionsflag totrueon your transaction manager if you want isolation level declarations to be rejected when participating in an existing transaction with a different isolation level. This non-lenient mode also rejects read-only mismatches (that is, an inner read-write transaction that tries to participate in a read-only outer scope).
它的使用,引用官方文档中的一段叙述来说明 :
PROPAGATION_REQUIREDenforces a physical transaction, either locally for the current scope if no transaction exists yet or participating in an existing 'outer' transaction defined for a larger scope. This is a fine default in common call stack arrangements within the same thread (for example, a service facade that delegates to several repository methods where all the underlying resources have to participate in the service-level transaction).
Understanding PROPAGATION_REQUIRES_NEW
这是创建一个新的事务。完全独立于上一个事务的操作。
PROPAGATION_NESTED
PROPAGATION_NESTEDuses a single physical transaction with multiple savepoints that it can roll back to. Such partial rollbacks let an inner transaction scope trigger a rollback for its scope, with the outer transaction being able to continue the physical transaction despite some operations having been rolled back. This setting is typically mapped onto JDBC savepoints, so it works only with JDBC resource transactions.
PROPAGATION_NESTED设置了多个保存位置,让它遇到异常时只回滚一小部分,而不是全部,它只能在 JDBC resource transactions中使用。执行逻辑就是假如存在事务则嵌套执行,没有则和 require 一样。
关于Understanding PROPAGATION_REQUIRED 和 Understanding PROPAGATION_REQUIRES_NEW的应用场景,可以看到下面的例子 :
public class FooService {
private Repository repo1;
private Repository repo2;
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void provideService() {
repo1.retrieveFoo();
repo2.retrieveFoo();
}
}
我们可以写一个测试来对比它们两者表现的差异。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:/fooService.xml")
public class FooServiceTests { private @Autowired TransactionManager transactionManager;
private @Autowired FooService fooService; @Test
public void testProvideService() {
TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
fooService.provideService();
transactionManager.rollback(status);
// assert repository values are unchanged ...
}
Requires newwe would expectfooService.provideService()was NOT rolled back since it created it's own sub-transaction.Requiredwe would expect everything was rolled back and backing store unchanged.
例子来自于 Stack
isolation 隔离级别
隔离级别看这篇文章 :Mysql学习
使用场景
- REQUIRE_NEW : 新建事务,单独提交,单独回滚,不受外层事务影响
- Nested : 利用还原点来回滚,没有事务创建和创建,轻量级,性能好。(例如在批量处理某个事件,不至于全部回滚,只回滚到某个 savepoint)
原理解析
总结
参考资料
Spring 学习(五)--- 事务(未完成)的更多相关文章
- Spring学习8-Spring事务管理
http://blog.sina.com.cn/s/blog_7ffb8dd501014e0f.html Spring学习8-Spring事务管理(注解式声明事务管理) 标签: spring注 ...
- Spring 学习7 -事务
1 初步理解 理解事务之前,先讲一个你日常生活中最常干的事:取钱. 比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱:然后ATM出1000元钱.这两个步骤必须是 ...
- Spring学习之事务注解@Transactional
今天学习spring中的事务注解,在学习Spring注解事务之前需要明白一些事务的基本概念: 事务:并发控制的单位,是用户定义的一个操作序列.这些操作要么都做,要么都不做,是一个不可分割的工作单位.通 ...
- Spring学习8-Spring事务管理(编程式事务管理)
一.Spring事务的相关知识 1.事务是指一系列独立的操作,但在概念上具有原子性. 比如转账:A账号-100, B账号+100,完成.这两个操作独立是没问题的. 但在逻辑上,要么全部完成,要么一 ...
- Spring基础学习(五)—事务管理
一.事务基本认识 1.事务的概述 为了保证数据库中数据的一致性,数据的操作应当是离散的成组的逻辑单元.当它全部完成时,数据的一致性可以保持,而当这个单元中的一部分操作失败,整个事务应当全部视 ...
- Spring学习8-Spring事务管理(AOP/声明式式事务管理)
一.基础知识普及 声明式事务的事务属性: 一:传播行为 二:隔离级别 三:只读提示 四:事务超时间隔 五:异常:指定除去RuntimeException其他回滚异常. 传播行为: 所谓事务的传播行为 ...
- Spring学习8-Spring事务管理(注解式声明事务管理)
步骤一.在spring配置文件中引入<tx:>命名空间 <beans xmlns="http://www.springframework.org/schema/beans& ...
- spring学习(五) ———— 整合web项目(SSM)
一.SSM框架整合 1.1.整合思路 从底层整合起,也就是先整合mybatis与spring,然后在编写springmvc. 1.2.开发需求 查询商品列表(从数据库中查询) 1.3.创建web工程 ...
- Spring学习_day03_事务
本文为博主辛苦总结,希望自己以后返回来看的时候理解更深刻,也希望可以起到帮助初学者的作用. 转载请注明 出自 : luogg的博客园 谢谢配合! Spring_day03 一.事务 1.1 事务 事务 ...
- Spring学习五(JDBC支持)
Spring的jdbc支持 1配置db.properties,将有关JDBC的信息载入 2bean文件配置数据源,这里用e3p0作为数据源载入db.properties 3配置template的bea ...
随机推荐
- pageadmin CMS Sql Server2008 R2数据库安装教程
sql sever数据库建议安装sql2008或以上版本,如果电脑上没有安装数据库,参考下面步骤安装. sql2008 r2下载地址:点击下载 提取码: wfb4 下载后点击安装文件,安装步骤如下 ...
- Android intent 传值不更新的原因和解决办法
当 Activity 的启动模式是 singleTask 或者 singleInstance 的时候.如果使用了 intent 传值,则可能出现 intent 的值无法更新的问题.也就是说每次 int ...
- Java中的内部类(一)静态内部类
Java中的静态内部类:在定义的内部类前加static修饰符,此时的内部类就是静态内部类.通过一个例子来了解静态内部类都有哪些特点. public class Outer { //定义一个实例变量和一 ...
- “全栈2019”Java第九十一章:内部类具有多态特性吗?
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- 配置DNS服务器转发器
1.(windows server 2008 r2)控制面板->管理工具->服务器管理器->DNS->服务器图标->属性 2.转发器->编辑 3.填写DNS并点击确 ...
- oracle根据四位年周取当周周一的日期函数
create or replace function FUNC_GET_DATE_BY_WEEK( theYearWeek IN VARCHAR2)return date is normalDate ...
- nginx实现动静分离--附nginx配置文件详解
转自http://www.cnblogs.com/1214804270hacker/p/9299462.html 一.认识访问静态资源与访问动态资源的区别 静态资源:指存储在硬盘内的数据,固定的数据, ...
- python有哪些比较隐藏的知识点?
一.复用小整数以及小字符串 在Python语言中,设计者在优化Python语言时,为了提高Python的运行效率,所以就将一些小整数保存在系统表,没有释放回收(正常情况下,当Python中一个对象没有 ...
- docker微服务部署之:一,搭建Eureka微服务项目
先说明一下docker需要搭建的微服务的基本情况: 项目情况:一个demo_parent项目,下面三个子模块:demo_eureka(eureka服务).demo_article(文章服务).demo ...
- Java实现BF算法
package 串的算法; public class BF { public static void main(String[] args) { String a = "aaabbaaacc ...