如何在没有 spring 的情况下在 JPA 中获取当前的 EntityManager?

How to get current EntityManager in JPA without spring?

我正在做一个使用 JPA 但没有 spring 的家庭作业。 它具有服务层和存储库层。 我尝试在服务中开始事务并从存储库调用保存或更新,然后在服务中提交。 但是如何在存储库中获取 Current EntityManager 呢? 我的鳕鱼是这样的:

服务:

public void save(Entity entity){
    var em = factory.createEntityManager();
    var t = em.getTransaction();
    try {
        t.begin();

        repository1.save(entity);

        // For saving one to many relation 
        repository2.save(entity.getChildEntity());

        t.commit();
    } catch (Exception e) {
        t.rollback();
    }
}

存储库:

// I don't want to pass EntityManager to method

public void save(T entity) {
    var em = ?      // How can I get EntityManager hear?

    em.persist(entity);
}
public class EntityManagerProvider {

   private static final EntityManager entityManager;

   public EntityManagerProvider() {
      EntityManagerFactory emf = Persistence.createEntityManagerFactory("com.example.factory");
      this.entityManager = emf.createEntityManager();
   }
   
   public static EntityManager getEntityManager() {
       return entityManager;
   }
}

第二种方法:

public class EntityManagerProvider {

   private static final EntityManager entityManager;

   private EntityManagerProvider() {}

   public static synchronized EntityManager createOrGetEntityManager() {
        if(entityManager == null) {
           EntityManagerFactory emf = Persistence.createEntityManagerFactory("com.example.factory");
           EntityManagerProvider.entityManager = emf.createEntityManager();
           return EntityManagerProvider.entityManager;
        }
        
        return EntityManagerProvider.entityManager;
   }
}

您需要一次创建 entityManager 并在所有地方使用它。我不知道你在哪里创建工厂 class 但你可以在创建工厂 class.

之后创建 entityManagerProvider class

您只需调用 EntityManagerProvider.getEntityManager() 即可从 class 接收 entityManager。

请注意,您无需在所有地方都进行初始化,只需一次即可在所有地方使用。

SecondApproach 更好,您可以在任何地方轻松使用它。 EntityManagerProvider.createOrGetEntityManager 方法会给你 entityManager.

在您的第一个服务片段中,我看到您有一个 factory 并在那里创建了一个 EntityManager。所以 factory 存在...

带上你的工厂,让它在你的程序中随处可见。如何? 创建一个仅用于创建工厂和休眠会话的 class。在那里,您为所需的字段(例如 factoryEntityManager)创建 public 静态吸气剂。

示例:

public class HibernateUtils
{
    public static final SessionFactory sessionFactory = buildSessionFactory();

    private static SessionFactory buildSessionFactory()
    {
        try
        {
            // Create the SessionFactory from hibernate.cfg.xml
            return new Configuration().configure().buildSessionFactory();
        }
        catch (Throwable ex)
        {
            // Make sure you log the exception, as it might be swallowed
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public static void shutdown() {
        // Close caches and connection pools
        getSessionFactory().close();
    }
}

在Spring中,Services和Repositories的使用是对JPA的进一步抽象。 如果您想在没有 Spring 的情况下使用 JPA,您可以使用标准 JavaEE/JakartaEE 技术注入 EntityManager,这就是 Spring 在幕后所做的。

否则,如果您想自己做,请记住 JPA 是一个标准,有几个实现。

让我们考虑一下 Hibernate,去阅读文档,坚持使用 EntityManagerFactory 和 EntityManager 而不是 SessionManager(特定于 Hibernate)。

您可以将 EntityManager 实例化为:

EntityManagerFactory emf = Persistence.createEntityManagerFactory("my_PU");
EntityManager em = emf.createEntityManager(); 

“my_PU”是您需要定义的持久化单元。

此处有更多信息:https://docs.oracle.com/cd/E19798-01/821-1841/bnbrj/index.html#:~:text=A%20persistence%20unit%20defines%20a,the%20persistence.xml%20configuration%20file

一段时间后,我找到了一种在当前线程中获取 Current EntityManager 的安全方法。

我渴望 link 所以只是分享代码,我希望得到你的反馈和意见。 我想这样我什至也可以使用 Aspectj。

public class EntityManagerUtil {
    //for holding EntityManager in current thread
    private static final ThreadLocal<EntityManager> THREAD_LOCAL;
    
    static {
        THREAD_LOCAL = new ThreadLocal<>();
    }
    // singleton creating EntityManagerFactory 
    private static class LazyHolder {
        private static final EntityManagerFactory ENTITY_MANAGER_FACTORY =
                Persistence.createEntityManagerFactory("persistence-unit");
    }

    public static EntityManagerFactory getEntityManagerFactory() {
        return LazyHolder.ENTITY_MANAGER_FACTORY;
    }

    public static EntityManager getCurrentEntityManager() {
        EntityManager entityManager = THREAD_LOCAL.get();

        if (entityManager == null) {
            entityManager = getEntityManagerFactory().createEntityManager();
            // set your flush mode here
            THREAD_LOCAL.set(entityManager);
        }
        return entityManager;
    }

    public static void closeCurrentEntityManager() {
        EntityManager em = THREAD_LOCAL.get();
        if (em != null) {
            em.close();
            THREAD_LOCAL.remove();
        }
    }
}