java如何高并发处理mysql中的有限资源(车票、优惠券等)

nyhyn 2015-12-22 08:56:57
业务场景:
有不同种类的优惠券,用户领取优惠券也有限制,活动期限领或每日限领。
领取过程有以下几个步骤:
1、查询优惠券表cp_info,是否有剩余;
2、查询用户是否已经领取过了,表cp_draw_details中是否有记录(若每日限领,会根据领取时间进行过滤)
3、若可以领取,表cp_draw_details中插入一条记录,表cp_info中更新剩余数量

上午查mysql有行锁和表锁,还有查询时使用for update进行锁定(查询条件的字段是索引字段,才会行锁,否则表锁)。
不清楚java代码中是不是也要加synchronized同步块。
当前是在领取时,将领取过程写在一个synchronized同步块中,知道这样效率十分低,最近也正在考虑如何处理。
有知道如何优化的可以说一下思路。
...全文
928 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
nyhyn 2015-12-31
  • 打赏
  • 举报
回复
当前解决办法分享: 1、请求进来后,将user_id存放到缓存中,超过1分钟失效。请求处理完后也会删除缓存。 2、Java代码中同步代码块控制券数量,第一次从库中查询后,放入缓存,1个小时后会超时,处理一个请求-1。缓存中的值又多了一个小时的有效时间,(这样请求正常处理完后,缓存和数据库中的值理论上相等)。若券数量<=0,直接返回提示券已领完,解决券少,请求多的问题。 3、update券数量时添加条件last_num>0,若更新行数!=1,将缓存中的券数量再同步+1。 4、insert库时,若返回的递增id为0(long字段默认值为0),说明插入失败。缓存券数量同步+1,数据库中update券数量+1。 将代码中的事务@Tranactional注解去掉了,如果有事务,update语句回加锁,其他线程的事务执行到update时需等待执行的事务提交后才能执行,严重影响效率。 性能测试后200个线程,评价耗时300ms,1秒处理200多个请求。
文修 2015-12-30
  • 打赏
  • 举报
回复
跪求楼主结贴给分
nyhyn 2015-12-22
  • 打赏
  • 举报
回复
你有在项目中使用过for update,会不会带来其他方面的问题。譬如双11数据量很大时,不会造成系统脱机等
LongRui888 2015-12-22
  • 打赏
  • 举报
回复
引用 2 楼 nyhyn 的回复:
谢谢你的回答,看过你发的那篇文章,也很有启发。 我自己做过一个测试,使用select ... for update,若查询条件字段是索引,会锁住这条记录。需要使用ENGINE=InnoDB。 在整个事务处理完后,其他事务才可以更新这条记录。 当前只有表添加一个标志字段,第一个查询来时将其置为1,后面的就查询不到等待。处理完后再 置为0。这样就不至于将所有优惠券都放在同一个synchronized块中。 欢迎感兴趣和有其他解决思路的一起探讨。
这种对于资源的获取问题,因为你的资源实际上就是数据库中的记录,所以这种锁,可以放到数据库中来实现,通过加上for update,也就是在查询数据的时候,通过索引,就对那一个记录加上独占锁,一方面避免了表锁,也避免了多线程并发访问数据时,产生不一致的问题。
nyhyn 2015-12-22
  • 打赏
  • 举报
回复
谢谢你的回答,看过你发的那篇文章,也很有启发。 我自己做过一个测试,使用select ... for update,若查询条件字段是索引,会锁住这条记录。需要使用ENGINE=InnoDB。 在整个事务处理完后,其他事务才可以更新这条记录。 当前只有表添加一个标志字段,第一个查询来时将其置为1,后面的就查询不到等待。处理完后再 置为0。这样就不至于将所有优惠券都放在同一个synchronized块中。 欢迎感兴趣和有其他解决思路的一起探讨。
文修 2015-12-22
  • 打赏
  • 举报
回复
楼主你好 架构这种事情,除非很了解业务的人,否则无法给出切实有效的解决方案,下面这篇文档希望能够帮助你 http://www.cnblogs.com/javathread/archive/2012/01/10/2634963.html

56,687

社区成员

发帖
与我相关
我的任务
社区描述
MySQL相关内容讨论专区
社区管理员
  • MySQL
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧