Java高并发秒杀优化

只要抛出异常事务就会回滚吗?前端

Spring 的事务默认是发生了RunTimeException才会回滚,发生了其余异常不会回滚数据库

不是全部的方法都须要事务,如只有一条修改操做、只读操做json

Service层中的抛出异常是为了让Spring可以回滚,Controller层中捕获异常是为了将异常转换为对应的json供前台使用。后端

return "detail";  //我认为是没有意义的,只是一个字符串而已

优化总结缓存

  • 前端控制

暴露接口,按钮防重复(点击一次按钮后就变成灰色,禁止重复点击按钮)服务器

  • 动静态数据分离

CDN缓存,后端缓存网络

  • 事务竞争优化

减小事务行级锁的持有时间并发


Redis属于NoSQL,即非关系型数据库,它是key-value型数据库,是直接在内存中进行存取数据的,因此有着很高的性能。
利用Redis能够减轻MySQL服务器的压力,减小了跟数据库服务器的通讯次数。秒杀的瓶颈就在于跟数据库服务器的通讯速度(MySQL自己的主键查询很是快)
Redis有不少客户端,咱们的项目是用Java语言写的,天然选择对应Java语言的客户端,而官网最推荐咱们的Java客户端是Jedis,在pom.xml里配置了Jedis依赖就可使用它了,记得要先开启Redis的服务器,Jedis才能链接到服务器。
因为Jedis并无实现内部序列化操做,而Java内置的序列化机制性能又不高,咱们是一个秒杀系统,须要考虑高并发优化,在这里咱们采用开源社区提供的更高性能的自定义序列化工具protostuff。
使用Redis优化地址暴露接口
本来查询秒杀商品时是经过主键直接去数据库查询的,选择将数据缓存在Redis,在查询秒杀商品时先去Redis缓存中查询,以此下降数据库的压力。若是在缓存中查询不到数据再去数据库中查询,再将查询到的数据放入Redis缓存中,这样下次就能够直接去缓存中直接查询到。
 

第一:经过Jedis储存对象的方式有大概三种高并发

  1. 本项目采用的方式:将对象序列化成byte字节,最终存byte字节;
  2. 对象转hashmap,也就是你想表达的hash的形式,最终存map;
  3. 对象转json,最终存json,其实也就是字符串

3. 秒杀操做——并发优化

3.1 简单优化

为何要先insert再update
首先是在更新操做的时候给行加锁,插入并不会加锁,若是更新操做在前,那么就须要执行完更新和插入之后事务提交或回滚才释放锁。而若是插入在前,更新在后,那么只有在更新时才会加行锁,以后在更新完之后事务提交或回滚释放锁。
在这里,插入是能够并行的,而更新因为会加行级锁是串行的。
也就是说是更新在前加锁和释放锁之间两次的网络延迟和GC,若是插入在前则加锁和释放锁之间只有一次的网络延迟和GC,也就是减小的持有锁的时间。
这里先insert并非忽略了库存不足的状况,而是由于insert和update是在同一个事务里,光是insert并不必定会提交,只有在update成功才会提交,因此并不会形成过量插入秒杀成功记录。
相关文章
相关标签/搜索