java 提交订单 优化,提交订单性能优化系列之011-放弃java同步,引入数据库修改行数来验证库存【重要】...

概括总结

既然Java同步之后,性能这么差,那么有没有办法可以不使用Java同步呢?有的,那就是利用数据库修改的行数来验证库存。另外,假设现在库存是10,需要减少1,推荐的做法是update Goods set stock=stock-1,而不是update Goods set stock=9,后面的写法有同步的情况下性能差,在未同步的情况下直接是错的。

011版本更新说明

更新的思路是这样的:

对于SQL语句update Goods as t set t.stock=stock-1 where t.id=1来说,如果执行成功的话,一定会修改一条记录,也就是把库存减少1。对于JDBC来说,也就是说影响了结果的条数为1。

对于SQL语句update Goods as t set t.stock=(stock-1) where t.id=1 and (stock-1) >= 0来说,如果执行成功的话,不一定会修改一条记录,因为(stock-1)可能会小于零。也就是说,如果库存充足,则影响了结果的条数就为1,如果库存不足,则影响了结果的条数就为0。

这里的关键点在于,对于同一条SQL语句中,虽然出现两次(stock-1),但是不会因为并发线程多而导致这两次计算的值不一样,换句话说:同一条SQL语句是线程安全的。 于是我们就可以把Java代码中的同步去掉了。

这次一共写了三个相似的类,分别是:

Version011Bad.java:性能差、结果正确的版本。它使用了Java代码同步,执行的SQL语句为:update Goods as t set t.stock=stock-1 where t.id=1。

Version011Good.java:性能好、结果正确的版本。它没有使用Java代码同步,执行的SQL语句为:update Goods as t set t.stock=stock-1 where t.id=1 and (stock-1) >= 0。

Version011Wrong.java:性能好、结果错误的版本。它没有使用Java同步,执行的SQL语句为:update Goods as t set t.stock=传来的参数 where t.id=1 and (stock-1) >= 0。其中传来的参数是在Java代码中计算出来的。

测试结果

统计10次测试的平均值之后:

第1种:性能差、结果正确的版本,每秒钟可以提交的订单数为:15

第2种:性能好、结果正确的版本,每秒钟可以提交的订单数为:220

第3种:性能好、结果错误的版本,每秒钟可以提交的订单数为:165

第1种:性能差、结果正确的版本,提交每个订单平均耗时的纳秒数:65095881

第2种:性能好、结果正确的版本,提交每个订单平均耗时的纳秒数:4551771

第3种:性能好、结果错误的版本,提交每个订单平均耗时的纳秒数:6029099

由于第3种的结果是错误的,没有比较的意义,因此这里只比较第1种和第2种的差别。

性能差别为:(65095881 - 4551771) / 4551771 = 13.30,即第二种方法比第一种方法的性能提升了13.3倍。 (由于差别太大,这里直接使用的是倍数,而没有使用百分比。)

【备注】:不同的机器上的测试结果会不一样,以上测试结果仅供参考。

测试结果说明

说明1:为什么第1种性能差?

因为使用了Java同步,即同一时间,只允许有一个线程查询商品,也只允许有一个线程修改库存。这就意味着多线程在查询商品和修改库存时变成了单线程。

说明2:为什么第2种性能好?

因为它没有使用Java同步,同一时间,允许有多个线程同时查询商品和修改库存。对库存的验证操作从Java代码中转移到了SQL语句中,也可以认为对同步的处理从Java中转移到了Mysql中。

说明3:为什么第3种是错的?

假设如下执行顺序:

线程A查询出商品,库存为10

线程B查询出商品,库存为10

线程A在自己查出的库存的基础上减1,得到9,修改数据库,数据库中的库存为9

线程B在自己查出的库存的基础上减1,得到9,修改数据库,数据库中的库存为9

也就是说,两个线程提交了两个订单,数据中的库存应该由10变成8,但实际上却是9。

因此推荐的做法是update Goods set stock=stock-1,而不是update Goods set stock=9。

补充说明

关于Mysql相关的锁的知识,我目前还很欠缺,还没有开始研究,所以目前只是靠试探发现这么做是可以的,并没有严格的理论依据,希望日后可以补上。

另外,这个例子中,使用的线程数是32,性能提升了13倍。后来我又试过一次使用320个线程,性能提升了41倍。但是为了测试时间短一点,以后还是会使用32个线程,不过你心里应该有一个印象,即32几乎肯定不是一个最佳的的线程数。

源码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值