1、 最简单的,页面的《提交》按钮,在点击后(校验通过后)Disabled ,这样用户就不会重复点击《提交》按钮;
2、 数据库表增加唯一性索引(比如memberId ),这个只能解决一般(为什么一般,继续看)并发插入的问题;
如果两条一样的数据插入,只有一条会成功,另外一次插入失败;
3、 使用乐观锁,在Table 里增加一个version int 字段,这个可以保证更新操作的并发问题;
Select version, .. from table1 where id=?
//do biz
Update set version=version+1 where id=? And version=?
在代码里,需要判断update 返回的更新条数(count ==1?true:false )来判断本次更新是否成功
4、 使用悲观锁,一般使用数据库提供的功能(不建议);
select … for update (悲观锁)
//do biz
Update ( 事物提交,锁释放)
5、 有时候,数据库不能加唯一性索引(比如由memberId,status 两个字段,业务要求memberId,status=approved 的数据唯一,其他状态的数据不做限制);
这个时候,需要寻求新的协调中心(之前是数据库光荣的承担这一角色),我们现在使用的Memcached 可以完成这个任务,利用memcached 协议规定add 的原子性,详细请点击这里
我们在信联项目里使用了这个方案,有一个缺点,就是需要侵入到业务代码里来控制并发,参考代码:
方式1- 回调(推荐): try { concurrentTemplate.execute(key, new ConcurrentCallback() { public Object doInConcurrent() { // do your biz return null; } }); } catch (ConcurrentException e) { // catch this exception // return value; } 方式二:自助获取和释放锁 ConcurrentLock lock = null; try { lock = concurrentTemplate.acquireLock(key); // do your biz } catch (ConcurrentException e) { // catch this exception // return value; } finally { concurrentTemplate.releaseLock(lock); } |
更多实现,请参考
http://svn.alibaba-inc.com/repos/ali_cn/olps/credit_shared/trunk/common/concurrent
6、 上面的故障4 案例,以上方案都解决不了,这个需要从设计入手来解决此问题,此方案敬请期待宝委会最近的案例分享;
写在最后
随着我们现在系统的复杂性上升,在我们的设计上,必须要考虑并发问题 ,接下来我们会在《设计文档模板》上,增加并发这一章节的hit ,以提醒大家;
同时,测试同学也需要提高并发方面的测试意识。
同理,下次再出并发引起的故障,那就需要新的解释理由了。