主键肩负的功能越来越多,不仅承担表内数据唯一性标识的任务,而且起到数据库切分、资源定位等更重要的角色。
在实际应用中必须慎重规划好主键方案,它直接影响到应用系统的运行效率、扩展性及维护性等方面的内容,一个欠考虑的主键方案不但会带来并发性的问题,还可能造成系统难于变成,不好维护等问题。
从创建者的角度看,创建方案可分为两类:
一、应用层主键方案,主键由应用层来分配,如采用UUID,DataFieldMaxValueIncrementer生成主键方式。
缺点:
1.应用层开发不方便,必须通过一个查询获取新增数据的主键值。
2.主键值的全局管理和控制不方便控制,使系统丧失灵活性。
3.不方便数据的整合和迁移。
二、数据库层主键方案,由数据库来负责分配,如表结果定义时,将主键列设置为auto increment或者表的触发分配主键。
优点:保证不同表不同数据不会有主键冲突的问题。
缺点:UUID是一个36位字符串,占用较多的存储空间。
在高并发的系统中,如果使用基于序列表的方式创建主键值,应考虑两个层面的并发问题:
一、应用层获取主键的并发问题,Spring的DataFieldMaxValueIncreatementer实现类已经对获取主键值的代码进行了同步,因此保证了同一个JVM内应用不会发生并发问题。
二、全局的并发问题,如果应用是集群部署,所有集群节点都通过同一张序列表获取主键值,那么就必须对这个序列表进行乐观锁定(即序列表必须添加一个版本或者时间戳字段,以防止集群节点的并发问题。Spring的DataFieldMaxValueIncreatementer实现类并没有对序列列表进行乐观锁定)
DataFieldMaxValueIncrementer接口只能为一个表提供主键,这种方案太死板,所以你可以参考这个类写一个并发性好和多个表的类来更好地创建主键方案。