Intercept transaction only when is sure to be comm

2019-03-24 14:49发布

Context is Java - JPA with Hibernate and Spring.

Let's take the scenario of two-phase commit protocol (but only with one resource):

  1. Query to commit from application

  2. Vote Yes/No (from database in our case)

3.1. If yes from database

3.1.1. (Make callback in code) - not part of the protocol

3.1.2. Commit to database

3.2 If no

3.2.1 Rollback to database

What I want is a way to do the callback from 3.1.1 in code, but only when it is known that the transaction will be committed, but before is actually committed. Also, if an exception is thrown here, then the transaction should be be rolled-back.

Using TransactionSynchronization (*) from Spring, allows you to intercept a transaction before it is committed/completed or after it was committed/completed.

  • beforeCommit() callback says that a rollback can still occur after the method was called;
  • beforeComplete() is called even if transaction is failing
  • afterCommit/Complete() is called after transaction was actually committed to database and there is no way to rollback.

Now that I look it seems that what I want is another in a full two-phase commit protocol; but I'm wondering if there is a workaround in Spring. The difference is that the call done in the callback cannot be rolled back.

(*) from Spring 4.2 is very simple with @TransactionalEventListener and TransactionPhase which nicely abstracts TransactionSynchronization

2条回答
ら.Afraid
2楼-- · 2019-03-24 15:29

I just want to firstly go back to a transaction, being a unit of work which either all passes or all fails. With what you are saying about your method about that it cannot be rolled back, and needs to be executed between the start and end of the transaction, then I'm sorry to say you don't have a transaction.

You could do a lot of checks in your method to make sure the likely hood of a rollback is extremely slim, but there will always be a chance your method will execute and a rollback occurs, but this chance could be extremely negligible and you may be happy with that, I don't know.

Edit: I think an analogy would be nice.

Case 1: So classic example of a transaction is buying a banana at the store, if you have no money, or the store has no banana, the store doesn't get money, you don't get a banana, this is what normally happens. But if all conditions are set then the transaction will commit successfully.

Case 2: Now for what you are asking. For arguments sake lets say you are a thief, and you only want to steal the banana if you'll get away with it. You can't know this for certain, because your asking about the future, unless you are a fortune teller, when you go to steal the banana you could get caught.

If you go back to the 1st case, you could check that you have money, the store has a banana, give the store your money, throw all the customers out, lock the doors to the store so the store is in an unchangeable state. Go do your method which you can't rollback, come back to the store, and take the banana. No one can assure you that the banana will still be there, but it's very likely.

查看更多
我命由我不由天
3楼-- · 2019-03-24 15:32

Your case is that one of your resource is not compatible with two-phase-commit (not XA-capable). Your idea goes in the direction of the pattern described in paragraph XA and the Last Resource Gambit of http://www.javaworld.com/article/2077963/open-source-tools/distributed-transactions-in-spring--with-and-without-xa.html

The use of the last resource gambit is briefly explained in the answer of How to set up Spring Boot + Bitronix + non-XA Datasource + XA JMS Connection

By the way, your question doesn't mention which implementation of a transaction manager you use (JBossTS, Bitronix JTA, Atomikos Transaction Essentials, ...).

查看更多
登录 后发表回答