如何为EntityManagerFactory

时间:2016-01-07 12:44:04

标签: java hibernate jpa orm hibernate-mapping

我正在使用JPA,但我需要解开我的EntityManagerFactory,所以我可以在Session中添加一个拦截器。之后我想将Session包装回EntityManager。

“为什么不使用Session而不是EntityManager?”我们仍然希望减少可能的技术迁移的影响

  

我想使用拦截器:

我可以通过以下方式恢复问题:项目在警报数据库上运行查询。每个地方都有一个带有报警表的数据库,但是客户希望有一个数据库,我们必须创建多个“报警表”,每个地方一个(例如:Table_Alarm-Place1,Table_Alarm-Place2)。这意味着我们将为同一个实体提供多个表,拦截器的目标是在最终的SQL中通过hibernate更改表名生成

  

我如何假装使用拦截器:

public class SqlInterceptor extends EmptyInterceptor {

    private String tableSufix;

    private static final Logger LOGGER = LoggerFactory.getLogger(SqlInterceptor.class);

    public SqlInterceptor(String tableSufix) {...}

    @Override
    public String onPrepareStatement(String sql) {
        String finalSql;

        //Manipulated SQL (parsed by Hibernate)

        return finalSql;
    }

}
  • 该项目使用JPA 2.1和Hibernate 4.3.11.Final

5 个答案:

答案 0 :(得分:0)

为什么不简单地执行以下操作:

EntityManagerFactory entityManagerFactory = // created from somewhere.
SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
// do whatever you need with the session factory here.

// Later in your code, initially use EntityManager and unwrap to Session.
EntityManager entityManager = entityManagerFactory.createEntityManager();
Session session = entityManager.unwrap(Session.class);

基本上,不是试图获取Session然后将其重新包装回EntityManager,而是简单地传递JPA EntityManager并将其解包到Session上根据需要。

答案 1 :(得分:0)

在构建Interceptor

时,您可以提供EntityManagerFactory
String persistenceUnitName = ...;
PersistenceUnitInfo persistenceUnitInfo = persistenceUnitInfo(persistenceUnitName);
Map<String, Object> configuration = new HashMap<>();
configuration.put(AvailableSettings.INTERCEPTOR, new SqlInterceptor());

EntityManagerFactoryBuilderImpl entityManagerFactoryBuilder = new EntityManagerFactoryBuilderImpl(
    new PersistenceUnitInfoDescriptor(persistenceUnitInfo), configuration
);
EntityManagerFactory emf = entityManagerFactoryBuilder.build();

答案 2 :(得分:0)

看起来您想拥有一个多租户数据库。之前我遇到过类似的问题,并使用aspectj实现了一个拦截器来正确设置过滤器。即使您没有使用过滤器选项,也可以在每次使用aspectj创建时使用te session,如下所示。

public privileged aspect MultitenantAspect {

    after() returning (javax.persistence.EntityManager em): execution (javax.persistence.EntityManager javax.persistence.EntityManagerFactory.createEntityManager(..)) {
        Session session = (Session) em.getDelegate();
        Filter filter = session.enableFilter("tenantFilter");
        filter.setParameter("ownerId", ownerId);
    }

}

在下面的示例中,我只是设置了需要在需要过滤的实体上配置的过滤器:

@Entity
@FilterDef(name = "tenantFilter", parameters = @ParamDef(name = "ownerId", type = "long"))
@Filters({
    @Filter(name = "tenantFilter", condition = "(owner=:ownerId or owner is null)")
})
public class Party {
}

当然,要使用过滤器而不是表名,您必须添加一列来区分表 - 我认为这比具有多个表名更好。

答案 3 :(得分:0)

您可以将所有必要的信息存储在静态ThreadLocal实例中,然后再将其读取。

这样可以避免会话范围拦截器的复杂化,并且可以使用其他机制来实现相同的目标(例如,使用会话工厂范围的拦截器,这更容易配置)。

答案 4 :(得分:0)

覆盖Hibernate的EmptyInterceptor的一种超级简单的方法就是在属性文件中添加

spring.jpa.properties.hibernate.session_factory.interceptor=<fully-qualified-interceptor-class-name>

干杯:)