该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2012-04-24
最后修改:2012-04-24
1、问题
Connection conn = DataSourceUtils.getConnection(); //开启事务 conn.setAutoCommit(false); try { Object retVal = callback.doInConnection(conn); conn.commit(); //提交事务 return retVal; }catch (Exception e) { conn.rollback();//回滚事务 throw e; }finally { conn.close(); } Session session = null; Transaction transaction = null; try { session = factory.openSession(); //开启事务 transaction = session.beginTransaction(); transation.begin(); session.save(user); transaction.commit();//提交事务 } catch (Exception e) { e.printStackTrace(); transaction.rollback();//回滚事务 return false; }finally{ session.close(); }缺点:不一致的事务管理,复杂
2、高层次解决方案(编程式实现事务)
public interface PlatformTransactionManager { TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; void commit(TransactionStatus status) throws TransactionException; void rollback(TransactionStatus status) throws TransactionException; } //1.获取事务管理器 PlatformTransactionManager txManager = (PlatformTransactionManager) ctx.getBean("txManager"); //2.定义事务属性 DefaultTransactionDefinition td = new DefaultTransactionDefinition(); td.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED); //3开启事务,得到事务状态 TransactionStatus status = txManager.getTransaction(td); try { //4.执行数据库操作 System.out.println(jdbcTempate.queryForInt("select count(*) from tbl_doc")); //5、提交事务 txManager.commit(status); }catch (Exception e) { //6、回滚事务 txManager.rollback(status); }
3、高层次解决方案(模板解决方案)
//1.获取事务管理器 PlatformTransactionManager txManager = (PlatformTransactionManager) ctx.getBean("txManager"); //2、定义事务管理的模板 TransactionTemplate transactionTemplate = new TransactionTemplate(txManager); //3.定义事务属性 transactionTemplate. setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED); //4.回调,执行真正的数据库操作,如果需要返回值需要在回调里返回 transactionTemplate.execute(new TransactionCallback() { @Override public Object doInTransaction(TransactionStatus status) { //5.执行数据库操作 System.out.println(jdbcTempate.queryForInt("select count(*) from tbl_doc")); return null; } }); 4、AOP解决方案
nSpring框架提供了一致的事务管理抽象,这带来了以下好处:
1:为复杂的事务API提供了一致的编程模型,如JTA、JDBC、Hibernate、JPA和JDO
2:支持声明式事务管理
3:提供比复杂的事务API(诸如JTA)更简单的、更易于使用的编程式事务管理API
4:非常好地整合Spring的各种数据访问抽象
实施事务的步骤
1、定义(资源)DataSource/SessionFactory……
2、定义事务管理器(管理资源的事务)
3、定义事务通知:定义了如何实施事务(实施事务的方法名和对应的事务属性),需要使用事务管理器管理事务,定义了如何选择目标对象的方法及实施的事务属性
4、定义advisor(切入点和事务通知):切入点选择需要实施事务的目标对象
5、Spring织入事务通知到目标对象(AOP代理)
实施流程:
更多相关知识请参考:
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2012-04-25
楼猪高手的哦
|
|
返回顶楼 | |
发表时间:2012-04-25
steafler 写道 楼猪高手的哦
楼猪? |
|
返回顶楼 | |
发表时间:2012-04-25
写的不错,加油啊。楼主水平好高啊。
|
|
返回顶楼 | |
发表时间:2012-04-25
dominic6988 写道 写的不错,加油啊。楼主水平好高啊。
过奖了,水平一般,贵在坚持 |
|
返回顶楼 | |
发表时间:2012-04-25
最后修改:2012-04-26
对于单数据源的应用来说,一般只要使用声明式事务管理就可以了,如果是多数据源(如数据库分库),如果数据源数据不多(尽量是小于5),也许可以使用JTA,但是JTA由于需要多数源协调,二次提交,性能要慢很多,因此,除非是银行,金融的系统,不建议使用JTA。
如果数据源很多(如互联网应用中,数据库被切分成很多个库),这时直接使用声明式事务就无法应对了。这时,可以采用Spring的编程式事务来解决。 思路参照TransactionTemplate的设计思路,做一个多数据源环境下的事务管理模板,以下是我的实现: package com.book.shard; import org.springframework.transaction.TransactionStatus; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * <pre> * 多数据源事务管理模板类 * </pre> * * @author stamen * @version 2.0 */ public class MultiTransactionTemplate { private MultiTransactionHolder multiTransactionHolder; private MultiTransactionTemplate(MultiTransactionHolder multiTransactionHolder) { this.multiTransactionHolder = multiTransactionHolder; } /** * 构建一个多数据源事务模板类 * * @param b2BB2BMultiTransactionHolder * @return */ public static MultiTransactionTemplate build(MultiTransactionHolder multiTransactionHolder) { MultiTransactionTemplate multiTransactionTemplate = new MultiTransactionTemplate(multiTransactionHolder); return multiTransactionTemplate; } /** * 执行多数据源的事务操作 * * @param action * @param <T> * @return */ public <T> T execute(MultiTransactionCallback<T> action) { List<TransactionHolder> transactionHolders = multiTransactionHolder.getTransactionHolders(); List<TransactionHolderStatus> transactionHolderStatusList = new ArrayList<TransactionHolderStatus>(transactionHolders.size()); T t = null; try { for (TransactionHolder transactionHolder : transactionHolders) { transactionHolderStatusList.add( new TransactionHolderStatus(transactionHolder, transactionHolder.getTransactionStatus())); } Collections.reverse(transactionHolderStatusList); //最后初始化的必须最先回滚或提交\ t = action.doInTransaction(); } catch (Throwable e) { for (TransactionHolderStatus transactionHolderStatus : transactionHolderStatusList) { transactionHolderStatus.rollback(); } throw new ShardException("事务处理时发生异常。", e); } for (TransactionHolderStatus transactionHolderStatus : transactionHolderStatusList) { transactionHolderStatus.commit(); } return t; } private static final class TransactionHolderStatus { private TransactionHolder transactionHolder; private TransactionStatus transactionStatus; private TransactionHolderStatus(TransactionHolder transactionHolder, TransactionStatus transactionStatus) { this.transactionHolder = transactionHolder; this.transactionStatus = transactionStatus; } public TransactionHolder getTransactionHolder() { return transactionHolder; } public TransactionStatus getTransactionStatus() { return transactionStatus; } public void rollback() { this.transactionHolder.rollback(this.transactionStatus); } public void commit() { this.transactionHolder.commit(this.transactionStatus); } } } MultiTransactionHolder的代码如下: package com.book.shard; import java.util.List; /** * <pre> * 功能说明:多数据源事务管理维护器 * </pre> * * @author stamen * @version 1.0 */ public interface MultiTransactionHolder { /** * 获取事务持有器列表 * * @return */ List<TransactionHolder> getTransactionHolders(); /** * 添加分库数据源 * * @param shardToken * @return */ MultiTransactionHolder ds(ShardToken shardToken); } ShardToken是数据库分库凭据(支持纵向,水平切分),凭据不同,取得的数据源不同。 MultiTransactionCallback代码为: package com.book.shard; /** * <pre> * 多数据源事务处理回调接口,它被{@link MultiTransactionTemplate} * </pre> * * @author stamen * @version 2.0 */ public interface MultiTransactionCallback<T> { /** * 在多数据源中完成事务 * @param multiTransactionHolder * @return */ T doInTransaction(); } TransactionHolder为: package com.book.shard; import org.springframework.transaction.TransactionException; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionTemplate; /** * 通过Spring的事务管理基础设施进行多数据源事务管理 * @author stamen * @version 2.0 */ public interface TransactionHolder { /** * 事务管理器模板 * @return */ TransactionTemplate getTransactionTemplate(); /** * 事务的状态 * @return */ TransactionStatus getTransactionStatus(); /** * 提交某个事务 * @param transactionStatus * @throws org.springframework.transaction.TransactionException */ void commit(TransactionStatus transactionStatus) throws TransactionException; /** * 回滚某个事务 * @param transactionStatus * @throws org.springframework.transaction.TransactionException */ void rollback(TransactionStatus transactionStatus) throws TransactionException; } |
|
返回顶楼 | |
发表时间:2012-04-25
最后修改:2012-04-26
stamen 写道 对于单数据源的应用来说,一般只要使用声明式事务管理就可以了,如果是多数据源(如数据库分库),如果数据源数据不多(尽量是小于5),也许可以使用JTA,但是JTA由于需要多数源协调,二次提交,性能要慢很多,因此,除非是银行,金融的系统,不建议使用JTA。
如果数据源很多(如互联网应用中,数据库被切分成很多个库),这时直接使用声明式事务就无法应对了。这时,可以采用Spring的编程式事务来解决。 思路参照TransactionTemplate的设计思路,做一个多数据源环境下的事务管理模板,以下是我的实现: 1、多库时你的实现确实不错,不需要JTA,相当于客户端JTA啦 for (TransactionHolderStatus transactionHolderStatus : transactionHolderStatusList) { transactionHolderStatus.rollback(); } transactionHolderStatus.rollback();是否也需要try-catch 如果不try 是不是可能有的事务不回滚 try { result = action.doInTransaction(status); } catch (RuntimeException ex) { // Transactional code threw application exception -> rollback rollbackOnException(status, ex); throw ex; } catch (Error err) { // Transactional code threw error -> rollback rollbackOnException(status, err); throw err; } catch (Exception ex) { // Transactional code threw unexpected exception -> rollback rollbackOnException(status, ex); throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception"); } this.transactionManager.commit(status); 2、在调用MultiTransactionHolder的ds方法时是不是通过TransactionSynchronizationManager绑定ConnectionHolder实现? 3、在调用MultiTransactionTemplate回调时是不是已经决定了所有ds? 4、传播行为如何定义? 是不是不允许Requires_New Not_SUPPORT Never这种无事务/新事务的场景? 5、TransactionTemplate是如何选择的呢?通过MultiTransactionHolder ds(ShardToken shardToken) 拿到MultiTransactionHolder然后通过最后一个TransactionHolder来获取TransactionTemplate的? 最近一哥们正好遇到另一种场景,读写分离的问题。我给的建议是: 1、通过AOP选择数据源(使用spring的AbstractRoutingDataSource) 写操作 使用写库 ThreadLocal绑定 读操作 默认使用读库,如果当前是写 直接使用写库 读操作全部 SUPPORTS AOP实现方式和tx:advice一样 只是写操作 将通过 ThreadLocal绑定写库,,这种方式最简单。 你的这种方式是否可以考虑用AOP+注解等方案来解决呢? |
|
返回顶楼 | |
发表时间:2012-04-25
stamen 写道 对于单数据源的应用来说,一般只要使用声明式事务管理就可以了,如果是多数据源(如数据库分库),如果数据源数据不多(尽量是小于5),也许可以使用JTA,但是JTA由于需要多数源协调,二次提交,性能要慢很多,因此,除非是银行,金融的系统,不建议使用JTA。
如果数据源很多(如互联网应用中,数据库被切分成很多个库),这时直接使用声明式事务就无法应对了。这时,可以采用Spring的编程式事务来解决。 大概看了下stamen的实现方式,总体感觉其实就是一个嵌套事务的执行,所有的事务都纳入一个集合中,循环提交事务,最先加入的事务最后执行,这样在整体上可以回滚,类似于一个jta的实现。 |
|
返回顶楼 | |
发表时间:2012-04-26
jinnianshilongnian 写道 stamen 写道 对于单数据源的应用来说,一般只要使用声明式事务管理就可以了,如果是多数据源(如数据库分库),如果数据源数据不多(尽量是小于5),也许可以使用JTA,但是JTA由于需要多数源协调,二次提交,性能要慢很多,因此,除非是银行,金融的系统,不建议使用JTA。
如果数据源很多(如互联网应用中,数据库被切分成很多个库),这时直接使用声明式事务就无法应对了。这时,可以采用Spring的编程式事务来解决。 思路参照TransactionTemplate的设计思路,做一个多数据源环境下的事务管理模板,以下是我的实现: 1、多库时你的实现确实不错,不需要JTA,相当于客户端JTA啦 for (TransactionHolderStatus transactionHolderStatus : transactionHolderStatusList) { transactionHolderStatus.rollback(); } transactionHolderStatus.rollback();是否也需要try-catch 如果不try 是不是可能有的事务不回滚 try { result = action.doInTransaction(status); } catch (RuntimeException ex) { // Transactional code threw application exception -> rollback rollbackOnException(status, ex); throw ex; } catch (Error err) { // Transactional code threw error -> rollback rollbackOnException(status, err); throw err; } catch (Exception ex) { // Transactional code threw unexpected exception -> rollback rollbackOnException(status, ex); throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception"); } this.transactionManager.commit(status); 2、在调用MultiTransactionHolder的ds方法时是不是通过TransactionSynchronizationManager绑定ConnectionHolder实现? 3、在调用MultiTransactionTemplate回调时是不是已经决定了所有ds? 4、传播行为如何定义? 是不是不允许Requires_New Not_SUPPORT Never这种无事务/新事务的场景? 5、TransactionTemplate是如何选择的呢?通过MultiTransactionHolder ds(ShardToken shardToken) 拿到MultiTransactionHolder然后通过最后一个TransactionHolder来获取TransactionTemplate的? 最近一哥们正好遇到另一种场景,读写分离的问题。我给的建议是: 1、通过AOP选择数据源(使用spring的AbstractRoutingDataSource) 写操作 使用写库 ThreadLocal绑定 读操作 默认使用读库,如果当前是写 直接使用写库 读操作全部 SUPPORTS AOP实现方式和tx:advice一样 只是写操作 将通过 ThreadLocal绑定写库,,这种方式最简单。 你的这种方式是否可以考虑用AOP+注解等方案来解决呢? 我在项目中采用MySQL读写分离,使用Spring的AbstractRoutingDataSource切换主从数据源,如果在业务层设置ThreadLocal是不起作用的,在控制层设计才有效。 请问如果一个业务中同时有读写,如何切换? |
|
返回顶楼 | |
发表时间:2012-04-26
如果读操作全部 SUPPORTS,能保证业务层结束后,连接正常返回连接池吗?能否说说spring释放数据连接的机制?
|
|
返回顶楼 | |