为了账号安全,请及时绑定邮箱和手机立即绑定

如何防止使用 guice-persist 和 @Transactional 重用

如何防止使用 guice-persist 和 @Transactional 重用

蝴蝶不菲 2023-06-14 16:20:22
使用时guice-persist,EntityManager是事务范围的。如果我理解正确的话,这意味着EntityManager将为每笔交易创建一个新的。使用时guice-persist,建议使用JpaPersistModule,它提供了所有的绑定,并简单地注入Provider<EntityManager>到某个类中,就像这样:public class ProjectDAO {  private final Provider<EntityManager> entityManagerProvider;  @Inject  public ProjectDAO(Provider<EntityManager> entityManagerProvider) {    this.entityManagerProvider = entityManagerProvider;  }} 现在,我试过了,每个线程都有自己的EntityManager. 然而,它似乎并没有被移除并重新设置,而是被重新用于后续事务,即Hibernate的一级缓存没有被清除。这是一个完整的示例,它从两个不同的线程(顺序地,而不是并行地)插入和删除一些实体,这会导致一个线程具有陈旧的信息:项目(一个简单的实体)   @NamedQueries({        @NamedQuery(name = "project.findAll", query = "from project"),        @NamedQuery(name = "project.deleteByProjectName", query = "delete from project p where p.name = :project_name")    }    )    @Entity(name = "project")    public class Project {        @Id        @GeneratedValue        private Long id;        @Column(name="name")        private String name;        // ... getters/setters    }项目DAO    public class ProjectDAO {      private final Provider<EntityManager> entityManagerProvider;      @Inject      public ProjectDAO(Provider<EntityManager> entityManagerProvider) {        this.entityManagerProvider = entityManagerProvider;      }      public void insert(Project project) {        entityManagerProvider.get().persist(project);      }      public List<Project> findAll() {        return entityManagerProvider.get()            .createNamedQuery("project.findAll", Project.class)            .getResultList();      }
查看完整描述

1 回答

?
江户川乱折腾

TA贡献1851条经验 获得超5个赞

上面的代码有两个问题:

1)下面一行

System.out.println("TEST: " +"EntityManager: " + projectService.getEntityManager().hashCode());

被添加用于调试目的。ProjectService.getEntityManager()但是,调用 的方法ProjectDAO.getEntityManager()又调用entityManagerProvider.get(),没有用 注释@Transactional。这会导致EntityManager每个线程设置一次并且永远不会取消设置,即使@Transactional稍后调用 ProjectService 中具有注释的其他方法也是如此。只需添加此注释即可解决问题。

2)在一个线程中,名称为“project1”的实体被删除

   //----
   projectService.delete("project1");
      //----

然而,在另一个线程中,验证了另一个实体的存在

   // project3, which was deleted in Thread 2 is still visible in this EntityManager
   Project project = projectService.findById(3L);
   System.out.println("Project still exists " + project);

一开始就没有删除。实体被一个接一个地添加 - project1、project2、project3... 并分别为它们分配 ID 1、2、3...。所以代码应该是

   // project1, which was deleted in Thread 2 is still visible in this EntityManager
   Project project = projectService.findById(1L);
   System.out.println("Project still exists " + project);


查看完整回答
反对 回复 2023-06-14
  • 1 回答
  • 0 关注
  • 111 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信