一、三种事务模型

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>() {@Overridepublic 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{@Autowiredprivate UserDao userDao;private UserDao proxyUserDao;@Resource(name="transactionManager")private PlatformTransactionManager transactionManager;@Overridepublic 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 事务模型相关推荐

  1. spring上下文是什么意思_Java程序员只会CRUD连Spring事务传播机制都不懂?

    AQS到底有什么用?难道就真的只是为了面试吗? 当然不是说AQS没用,如果你不是做基础架构或者中间件开发,你很难感受到AQS的威力.当然,学习很多时候,需要的是正向反馈,学了太多造火箭的东西,面试完就 ...

  2. Spring事务管理 与 SpringAOP

    1,Spring事务的核心接口 Spring事务管理的实现有许多细节,如果对整个接口框架有个大体了解会非常有利于我们理解事务,下面通过讲解Spring的事务接口来了解Spring实现事务的具体策略.  ...

  3. 原创 | CRUD更要知道的Spring事务传播机制

    来自:肥朝 AQS到底有什么用?难道就真的只是为了面试吗? 当然不是说AQS没用,如果你不是做基础架构或者中间件开发,你很难感受到AQS的威力.当然,学习很多时候,需要的是正向反馈,学了太多造火箭的东 ...

  4. Spring 事务管理高级应用难点剖析

    Spring 事务管理高级应用难点剖析: 第 1 部分 http://www.ibm.com/developerworks/cn/java/j-lo-spring-ts1/index.html htt ...

  5. spring事务介绍

    一.spring事务介绍 spring事务优点 对不同的api进行统一编程模型,如JTA,JDBC,Hibernate,JPA,JDO... 支持声明式事务 简化编程式事务api 对spring数据层 ...

  6. Spring 事务管理高级应用难点剖析--转

    第 1 部分 http://www.ibm.com/search/csass/search/?q=%E4%BA%8B%E5%8A%A1&sn=dw&lang=zh&cc=CN& ...

  7. Spring事务管理(详解+实例)

    写这篇博客之前我首先读了<Spring in action>,之后在网上看了一些关于Spring事务管理的文章,感觉都没有讲全,这里就将书上的和网上关于事务的知识总结一下,参考的文章如下: ...

  8. Spring事务专题(四)Spring中事务的使用、抽象机制及模拟Spring事务实现

    前言 本专题大纲如下: 事务专题大纲 「对于专题大纲我又做了调整哈,主要是希望专题的内容能够更丰富,更加详细」,本来是想在源码分析的文章中附带讲一讲事务使用中的问题,这两天想了想还是单独写一篇并作为事 ...

  9. Spring事务原理一探

    概括来讲,事务是一个由有限操作集合组成的逻辑单元.事务操作包含两个目的,数据一致以及操作隔离.数据一致是指事务提交时保证事务内的所有操作都成功完成,并且更改永久生效:事务回滚时,保证能够恢复到事务执行 ...

  10. 【技术干货】Spring事务原理一探

    本篇文章是网易云信研发工程师对Spring事务实现原理及实现的研究和总结,分享给大家,希望和大家共同探讨. 事务是一个由有限操作集合组成的逻辑单元.事务操作包含两个目的,数据一致以及操作隔离.数据一致 ...

最新文章

  1. python-docx表格设置实线_python docx加入表格 在表格中加图,设置框线
  2. SAP附件UI里选择的文件是如何传到ABAP服务器的
  3. java输入输出及文件_(java基础)Java输入输出流及文件相关
  4. 新入职了一个卷王,天天加班12点!张口闭口就是性能优化,太让人崩溃……...
  5. 201671030107 胡文艳 实验十四 团队项目评审课程项目总结
  6. 计算机各个部件配合完成加减乘除(计组学习二)
  7. 使用篇-基于Laravel开发博客应用系列 —— 联系我们 发送邮件 队列使用(基于数据库)...
  8. 商业数据分析的层次与步骤有哪些
  9. 早教机器人刷固件_E-puck2机器人系列教程-固件修复升级
  10. 微信抢号软件_强推|那些写微信公众号一定要拥有的软件
  11. 如何打开.azw3 .epub .mobi文件?
  12. 【LaTeX】 案例分析 (8) - 高等数学分析 Mathematica 实验报告
  13. win7打开xp共享的计算机,高手教你如何让XP与Win7系统局域网共享
  14. HTTP 和 HTTPS 有什么区别?
  15. 初识Cpp之 三、Cpp预处理器
  16. 千万别小看一个面相好的女人!
  17. 事件的独立和事件互不相容两个概念的区别
  18. 初识MyBatis Plus
  19. PHP实现网易夺宝的算法
  20. 【Linux随笔随记】三、sheel语法-数组

热门文章

  1. 生成.pkl文件,读取.pkl文件的内容
  2. vsftp如何确定地址_VSFTP配置参数详解
  3. oracle还原数据库方法,oracle数据库备份与还原(命令与方法)
  4. netbeans linux 安装教程,linux下安装NetBeans 6.0
  5. php 去除空余字符,PHP 删除字符串末端的空白字符(或者其他字符)
  6. 职称计算机和英语有效性,2015职称计算机考试突破小诀窍
  7. python import as 实例化_python中import list,dictionary常量在class实例化时遇到的坑
  8. SQL Serever学习14——存储过程和触发器
  9. Android知识点复习1(Activity与Fragment)
  10. Cesium 显示CZML数据