簡介
- 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: [攔截器類名]