Eclipse Link Multitenant JSF / EJB / JPA应用程序

时间:2015-04-08 17:36:22

标签: java jpa eclipselink ejb-3.0

我正在尝试使用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实体的持久性,但在任何租户数据库中都没有保存。

什么代码可能导致问题?

1 个答案:

答案 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"/>