Calling a HTTP service within a JPA/JTA transaction - transaction integrity
I have a JSF/EJB/JPA application which uses container managed persistence. There is one case where a call is made to an external service via HTTP which has a cost, this cost being allocated back to the requesting user. In the current implementation the process of making the HTTP request is performed by a EJB timer method running periodically in the background.
The timer method may have to deal with a number of requests in one invocation, although each request needs to be treated independently, independently with respect to allocating the cost back to the user, that is. If user A doesn't have enough credit to purchase a book, this musn't prevent the successful purchase of a book by user B resulting in their balance being debited due to a rollback.
To provide control over the transaction demarcation for independent processing of each开发者_如何学Go request I'm using bean managed transactions for the class in which the timer method resides. This is a java-pseudo-code version of what I've got now:
@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class MessageTimer {
private void processMessages(UserMessage msg) {
tx.begin();
em.joinTransaction();
try {
userData = em.find(..., PESSIMISTIC_WRITE);
if(user has enough credit) {
debit cost from user;
status = make external http request to order book from supplier;
if(status == success) {
commit = true;
}
}
} catch(Exception) {
tx.rollback();
}
if(commit) {
tx.commit();
}
else {
tx.rollback();
}
}
}
So the idea is that I start a transaction, assume success and debit the cost from the user, call the http service and commit if it succeeds or rollback otherwise.
I have an uneasy feeling that I may not be anywhere near the right ballpark with this design, particularly having the lengthy http call (actually done using jax-rs) inside the pessimistic_write transaction. I wondered if I could firstly, within a transaction debit the user (begin/debit/commit), make http call, then credit the user if any error happens, but there's no transaction integrity.
This is new territory for me, can anyone point me in the right direction, is there an established way of doing what I'm trying to do?
Many Thanks.
p.s. I'm using a glassfish 3.1 stack with Seam 3
I am not sure how jax-rs communication layer is. if the communication is single threaded, then the code you have written is a long running transaction. which might make your application slower.
I am not a tech guru, but what i can suggest is -
Credit the account and make the jax-rs call on a thread. on that case the transaction will be closed before sending the call to remote node. and it will not be a long running transaction, so the application will be faster.
精彩评论