【问题标题】:Eclipse Link Multitenant JSF/EJB/JPA appEclipse Link 多租户 JSF/EJB/JPA 应用程序
【发布时间】:2015-04-08 17:36:21
【问题描述】:

我正在尝试在 JPA/EclipseLink/EJB3/JSF 2.2 应用程序中使用 Table per tenant/Schema 策略实现多租户。

我正在进行的测试是针对一个 mysql 应用程序(其中创建了 3 个数据库)一个所有租户共有的系统数据库,以及每个租户的相同数据库。

系统数据库只有一张表tenant_user(登录名、密码、schema_name)

这里是主要代码的 sn-ps : 登录 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 表中检索用户租户,并设置了 EntityManagerProvider 中的模式名称的tenantId。 我还在作为 Singleton EJB 的 EntityManagerProvider 中创建具有相应租户 ID 的 EntityManager。因此,我有一张 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 实体上的持久性,但没有任何内容保存在任何租户数据库中。

什么代码可能导致问题?

【问题讨论】:

  • 你没有展示你是如何持久化或提交你的事务的,或者与事务有关的任何事情。尝试调用flush,因为如果Persistence 单元没有加入事务,它会立即抛出异常。
  • 好吧,我想我可以使用容器管理的实体管理器,但是在多租户应用程序中,我必须自己创建我的实体管理器(EntityManagerProvide 代码),所以我必须自己打开一个事务并提交它。现在很好,我将 BMT 与我的自定义实体管理器一起使用。
  • 但是有没有办法在所有 EJB 之间共享tenantId?我不想随时传递tenantId,从我的 JSF 托管 Bean 到 EJB。

标签: java jpa eclipselink ejb-3.0


【解决方案1】:

您的代码看起来不错。很高兴看到一些日志。顺便说一句,您在 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"/>

【讨论】:

    猜你喜欢
    • 2012-05-29
    • 2012-09-24
    • 1970-01-01
    • 2018-08-29
    • 2011-05-05
    • 2015-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多