spring事务原理二
2015-11-30 22:36
399 查看
(1)对业务方法aop横切
如果我们从原来硬编码的事务管理系统中,将事务管理相关代码剥离出来,我们会怎么做?最直观的方法就是提供一个工具类,将事务管理逻辑几种到这个类中,而service实现类必须在执行前后调用工具类即可。
虽然这种方法可以让事务管理代码和业务代码分离,但是也是有很大缺陷的。实际上最好的方法就是使用aop,在执行前后进行事务管理操作。现在用拦截器实现,代码如下:
(2)保证spring和DAO框架使用的是同一个Connection
1.为何必须保证在同一个连接中?
类比jdbc操作,都是先setAutoCommit(false),然后再进行CURD操作,最后commit
只有这样才能保证能够对事务中的操作进行回滚和提交
所以,必须要保证spring进行的事务操作和DAO框架使用的Connection是同一个
2.如何保证在同一个连接中?
1)先看一下spring中定义
可以看出spring的TransactionManager和ibatis使用的是同一个dataSource
2)spring可以偷偷将这个dataSource替换为动态代理类
有了这个动态代理类,spring就可以在getConnection方法前后进行一系列操作了
那么再来看下ResourceHolder
如果我们从原来硬编码的事务管理系统中,将事务管理相关代码剥离出来,我们会怎么做?最直观的方法就是提供一个工具类,将事务管理逻辑几种到这个类中,而service实现类必须在执行前后调用工具类即可。
虽然这种方法可以让事务管理代码和业务代码分离,但是也是有很大缺陷的。实际上最好的方法就是使用aop,在执行前后进行事务管理操作。现在用拦截器实现,代码如下:
public class PrototypeTransactionInterceptor implements MethodInterceptor { private PlatformTransactionManager transactionManager; public Object invoke(MethodInvocation invocation) throws Throwable { Method method = invocation.getMethod(); TransactionDefinition definition = getTransactionDefinitionByMethod(method); TransactionStatus txStatus = transactionManager.getTransaction(definition);//开启事务 Object result = null; try { result = invocation.proceed(); } catch (Throwable t) { if (needRollbackOn(t)) { transactionManager.rollback(txStatus); } else { transactionManager.commit(txStatus); } throw t; } transactionManager.commit(txStatus); return result; } private boolean needRollbackOn(Throwable t) { // TODO ... return false; } private TransactionDefinition getTransactionDefinitionByMethod( Method method) { // TODO ... return null; } public PlatformTransactionManager getTransactionManager() { return transactionManager; } public void setTransactionManager(PlatformTransactionManager transactionManager) { this.transactionManager = transactionManager; } }
(2)保证spring和DAO框架使用的是同一个Connection
1.为何必须保证在同一个连接中?
类比jdbc操作,都是先setAutoCommit(false),然后再进行CURD操作,最后commit
只有这样才能保证能够对事务中的操作进行回滚和提交
所以,必须要保证spring进行的事务操作和DAO框架使用的Connection是同一个
2.如何保证在同一个连接中?
1)先看一下spring中定义
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/test" /> <property name="username" value="root" /> <property name="password" value="123" /> </bean> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"> <property name="configLocation"> <!-- name 为configLocation或s 不可为其他 --> <value>sqlMap.xml</value> <!-- 不区分大小写,路径前可加'/' --> </property> <property name="dataSource"> <ref local="dataSource" /> </property> </bean>
可以看出spring的TransactionManager和ibatis使用的是同一个dataSource
2)spring可以偷偷将这个dataSource替换为动态代理类
有了这个动态代理类,spring就可以在getConnection方法前后进行一系列操作了
public class DatasourceHandler implements InvocationHandler { private DataSource dataSource; /** * @param dataSource */ public DatasourceHandler(DataSource dataSource) { super(); this.dataSource = dataSource; } /* (non-Javadoc) * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(method.getName().equals("getConnection")){ if(ResourceHolder.getResource(proxy)==null){ Connection connection = (Connection) method.invoke(this.dataSource, args); ResourceHolder.addResource(proxy, connection); } return ResourceHolder.getResource(proxy); }else{ return method.invoke(this.dataSource, args); } } }可以看出:先判断是否是getConnection方法,如果是,就判断ResourceHolder的resource中是否存在连接,如果不存在,就通过原来的DataSource(也就是spring中直接定义的那个)获取数据库连接,然后存放在ResourceHolder的resource中
那么再来看下ResourceHolder
public class ResourceHolder { private static ThreadLocal<Map<Object,Object>> resources= new ThreadLocal<Map<Object,Object>>(); public static void addResource(Object key,Object value){ if(resources.get()==null){ resources.set(new HashMap<Object,Object>()); } resources.get().put(key, value); } public static Object getResource(Object key){ return resources.get().get(key); } public static void clear(){ resources.remove(); } }可以看出resources实际上是ThreadLocal类型的,也就保证了一个线程中的connection肯定是同一个,这就保证了spring和DAO框架使用的是同一个connection,那么就可以进行事务管理了
相关文章推荐
- Java NIO和IO的主要区别
- java中的Collection
- SpringMVC文件上传注意事项
- 安装eclipse开发android
- spring4声明式事务—02 xml配置方式
- spring security 自定义登陆 - AJAX
- spring4声明式事务--01注解方式
- Spring面试题
- eclipse Android模拟器无法创建
- JAVAWEB之自定义TAG开发二
- 终极解释: java方法传递参数的方式
- jsp 百度编辑器配置 整合springmvc注意细节
- 菜鸟好文推荐(二十六)——避免Java堆空间错误的5个步骤
- Javaweb邮箱验证注册的实现
- 观察者模式
- java Swing局域网聊天软件+ 情侣电脑钢琴
- 跑批利器--往数据库里配置SpringBatch
- 用户角色权限管理系统-----java web 脚手架搭建(一)
- 跑批利器--SpringBatch框架
- HD1001 java版答案