SpringBoot-JPA 支持分表

简介

- JPA Entity对象继承,通过@Inheritance配置,有三种方式SINGLE_TABLE、TABLE_PER_CLASS、JOINED,这里不作赘述。
- Entity对象的分库分表操作
    - 分库,为了管理DB的连接数,建议通过入口的分流,将不同DB的数据分流到不同的应用;
    - 分表,这是本文关注的主要问题,目标是调用JPA时不需要关心是否分表以及映射的规则,即分表对于Entity操作层是透明的;主要的步骤如下:
          - 对象声明
          - 实现JPA interceptor 拦截器
          - 加载拦截器

对象声明

- 数据对象的基类,引入了@MappedSuperclass,如下面的样例
@MappedSuperclass
class UserBase {

	@Id
	private Long id;

	private String name;

	private int age;
... ... 
}
- 数据对象,继承基类,使用[@Entity](https://my.oschina.net/u/1260961),如下面的样例
 //模板表,用于JPA代码编写
@Entity
@Table(name = "t_user")
public class User extends UserBase { ... ...}
 //id是0或者偶数的数据分表,用于配置了hibernate.ddl-auto时维护库表结构,不会出现在JPA相关代码中
@Entity
@Table(name = "t_user_0")
public class User0 extends UserBase { ... ...}
//与User0对应,id是奇数的数据分表
@Entity
@Table(name = "t_user_1")
public class User1 extends UserBase { ... ...}
// 数据对象操作类声明
public interface UserDao extends CrudRepository<User, Long> {}

JPA interceptor 拦截器

- 声明
import org.hibernate.EmptyInterceptor;

public class MyInterceptor extends EmptyInterceptor {
- 推荐使用ThreadLocal缓存业务对象类型和ID
static class Cached {
	Class<?> clazz;
	Serializable id;
	Cached(Class<?> clazz, Serializable id) {
		super();
		this.clazz = clazz;
		this.id = id;
	}
 ... ... //自动生成的hashCode、equals方法
}
- 重载如下的方法onLoad、onSave、getEntity,调用ThreadLocal.set
- 重载onPrepareStatement方法,示意代码如下
Cached id = threadLocal.get();
threadLocal.remove();
if(id == null) {
	return sql;
}
if(id.clazz == User.class) {
	long offset = ((Long)id.id).longValue() / 2;
	return sql.replace("t_user", "t_user_" + offset);
}

加载拦截器 Application.yml

spring:
    jpa:
        properties:
               hibernate:
                      ejb:
                            interceptor: [拦截器类名]

猜你喜欢

转载自my.oschina.net/u/1053238/blog/1611773