使用Hibernate / JPA / Spring-Data

时间:2016-08-29 04:16:58

标签: hibernate spring-data spring-data-jpa

我正在尝试创建一个多租户架构,其中每个表都有一个namespace字段。无论何时执行任何方法,ThreadLocal存储都可以访问当前namespace。我想要的是我的业务层完全不知道命名空间的概念。举个例子:

@Entity
@Table(name = "users")
class Users {
    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    ...
}

users定义为:

CREATE TABLE users(
    first_name CHARACTER VARYING,
    last_name CHARACTER VARYING,
    namespace CHARACTER VARYING NOT NULL
    ...
);

为了简洁起见,我正在跳过主键和其他字段。对SELECT * FROM users WHERE (condition)类型的任何查询都必须基本上为SELECT * FROM users WHERE (condition & namespace = :1),或者就spring-data而言,findUsersByName(String name)应为findUsersByNameAndNamespace(String name, String namespace)。此外,每个save操作都应该要求使用命名空间填充模型。

但是,我不想在模型定义中包含命名空间。这是一个双面问题:

  1. 每个fetch都需要在查询中设置命名空间。
  2. 每个save都需要在模型中保存命名空间。
  3. 虽然,我完全不知道如何解决第一个问题,但是第二个问题可以(部分)通过使用具有TenantedModel属性的父类namespace来解决,然后使用该属性进行设置一个Hibernate拦截器。问题是业务层仍然能够看到namespace属性。

    使用带有Spring Data的JPA有没有一种干净的方法来执行此操作?

1 个答案:

答案 0 :(得分:1)

您可以使用Interceptor来修改hibernate生成的SQL。

public String onPrepareStatement(String sql) {
    String newSQLWithNamespace = sql+" and (namespace = "+ nameSpaceValue+")";
    return super.onPrepareStatement(newSQLWithNamespace);
}

参见例如Add a column to all MySQL Select Queries in a single shot

您的拦截器可以读取线程本地命名空间值并更改SQL。