Wednesday, 30 September 2009

Persisting Users - Yikes! I Had To Think About Transactionality

A SwagItem has a JDO 1-to-1 owned relationship with a SwagImage. A User can own many SwagItems. However, I decided not to let JDO manage that relationship. Instead I simply use the user email as an (informal) foreign key in SwagItem.

This means that SwagItem and User are not in the same JDO entity group which means they may not be mutated in the same transaction.

In order for my service method overcome this, I had to think about transactionality. Let's take a look at ItemService.save():

@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void save(SwagItem swagItem) {
if (swagItem.isNew()) {
String currentUserEmail = googleUserService.getCurrentUser().getEmail();
swagItem.setOwnerEmail(currentUserEmail);
String currentUserNickName = googleUserService.getCurrentUser().getNickname();
swagItem.setOwnerNickName(currentUserNickName);
itemDao.insert(swagItem);
// insert user if they don't exist (this only happens when creating a new item
// since only existing users can update
SwagSwapUser swagSwapUser = swagSwapUserService.findByEmail(currentUserEmail);
if (swagSwapUser==null) { //add them
swagSwapUserService.insert(new SwagSwapUser(currentUserEmail,currentUserNickName));
}
}
else { //update
checkPermissions(swagItem.getKey());
itemDao.update(swagItem);
}
}


You'll notice that I'm inserting the user if they don't exist. This caused an exception since User is in a different entity group than SwagItem (not allowed to be committed in the same transaction). To fix this I added the spring transaction annotation Propagation.REQUIRES_NEW to the swagSwapUserService.insert() method:


@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void insert(SwagSwapUser swagSwapUser) throws UserAlreadyExistsException {
if (findByEmail(swagSwapUser.getEmail()) !=null) {
throw new UserAlreadyExistsException(swagSwapUser);
}
userDao.insert(swagSwapUser);
}

And it works fine.

No comments:

Post a Comment