有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java无法从@Transaction中具有关系的两个表中删除

我一直在使用Spring 4的UserDetailsManager来创建用户,该模式是他们的文档为USERSAUTHORITIES表建议的模式

我还一直在使用Spring Data @Repository注释接口来管理一个单独的REGISTRATIONS表中的数据,该表定义为在USERS表中的username字段上有一个关系

我一直面临的问题是,当我想要删除一个用户时,我首先使用注入的Spring数据存储库从REGISTRATIONS表中删除记录,然后使用UserDetailsManager调用deleteUser()。(这只是在@Service注释类中的@Transactional方法中的两个连续调用)

比如

registrationsRepository.delete(uuid);
userDetailsManager.deleteUser(registration.getUsername());

但是,删除用户失败,因为REGISTRATIONS表(第1行)中的记录尚未删除。随后,我收到一个异常(第二行),抱怨无法删除用户,因为REGISTRATIONS表中存在外键约束,无法删除它

如果这些更新发生在同一事务中,为什么会失败

编辑:

@Repository
public interface RegistrationsRepository extends CrudRepository<Registration, UUID>
{
    // No EntityManager injected - uses Spring Data method queries
    // No additional methods defined
}

注册表定义如下:

CREATE TABLE Registrations (
  username varchar(64) NOT NULL REFERENCES Users (username),
  uuid UUID NOT NULL PRIMARY KEY
);

共 (1) 个答案

  1. # 1 楼答案

    因此,据我所知,Spring的UserDetailsManager使用JDBC调用从相应的表中删除“用户”和“权限”

    我的“注册”实体由一个EntityManager管理,它与“用户”记录没有定义的关系(在ORM级别)。这种关系纯粹是在数据库级别指定的

    EntityManager将标记要删除的“注册”实体,而UserDetailsManager将实际删除“用户”,这发生在事务结束时刷新EntityManager之前。这会失败,因为“注册”实体尚未被删除,事务仍未完成,但JDBC调用已尝试删除“用户”和“权限”

    为了解决这个问题,我做了以下工作

    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,以确保为该事务获得绑定到此线程的正确管理器。如果这是过分的,或者有更好的方法,请评论

    希望这能帮助别人。这是正确的