我在春季论坛发布此消息的人遇到类似问题:http://forum.springsource.org/archive/index.php/t-20943.html
基本上我正在为我工作的网站编写自动注册功能。如果用户存在于第三方数据库中,我们将从而不是在我们的数据库中迁移用户,那么登录过程将自动在我们的数据库中创建用户。
要做到这一点,我必须首先尝试使用电子邮件和密码在登录时验证用户身份。如果失败,我检查第三方数据库并尝试使用此信息创建用户。如上面的链接,似乎这个存在检查后跟一个插入导致该方法被Hibernate标记为仅回滚。
我已经尝试在存在检查中使用Transactional Requires_New强制它进入一个新的Transaction,我希望这个事务只会被标记为Roll-back而不是父事务,但是这没有用。
有人可以建议如何做到这一点吗?上面的链接建议插入并使用重复键错误作为用户已经存在的检查,但这看起来很混乱,需要进行大量的重新设计。
顺便说一句,我们正在使用Hibernate,Spring和Annotations来处理事务。
答案 0 :(得分:0)
假设login方法抛出异常,你可以修复它 在存在检查方法上为@Transactional属性添加noRollbackFor选项。
@Transactional(noRollbackFor=SecuirtyExcepion.class)
public boolean authenticate(String email,String password) throws SecurityException {
}
@Transactional
public void someMethod() {
try {
// without noRollbackFor this would result in transaction being marked as
// rollback only
authenticate(email,password);
} catch(SecurityException e) {
// create user
}
}
答案 1 :(得分:0)
我找到的解决方案是将相关部分分成单独的事务。在我的情况下,我正在检查用户是否存在,如果它不存在,但它在我的第三方数据库创建它。这意味着如果authenticate失败,则新用户的创建将不会回滚,但如果需要,则可以不同地分隔,因此create和authenticate方法在同一事务方法中。
public void login(String username, String password)
{
User user = null;
try {
user = userHelper.findUserByUsername(username);
} catch (UserNotFoundException e) {
log.warn(e);
if (integrationLayer.checkUserExists(username))
{
user = userHelper.createUser(username, password);
}
else
{
return false;
}
}
return userHelper.authenticate(user, password);
}
@Transactional
public User userHelper.findUserByUsername(String Username)
{
... find and return user ...
... throw user not found exception if not found ...
}
@Transactional
public User userHelper.createUser(String Username, String Password)
{
... create and return the new user ...
}
@Transactional
public Boolean userHelper.authenticate(String Username, String Password)
{
... authenticate the user ...
}
@Transactional
public Boolean integrationLayer.checkUserExists(String username)
{
... if the user exists in the third party DB return true ...
}