【问题标题】:multi-tenant with eclipse link带有 Eclipse 链接的多租户
【发布时间】:2013-09-28 04:45:36
【问题描述】:

我正在尝试使用 eclipselink 实现多租户架构。我有一张 Entidade 表,Entidade 的名称将是租户。我有一个 Usuario 表,其中每个 usuario 都连接到一个 Entidade。表 Usuario 和 Entidade 有一个租户默认值,因为当使用 Usuario 登录时,我无法知道 Usuario 属于哪个 Entidade。通过在数据库中插入实体,不会出现任何问题。问题是查询用户类,特别是搜索子类Entidade时,抛出如下异常:

[EL Warning]: metadata: 2013-09-18 11:39:50.976--ServerSession(20689274)--The tenant discriminator context property for the tenant discriminator column [USUARIO.id_tenant] on the element [class teste.Usuario] is being defaulted to: eclipselink.tenant-id.
[EL Warning]: metadata: 2013-09-18 11:39:50.993--ServerSession(20689274)--The tenant discriminator context property for the tenant discriminator column [ENTIDADE.id_tenant] on the element [class teste.Entidade] is being defaulted to: eclipselink.tenant-id.
[EL Info]: 2013-09-18 11:39:51.604--ServerSession(20689274)--EclipseLink, version: Eclipse Persistence Services - 2.5.0.v20130507-3faac2b
[EL Warning]: metadata: 2013-09-18 11:39:51.823--ServerSession(20689274)--Reverting the lazy setting on the OneToOne or ManyToOne attribute [entidade] for the entity class [class teste.Usuario] since weaving was not enabled or did not occur.
[EL Info]: connection: 2013-09-18 11:39:51.894--ServerSession(20689274)--file:/D:/java/workspaceweb/TesteTenant/bin/_teste login successful
[EL Fine]: sql: 2013-09-18 11:39:51.93--ServerSession(20689274)--Connection(29390792)--SELECT id_usuario, id_tenant, nome, id_entidade FROM USUARIO WHERE (id_tenant = ?)
    bind => [usuario]
[EL Warning]: 2013-09-18 11:39:51.957--ServerSession(20689274)--Exception [EclipseLink-6174] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.QueryException
Exception Description: No value was provided for the session property [eclipselink.tenant-id]. This exception is possible when using additional criteria or tenant discriminator columns without specifying the associated contextual property. These properties must be set through Entity Manager, Entity Manager Factory or persistence unit properties. If using native EclipseLink, these properties should be set directly on the session.
Query: ReadObjectQuery(name="readEntidade" referenceClass=Entidade sql="SELECT id_entidade, id_tenant, nome FROM ENTIDADE WHERE ((id_entidade = ?) AND (id_tenant = ?))")
Exception in thread "main" javax.persistence.PersistenceException: Exception [EclipseLink-6174] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.QueryException
Exception Description: No value was provided for the session property [eclipselink.tenant-id]. This exception is possible when using additional criteria or tenant discriminator columns without specifying the associated contextual property. These properties must be set through Entity Manager, Entity Manager Factory or persistence unit properties. If using native EclipseLink, these properties should be set directly on the session.
Query: ReadObjectQuery(name="readEntidade" referenceClass=Entidade sql="SELECT id_entidade, id_tenant, nome FROM ENTIDADE WHERE ((id_entidade = ?) AND (id_tenant = ?))")
    at org.eclipse.persistence.internal.jpa.QueryImpl.getResultList(QueryImpl.java:479)
    at teste.TesteBuscaMain.main(TesteBuscaMain.java:29)
Caused by: Exception [EclipseLink-6174] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.QueryException
Exception Description: No value was provided for the session property [eclipselink.tenant-id]. This exception is possible when using additional criteria or tenant discriminator columns without specifying the associated contextual property. These properties must be set through Entity Manager, Entity Manager Factory or persistence unit properties. If using native EclipseLink, these properties should be set directly on the session.
Query: ReadObjectQuery(name="readEntidade" referenceClass=Entidade sql="SELECT id_entidade, id_tenant, nome FROM ENTIDADE WHERE ((id_entidade = ?) AND (id_tenant = ?))")
    at org.eclipse.persistence.exceptions.QueryException.missingContextPropertyForPropertyParameterExpression(QueryException.java:260)
    at org.eclipse.persistence.internal.expressions.ParameterExpression.getValue(ParameterExpression.java:269)
    at org.eclipse.persistence.internal.databaseaccess.DatabaseCall.translate(DatabaseCall.java:1102)
    at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:241)
    at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:228)
    at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.selectOneRow(DatasourceCallQueryMechanism.java:714)
    at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.selectOneRowFromTable(ExpressionQueryMechanism.java:2777)
    at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.selectOneRow(ExpressionQueryMechanism.java:2730)
    at org.eclipse.persistence.queries.ReadObjectQuery.executeObjectLevelReadQuery(ReadObjectQuery.java:526)
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1155)
    at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:899)
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1114)
    at org.eclipse.persistence.queries.ReadObjectQuery.execute(ReadObjectQuery.java:429)
    at org.eclipse.persistence.internal.sessions.AbstractSession.internalExecuteQuery(AbstractSession.java:3207)
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1797)
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1779)
    at org.eclipse.persistence.internal.indirection.NoIndirectionPolicy.valueFromQuery(NoIndirectionPolicy.java:326)
    at org.eclipse.persistence.mappings.ForeignReferenceMapping.valueFromRowInternal(ForeignReferenceMapping.java:2234)
    at org.eclipse.persistence.mappings.OneToOneMapping.valueFromRowInternal(OneToOneMapping.java:1790)
    at org.eclipse.persistence.mappings.ForeignReferenceMapping.valueFromRow(ForeignReferenceMapping.java:2120)
    at org.eclipse.persistence.mappings.ForeignReferenceMapping.readFromRowIntoObject(ForeignReferenceMapping.java:1455)
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildAttributesIntoObject(ObjectBuilder.java:455)
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:862)
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildWorkingCopyCloneFromRow(ObjectBuilder.java:1948)
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObjectInUnitOfWork(ObjectBuilder.java:726)
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:629)
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:587)
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:571)
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.buildObject(ObjectLevelReadQuery.java:782)
    at org.eclipse.persistence.queries.ReadAllQuery.registerResultInUnitOfWork(ReadAllQuery.java:848)
    at org.eclipse.persistence.queries.ReadAllQuery.executeObjectLevelReadQuery(ReadAllQuery.java:490)
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1155)
    at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:899)
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1114)
    at org.eclipse.persistence.queries.ReadAllQuery.execute(ReadAllQuery.java:402)
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1202)
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2894)
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1797)
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1779)
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1744)
    at org.eclipse.persistence.internal.jpa.QueryImpl.executeReadQuery(QueryImpl.java:258)
    at org.eclipse.persistence.internal.jpa.QueryImpl.getResultList(QueryImpl.java:468)
    ... 1 more

创建 EntityManagerFactory 和 EntityManager 的类:


public class JPAUtil {

    private static JPAUtil instance = null;

    private static EntityManagerFactory emf;
    private static EntityTransaction transaction;

    private static ThreadLocal entityManagers = new ThreadLocal();

    static {
        instance = new JPAUtil();
    }

    private JPAUtil() {
        emf = Persistence.createEntityManagerFactory("PUAequalis");
    }

    public static JPAUtil getInstance() {

        if (instance == null) {
            instance = new JPAUtil();
        }
        return instance;
    }

    public static void openEntityManager(String tenant) {
        if (entityManagers == null || entityManagers.get() == null
                || !entityManagers.get().isOpen()) {
            HashMap properties = new HashMap();

            EntityManager em = emf.createEntityManager();
            em.setProperty("eclipselink.tenant-id", tenant);
            em.setProperty(PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT, tenant);
            entityManagers.set(em);

        } else {
            closeOpenEntityManager(tenant);
        }
    }

    public EntityManager getEntityManager() {
        return entityManagers.get();
    }

    public static void closeEntityManager() {

        if (entityManagers != null && entityManagers.get().isOpen()) {
            entityManagers.get().close();
        }
    }

    public static void closeOpenEntityManager(String tenant) {
        if (entityManagers != null && entityManagers.get().isOpen()) {
            entityManagers.get().close();
            entityManagers.remove();
            HashMap properties = new HashMap();
            properties.put("eclipselink.tenant-id", tenant);
            entityManagers.set(emf.createEntityManager(properties));
        }
    }

    public static void closeEntityManagerFactory() {
        if (emf != null && emf.isOpen()) {
            emf.close();
        }
    }

    public EntityTransaction getTransaction() {
        if (transaction == null || !transaction.isActive()) {
            transaction = entityManagers.get().getTransaction();
        }
        return transaction;
    }

}

persistence.xml:

    <?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="teste" transaction-type="RESOURCE_LOCAL">
        <provider> org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <properties>
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/teste" />
            <property name="javax.persistence.jdbc.user" value="root" />
            <property name="javax.persistence.jdbc.password" value="root" />
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
            <property name="eclipselink.multitenant.tenants-share-cache"
                value="true" />
            <!-- <property name="eclipselink.ddl-generation" value="create-tables" /> -->
            <property name="eclipselink.logging.level.sql" value="ALL" />
            <property name="eclipselink.logging.parameters" value="true" />
            <property name="eclipselink.logging.session" value="true"/>

        </properties>
    </persistence-unit>

</persistence>

和德实体:



    @Entity
    @Multitenant
    @TenantDiscriminatorColumn(name = "id_tenant")
    public class Entidade implements Serializable {

    private static final long serialVersionUID = 8179478584980079687L;

    @Id
    @Column(name = "id_entidade", length = 10)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer idEntidade;

    @Column(name = "nome")
    private String nome;

    @Column(name = "id_tenant", insertable=false, updatable=false)
    private String idTenant;

    ...get and setters

}


    @Entity
    @Multitenant
    @TenantDiscriminatorColumn(name = "id_tenant")
    public class Usuario implements Serializable {
    private static final long serialVersionUID = 8956344014336399968L;
    @Id
    @Column(name = "id_usuario", length = 10)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer idUsuario;

    @Column(name = "nome")
    private String nome;

    @Column(name = "senha")
    private String senha;

    @Column(name = "nomeCompleto")
    private String nomeCompleto;

    @Column(name = "email")
    private String email;

    @Column(name = "tipo_usuario")
    @Enumerated(EnumType.STRING)
    private TipoUsuario tipoUsuario;

    @ManyToOne(fetch = FetchType.LAZY,cascade = CascadeType.ALL, optional = false, targetEntity = Entidade.class)
    @JoinColumn(name = "id_entidade")
    private Entidade entidade;

    @Column(name = "id_tenant", insertable = false, updatable = false)
    private String idTenant;

    ...get and setters
    }

有人遇到过这个问题吗?

【问题讨论】:

  • 用织法还会出现问题吗? wiki.eclipse.org/EclipseLink/UserGuide/JPA/… weaving 需要在 OneToOne 映射上实现惰性。该错误表明在尝试急切地获取 entidade 引用时会发生问题,因此编织可能会解决问题,或者将其延迟到您访问关系为止。出于性能原因,您可能仍需要它,即使它对解决此错误没有帮助。

标签: java jpa eclipselink multi-tenant


【解决方案1】:

这可能是因为您需要在事务开始后使用租户值设置上下文属性。

http://codecrafters.blogspot.it/2013/03/multi-tenant-cloud-applications-with.html

让我知道...

【讨论】:

  • 是否可以在不进行任何更改的情况下关闭多租户?这意味着即使我使用@Multi-Tenant 注释对实体进行了注释,甚至在数据库中有一个 TENANT_ID 列,但是如果我没有设置 PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT,它不应该抛出异常并且任何 CRUD 操作都应该成功。
猜你喜欢
  • 1970-01-01
  • 2018-06-03
  • 2022-01-22
  • 1970-01-01
  • 2013-11-17
  • 1970-01-01
  • 2017-11-30
  • 2016-10-04
  • 2017-01-14
相关资源
最近更新 更多