@PersistenceContext注入未获取Hibernate EntityManager实现问题
JPA注入EntityManager类型不符合预期问题
问题背景
当前正在学习Java EE JPA规范,选用Hibernate作为JPA实现,遇到注入的EntityManager实际类型和预期不符的问题,相关代码与配置如下:
Book实体类定义
@Entity public class Book { @Id @GeneratedValue private Long id; private String title; private String description; private Float unitCost; public Book() { } // 省略getter、setter方法 }
BookService服务类定义
public class BookService { @PersistenceUnit(unitName = "book_store") private EntityManager entityManager; public void create(Book book) { entityManager.persist(book); entityManager.flush(); } }
persistence.xml配置
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd" version="2.2"> <persistence-unit name="book_store"> <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> <class>com.example.jpatest1.Book</class> <properties> <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/> <property name="javax.persistence.jdbc.password" value="somePasss"/> <property name="javax.persistence.jdbc.user" value="sammy"/> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/book_store?autoReconnect=true&useSSL=false"/> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/> <property name="hibernate.show_sql" value="true"/> <property name="hibernate.hbm2ddl.auto" value="create-drop"/> </properties> </persistence-unit> </persistence>
核心疑问
- 注入到
BookService中的EntityManager实际类型为org.jboss.as.TransactionScopedEntityManager,而非Hibernate提供的SessionImpl,为什么拿不到Hibernate原生实现? - 为什么使用
@PersistenceContext注解无法直接获取Hibernate原生的EntityManager实现?
问题解答
- 首先纠正代码里的注解误用:你当前代码里用的
@PersistenceUnit注解作用是注入EntityManagerFactory,而非EntityManager。要注入容器托管的EntityManager,必须使用@PersistenceContext注解,直接给EntityManager类型的字段加@PersistenceUnit本身就是错误用法。 - 容器不会直接注入JPA提供者的原生实现:你看到的
org.jboss.as.TransactionScopedEntityManager是JBoss/WildFly容器提供的代理对象,这是Java EE规范的要求,不是bug。这个代理层负责处理事务上下文绑定、EntityManager生命周期管理、连接资源分配与回收、权限校验等容器级逻辑,在实际执行持久化操作时,会自动委托给当前事务绑定的Hibernate原生实现类完成实际数据库操作。 - 这是JPA规范的解耦设计:JPA作为标准ORM规范,核心目标就是屏蔽底层ORM实现的差异,业务代码只需要面向
javax.persistence.EntityManager接口编程即可,不需要关心底层实现类是Hibernate的SessionImpl还是其他JPA提供者的实现类,后续切换JPA实现时业务代码不需要改动。 - 获取Hibernate原生对象的方式:如果确实需要使用Hibernate特有的API,可以在业务方法中通过解包方法获取底层原生对象,示例代码如下:
注意:这种写法会让代码和Hibernate强耦合,失去JPA的跨实现移植能力,非必要场景不推荐使用。// 获取Hibernate原生Session Session hibernateSession = entityManager.unwrap(Session.class); - 额外的事务配置提醒:当前
BookService的create方法没有配置事务,在Java EE容器环境下直接调用写操作会抛出事务required异常,需要在类或者create方法上添加@javax.transaction.Transactional注解,标记方法运行在事务上下文中。
内容的提问来源于stack exchange,提问作者Anatolii
相关产品推荐
相关产品推荐

