我正在使用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;
}
}
答案 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>
干杯:)