我一直在使用Spring 4的UserDetailsManager
来创建用户,该模式是他们的文档为USERS
和AUTHORITIES
表建议的模式。
我也一直在使用Spring Data @Repository
带注释的接口来管理单独的REGISTRATIONS
表中的数据,该表被定义为在{{1} username
字段上有关系表格。
我遇到的问题是,当我想删除用户时,我首先使用注入的Spring Data存储库从USERS
表中删除记录,然后调用REGISTRATIONS
使用deleteUser()
。 (这只是UserDetailsManager
注释类中@Transactional
方法中的两个连续调用。
例如
@Service
但是,删除用户失败,因为registrationsRepository.delete(uuid);
userDetailsManager.deleteUser(registration.getUsername());
表(第1行)中的记录尚未删除。随后我得到一个异常(第二行)抱怨无法删除用户,因为REGISTRATIONS
表中存在外键约束,导致其被删除。
如果这些更新发生在同一个事务中,为什么会失败?
编辑:
REGISTRATIONS
注册表定义如下:
@Repository
public interface RegistrationsRepository extends CrudRepository<Registration, UUID>
{
// No EntityManager injected - uses Spring Data method queries
// No additional methods defined
}
答案 0 :(得分:1)
因此,据我了解,Spring的UserDetailsManager
使用JDBC调用删除&#39;用户&#39;和当局&#39;来自各自的表格。
我的注册&#39;实体由EntityManager
管理,该用户与“用户”之间没有明确的关系(在ORM级别)。记录。这种关系纯粹是在DB级别指定的。
EntityManager
会标记注册&#39;要删除的实体,而UserDetailsManager
实际上会删除&#39;用户&#39;这是在事务结束时刷新EntityManager
之前发生的。这是因为注册&#39;实体尚未被删除,事务仍未完成,但JDBC调用已经尝试删除用户和&#39;当局&#39;。
为了解决这个问题,我做了以下工作。
class DefaultService implements MyService {
private final EntityManagerFactory emf;
// Inject RegistrationRepository and UserDetailsManager...
@Inject
public DefaultService(EntityManagerFactory emf, ...) {
// ...
this.emf = emf;
}
@Override
@Transactional
public void serviceMethod(UUID uuid, String username) {
registrationsRepository.delete(uuid);
// Flush the entity manager to remove this record from the DB first.
EntityManagerHolder entityManagerHolder = (EntityManagerHolder) TransactionSynchronizationManager.getResource(emf);
entityManagerHolder.getEntityManager().flush();
// These will be JDBC calls, 'users' are not managed entities
userDetailsManager.deleteUser(username);
}
}
我以这种方式获得了EntityManager,以确保我为此事务获得绑定到此线程的正确结果。如果这是矫枉过正或有更好的方法,请发表评论!
希望有人帮助。并且是对的!