谁能解释 Spring Framework 的LocalContainerEntityManagerFactoryBean和LocalEntityManagerFactoryBean 有什么区别?
8 回答
基本上, JPA 规范定义了两种类型的实体管理器。它们是:
i) 应用程序管理:应用程序管理实体管理器意味着“实体管理器仅由应用程序(即我们的代码)创建和管理”。
ii) 容器管理:容器管理实体管理器意味着“实体管理器仅由 J2EE 容器创建和管理(即我们的代码不直接管理,而是由容器创建和管理实体管理器,我们的代码通过某种方式获得 EM,例如使用 JNDI )。
注:Created and Managed(上)是指“在交易中打开、关闭和涉及实体经理”
LocalContainerEntityManagerFactoryBean - 容器管理
LocalEntityManagerFactoryBean - 应用程序管理
一个重要说明:对于基于弹簧的应用程序,差异并不大。Spring 仅扮演角色(如果配置LocalContainerEntityManagerFactoryBean则作为容器,如果配置LocalEntityManagerFactoryBean则作为应用程序)
文档说明了一切:
LocalContainerEntityManagerFactoryBean -- 来自链接:FactoryBean,它根据 JPA 的标准容器引导合同创建 JPA EntityManagerFactory。
LocalEntityManagerFactoryBean——来自链接:FactoryBean,它根据 JPA 的标准独立引导合同创建 JPA EntityManagerFactory。
本质上,唯一的区别在于它们创建 JPA 的方式EntityManagerFactory
。
LocalEntityManagerFactoryBean
是最简单也是最有限的。您不能引用现有的 JDBC DataSource bean 定义,并且不存在对全局事务的支持。
LocalContainerEntityManagerFactoryBean
是最强大的 JPA 设置选项,允许在应用程序中进行灵活的本地配置。它支持到现有 JDBC 数据源的链接,支持本地和全局事务
REF:spring-framework-reference.pdf “Spring 3”
LocalEntityManagerFactoryBean 产生一个应用程序管理的 EntityManagerFactory。
LocalContainerEntityManagerFactoryBean 生成一个容器管理的 EntityManagerFactory。
Ref : Spring In Action - Craig Walls
JPA 规范定义了两种实体管理器:
应用程序管理——当应用程序直接从实体管理器工厂请求实体管理器时,就会创建实体管理器。对于应用程序管理的实体管理器,应用程序负责打开或关闭实体管理器并让实体管理器参与事务。这种类型的实体管理器最适合用于不在 Java EE 容器中运行的独立应用程序。
容器管理——实体管理器由 Java EE 容器创建和管理。应用程序根本不与实体管理器工厂交互。相反,实体管理器是直接通过注入或从 JNDI 获得的。容器负责配置实体管理器工厂。这种类型的实体管理器最适合 Java EE 容器使用,该容器希望保持对 JPA 配置的控制超出 persistence.xml 中指定的内容。
Application-managed EntityManagers
是EntityManagerFactory
通过调用createEntityManagerFactory()
PersistenceProvider的方法获得的。同时,容器管理的EntityManagerFactorys是通过PersistenceProvider的 createContainerEntityManagerfactory()
方法获取的。
实体管理器工厂的每种风格都由相应的 Spring 工厂 bean 生成:
LocalEntityManagerFactoryBean
生成应用程序管理的 EntityManagerFactory。LocalContainerEntityManagerFactoryBean
产生一个容器管理的 EntityManagerFactory
需要指出的是,在应用程序管理
EntityManagerFactory
和容器管理之间做出的选择EntityManagerFactory
对于基于 Spring 的应用程序是完全透明的。当您使用 Spring 和 JPA 时,处理任何一种形式的复杂细节EntityManagerFactory
都被隐藏起来,让您的数据访问代码专注于其真正目的:数据访问。
就 Spring 而言,应用程序管理的实体管理器工厂和容器管理的实体管理器工厂之间唯一真正的区别是它们在 Spring 应用程序上下文中的配置方式。
- LocalEntityManagerFactoryBean 和 LocalContainerEntityManagerFactoryBean 两种实现都从 org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl 返回 EntityManagerFactory 引用。
- 除非我们明确要求 Spring 使用 JTA,否则每个实现都将使用 resource_local 事务。
- 两个实现之间的主要区别是 LocalContainerEntityManagerFactoryBean 提供以编程方式设置持久性单元(数据源和 packageToScan),更灵活的是我们可以覆盖persistence.xml 文件的位置,与我们必须使用预定义名称持久性的 LocalEntityManagerFactoryBean 相比.xml
如果两者都使用 resource_local 作为默认值,那么它并没有拇指规则 LocalContainerEntityManagerFactoryBean 正在使用容器管理的事务而其他正在使用应用程序管理的事务。
在依赖注入容器之外使用 JPA 时,开发人员需要以编程方式处理事务。如果在 Spring 依赖注入容器中使用 JPA,那么它可以由 Spring 容器处理。
使用 LocalContainerEntityManagerFactoryBean 的示例
public class DataConfig {
@Bean
LocalContainerEntityManagerFactoryBean entityManagerFactory() {
//LocalEntityManagerFactoryBean lfb = new LocalEntityManagerFactoryBean();
LocalContainerEntityManagerFactoryBean lfb = new LocalContainerEntityManagerFactoryBean();
lfb.setDataSource(dataSource());
lfb.setPersistenceUnitName("localEntity");
lfb.setPersistenceProviderClass(HibernatePersistence.class);
lfb.setPackagesToScan("com.javasampleapproach.h2database.model");
lfb.setJpaProperties(hibernateProps());
return lfb;
}
}
@Component
public class PostRepository {
@Autowired
EntityManagerFactory emf;
}
public void create(){
EntityManager em = emf.createEntityManager();
Post post = new Post("First post");
em.getTransaction().begin();
em.persist(post);
em.getTransaction().commit();
}
}
LocalEntityManagerFactoryBean 出错
java.lang.IllegalStateException:不允许在共享 EntityManager 上创建事务 - 改用 Spring 事务或 EJB CMT
public class DataConfig {
@Bean
LocalEntityManagerFactoryBean entityManagerFactory() {
LocalEntityManagerFactoryBean lfb = new LocalEntityManagerFactoryBean();
lfb.setPersistenceUnitName("localEntity");
lfb.setPersistenceProviderClass(HibernatePersistence.class);
lfb.setJpaProperties(hibernateProps());
return lfb;
}
}
@Component
public class PostRepository {
@Autowired
EntityManager em;
public void create(){
EntityManager em = emf.createEntityManager();
Post post = new Post("First post");
em.getTransaction().begin();
em.persist(post);
em.getTransaction().commit();
}
}
<persistence-unit name="localEntity">
</persistence-unit>
使用 LocalEntityManagerFactoryBean 的工作代码
在 LocalEntityManagerFactoryBean 的情况下,Spring 托管事务类似于容器管理。
public class DataConfig {
@Bean
LocalEntityManagerFactoryBean entityManagerFactory() {
LocalEntityManagerFactoryBean lfb = new LocalEntityManagerFactoryBean();
lfb.setPersistenceUnitName("localEntity");
lfb.setPersistenceProviderClass(HibernatePersistence.class);
lfb.setJpaProperties(hibernateProps());
return lfb;
}
}
@Component
public class PostRepository {
@Autowired
EntityManagerFactory emf;
@Transactional
public void create() {
Post post = new Post("First post");
em.persist(post);
}
}
<persistence-unit name="localEntity">
</persistence-unit>
这两种实现都可以在容器管理的事务下使用,如果需要更正,请更正我。
要在 Spring 项目中使用 JPA,我们需要设置 EntityManager。
这是配置的主要部分,我们可以通过 Spring 工厂 bean 来完成。这可以是更简单的LocalEntityManagerFactoryBean或更灵活的LocalContainerEntityManagerFactoryBean。
baeldung.com/the-persistence-layer-with-spring-and-jpa
LocalEntityManagerFactoryBean 通过 PersistenceProvider.createEntityManagerFactory() 创建 EntityManagerFactory
LocalContainerEntityManagerFactoryBean 通过 PersistenceProvider.createContainterEntityManagerFactory() 创建 EntityManagerFactory