论坛首页 Java企业应用论坛

关于数据库主键生成策略的一些想法

浏览 26612 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2013-10-03   最后修改:2013-10-03
最近自己在做一个javaWeb项目,使用的SpringMVC+ibatis,基于性能考虑及个人习惯没有使用hibernate。目前数据库用的mysql,对于主键生成采用那一种方法很是头疼,目前生成主键方法主要有以下几种:
  1、采用mysql自增长主键策略
     :简单,不需要程序特别处理
     :这种方法对以后如果项目移植到其它数据库上改动会比较大,oracle、    db2采用Sequence,mysql、sqlServer又采用自增长,通用性不好
  2、使用时间戳+随机数
    :实现简单,与数据库无关,移植性较好
     :长度太长,最少也得20位,不仅占空间并且建索引的话性能会比较差点吧
  3、每次取主键最大值+1做为新的主键
    :主键长度可控,移植性较好
    :并发写可能会造成主键冲突,对并发也不太好控制
  4、单独建一个存放主键的表
    :实现简单,移植性较好
    :需要考虑并发问题,整个系统主键生成都依赖该表,性能影响可能较大

大概就是这几种比较容易想到,
即想做到移植性好,性能好,又不会出现并发问题,似乎是没有完美的方案了吗,不知道有木有童鞋有更好的推荐吗?

既然这样又经过思考后打算根据项目实际情况来定,主要分为以下几种情况

1、项目基础功能部分,例如菜单功能管理、用户管理、权限管理、机构组织管理、参数管理等采用【方案3】,这些功能一般数据量不大,基本没有大的性能问题和并发问题,如果移植的话改动也比较小

2、对于某些流水、日志类的表可采用【方案2】时间戳+随机数,时间戳做主键此时会更有意义

3、对于系统中大部分实际的业务功能采用【方案1】mysql的自增长策略,这样可减少开发工作量,并且性能和并发都有保障,如果项目就算移植的话,业务功能这部分肯定会有些变动,做二次开发,所以就暂不考虑移植性了。

PS:希望童鞋们推荐一些更好的解决方法。
   发表时间:2013-10-05   最后修改:2013-10-05
2. 并发情况下时间戳+随机数无法保证不重复。建议使用uuid
3. 单个jvm下堪用。分布式环境下此方法行不通

0 请登录后投票
   发表时间:2013-10-05  
低下头是人间 写道
2. 并发情况下时间戳+随机数无法保证不重复。建议使用uuid
3. 单个jvm下堪用。分布式环境下此方法行不通



当并发比较大时,时间戳(精确到毫秒)+随机数是有可能重,而一个系统中也就几个功能并发会比较大,对这些并发大功能的可以使用其它主键策略。

uuid生成的id主要是也太长,uuid可以用在分布式下,uuid可以根据mac地址,时间戳等一些算法生成的。
0 请登录后投票
   发表时间:2013-10-05   最后修改:2013-10-05
caizi12 写道
低下头是人间 写道
2. 并发情况下时间戳+随机数无法保证不重复。建议使用uuid
3. 单个jvm下堪用。分布式环境下此方法行不通



当并发比较大时,时间戳(精确到毫秒)+随机数是有可能重,而一个系统中也就几个功能并发会比较大,对这些并发大功能的可以使用其它主键策略。

uuid生成的id主要是也太长,uuid可以用在分布式下,uuid可以根据mac地址,时间戳等一些算法生成的。




方法2的问题,无关并发大小。只要有并发,就可能会重复。虽然几率小,但是一旦发生一次,那也是100%的错误,所以2这个方法根本不可取。


另:我说的分布式环境下行不通不是说uuid行不通,而是说你的方法3在分布式环境下行不通

抱歉,对于你的方法3我理解错了。我理解成了需要在内存中保存主键最大值,所以才有上述评论

 

其实你是想每次生成主键时再从表中读取主键的最大值对伐?这种方式其实跟方法4很类似。

方法3控制并发可以采用锁表的方式。

方法4控制并发无需锁全表,只要锁一行即可。

 

0 请登录后投票
   发表时间:2013-10-05  
低下头是人间 写道
caizi12 写道
低下头是人间 写道
2. 并发情况下时间戳+随机数无法保证不重复。建议使用uuid
3. 单个jvm下堪用。分布式环境下此方法行不通



当并发比较大时,时间戳(精确到毫秒)+随机数是有可能重,而一个系统中也就几个功能并发会比较大,对这些并发大功能的可以使用其它主键策略。

uuid生成的id主要是也太长,uuid可以用在分布式下,uuid可以根据mac地址,时间戳等一些算法生成的。




方法2的问题,无关并发大小。只要有并发,就可能会重复。虽然几率小,但是一旦发生一次,那也是100%的错误,所以2这个方法根本不可取。


另:我说的分布式环境下行不通不是说uuid行不通,而是说你的方法3在分布式环境下行不通

抱歉,对于你的方法3我理解错了。我理解成了需要在内存中保存主键最大值,所以才有上述评论

 

其实你是想每次生成主键时再从表中读取主键的最大值对伐?这种方式其实跟方法4很类似。

方法3控制并发可以采用锁表的方式。

方法4控制并发无需锁全表,只要锁一行即可。

 

方案2:如果并发小,时间戳(精确到毫秒),基本上是出现机率非常小了,即使出现最多插入数据时异常,也没什么大的影响,非核心功能觉得可以考虑使用。

方案3,4有些相似,只是具体实现方法不太一样,目前暂不太倾向于给数据或者表加锁表的方式,开发起来麻烦些,不同的数据库,加锁方式也不一样。

0 请登录后投票
   发表时间:2013-10-06  
采用方案4不错,我现在的消息推送就是这么做的,在内部实现一个主键队列,比如缓存1w个,用完了在从表里面更新生成1w,当然具体缓存多少个,要看你的并发
0 请登录后投票
   发表时间:2013-10-06  
yunsong 写道
采用方案4不错,我现在的消息推送就是这么做的,在内部实现一个主键队列,比如缓存1w个,用完了在从表里面更新生成1w,当然具体缓存多少个,要看你的并发


那是不是主键都是从缓存里面取的呢,永远不会从表中取了? 当缓存中的1w个主键取完了,然后再生成1w个主键,同时更新表中的最大值,每次都从缓存中取的吧。
0 请登录后投票
   发表时间:2013-10-08  
https://github.com/twitter/snowflake

twitter使用的,如果要看java版本的参考

https://github.com/adyliu/idcenter
0 请登录后投票
   发表时间:2013-10-09  
http://cuishuangjia.iteye.com/blog/1934659
提供单体测试,结合测试解决方案。
性能优化。
DbTools工具下载:
http://cuishuangjia.iteye.com/
支持ORACLE,MYSQL,SQLSERVER,POSTGRE,DB2数据库相互转换功能

功能:
1。将数据库中的表结构和数据保存到EXCEL中。
2。将EXCEL中的数据,同步到数据库中。
3。当表结构发生变化时,数据不会丢失。
4。根据EXCEL中的表结构,生成建表语句SQL文。
5。多用户使用该软件时,可以随时记录某个用户对数据库的操作。
6。可以为进行压力测试,自动生成数据。
7。导出表结构,根据表结构和数据库中的表结构进行差分。
8。导出DB结构,和现有环境DB进行表结构差分
9。导出用户自定义表结构,根据表结构导入,导入数据前对EXCEL校验进行数据库验证和业务逻辑验证
10。单体测试,结合测试解决方案。
亲,请将5个压缩文件全部下载后,将5个压缩包解压后,将解压后的5个rar文件放入同一文件件下,再解压。
作者邮件:cuishuangjia@gmail.com
企鹅群:数据库第三方工具交流  184715368
0 请登录后投票
   发表时间:2013-10-10  
finallygo 写道
https://github.com/twitter/snowflake

twitter使用的,如果要看java版本的参考

https://github.com/adyliu/idcenter



idcenter连个注释都没有。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics