Eclipse Link多租户无法正常运行。
示例实体(模式由liquibase创建):
@Entity
@Table(name = "ENTITIES")
@Multitenant(MultitenantType.SINGLE_TABLE)
@TenantDiscriminatorColumn(name = "TENANT_ID", contextProperty = "eclipselink.tenant-id")
public class EntityClass
要在实体管理器上设置多租户属性,我使用一个方面,如下所示:
@Around("execution(* javax.persistence.EntityManagerFactory.*(..))")
public Object invocate(ProceedingJoinPoint joinPoint) throws Throwable {
final Object result = joinPoint.proceed();
if (result instanceof EntityManager) {
EntityManager em = (EntityManager) result;
final String tenantId = TenantContext.getCurrentTenantId();
LOG.debug("Set EntityManager property for tenant {}.", tenantId);
em.setProperty(EntityManagerProperties.MULTITENANT_PROPERTY_DEFAULT,
tenantId);
return em;
}
return result;
}
当我启动Spring Boot应用程序时,这非常有效。为了在集成测试期间提供租户信息,我定义了一个注释:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AsTenant {
String value();
}
要绑定此值,我使用TestExecutionListener
:
@Override
public void beforeTestMethod(TestContext testContext) throws Exception {
final Method testMethod = testContext.getTestMethod();
final AsTenant asTenantAnnotation = testMethod
.getAnnotation(AsTenant.class);
if (asTenantAnnotation != null) {
TenantContext.setCurrentTenantId(asTenantAnnotation.value());
}
}
通过调试,我可以清楚地说明在创建任何EM之前调用TestExectionListener
并且为EM正确设置了属性。将任何内容持久保存到数据库时,Eclipse Link不会为该列设置值。
也许有人可以帮我解决这个问题,我不知道为什么EclipseLink Multitenancy无效。
答案 0 :(得分:0)
好的,我明白了。如果有人遇到类似的问题,这是我的解决方案。
如果使用交易,则必须在交易开始后设置租户歧视的上下文属性(http://www.eclipse.org/eclipselink/documentation/2.5/solutions/multitenancy002.htm)。
EntityManager em = createEntityManager(MULTI_TENANT_PU);
em.getTransaction().begin();
em.setProperty(EntityManagerProperties.MULTITENANT_PROPERTY_DEFAULT, "my_id");
为了在Spring Boot / Data环境中实现这一点,我定制了Spring的JpaTransactionManager
。这是问题中Aspect的补充,因为SELECT
查询没有事务。
public class MultitenantJpaTransactionManager extends JpaTransactionManager {
/* (non-Javadoc)
* @see org.springframework.orm.jpa.JpaTransactionManager#doBegin(java.lang.Object, org.springframework.transaction.TransactionDefinition)
*/
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
super.doBegin(transaction, definition);
final EntityManagerHolder emHolder = (EntityManagerHolder) TransactionSynchronizationManager.getResource(getEntityManagerFactory());
final EntityManager em = emHolder.getEntityManager();
final String tenantId = TenantContext.getCurrentTenantId();
if (tenantId != null) {
em.setProperty(EntityManagerProperties.MULTITENANT_PROPERTY_DEFAULT, tenantId);
}
}
}
这很容易通过JpaConfiguration连接:
/**
* Configures Eclipse Link as JPA Provider.
*/
@Configuration
@EnableTransactionManagement
@AutoConfigureAfter({ DataSourceAutoConfiguration.class })
public class JpaConfiguration extends JpaBaseConfiguration {
@Bean
@Override
public PlatformTransactionManager transactionManager() {
return new MultitenantJpaTransactionManager();
}
@Override
protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
EclipseLinkJpaVendorAdapter adapter = new EclipseLinkJpaVendorAdapter();
return adapter;
}
@Override
protected Map<String, Object> getVendorProperties() {
HashMap<String, Object> properties = new HashMap<String, Object>();
properties.put(PersistenceUnitProperties.WEAVING, detectWeavingMode());
return properties;
}
private String detectWeavingMode() {
return InstrumentationLoadTimeWeaver.isInstrumentationAvailable()
? "true" : "static";
}
}
答案 1 :(得分:-1)
免责声明:这不会回答上述查询,但提供了一种替代方法。
我使用字节码工具在Eclipse Link和Spring Data的Multi-Tenancy(每个租户表)上创建了一个Java示例。选择这个想法是为了利用Spring Data的全部功能。
一个人可以执行MultiTenantTest来查看其工作情况。
该想法是开源的,可在Maven Central上获得
步骤:
1.Include依赖项
<dependency>
<groupId>org.bitbucket.swattu</groupId>
<artifactId>jpa-agent</artifactId>
<version>2.0.2</version>
</dependency>
2。创建一个如下所示的类。包,类和方法必须完全相同。
package org.swat.jpa.base;
import javax.persistence.EntityManager;
public class EntityManagerFactoryListener {
/**
* This method is called by JPA Agent.
*
* @param entityManager the entity manager
*/
public static void afterCreateEntityManager(EntityManager entityManager) {
//Business logic to set appropriate values in entityManager
final String tenantId = TenantContext.getCurrentTenantId();
if (tenantId != null) {
em.setProperty(EntityManagerProperties.MULTITENANT_PROPERTY_DEFAULT, tenantId);
}
}
}
3。启动java时添加javaagent
-javaagent:{path-to-jpa-agent-jar}