求教:spring控制jdbc事务

路飞 发布于 2011/04/25 15:08
阅读 4K+
收藏 1

初学,初学

简单来说就是业务层的方法要调用两个DAO层的方法,这两个方法要么都成功,要么都回滚掉

以前我是把两个DAO方法合并成一个,然后手动commit和rollback

现在看到spring能在业务层中控制,于是试了试,结果不成功,两个DAO的事务是分开控制的……

 

我的代码大致如下:

spring的配置文件

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
	<property name="driverClassName">
                <value>oracle.jdbc.driver.OracleDriver</value>
        </property>
	<property name="username" value="xxx"></property>
	<property name="password" value="xxx"></property>
	<property name="url" value=""></property>
</bean>

<bean id="userDAO" class="test.dao.UserDAOImpl">
	<property name="dataSource" ref="dataSource" />
</bean>

<bean id="userBO" class="test.service.UserBOImpl">
	<property name="userDAO" ref="userDAO" />
</bean>

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource" />
</bean>
	
<tx:advice id="txAdvice" transaction-manager="txManager">
	<tx:attributes>
		<tx:method name="*" rollback-for="SQLException" />
	</tx:attributes>
</tx:advice>
	
<aop:config>
	<aop:pointcut id="fooServiceOperation" expression="execution(* test.service.UserBOImpl.*(..))" />
	<aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation" />
</aop:config>

两个DAO方法

    private DataSource dataSource;// 省略setDataSoure

    private static Logger logger = Logger.getLogger(UserDAOImpl.class);

    public boolean insert(String foo) throws SQLException{
           //省略声明、pstmt等
           conn = dataSource.getConnection();
            logger.info("insert方法的conn对象的hashCode:"+conn.hashCode());
            logger.info("insert方法的conn对象的toString:"+conn.toString());
            //省略执行
    }
    public boolean update(String bar) throws SQLException{
           conn = dataSource.getConnection();
            logger.info("update方法的conn对象的hashCode:"+conn.hashCode());
            logger.info("update方法的conn对象的toString:"+conn.toString());
   }

然后是业务类方法

    private UserDAO userDAO;   // 省略setUserDAO 

    public boolean sum(String foo, String bar) throws SQLException
    {
        return userDAO.insert(foo) && userDAO.update(bar);
    }

 

然后开始测试,我在update方法里搞了个SQLException,然后执行业务类的sum方法,看日志

Using transaction object [org.springframework.jdbc.datasource.DataSourceTransactionManager$DataSourceTransactionObject@911fb5]
Creating new transaction with name [test.service.UserBO.sum]
Acquired Connection [org.apache.commons.dbcp.PoolableConnection@16b724d] for JDBC transaction
Switching JDBC Connection [org.apache.commons.dbcp.PoolableConnection@16b724d] to manual commit
Bound value [org.springframework.jdbc.datasource.ConnectionHolder@a40787] for key [org.apache.commons.dbcp.BasicDataSource@167e003] to thread [http-8088-1]
insert方法的conn对象的hashCode:15359367
insert方法的conn对象的toString:org.apache.commons.dbcp.PoolableConnection@ea5d87
update方法的conn对象的hashCode:15359367
update方法的conn对象的toString:org.apache.commons.dbcp.PoolableConnection@ea5d87
update方法异常:
Winning rollback rule is: RollbackRuleAttribute with pattern [SQLException]
Invoking rollback for transaction on test.service.UserBO.sum due to throwable [java.sql.SQLException: 索引中丢失  IN 或 OUT 参数:: 2]    /*这个是我搞的异常 */
 Initiating transaction rollback
Rolling back JDBC transaction on Connection [org.apache.commons.dbcp.PoolableConnection@16b724d]
Removed value [org.springframework.jdbc.datasource.ConnectionHolder@a40787] for key [org.apache.commons.dbcp.BasicDataSource@167e003] from thread [http-8088-1]
Releasing JDBC Connection [org.apache.commons.dbcp.PoolableConnection@16b724d] after transaction
Returning JDBC Connection to DataSource
这个日志,我怕太乱,就私自去了些非必需的东西

看日志里,确实是调用业务方法时启动的事务,异常后回滚,但是,但是,数据库中结果是insert方法的结果已经持久化了……只有update方法的结果被回滚了……

 

我刚接触spring不久,也在努力看它的文档,无奈最近加班好多好多,头晕了……连续3周每天晚上11点回寝室了

加载中
0
cwledit
cwledit

你试试

catch (SQLException e) {
throw new java.lang.RuntimeException();
}

0
yanyan
yanyan

rollback-for="SQLException"

  1. <tx:advice id="txAdvice" transaction-manager="txManager">  
  2.     <tx:attributes>  
  3.         <tx:method name="*" rollback-for="SQLException" />  
  4.     </tx:attributes>  
  5. </tx:advice> 

0
郑雨涵
郑雨涵

如果你使用的是mysql数据库,请检查是不是用的MyISAM引擎

0
路飞
路飞

引用来自#2楼“cwledit”的帖子

你试试

catch (SQLException e) {
throw new java.lang.RuntimeException();
}

不是异常类型的问题,你可以看日志里已经根据SQLException启动回滚操作了

0
路飞
路飞

引用来自#4楼“xiaojia2008”的帖子

如果你使用的是mysql数据库,请检查是不是用的MyISAM引擎

oracle

0
无言独上西楼
无言独上西楼

两个方法搞了两个connection让spring怎么回滚?数据库连接应该交给spring自己管理,使用template模式。

0
路飞
路飞

引用来自#7楼“zc_programmer”的帖子

两个方法搞了两个connection让spring怎么回滚?数据库连接应该交给spring自己管理,使用template模式。

template还没看到,不清楚怎么用呢……

两个方法两个conn感觉确实有问题,但是看日志他们貌似是同一个的啊

0
szf
szf

引用来自#8楼“路飞”的帖子

引用来自#7楼“zc_programmer”的帖子

两个方法搞了两个connection让spring怎么回滚?数据库连接应该交给spring自己管理,使用template模式。

template还没看到,不清楚怎么用呢……

两个方法两个conn感觉确实有问题,但是看日志他们貌似是同一个的啊

 是不是同一个连接,是连接池管理的,spring在第一次归还连接时,就会自动提交事务,第二次只是“碰巧”拿到跟上次同一个连接而已,但事务控制不能基于这种碰巧。。。。

7L说得对,具体做法如下:

     <bean id ="JdbcTemplate" 
          class ="org.springframework.jdbc.core.JdbcTemplate">   
          <property name ="dataSource">    
              <ref bean ="dataSource"  />    
          </property>   
      </bean>  

in DAO:

jdbcTemplate.execute(SQL);

0
路飞
路飞

引用来自#9楼“szf”的帖子

引用来自#8楼“路飞”的帖子

引用来自#7楼“zc_programmer”的帖子

两个方法搞了两个connection让spring怎么回滚?数据库连接应该交给spring自己管理,使用template模式。

template还没看到,不清楚怎么用呢……

两个方法两个conn感觉确实有问题,但是看日志他们貌似是同一个的啊

 是不是同一个连接,是连接池管理的,spring在第一次归还连接时,就会自动提交事务,第二次只是“碰巧”拿到跟上次同一个连接而已,但事务控制不能基于这种碰巧。。。。

7L说得对,具体做法如下:

     <bean id ="JdbcTemplate" 
          class ="org.springframework.jdbc.core.JdbcTemplate">   
          <property name ="dataSource">    
              <ref bean ="dataSource"  />    
          </property>   
      </bean>  

in DAO:

jdbcTemplate.execute(SQL);

恩感谢提示,现在已经搞定了

也感谢上面热心的各位了

返回顶部
顶部