I'd appreciate help in understanding why my application fails to find an entity, even though it exists in the database; I believe the issue is related to concurrent writing/reading. I'm using jpa2/hibernate 4 and spring 3.
I have a method that creates a user then sends the id, as a json object message, to a message queue where the user is further processed. Problem occurs when the message handler (UserProcessor.class) attempts to find
the user (see below).
Registration.class
@Transactional
public Response createUser(String firstName, String lastName) {
User tmpUser = new User(firstName, lastName);
User savedUser = this.em.merge(tmpUser);
this.em.flush();
if (savedUser != null) {
processUser(savedUser.getId()); // message sent to queue.
} else {
// Throw exception...
}
}
UserProcessor.class
@Transactional(rollbackFor={javax.ws.rs.WebApplicationException.class})
public void processUser(Long id) {
User user = this.em.find(User.class, id); // No user entity is found, "user" is null.
if (user == null) {
// throw exception
}
...
}
I think you may have a concurrency problem.
As far as I understand your code, it works this way:
Registration.createUser:
Step A4) commits the transaction (I)
UserProcessor.processUser(Long id)
Step B1) takes the user id from the queue
You know (depending on your transaction isolation level) the data written in a transaction (I) can read in an other transaction (II) only if the first transaction (I) is committed.
So if the UserProcessor.processUser try to process step B3 before transaction (I) is committed in step A4, it will not see the user in the database. (If you use higher transaction isolation levels, than may you even need to do step A4 before B2.)
One workaround would be switching the order of step A3 and A4. One important point: If there method Response.createUser
is called in the context of then other (outer) transaction, then it will committed with the outer transaction!
You could use two methods :
@Transactional(rollbackFor={javax.ws.rs.WebApplicationException.class})
public void processUser(Long id) {
processUser(this.em.find(User.class, id));
}
public void processUser(User aUser) {
...
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.