java自各儿实现序列自动增长,高并发时出现重复和超时
具体情况是这样: 通过java和数据库,自己实现序列自动增长。
实现代码大致如下:
id_table表结构, 主要字段:
id_name varchar2(16);
id_val number(16,0);
id_prefix varchar2(4);
//操作DB
public synchronized String nextStringValue(String id){
SqlSession sqlSess = SqlSessionUtil.getSqlSession();
sqlSess.update("update id_table set id_val = id_val + 1 where id_name="+id);
Map map = sqlSess.getOne("select id_name, id_prefix, id_val from id_table where id_name="+ id);
BigDecimal val = (BigDecimal) map.get("id_val");
//id_val是具体数字,rePack主要是统一返回固定长度的字符串;如:Y0000001, F0000001, T0000001等
String idValue = rePack(val, map);
return idValue;
}
//公共方法
public class IdHelpTool{
public static String getNextStringValue(String idName){
return getXX().nextStringValue(idName);
}
}
具体使用者,都是通过类似这种方式:IdHelpTool.getNextStringValue("PAY_LOG");来调用。
问题:
(1) 当出现并发时, 有时会获取重复的ID;
(2) 由于服务器做了相关一些设置,有时调用这个方法,好像还会导致超时。
为了解决问题(1), 考虑过在方法getNextStringValue上,也加上synchronized , 同步关键字过多,会不会更导致超时?
跪求大侠提供个解决问题的大概思路!!!
------解决思路----------------------
1、推荐 https://github.com/adyliu/idcenter
2、可以通过第三方redis来实现。
------解决思路----------------------
你的getXX()返回是同一个对像么, 要是不同线程访问是不是同一对像,你这锁就没用了
------解决思路----------------------
自增流水号用序列不是更省事么?
------解决思路----------------------
可以参考oracle的序列实现机制。。
做一个池子,缓存一定数量的自增ID。。。在请求使用的时候注意同步处理即可。。但有一个缺点,当你的应用多个布署,就会出现你说的有可能会出现重复。。
在数据库端做比较好。
------解决思路----------------------
补充一点。如果单位时间内请求访问大,在数据库做也会遇到性能问题,就好像,你在不停的请求数据库查询。。
又要想高并发,还是在JAVA端+数据库端相结合来实现,。。
------解决思路----------------------
1、出现重复ID,是因为脏读了,并发的时候不加 synchronized 比如会出现问题
2、但是加了 synchronized ,性能急剧下降了,本身 java 就是多线程的,你把它单线程使用,不是明智的选择,同时,如果分布式部署的时候,加了 synchronized 也无法控制并发
3、调用这个方法,出现超时的情况,说明你的并发已经超过了数据库所能处理的极限,数据库无限等待导致超时
基于上面的分析,建议采用线程池的方案,支付宝的单号就是用的线程池的方案进行的。
数据库 update 不是一次加1,而是一次加几百甚至上千,然后取到的这 1000个序号,放在线程池里慢慢分配即可,能应付任意大的并发,同时保证数据库没任何压力。
------解决思路----------------------
学习了...楼上分析的比较中肯