Spring事务的陷阱(3)

示例代码

    以下代码的方法addBook(Book book)有意抛出一个数据库相关的运行时异常,调用者registerBook()方法却不能捕获到该异常。

package walker.basewf.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import walker.basewf.dao.BookDao;
import walker.basewf.vo.Book;

@Service
@Transactional
public class TrapAService {
    @Autowired
    private BookDao bookDao;

    @Transactional(rollbackFor = Exception.class)
    public void registerBook(Long userId, Book book) {
        try {
            System.out.println(">>Begin...");

            this.addBook(book);

            //虽然上行代码有运行时异常,但似乎并没有及时抛出,所以仍然打印出">>Success!"
            System.out.println(">>Success!");

        } catch (Exception e) {
            //没有捕获到异常,这行代码不会被执行!奇怪!
            System.out.println(">>Failed, here catched a exception! ");
            e.printStackTrace();
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void addBook(Book book) throws Exception {
        //往Book表插入一条记录,有意制造主键冲突或列名不正确的运行时异常
        bookDao.save(book);
    }
}
package walker.basewf.service;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import walker.basewf.common.utils.DateTimeUtil;
import walker.basewf.vo.Book;

import java.util.Date;

@Service
@Transactional
public class Trap3Test {

    public static ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");

    public static void main(String[] args) {

        Book book = new Book();
        book.setTitle(new String("三国演义"));
        book.setPrice(new Double(200.0));
        book.setPublishTime(DateTimeUtil.toSqlDate(new Date()));

        try {
            TrapAService aService = context.getBean(TrapAService .class);
            aService.registerBook(new Long(101), book);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

其它讨论

    对于以上现象,我困惑不已,很多网友也遇到这个问题,关于这个问题的讨论见:

http://bbs.csdn.net/topics/390050093?page=1#post-398522654

http://bbs.csdn.net/topics/390688795

http://www.360doc.com/content/12/1109/18/6161903_246870991.shtml

结论(2015-10-13)

    后来,发现这个问题仅与myBatis有关:由于我的mybatis.xml中的<configuration><settings>内有一行: <setting name="defaultExecutorType" value="BATCH"/>

    这样就使得mybatis在执行dao.save()动作时,只是执行了相当于JDBC的stmt.addBatch(),而不是stmt.execute(), 所以此时不会抛出主键冲突等运行时异常;而只有等到代理对象在临近 commit前执行stmt.execteBatch() 后才会抛出异常。

    我将参数"defaultExecutorType"的值由"BATCH"改为:"REUSE"或"SIMPLE",就解决了这个问题。

转载于:https://my.oschina.net/HuQingmiao/blog/515400

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值