Spring 事务模型
一、三种事务模型
1、本地事务模型:开发人员不用知道事务的存在,事务全部交给数据库来管理,数据库自己决定什么时候提交或回滚,所以数据库是事务的管理者。
Connection conn=jdbcDao.getConnection();
PreparedStatement ps=conn.prepareStatement("insert into user(name,age) value(?,?)");
ps.setString(1,user.getName());
ps.setInt(2,user.getAge());
ps.execute();
2、编程式事务模型:事务的提交和回滚操作完全交给开发人员,开发人员来决定事务什么时候提交或回滚,所以开发人员是事务的管理者。
Connection conn=jdbcDao.getConnection();
conn.setAutoCommit(false);
try {
PreparedStatement ps=conn.prepareStatement("insert into user(name,age) value(?,?)");
ps.setString(1,user.getName());
ps.setInt(2,user.getAge());
ps.execute();
conn.commit();
} catch (Exception e) {
e.printStackTrace();
conn.rollback();
} finally {
conn.close();
}
InitialContext ctx = new InitialContext();
UserTransaction txn = (UserTransaction)ctx.lookup("UserTransaction");
try {
txn.begin();
//业务代码
txn.commit();
} catch (Exception up) {
txn.rollback();
throw up;
}
3、声明式事务模型:开发人员完全不用关心事务,事务的提交和回滚操作全部交给Spring来管理,所以Spring是事务的管理者
@Transactional
public void save(User user){
jdbcTemplate.update("insert into user(name,age) value(?,?)",user.getName(),user.getAge());
}
二、编程式事务
编程式事务:即通过手动编程方式来实现事务操作,大部分情况,都是类似于上述案例2、3情况,开发人员来管理事务的提交和回滚,但也可能是Spring自己来管理事务,如Spring的TransactionTemplate
。
2.1 Spring的TransactionTemplate
使用jdbc操作事务,编程非常麻烦,老是需要写一套模板式的try catch代码,所以我们可以将try catch代码封装成一个模板,这就引出了Spring的TransactionTemplate:
TransactionTemplate template=new TransactionTemplate();
template.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
template.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
template.setTransactionManager(transactionManager);
template.execute(new TransactionCallback<User>() {
@Override
public User doInTransaction(TransactionStatus status) {
//可以使用DataSourceUtils获取Connection来执行sql
//jdbcTemplate.update(sql2); //可以使用SessionFactory的getCurrentSession获取Session来执行
//hibernateTemplate.save(user1)
return null;
}
});
1、TransactionTemplate继承了DefaultTransactionDefinition,有了默认的事务定义,也可以自定义设置隔离级别、传播属性等;
2、TransactionTemplate需要一个PlatformTransactionManager事务管理器,来执行事务的操作;
3、TransactionTemplate在TransactionCallback中执行业务代码,try catch的事务模板代码,则被封装起来,包裹在业务代码的周围,详细见TransactionTemplate的execute方法,如下:
详细过程如下:
1、第一步:根据事务定义获取事务
由于TransactionTemplate继承了DefaultTransactionDefinition,所以使用PlatformTransactionManager事务管理器来根据TransactionTemplate来获取事务;
2、第二步:执行业务代码
在TransactionCallback中的doInTransaction中执行相应的业务代码。如果使用的是DataSourceTransactionManager,你就可以使用JdbcTemplate来执行业务逻辑;或者直接使用Connection,但是必须使用DataSourceUtils来获取Connection。如果使用的是HibernateTransactionManager,就可以使用HibernateTemplate来执行业务逻辑,或者则可以使用SessionFactory的getCurrentSession方法来获取当前线程绑定的Session,不可使用SessionFactory的openSession方法。也是不可乱用的,下面详细解释。
3、第三步:如果业务代码出现异常,则回滚事务,没有异常则提交事务。回滚与提交都是通过PlatformTransactionManager事务管理器来进行的
三、Spring声明式事务
Spring可以有三种形式来配置事务拦截,不同配置形式仅仅是外在形式不同,里面的拦截原理都是一样的,所以先通过一个小例子了解利用AOP实现事务拦截的原理
@Transactional
public void save(User user){
jdbcTemplate.update("insert into user(name,age) value(?,?)",user.getName(),user.getAge());
}
上面使用的就是Spring AOP,这里给出一个简单的AOP事务拦截原理的小例子:
@Repository
public class AopUserDao implements InitializingBean{ @Autowired
private UserDao userDao; private UserDao proxyUserDao; @Resource(name="transactionManager")
private PlatformTransactionManager transactionManager; @Override
public void afterPropertiesSet() throws Exception {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(userDao); TransactionInterceptor transactionInterceptor=new TransactionInterceptor();
transactionInterceptor.setTransactionManager(transactionManager);
Properties properties=new Properties();
properties.setProperty("*","PROPAGATION_REQUIRED");
transactionInterceptor.setTransactionAttributes(properties); proxyFactory.addAdvice(transactionInterceptor);
proxyUserDao=(UserDao) proxyFactory.getProxy();
} public void save(User user){
proxyUserDao.save(user);
}
}
代码分析如下:
1、首先需要一个原始的UserDao,我们需要对它进行AOP代理,产生代理对象proxyUserDao,之后保存的功能就是使用proxyUserDao来执行
2、对UserDao具体的代理过程如下:
- 使用代理工厂,设置要代理的对象,即target
proxyFactory.setTarget(userDao);
- 对代理对象加入拦截器:分成2种情况,一种默认拦截原UserDao的所有方法,一种是指定Pointcut,即拦截原UserDao的某些方法
这里使用proxyFactory.addAdvice(transactionInterceptor);就表示默认拦截原UserDao的所有方法。如果使用proxyFactory.addAdvisor(advisor),这里的Advisor可以简单看成是Pointcut和Advice的组合,Pointcut则是用于指定是否拦截某些方法。上述addAdvice就是使用了默认的Pointcut,表示对所有方法都拦截,源码如下:
addAdvisor(pos, new DefaultPointcutAdvisor(advice));
DefaultPointcutAdvisor内容如下:
public DefaultPointcutAdvisor(Advice advice) {
this(Pointcut.TRUE, advice); // Pointcut.TRUE便表示拦截所有方法。
}
- 设置好代理工厂要代理的对象和拦截器后,便可以创建代理对象
proxyUserDao=(UserDao) proxyFactory.getProxy();
之后,我们在使用创建出的proxyUserDao时,就会首先进入拦截器,执行相关拦截器代码,因此我们可以在这里实现事务的处理。
3.1 事务拦截器的原理分析
事务拦截器需要2个参数:
1、事务配置的提供者:用于指定哪些方法具有什么样的事务配置。可以通过属性配置方式,或者通过其他一些配置方式,如下三种方式都是为了获取事务配置提供者:
2、事务管理器PlatformTransactionManager:有了事务的配置,我们就可以通过事务管理器来获取事务了
在执行代理proxyUserDao的save(user)方法时,会先进入事务拦截器中,具体的拦截代码如下:
第一步:首先获取所执行方法的对应的事务配置
第二步:然后获取指定的事务管理器PlatformTransactionManager
第三步:根据事务配置,使用事务管理器创建出事务
第四步:继续执行下一个拦截器,最终会执行到代理的原始对象的方法
第五步:一旦执行过程发生异常,使用事务拦截器进行事务的回滚
第六步:如果没有异常,则使用事务拦截器提交事务
3.2 Spring的三种事务配置形式
1、使用TransactionProxyFactoryBean
<bean id="proxy"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!-- 为事务代理工厂Bean注入事务管理器 -->
<property name="transactionManager" ref="transactionManager" />
<!-- 要在哪个Bean上面创建事务代理对象 -->
<property name="target" ref="productDao" />
<!-- 指定事务属性 -->
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
上面有三大配置:
- 事务管理器transactionManager
- 事务配置的提供者transactionAttributes(用于指定哪些方法具有什么样的事务配置)
有了以上2个元素,我们就可以创建出一个事务拦截器TransactionInterceptor
- 要代理的对象target
TransactionProxyFactoryBean这个工厂bean创建代理对象的原理就是:通过ProxyFactory来对target创建出代理对象了,同时加入上述事务拦截器,就可以实现事务拦截功能了
2、使用aop:config和tx:advice
使用TransactionProxyFactoryBean的方式只能针对一个target进行代理,如果想再代理一个target,就需要再配置一个TransactionProxyFactoryBean,比较麻烦,所以使用apo:config的配置形式,就可以针对符合Pointcut的所有target都可以进行代理
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="add*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice> <aop:config>
<aop:pointcut id="pc" expression="execution(public * com.qding..service.*.*(..))" />
<aop:advisor pointcut-ref="pc" advice-ref="txAdvice" />
</aop:config>
- tx:advice:有事务管理器transactionManager和事务配置提供者attributes,就可以产生一个事务拦截器TransactionInterceptor
- aop:config:这里会对符合pointcut的bean创建出代理对象,同时加入上述创建的事务拦截器
3、使用@Transactional
使用aop:config可以在xml中进行代理的配置,有时候想在代码中直接进行配置,这时候就需要使用注解@Transactional。
xml中启动@Transactional注解扫描:
<tx:annotation-driven transaction-manager="transactionManager" />
在代码中就可以通过配置@Transactional来实现事务拦截了:
@Transactional(propagation=Propagation.REQUIRED)
public void save(User user){
xxxx
}
在xml配置中启动注解扫描,会把那些加入了@Transactional标记的容器bean创建出代理对象,同时加入事务拦截器。在执行事务拦截的时候,会从@Transactional注解中取出对应的事务配置和事务管理器配置,进而可以执行事务的创建等操作。
参见:http://my.oschina.net/xianggao/blog/541527?fromerr=f37Nd3l5
Spring 事务模型的更多相关文章
- java面试记录二:spring加载流程、springmvc请求流程、spring事务失效、synchronized和volatile、JMM和JVM模型、二分查找的实现、垃圾收集器、控制台顺序打印ABC的三种线程实现
注:部分答案引用网络文章 简答题 1.Spring项目启动后的加载流程 (1)使用spring框架的web项目,在tomcat下,是根据web.xml来启动的.web.xml中负责配置启动spring ...
- spring事务管理器设计思想(一)
在最近做的一个项目里面,涉及到多数据源的操作,比较特殊的是,这多个数据库的表结构完全相同,由于我们使用的ibatis框架作为持久化层,为了防止每一个数据源都配置一套规则,所以重新实现了数据源,根据线程 ...
- Spring事务管理(转)
1 初步理解 理解事务之前,先讲一个你日常生活中最常干的事:取钱. 比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱:然后ATM出1000元钱.这两个步骤必须是 ...
- Spring 事务管理高级应用难点剖析--转
第 1 部分 http://www.ibm.com/search/csass/search/?q=%E4%BA%8B%E5%8A%A1&sn=dw&lang=zh&cc=CN& ...
- 2015第24周三Spring事务3
在一个典型的事务处理场景中,有以下几个参与者: Resource Manager(RM) ResourceManager简称RM,它负责存储并管理系统数据资源的状态,比如数据库服务器,JMS消息服务器 ...
- 2015第24周一Spring事务
1. Spring事务管理简介 (1)Spring为多种不同类型的事务管理机制提供统一编程模型,这些事务管理模型包括JTA.JDBC.Hibernate.JPA和JDO. (2)Spring支持声明式 ...
- Spring 事务管理笔记
本文为 Spring 框架的事务管理学习笔记,官网文档地址为:Transaction Management,隔离级别及传播属性解释来自 org.springframework.transaction. ...
- spring事务详解(一)初探事务
系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 引子 很多 ...
- 框架源码系列十一:事务管理(Spring事务管理的特点、事务概念学习、Spring事务使用学习、Spring事务管理API学习、Spring事务源码学习)
一.Spring事务管理的特点 Spring框架为事务管理提供一套统一的抽象,带来的好处有:1. 跨不同事务API的统一的编程模型,无论你使用的是jdbc.jta.jpa.hibernate.2. 支 ...
随机推荐
- mysql数据库基础的简单操作指南
最近在学习mysql,本文是做的关于mysql学习的笔记,跟大家分享一下,希望对大家学习mysql知识有所助益.mysql现在几乎已经成了网站建设的主流数据库,很多php网站系统都采用了mysql数据 ...
- codeforces 354 DIV2
B - Pyramid of Glasses n层杯子,问k分钟能流满多少个杯子?和到香槟一样的过程? 思路:应为水的流速为每分钟一立方体(YY),可以做个转化,把最上层的杯子最原始的容积看成K,每个 ...
- 50道经典的JAVA编程题 (11-15)
50道经典的JAVA编程题 (11-15),新年的第一天,继续啦...\(^o^)/~,这50道题都跨年了啊...哈哈 [程序11] TestTN.java 题目:有1.2.3.4个数字,能组成多少个 ...
- 【Kafka入门】搭建Kafka本地环境
本博文介绍如何一步步搭建起Kafka本地环境. 下载Kafka 0.9.0.0 并配置软链接 下载好后,放入电脑本地安装目录,mac下我放在/usr/local下,解压Kafka. -0.9.0.0. ...
- 【Hadoop代码笔记】Hadoop作业提交之JobTracker等相关功能模块初始化
一.概要描述 本文重点描述在JobTracker一端接收作业.调度作业等几个模块的初始化工作.想过模块的介绍会在其他文章中比较详细的描述.受理作业提交在下一篇文章中会进行描述. 为了表达的尽可能清晰一 ...
- CoreSeek中文检索引擎
目的:安装coreseek中文检索引擎,配置MySQL数据库访问接口,使用PHP程序实现中文检索. CoreSeek官方网站: http://www.coreseek.cn/ http://www.c ...
- light oj 1138
Time Limit:2000MS Memory Limit:32768KB 64bit IO Format:%lld & %llu Submit Status Pract ...
- [iOS基础控件 - 5.1] UIScrollView
A.需要掌握 UIScrollView 是一个能够滚动的视图控件,可以用来展示大量内容,如手机的“设置” 1.常见属性 2.常用代理方法 3.缩放 4.UIScrollView和UIPageContr ...
- HTML5要点(一)
一.标签: <!-- -->:注释:cmd +/ <!DOCTYPE html><!--HTML5 专属版本声明标签(表明该页面使用HTML编写),代码最上层--> ...
- cocos2d-x ScrollView、TableView
转自:http://codingnow.cn/cocos2d-x/1024.html 在游戏和应用中经常要实现左右滑动展示游戏帮助.以列表显示内容的UI效果,就像android中的Gallery和Li ...