我正在尝试使用JPA / EclipseLink / EJB3 / JSF 2.2应用程序中的每个租户/架构策略实现多租户。
我正在进行的测试是针对一个mysql应用程序(其中已创建了3个数据库),所有租户共有的系统数据库,以及每个租户的相同数据库。
系统数据库只有一个表tenant_user(login,pasword,schema_name)
以下是主要代码的片段: 登录bean(JSF托管bean):
public void loginUser(){
UserTenant userTenant = systemFacade.getUserTenantByUserDetails(login, password);
System.out.println("User " + userTenant.getLogin() + " got connected ..");
emProvider.getEm(userTenant.getSchemaName());
achatFacade.setTenantId(userTenant.getSchemaName());
Achat achat = new Achat();
achat.setName("new achat");
achatFacade.create(achat);
}
@EJB
private IEntityManagerProvider emProvider;
@EJB
private SystemFacadeLocal systemFacade;
@EJB
private AchatFacadeLocal achatFacade;
EntityManagerProvider
@Singleton
public class EntityManagerProvider implements IEntityManagerProvider {
@PersistenceUnit(unitName = "multi")
private EntityManagerFactory emf;
private final Map<String, EntityManager> emMap = new HashMap<>();
public EntityManager getEm(String tenantId) {
if (emMap.containsKey(tenantId)) {
return emMap.get(tenantId);
}
return createEm(tenantId);
}
private EntityManager createEm(String tenantId) {
Map<String, String> props = new HashMap<>();
props.put("eclipselink.tenant-id", tenantId);
EntityManager em = emf.createEntityManager(props);
emMap.put(tenantId, em);
return em;
}
AchatFacade:
@Stateless
public class AchatFacade extends AbstractFacade implements AchatFacadeLocal {
@EJB
IEntityManagerProvider emProvider;
@Resource
SessionContext context;
private String tenantId;
@Override
protected EntityManager getEntityManager() {
return emProvider.getEm(tenantId);
}
@Override
public void setTenantId(String tenantId) {
this.tenantId = tenantId;
}
}
我的持久单位:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="systemPU" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/si_system</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<shared-cache-mode>NONE</shared-cache-mode>
<properties>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
</properties>
</persistence-unit>
<persistence-unit name="multi" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/multi</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<shared-cache-mode>NONE</shared-cache-mode>
</persistence-unit>
</persistence>
在我的JSF托管bean中,我正在从user_tenant表中检索用户租户,并且我正在设置tenantId,它是EntityManagerProvider中的模式名称。 我还在EntityManagerProvider中创建了一个EntityManager,其中包含相应的租户ID,这是一个Singleton EJB。因此,我有一张EntityManagers地图。 最后,我正在测试一个多租户实体的持久性,即Achat:
package com.intercom.model;
import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;
import org.eclipse.persistence.annotations.Multitenant;
import org.eclipse.persistence.annotations.MultitenantType;
import org.eclipse.persistence.annotations.TenantTableDiscriminator;
import org.eclipse.persistence.annotations.TenantTableDiscriminatorType;
/**
*
* @author
*/
@Entity
@Table(name = "achat")
@XmlRootElement
@Multitenant(value = MultitenantType.TABLE_PER_TENANT)
@TenantTableDiscriminator(type = TenantTableDiscriminatorType.SCHEMA, contextProperty = "eclipselink.tenant-id")
public class Achat implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "id")
private Integer id;
@Size(max = 45)
@Column(name = "name")
private String name;
@Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Achat)) {
return false;
}
Achat other = (Achat) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
@Override
public String toString() {
return "com.intercom.itManager.entities.Achat[ id =" + id + " ]";
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
测试结果: 用户在登录和密码后连接。 租客得到了解决 创建实体管理器,填充地图。 到达Achat实体的持久性,但在任何租户数据库中都没有保存。
什么代码可能导致问题?
答案 0 :(得分:0)
您的代码看起来不错。看到一些日志会很高兴。顺便说一下,persistence.xml中的日志记录配置不正确。可能是你从Hibernate持久性单元复制它。它必须是这样的:
<property name="eclipselink.logging.level.sql" value="ALL" />
<property name="eclipselink.logging.parameters" value="true" />
<property name="eclipselink.logging.session" value="true"/>