Java 带eclipse链接的多租户

Java 带eclipse链接的多租户,java,jpa,eclipselink,multi-tenant,Java,Jpa,Eclipselink,Multi Tenant,我正在尝试使用eclipselink实现一个多租户体系结构。我有一个表Entidade,该Entidade的名称将是租户。我有一个Usuario表,其中每个Usuario都连接到一个实体。表Usuario和Entidade具有租户默认值,因为使用Usuario登录时,我无法知道Usuario属于哪个Entidade。通过在数据库中插入实体,不会产生任何问题。问题在于查询用户类,尤其是在搜索子类Entidade时,抛出以下异常: [EL Warning]: metadata: 2013-09-1

我正在尝试使用eclipselink实现一个多租户体系结构。我有一个表Entidade,该Entidade的名称将是租户。我有一个Usuario表,其中每个Usuario都连接到一个实体。表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
    <?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>

创建EntityManager工厂和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文件:

[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
    <?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>

有人遇到过这个问题吗?

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


让我知道……

如果使用编织,问题是否仍然存在?在OneTONE映射上实现惰性需要编织。该错误显示,在尝试急切地获取entidade引用时出现问题,因此,编织可能会修复该问题,或者将其延迟到您访问关系为止。出于性能原因,您可能仍然需要它,即使它对此错误没有帮助。是否可以在不做任何更改的情况下关闭多租户?。这意味着,即使我用@Multi-Tenant annotation注释了实体,甚至数据库中有一个列Tenant_ID,但如果我没有设置PersistenceUnitProperties.Multi-Tenant_PROPERTY_默认值,它也不应该抛出异常,任何CRUD操作都应该成功。