- caizi12
- 等级:
- 性别:
- 文章: 400
- 积分: 110
- 来自: 北京
|
发表时间: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:希望童鞋们推荐一些更好的解决方法。
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
|
返回顶楼 |
|
|
- 低下头是人间
- 等级: 初级会员
- 性别:
- 文章: 22
- 积分: 30
- 来自: 北京
|
发表时间:2013-10-05
最后修改:2013-10-05
2. 并发情况下时间戳+随机数无法保证不重复。建议使用uuid
3. 单个jvm下堪用。分布式环境下此方法行不通
|
返回顶楼 |
|
|
- caizi12
- 等级:
- 性别:
- 文章: 400
- 积分: 110
- 来自: 北京
|
低下头是人间 写道 2. 并发情况下时间戳+随机数无法保证不重复。建议使用uuid
3. 单个jvm下堪用。分布式环境下此方法行不通
当并发比较大时,时间戳(精确到毫秒)+随机数是有可能重,而一个系统中也就几个功能并发会比较大,对这些并发大功能的可以使用其它主键策略。
uuid生成的id主要是也太长,uuid可以用在分布式下,uuid可以根据mac地址,时间戳等一些算法生成的。
|
返回顶楼 |
|
|
- 低下头是人间
- 等级: 初级会员
- 性别:
- 文章: 22
- 积分: 30
- 来自: 北京
|
发表时间: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控制并发无需锁全表,只要锁一行即可。
|
返回顶楼 |
|
|
- caizi12
- 等级:
- 性别:
- 文章: 400
- 积分: 110
- 来自: 北京
|
低下头是人间 写道
caizi12 写道
低下头是人间 写道
2. 并发情况下时间戳+随机数无法保证不重复。建议使用uuid 3. 单个jvm下堪用。分布式环境下此方法行不通
当并发比较大时,时间戳(精确到毫秒)+随机数是有可能重,而一个系统中也就几个功能并发会比较大,对这些并发大功能的可以使用其它主键策略。 uuid生成的id主要是也太长,uuid可以用在分布式下,uuid可以根据mac地址,时间戳等一些算法生成的。
方法2的问题,无关并发大小。只要有并发,就可能会重复。虽然几率小,但是一旦发生一次,那也是100%的错误,所以2这个方法根本不可取。
另:我说的分布式环境下行不通不是说uuid行不通,而是说你的方法3在分布式环境下行不通
抱歉,对于你的方法3我理解错了。我理解成了需要在内存中保存主键最大值,所以才有上述评论
其实你是想每次生成主键时再从表中读取主键的最大值对伐?这种方式其实跟方法4很类似。
方法3控制并发可以采用锁表的方式。
方法4控制并发无需锁全表,只要锁一行即可。
方案2:如果并发小,时间戳(精确到毫秒),基本上是出现机率非常小了,即使出现最多插入数据时异常,也没什么大的影响,非核心功能觉得可以考虑使用。
方案3,4有些相似,只是具体实现方法不太一样,目前暂不太倾向于给数据或者表加锁表的方式,开发起来麻烦些,不同的数据库,加锁方式也不一样。
|
返回顶楼 |
|
|
- yunsong
- 等级: 初级会员
- 文章: 57
- 积分: 50
|
采用方案4不错,我现在的消息推送就是这么做的,在内部实现一个主键队列,比如缓存1w个,用完了在从表里面更新生成1w,当然具体缓存多少个,要看你的并发
|
返回顶楼 |
|
|
- caizi12
- 等级:
- 性别:
- 文章: 400
- 积分: 110
- 来自: 北京
|
yunsong 写道 采用方案4不错,我现在的消息推送就是这么做的,在内部实现一个主键队列,比如缓存1w个,用完了在从表里面更新生成1w,当然具体缓存多少个,要看你的并发
那是不是主键都是从缓存里面取的呢,永远不会从表中取了? 当缓存中的1w个主键取完了,然后再生成1w个主键,同时更新表中的最大值,每次都从缓存中取的吧。
|
返回顶楼 |
|
|
- finallygo
- 等级: 初级会员
- 性别:
- 文章: 393
- 积分: 40
- 来自: 厦门-->北京
|
https://github.com/twitter/snowflake
twitter使用的,如果要看java版本的参考
https://github.com/adyliu/idcenter
|
返回顶楼 |
|
|
- cuishuangjia
- 等级: 初级会员
- 性别:
- 文章: 8
- 积分: 30
- 来自: 沈阳
|
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
|
返回顶楼 |
|
|
- caizi12
- 等级:
- 性别:
- 文章: 400
- 积分: 110
- 来自: 北京
|
finallygo 写道 https://github.com/twitter/snowflake
twitter使用的,如果要看java版本的参考
https://github.com/adyliu/idcenter
idcenter连个注释都没有。
|
返回顶楼 |
|
|