【问题标题】:How to access multiple tenants in eclipselink?如何在eclipselink中访问多个租户?
【发布时间】:2014-04-24 23:23:24
【问题描述】:

eclipselink(或 Hibernate)中的租户是一个很好的概念,可以将数据域彼此分开。我正在将 eclipselink 与单表策略一起使用。

有时需要访问不止一个租户的数据(例如,出于管理目的)。有没有好的方法来实现这一目标? (我不想跑遍所有租户来收集数据……)

例子:

@Entity
@Multitenant
@TenantDiscriminatorColumn(name = "TENANT", contextProperty = "tenant.id")
public class TenantEntity {
    ...

我可以使用参数化实体管理器访问特定租户中的对象:

private static EntityManager newEntityManager(String tenant) {
    Map<String, Object> map = new HashMap<String, Object>();
    map.put("tenant.id", tenant);
    return emf.createEntityManager(map);
}

有没有方便的方法查询所有租户? (或者是持久化对象的身份只在单个租户中定义?)

【问题讨论】:

    标签: java jpa eclipselink multi-tenant


    【解决方案1】:

    EclipseLink 有一个开放的功能请求,允许以更好的方式允许管理服务器访问多租户数据:https://bugs.eclipse.org/bugs/show_bug.cgi?id=355458 - 如果它对您很重要,请投票给它。

    解决方法是为您的管理控制台创建一个单独的持久性单元。解决此问题的一种方法是将多租户元数据移动到 EclipseLink orm.xml 文件中,并在租户持久性单元中使用它,而管理持久性单元仅使用实体类。您可能希望实体中的字段可以映射到管理控制台可以使用和查询的租户列,但对于租户特定的持久性单元是只读或不可访问的。

    【讨论】:

    • 很好的提示,谢谢。所以 - 直接做这件事是一个悬而未决的问题。公认的解决方法是使用两个独立的持久性单元。这也意味着可以保证多个租户的身份(在所有租户中只有一个具有特定 ID 的特定类的对象)。
    • 这种具有多个持久性单元的方法是否也适用于注释?你有什么提示吗?
    • 注解在共享类中,所以会被两个持久化单元接收。任何特定于一个持久性单元的内容都应该移至仅包含在该持久性单元中的 orm.xml。 Orm.xml 允许覆盖注释,但我不确定如何覆盖租户注释,因此您可能必须将它们放在特定于租户的 eclipselink-orm.xml 中。
    【解决方案2】:

    我找到了一种我将尝试的替代方法:我将使用@AdditionalCriteria,而不是使用@Multitenant 注释来过滤掉属于我的租户的那些实体。我上面问题的例子变成了

    @Entity
    @AdditionalCriteria(":ADMINACCESS = 1 or this.tenant=:TENANT")
    public class TenantEntity {
    
        private String tenant;
        ...
    

    这里我需要自己处理租户列。 我可以创建两个实体管理器。一个用于租户访问:

    private static EntityManager newEntityManager(String tenant) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("TENANT", tenant);
        map.put("ADMINACCESS", 0);
        return emf.createEntityManager(map);
    }
    

    另外一个用于管理员访问:

    private static EntityManager newEntityManager() {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("TENANT", "");
        map.put("ADMINACCESS", 1);
        return emf.createEntityManager(map);
    }
    

    查看@AdditionalCriteria here 的详细信息。有cmets吗?

    【讨论】:

    • 您的租户字段现在完全由应用程序负责。虽然租户无法通过实体读取其他租户数据,但应用程序逻辑本身需要确保防止租户写入错误的租户或将租户字段留空。您必须确保实体也没有缓存在第二级共享缓存中。
    • 是的,正确的。您需要强大的机制来防止突破租户沙箱。我还没有完成它,但这似乎是可行的。我有一个知道其租户的线程本地实体管理器。它控制所有动作,例如将租户值设置为持久。因此,persist 方法(和类似操作)不需要租户,也不需要实体本身。租户逻辑被封装得很底层。好吧,我希望这行得通。我还没有考虑过第二个 lecel 缓存的含义。
    • @FrankHenningsen 只是想知道这是怎么回事。我正在尝试解决同样的问题。我不认为你有任何你愿意分享的代码:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    相关资源
    最近更新 更多