读书人

spring aop事务为什么不回滚呢?解决办

发布时间: 2012-02-20 21:18:23 作者: rapoo

spring aop事务为什么不回滚呢?
大家帮我看下,太纠结了。数据库是oracle 10g 设置了回滚事务,就是不回滚,每次都插入了数据。

XML code
    <!-- spring2.0的配置方式 -->    <bean id="transactionManager"        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">        <property name="dataSource">            <ref bean="dataSource" />        </property>    </bean>    <!-- 事务通知 -->    <tx:advice id="txAdvice" transaction-manager="transactionManager">        <tx:attributes>            <!-- <tx:method name="add*" propagation="REQUIRED" /> -->            <tx:method name="mod*" propagation="REQUIRED" />            <tx:method name="*" read-only="true"                rollback-for="Exception,RuntimeException,SQLException"                propagation="REQUIRED" />        </tx:attributes>    </tx:advice>    <!-- Spring AOP config -->    <aop:config proxy-target-class="true">        <!-- 切入点 -->        <aop:pointcut id="servicesPointcut"            expression="execution(* com.zyujie.service..*Impl.*(..))" />        <!-- <aop:pointcut id="daoPointcut"            expression="execution(* com.zyujie.dao..*.*(..))" /> -->        <!-- 运行拦截 -->        <aop:advisor advice-ref="txAdvice"            pointcut-ref="servicesPointcut" />        <!-- <aop:advisor advice-ref="txAdvice" pointcut-ref="daoPointcut" /> -->    </aop:config>

Java code
/*     * 添加用户,为了测试是否开启事务。DAO层的方法     */    public int addUser(SysUser user) {        logger.debug("开始执行添加用户的操作......");        Connection con = ConnectionFactory.getConnection();        String sql = "INSERT INTO USER_INFO VALUES (?,?,?,?,?,?,?,?,sysdate)";        int result = 0;        PreparedStatement ps = null;        try {            // con.setAutoCommit(false);            ps = con.prepareStatement(sql);            for (int i = 0; i < 1000; i++) {                String temps = i + "user";                if (i == 600) {                    temps = null;                }                ps.setString(1, temps);                ps.setString(2, "test");                ps.setString(3, "99");                ps.setString(4, "测试地市");                ps.setString(5, "888");                ps.setString(6, "测试部门");                ps.setString(7, "888888");                ps.setString(8, "2");                // ps.setString(9, "");                result += ps.executeUpdate(); //有人说是这里本身就已经提交了,但是还是问问大家。            }            // con.commit();        } catch (Exception e) {            logger.debug("添加用户事务回滚了......");            // throw new RuntimeException("error"); // 抛出异常,测试回滚            throw new RuntimeException(); // 抛出异常,测试回滚        } finally {            try {                if (ps != null) {                    ps.close();                }                if (con != null) {                    con.close();                }            } catch (SQLException e) {                // e.printStackTrace();                // throw new RuntimeException(); // 抛出异常,测试回滚            }        }        return result;    }

Java code
    /*     * 添加用户,为了测试是否开启事务。Service层的接口实现类,方法     */    public int addUser(SysUser user) {        return sysUserDAO.addUser(user);    } 



[解决办法]
兄弟,看看你数据库的存储引擎是不是支不支持事务处理等高级处理,如果不支持要换成支持事务的存储引擎

[解决办法]
<tx:method name="mod*" propagation="REQUIRED" />
这里是不是写错了,, <tx:method name="add*" propagation="REQUIRED" /> 试试..

[解决办法]
网上资料多!找个模板看看!
[解决办法]
楼主你在DAO怎样把异常抛出给Spring的,你都说能成功插入,到底catch中的
throw new RuntimeException(); // 抛出异常,测试回滚
执行没有呢?

你在
result += ps.executeUpdate(); //有人说是这里本身就已经提交了,但是还是问问大家。
后加上
throw new RuntimeException(); // 抛出异常,测试回滚
测试下;
[解决办法]
ConnectionFactory 是怎么写的,如果你的ConnectionFactory跟spring毫无关系,spring又怎么能管理你的事务
[解决办法]
connectionfactory很重要,能否把代码拿上来看看?

因为connectionfactory如果用的是jdbc的和spring无关,只是从SPRING拿DATASOURCE的话,JDBC默认的setAutoCommit为(true)。

这也就是为什么你在一条executeupdate后抛出了一个exception后数据任能插入
[解决办法]
你这样写的话完全脱离了spring事务环境。

获取getConnection要使用spring提供的方法org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSource dataSource)方法,它返回与spring事务环境中使用的connection对象。

另外你的getConnection方法完全无需同步
[解决办法]
探讨

connectionfactory很重要,能否把代码拿上来看看?

因为connectionfactory如果用的是jdbc的和spring无关,只是从SPRING拿DATASOURCE的话,JDBC默认的setAutoCommit为(true)。

这也就是为什么你在一条executeupdate后抛出了一个exception后数据任能插入

[解决办法]
如果,楼主一定要用JDBC CONNECTION,并且支持Service层抛错,自动回滚,应该用jdbctemplate,这样,你的connectionfactory类都不需要用了,下面给出例子:

public class PriceCenterDaoImp extends SimpleJdbcDaoSupport implements IPriceCenterDao {

private Map<String, String> sqls;

@SuppressWarnings("unchecked")
public List<PriceCenter> getPriceCodeList() throws Exception {
// TODO Auto-generated method stub
return this.getJdbcTemplate().query(sqls.get("getPriceCodeList"), RowMapperUtil.getPriceCenterRowMapper());
}

public void setSqls(Map<String, String> sqls) {
this.sqls = sqls;
}

}
注意:extends SimpleJdbcDaoSupport implements IPriceCenterDao

该DAO如果是extend SimpleJdbcDaoSupport的话,需要用spring为其注入一个datasource,如下:
<?xml version="1.0" encoding="UTF-8" ?>
- <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:batch="http://www.springframework.org/schema/batch" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
- <bean id="priceCenterDao" class="com.ccc.batch.job.dao.impl.PriceCenterDaoImp">
<property name="dataSource" ref="dataSourceLocal" />
- <property name="sqls">
- <map>
- <entry key="getPriceCodeList">
<value>SELECT PRICE_CENTER_CODE, PRICE_TABLE_NAME FROM T_PRICE_CENTER WHERE VALID_FLAG = 'Y'</value>
</entry>
</map>
</property>
</bean>
</beans>
然后,把这个dao套到service里,你的service再throw出来任何exception,就能达到你的效果了。



结论:

自己用datasource造出的jdbc connection的事务,必须自己手动控制,用不了SPRING的AOP机制。

如果要用SPRING的AOP机制,就要用SimpleJdbcDaoSupport,HIBERNATE也是同理
[解决办法]

探讨

谢谢panhaichun,
Java code

// 定义静态变量
private static ClassPathXmlApplicationContext appctx;

/*
* 静态块,只加载一次
*/
static {
appctx = new ClassPathXmlApplicationContext("a……

[解决办法]
再给楼主一个例子帮助楼主理解:
<bean id="fxRateDarDao" class="x.batch.job.fxRate.FxRateDarImpl">
<property name="dataSource" ref="dataSourceDAR" />
- <property name="sqls">
- <map>
- <entry key="delSql">
<value>delete from TDAFRGN_XCHG_RT where datediff(d,EFF_DT,?)=0</value>
</entry>
- <entry key="insSql">
<value>INSERT INTO TDAFRGN_XCHG_RT( BASE_CUR_CD, TGT_CUR_CD,EFF_DT,XCHG_RT,MKT_ID) values(:baseCurrencyCode,:targetCurrencyCode,:effectiveDate, :currencyConversionRate,:marketId)</value>
</entry>
</map>
</property>
</bean>
package x.batch.job.fxRate;

import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcDaoSupport;

public class FxRateDarImpl extends SimpleJdbcDaoSupport implements FxRateDarDAO {

private Logger log = Logger.getLogger(this.getClass());

private Map sqls;

public void setSqls(Map sqls) {
this.sqls = sqls;
}

public void deleteFxRate(Date date) {
try {

this.getSimpleJdbcTemplate().update((String) sqls.get("delSql"), date);
} catch (Exception e) {
log.error("delete fxRate error:" + e.getMessage(), e);
return;
}

}

public void insertFxRate(List fxRateList) {
try {
for (Object fxRate : fxRateList) {
this.getSimpleJdbcTemplate().update((String) sqls.get("insSql"),
new BeanPropertySqlParameterSource(fxRate));
}
} catch (Exception e) {
log.error("insert fxRate error:" + e.getMessage(), e);
return;
}
}
}

读书人网 >J2EE开发

热点推荐