简介
- 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: [拦截器类名]