SpringMVC+ibatis数据库事务控制

本文探讨了在SpringMVC+ibatis环境中如何优雅地管理数据库事务,指出直接在DAO层进行事务控制的不足,并介绍了使用切面编程(AOP)来改善这一情况。通过在ctx-dao.xml配置切面,定义事务处理规则,特别是在方法异常时触发事务回滚。通过测试确保事务在出现错误时能正确回滚,从而实现事务管理的实用性。
摘要由CSDN通过智能技术生成

由于在系统中使用了关联表,逻辑上是关联的,实际数据库并没有做外键。就需要写大量的数据库事务操作。之前一直没有比较好的方式,直接在dao层侵入的方式进行,虽然该方式可以实现事务的管理,但是总觉得有些问题。实现方式如下:

    public int insert(ChuxinRecord t) {
        SqlMapClient sqlMapClient = getWriteTemplate().getSqlMapClient();
        try {
            sqlMapClient.startTransaction();
            sqlMapClient.getCurrentConnection().setAutoCommit(false);
            Object obj = sqlMapClient.insert("chuxin_record.insertEntry",t);
            //更新频道信息
            ChuxinChannel channel = new ChuxinChannel();
            channel.setId(t.getChannelId());
//          channel.setRecordNum(channel.getRecordNum()==null?1:(channel.getRecordNum()+1));
sqlMapClient.update("chuxin_channel.updateEntryByKey", channel);
            sqlMapClient.update("chuxin_channel.addOneRecord", t.getChannelId());
            //更新未读消息数量
            sqlMapClient.update("chuxin_user_channel.addOneRecordNum", t.getChannelId());
            sqlMapClient.commitTransaction();
            sqlMapClient.getCurrentConnection().commit();
            if (null!=obj) {
                return (Integer)obj;
            }
            return 0;
        } catch (Exception e) {
            logger.error("执行错误", e);
            try {
                sqlMapClient.getCurrentConnection().rollback();
            } catch (SQLException e1) {
                logger.error("事物回滚错误", e);
            }
        } finally {
            try {
                sqlMapClient.endTransaction();
                if (null != sqlMapClient.getCurrentConnection()) {
                    sqlMapClient.getCurrentConnection().close();
                }
            } catch (SQLException e) {
                logger.error("关闭事物错误", e);
            }
        }
        return 0;
    }

从以上代码可以看出我们通过显示的方式进行控制,这样很多逻辑就会写在dao层,逻辑复杂,实用性不强。
那么什么是更好的方式那?利用切面的方式控制。

1. 在ctx-dao.xml 文件中配置切面

<!--配置哪些方法,什么情况下需要回滚-->  
    <tx:advice id="serviceAdvice" transaction-manager="transactionManager">   
        <tx:attributes>
            <!--当代理的service层中的方法抛出异常的时候才回滚,必须加rollback-for参数-->  
            <tx:method name="insert*" propagation="REQUIRED" rollback-for="java.lang.RuntionException"/>  
            <tx:method name="del*" propagation="REQUIRED" rollback-for="java.lang.RuntionException"/>   
            <tx:method name="update*" propagation="REQUIRED" rollback-for="Throwable"/>   
            <tx:method name="tran*" propagation="REQUIRED" rollback-for="java.lang.RuntionException"/>   
            <!--除了上面标识的方法,其他方法全是只读方法-->  
            <tx:method name="*" read-only="true"/>   
        </tx:attributes>   
    </tx:advice>   
    <!-- 配置哪些类的方法需要进行事务管理 -->   
    <aop:config proxy-target-class="true">   
        <aop:pointcut id="servicePointcut" expression="execution(* com.hdd.service.impl.*.*(..))"/>   
        <aop:advisor pointcut-ref="servicePointcut" advice-ref="serviceAdvice"/>   
    </aop:config>  

我们定义了需要测试的方式为tran*开头的方法

 <tx:method name="tran*" propagation="REQUIRED" rollback-for="java.lang.RuntionException"/> 

观察在定义中有句:

rollback-for="java.lang.RuntionException"

该句话非常关键,会涉及到是否会回滚事务。之前配置很多一直没有注意这点,所以每次测试的时候事务总错误,并没有回滚。
在接口中定义方法:

void tranTest();

方法实现:

@Override
    public void tranTest() {
        try {
            HddAd hddAd = new HddAd();
            hddAd.setAbContent("123456");
            hddAdDao.insert(hddAd);

            Feedback feedback = new Feedback();
            feedback.setContactInfo("wwwwwwwwwwwww");
            feedbackDao.insert(feedback);

        } catch (Exception e) {
            logger.error("会回滚吗",e);
            throw new RuntimeException(e);
        }
    }

feedback类的contactInfo属性为8位,在插入过程中肯定会报错。而HddAd类是可以插入成功的。观察,当出现异常的时候,我们会抛出异常RuntimeException

throw new RuntimeException(e);

这行代码非常关键,刚好为我们之前在tx定义的rollback-for,这也是触发事务回滚的关键点。
编写测试类,测试错误时候是否回滚:

public class Insert {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("ctx-web.xml");

        HddAdService hddAdService = (HddAdService)ctx.getBean("hddAdService");
        hddAdService.tranTest();

    }
}

好了,运行观察事务是否回滚了。

关于tx相关配置,网上有太多说明,我就不逐个解释了,重点是让他可以顺利的实现预期功能,这是实用主义者的信条。


参考文档:

  1. http://www.cnblogs.com/hellojava/archive/2012/11/21/2780694.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值