当前位置: 首页>后端>正文

jpa简单分表

Spring Data Jpa 动态表处理

Jpa 分表问题
现在有一张学生表t_stu按年份进行了处理,物理表分别是t_stu_2020、t_stu_2021、t_stu_2022这样

如果是mybatis,可以直接把表后缀传入sql,然后使用t_stu_${year}对表名进行拼接

但是对于Jpa这个全自动化ORM框架来说不太好处理,因为Jpa的表名是写在实体类的注解上的,在运行时不能修改:

// 实体类
@Entity
@Table(name = "t_stu") // 这里的表名定义是无法在运行时修改的
@Getter
@Setter
public class TVisionStu {
private static final long serialVersionUID = 1L;

@Id
@Column(name = "id")
private String id;

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

}

// dao 层
@Repository
public interface TVisionStuDao extends JpaRepository<TVisionStu, String>, JpaSpecificationExecutor<TVisionStu> {}
解决方案
Hibernate 插件方式
Hibernate 插件可以在sql执行前对sql进行修改,从而达到动态表的功能

import org.apache.commons.lang3.StringUtils;
import org.hibernate.EmptyInterceptor;
import org.springframework.stereotype.Component;

@Component
public class HibernateInterceptor extends EmptyInterceptor {
@Override
public String onPrepareStatement(String sql) {
String schoolYear = ReqContextHolder.getSchoolYear();

    // 这里对表名进行替换
    if (StringUtils.isNotBlank(schoolYear)) {
        return sql.replaceAll("t_stu", "t_stu_" + schoolYear);
    }

    return super.onPrepareStatement(sql);
}

}
其中的ReqContextHolder是一个线程安全的类,用来保存要查找的实际年份

public class ReqContextHolder {
private ReqContextHolder() {
}

protected static ThreadLocal<String> schoolYearThreadLocal = new ThreadLocal<>();

public static void setSchoolYear(String schoolYear) {
    schoolYearThreadLocal.set(schoolYear);
}

public static String getSchoolYear() {
    return schoolYearThreadLocal.get();
}

public static void remove() {
    schoolYearThreadLocal.remove();
}

}
然后在application.yml中对插件进行配置:

spring:

设置jpa插件,可以实现分表

jpa:
properties:
hibernate:
ejb:
# 注册自定义的插件类
interceptor: com.power.aop.HibernateInterceptor
实际使用的话就像这样:

@RestController
@RequestMapping("/stu")
public class StuController{

@GetMapping("/query")
public List<TVisionStu> query(@RequestParam("schoolYear") String schoolYear) {
    ReqContextHolder.setSchoolYear(schoolYear);
    List<TVisionStu> list = this.stuDao.findAll();
    ReqContextHolder.remove();
    return list;
}

}
然后就可以到sql可以正常执行了。

如果觉得每个方法都需要设置学年非常麻烦,可以写一个拦截器进行处理,这里就不再赘述了。


https://www.xamrdz.com/backend/3w51939159.html

相关文章: