在@Transactional中提交try-catch中的更改 [英] commit changes in try-catch inside @Transactional

查看:690
本文介绍了在@Transactional中提交try-catch中的更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑我有一个方法在ActiveRecord模式风格中做一些东西和记录机制:

  @Transactional 
public void doSmt(){
try {
someOperation(); //可以抛出异常
Logger.logIntoDb(); //如果一切正常
} catch {Exception e} {
Logger.logIntoDbWithException(e.getMessage()); //将错误记录到db

中new MyCustomException(e);



public static void logIntoDbWithException(String message){
final LogEntry logEntry = new LogEntry();
logEntry.setDate(new Date());
logEntry.setMessage(message);
logEntry.persist();

$ / code>

如果失败,我想保留一条错误消息,在catch子句事务中重新抛出异常将被回滚,并且我的LogEntry不会被持久化。我看到的唯一方法是在 persist()之后手动调用 flush()



是否有更干净的解决方案来执行此操作?



谢谢。

UPD:



因为我有一个执行持久化的静态方法,所以我需要将以下hack应用于接受的答案:

  public static void logIntoDbWithException(String message){
new Runnable(){
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void run(){
final LogEntry logEntry = new LogEntry();
logEntry.setDate(new Date());
logEntry.setMessage(message);
logEntry.persist();
}
} .run();


解决方案

不会对你有什么好处:flush()不会提交任何内容,因为你在同一个事务中记录错误,插入将被回滚。因此,您需要启动一个新的嵌套事务来记录错误。

  

code> public class A {

@Autowired
private B b;

@Transactional
public void doSmt(){
try {
someOperation(); //可以抛出异常
b.logIntoDb(); //如果一切正常
} catch {Exception e} {
b.logIntoDbWithException(e.getMessage()); //将错误记录到db

中new MyCustomException(e);




公共类B {

//外部交易仍然有效
public void logIntoDb(字符串消息){
最终LogEntry logEntry = new LogEntry();
logEntry.setDate(new Date());
logEntry.setMessage(message);
logEntry.persist();
}

//'外部'事务将被暂停,直到此方法完成
//此新的事务将独立于外部事务提交/回滚
@Transactional (propagation = Propagation.REQUIRES_NEW)
public void logIntoDbWithException(String message){
final LogEntry logEntry = new LogEntry();
logEntry.setDate(new Date());
logEntry.setMessage(message);
logEntry.persist();
}
}


Consider I have a method doing some stuff and logging mechanism in ActiveRecord pattern style:

@Transactional
public void doSmt() {
    try {
        someOperation(); // can throw exception
        Logger.logIntoDb(); // if everything is OK
    } catch {Exception e} {
        Logger.logIntoDbWithException(e.getMessage()); // log error into db

        throw new MyCustomException(e);
    }
}

public static void logIntoDbWithException(String message) {
    final LogEntry logEntry = new LogEntry();
    logEntry.setDate(new Date());
    logEntry.setMessage(message);
    logEntry.persist();
}

I want to persist an error message in case of failure, but if I'd rethrow exception in catch clause transaction will be rollbacked and my LogEntry will not be persisted. The only way I see is manually call flush() after persist().

Is there is a more clean solution to perform this?

Thanks.

UPD:

Since I have a static method which performs persisting I need to apply following hack to accepted answer:

public static void logIntoDbWithException(String message) {
    new Runnable() {
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void run() {
            final LogEntry logEntry = new LogEntry();
            logEntry.setDate(new Date());
            logEntry.setMessage(message);
            logEntry.persist();
        }
    }.run();
}

解决方案

Firstly, calling flush() is not going to do you any good: flush() does not commit anything and, as you are logging the error in the same transaction, the insert will be rolled back.

You therefore need to start a new 'nested' transaction to log the error.

public class A {

    @Autowired
    private B b;

    @Transactional
    public void doSmt() {
        try {
            someOperation(); // can throw exception
            b.logIntoDb(); // if everything is OK
        } catch {Exception e} {
            b.logIntoDbWithException(e.getMessage()); // log error into db

            throw new MyCustomException(e);
        }
    }
}

public class B{

    //outer transaction is still active
    public  void logIntoDb(String message) {
        final LogEntry logEntry = new LogEntry();
        logEntry.setDate(new Date());
        logEntry.setMessage(message);
        logEntry.persist();
    }

    // 'outer' transaction will be suspended until this method completes
    // this new transaction will commit/rollback independently of the outer transaction
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public  void logIntoDbWithException(String message) {
        final LogEntry logEntry = new LogEntry();
        logEntry.setDate(new Date());
        logEntry.setMessage(message);
        logEntry.persist();
    }
}

这篇关于在@Transactional中提交try-catch中的更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆