如何在Spring Data JPA中用Hibernate过滤器实现同库同Schema的多租户hospitalId过滤?
解决Hibernate过滤器与JPA Repository配合自动租户过滤的问题
Hibernate过滤器本身是有效的,但默认处于关闭状态,JPA Repository不会主动触发过滤器启用,因此需要通过全局配置来自动开启并注入租户ID。
1. 通过Spring AOP全局启用过滤器
创建切面,在所有Repository方法执行前自动开启过滤器并设置当前的hospitalId,无需在每个业务逻辑中手动处理:
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.hibernate.Filter; import org.hibernate.Session; import org.springframework.stereotype.Component; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; @Aspect @Component public class TenantFilterAspect { @PersistenceContext private EntityManager entityManager; // 匹配所有Repository包下的方法 @Before("execution(* com.yourproject.repository..*(..))") public void enableTenantFilter(JoinPoint joinPoint) { Session session = entityManager.unwrap(Session.class); Filter filter = session.enableFilter("hospitalFilter"); // 从上下文获取当前租户ID,比如Spring Security上下文、ThreadLocal存储 String currentHospitalId = getCurrentHospitalId(); filter.setParameter("hospitalId", currentHospitalId); } private String getCurrentHospitalId() { // 实现实际获取逻辑,比如从登录用户信息中提取 // 示例:return ((CustomUserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getHospitalId(); return "当前有效租户ID"; } }
2. 统一实体过滤器配置(减少重复代码)
如果所有实体都需要租户过滤,可创建一个父类实体,将过滤器注解统一放在父类中,其他业务实体直接继承即可:
@MappedSuperclass @FilterDef(name = "hospitalFilter", parameters = @ParamDef(name = "hospitalId", type = "string")) @Filter(name = "hospitalFilter", condition = "hospital_id = :hospitalId") public abstract class BaseTenantEntity { @Column(name = "hospital_id", nullable = false) private String hospitalId; // getter、setter方法 } // 业务实体继承父类 @Entity public class PatientEntity extends BaseTenantEntity { @Id private Long patientId; // 其他业务字段 }
3. 关键注意点
- 租户ID的获取要保证线程安全,推荐使用ThreadLocal或者Spring Security上下文存储,避免多线程环境下的ID混乱。
- 如果使用了
@Transactional,需确保AOP切面的执行顺序在事务切面之后(可通过@Order注解调整,比如设置@Order(100),事务切面默认优先级最低)。 - 原生SQL查询不会触发Hibernate过滤器,这类查询需要手动拼接
hospital_id条件,或者改用Hibernate Criteria API、JPQL查询。
内容的提问来源于stack exchange,提问作者Himanshu Sharma
相关产品推荐
相关产品推荐

