UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

后端 未结 2 471
时光说笑
时光说笑 2021-01-31 02:05

I have this scenario:

  1. fetch (read and delete) a record from IncomingMessage table
  2. read record content
  3. insert something to some t
2条回答
  •  [愿得一人]
    2021-01-31 02:37

    The answer of Shyam was right. I already faced with this issue before. It's not a problem, it's a SPRING feature. "Transaction rolled back because it has been marked as rollback-only" is acceptable.

    Conclusion

    • USE REQUIRES_NEW if you want to commit what did you do before exception (Local commit)
    • USE REQUIRED if you want to commit only when all processes are done (Global commit) And you just need to ignore "Transaction rolled back because it has been marked as rollback-only" exception. But you need to try-catch out side the caller processNextRegistrationMessage() to have a meaning log.

    Let's me explain more detail:

    Question: How many Transaction we have? Answer: Only one

    Because you config the PROPAGATION is PROPAGATION_REQUIRED so that the @Transaction persist() is using the same transaction with the caller-processNextRegistrationMessage(). Actually, when we get an exception, the Spring will set rollBackOnly for the TransactionManager so the Spring will rollback just only one Transaction.

    Question: But we have a try-catch outside (), why does it happen this exception? Answer Because of unique Transaction

    1. When persist() method has an exception
    2. Go to the catch outside

      Spring will set the rollBackOnly to true -> it determine we must 
      rollback the caller (processNextRegistrationMessage) also.
      
    3. The persist() will rollback itself first.

    4. Throw an UnexpectedRollbackException to inform that, we need to rollback the caller also.
    5. The try-catch in run() will catch UnexpectedRollbackException and print the stack trace

    Question: Why we change PROPAGATION to REQUIRES_NEW, it works?

    Answer: Because now the processNextRegistrationMessage() and persist() are in the different transaction so that they only rollback their transaction.

    Thanks

提交回复
热议问题