Hibernate6 租户隔离实现:使用切面自动应用 tenant_id 条件
在 Hibernate6 中,可以使用 Session 拦截器实现自动应用'tenant_id'的租户条件。具体步骤如下:
-
创建一个实现了 Interceptor 接口的类,例如 TenantInterceptor。
-
在 TenantInterceptor 中实现 onPrepareStatement 方法,该方法会在每次执行 SQL 语句前被调用。在该方法中,可以获取当前线程的租户 ID,并将其加入到 SQL 语句中。
-
在 Spring 配置文件中配置 SessionFactory,并将 TenantInterceptor 作为其 interceptor 属性的值。
-
在每个需要使用 SessionFactory 的 DAO 类中添加 @Autowired 注解,并在 DAO 类中使用 @Autowired 注解注入 SessionFactory。
-
在每个需要执行数据库操作的方法上添加 @Transactional 注解,以确保每次操作都在同一个 Session 中进行。
示例代码如下:
- TenantInterceptor.java
public class TenantInterceptor implements Interceptor {
private static final ThreadLocal<Long> tenantIdThreadLocal = new ThreadLocal<>();
public static void setTenantId(Long tenantId) {
tenantIdThreadLocal.set(tenantId);
}
@Override
public void onPrepareStatement(PreparedStatement preparedStatement) {
try {
Long tenantId = tenantIdThreadLocal.get();
if (tenantId != null) {
preparedStatement.setLong(1, tenantId);
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
- Spring 配置文件
<bean id="sessionFactory" class="org.springframework.orm.hibernate6.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="com.example.domain"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL8Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
<property name="interceptor">
<bean class="com.example.interceptor.TenantInterceptor"/>
</property>
</bean>
- DAO 类
@Repository
public class UserDao {
@Autowired
private SessionFactory sessionFactory;
@Transactional
public User findById(Long id) {
TenantInterceptor.setTenantId(1L);
Session session = sessionFactory.getCurrentSession();
return session.get(User.class, id);
}
}
在上面的例子中,每次执行 findById 方法时,都会自动加入租户 ID 为 1 的条件。如果需要切换租户,只需要在调用方法前调用 TenantInterceptor.setTenantId 方法即可。
原文地址: https://www.cveoy.top/t/topic/oKKE 著作权归作者所有。请勿转载和采集!