SpringBoot JPA 自定义ID生成策略

在JPA中,我们是通过@id@GeneratedValue来指定id主键生成策略的,比如:

1
2
3
4
5
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private String id;

JPA内置提供了4种策略,分别是:

  • TABLE:使用一个特定的数据库表格来保存主键。

  • SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列。

  • IDENTITY:主键由数据库自动生成(主要是自动增长型)

  • AUTO:主键由程序控制(也是默认的,在指定主键时,如果不指定主键生成策略,默认为AUTO)

当然,很多时候,这么几种策略并不够用,所以JPA还提供了扩展,允许我们自定义id生成策略,

具体使用就是多了一个@GenericGenerator注解,指定自定义名称以及策略,然后在@GeneratedValue中使用该策略,比如:

1
2
3
4
5
@Id
@GeneratedValue(generator = "customId") // 这里注意generator里的值要和GenericGenerator的name一致
@GenericGenerator(name = "customId", strategy = "com.zshnb.config.CustomIdGenerator")
private String id;

1
2
3
4
5
6
7
8
9
10
11
public class CustomIdGenerator implements IdentifierGenerator{
/*
@param o: 表示当前保存的entity对象
*/
@Override
public Serializable generate(SessionImplementor sessionImplementor, Object o) throws HibernateException {
String date = String.valueOf(new Date().getTime());
return date.slice(4);
}
}

如果这时候希望在CustomIdGenerator里和SpringBoot集成,比如调用其他component的方法生成id,有以下类:

1
2
3
4
5
6
7
8
@Component
public class IdGenerator {
public String getId() {
// 查数据库,生成自定义前缀的id
return "";
}
}

这时候我们希望能在CustomIdGenerator里注入IdGenerator,调用getId方法,但CustomIdGenerator是hibernate管理的,没办法参与Spring的IOC机制,有什么办法呢?可以通过以下方式解决,首先新建ApplicationContextHolder

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Component
public class ApplicationContextHolder implements ApplicationContextAware {

private static ApplicationContext applicationContext;

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
synchronized (this) {
if (ApplicationContextHolder.applicationContext == null) {
ApplicationContextHolder.applicationContext = applicationContext;
}
}
}

public static <T> T getBean(Class<T> clazz) {
return applicationContext.getBean(clazz);
}

public static <T> T getBean(String qualifier, Class<T> clazz) {
return applicationContext.getBean(qualifier, clazz);
}

然后修改CustomIdGenerator,获取需要注入的对象即可。

1
2
3
4
5
6
7
8
9
10
11
public class CustomIdGenerator implements IdentifierGenerator{
/*
@param o: 表示当前保存的entity对象
*/
@Override
public Serializable generate(SessionImplementor sessionImplementor, Object o) throws HibernateException {
IdGenerator idGenerator = ApplicationContextHolder.getBean(IdGenerator.class);
return idGenerator.getId();
}
}