结合spring+hibernate与jdbc的事务

问题背景 :我们是一家工作流公司,客户采购我们的产品后,将其嵌入其项目中。我们的工作流采用的是   spring+hibernate的方式,客户项目则是jdbc直接进行数据库操作。
问题 :客户在其数据库操作过程中需要调用我们的工作流接口,这样就需要将我们的工作流操作与他们的业  务操作置于同一个事务中。我们的服务采用的都是spring的声明式事务,而客户采用的是对         connection进行事务处理。如何保证事务的一致性?
想到的解决方案一 :使用jta事务,用tomcat+jotm提供事务管理器。为什么一开始就想到要使用jta事务??实际上我们和客户都是使用的同一个数据库,为了方便,各自使用了不同的数据库连接方式,使用jta的话确实有bt的意思在里面。但是事实上是我们的第一反应都是jta。最后没有采用该方法的原因也很简单:我没有将jotm配置成功!汗一个。
想到的解决方案二 :将客户的这些特定代码用spring管理起来。因为要修改客户部分代码,这个方案遭到了客户的强烈反对。于是放弃。
想到的解决方案三 :客户数据库操作与我们的服务使用同一个数据库连接。然后编程处理事务。存在两种方式:一种是把客户的连接传给我们,另一种则是把我们的连接传给客户。第一种方式对我们的影响太大,所以最后决定采用后一种方式:从hibernate session中获取connection然后传递给客户。接下来查看一下HibernateTemplate的execute()方法,思路就很简单了:获取定义的sessionFactory-->创建一个新的session并打开-->将session与当前线程绑定-->给客户代码返回connection-->打开事务-->客户使用我们传递的connection进行数据库操作-->我们不带声明事务的服务操作-->提交事务-->解除绑定。
实际要注意的地方是 :1、将session与当前线程绑定使用的TransactionSynchronizationManager.bindResource()方法,这样在HibernateTemplate里才能找到session;
                    2、我们的服务一定要把声明式事务彻底干掉,否则会有commit;
                    3、我们服务调用完毕后一定要flush session,否则客户代码不会感知数据库里的数据变化。
最终解决:使用了spring里常用的模板和回调。代码如下:
public   class  TransactionTemplate {

    
protected   final  Log logger  =  LogFactory.getLog(TransactionTemplate. class );

    
private  FlushMode flushMode  =  FlushMode.ALWAYS;

    
public  Object execute(TransactionCallback callback) {
        
// 首先获取sessionFactory
        SessionFactory sessionFactory  =  (SessionFactory) Framework.getEngine()
                .getContainer().getComponent(
" sessionFactory " );
        
// 创建一个新的session并打开
        logger.debug( " Opening single Hibernate Session in TransactionTemplate " );
        Session session 
=  getSession(sessionFactory);
        
// 将session与当前线程绑定
        TransactionSynchronizationManager.bindResource(sessionFactory,  new  SessionHolder(session));
        
// 获取数据库连接
        Connection conn  =  session.connection();
        Object result 
=   null ;
        Transaction transaction 
=   null ;
        
try  {
            
// 开始处理事务
            transaction  =  session.beginTransaction();
            
try  {
                result 
=  callback.doInTransaction(conn);
            }
            
catch  (RuntimeException ex) {
                doRollback(session, transaction);
                
throw  ex;
            }
            
catch  (Error err) {
                doRollback(session, transaction);
                
throw  err;
            }
            
// 如果数据库操作过程中没有发生异常则提交事务
            transaction.commit();
        } 
catch  (WorkflowException e) {
            logger.error(
" 数据库操作失败,事务回滚也失败! " );
            
throw  e;
        } 
catch  (RuntimeException ex) {
            logger.error(
" 数据库操作失败,事务被回滚! " );
            
throw  ex;
        } 
catch  (Error err) {
            logger.error(
" 数据库操作失败,事务被回滚! " );
            
throw  err;
        } 
finally  {
            
//  将session与当前线程解除绑定
            TransactionSynchronizationManager.unbindResource(sessionFactory);
            doClose(session);
        }
        
return  result;
    }

    
protected  Session getSession(SessionFactory sessionFactory) {
        Session session 
=  SessionFactoryUtils.getSession(sessionFactory,  true );
        FlushMode flushMode 
=  getFlushMode();
        
if  (flushMode  !=   null ) {
            session.setFlushMode(flushMode);
        }
        
return  session;
    }

    
private   void  doRollback(Session session, Transaction transaction) {
        logger.debug(
" 数据库操作异常,开始回滚事务 " );
        
try  {
            transaction.rollback();
            logger.debug(
" 回滚事务成功! " );
        }
        
catch  (Exception e) {
            logger.error(
" 回滚事务失败! " );
            
throw   new  WorkflowException( " 回滚事务失败! " );
        } 
finally  {
            session.clear();
        }
    }

    
private   void  doClose(Session session) {
        logger.debug(
" 开始关闭连接 " );
        
try  {
            session.close();
        }
        
catch  (Exception e) {
            logger.error(
" 关闭连接失败! " );
            
throw   new  WorkflowException( " 关闭连接失败! " );
        }
    }

    
public  FlushMode getFlushMode() {
        
return  flushMode;
    }

    
public   void  setFlushMode(FlushMode flushMode) {
        
this .flushMode  =  flushMode;
    }
}

public   interface  TransactionCallback {

    Object doInTransaction(Connection conn);
}
调用伪代码:
     public   void  methodA(){
        TransactionTemplate transactionTemplate
= new  TransactionTemplate();
        transactionTemplate.execute(
new  TransactionCallback(){
            
public  Object doInTransaction(Connection conn) {
                
// 客户代码
                client.method1( " 1 " );
                
// 我们代码 直接使用
                our.method2();
                
// 客户代码
                client.method3( " l " );
                
return   null ;  
            }
        });
    }




http://www.blogjava.net/ronghao 荣浩原创,转载请注明出处:)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值