java高并发秒杀活动的各种简单实现

article/2025/9/19 0:49:51

最近遇到比较多数据不一致的问题,大多数都是因为并发请求时,没及时处理的原因,故用一个比较有代表性的业务场景【活动秒杀】来模拟一下这个这种高并发所产生的问题。

众所周知,电商系统的秒杀活动是高并发的很好应用场景,这里用的demo模拟的基本框架是springBoot+mybatis+redis+mysql,搭建的过程,我这里就不提了,有需要的可以自行百度。

1.搭好的项目目录:

2.建了一张表(记录商品名称、本次可秒杀的库存量):

加了一条记录(后面每次测试都先手动把库存恢复成100才进行测试)

3.实体:

package com.mybatis.model;public class MiaoShaGoods {private Integer id;private String goodsName;private Integer goodsSum;private Integer version;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getGoodsName() {return goodsName;}public void setGoodsName(String goodsName) {this.goodsName = goodsName == null ? null : goodsName.trim();}public Integer getGoodsSum() {return goodsSum;}public void setGoodsSum(Integer goodsSum) {this.goodsSum = goodsSum;}public Integer getVersion() {return version;}public void setVersion(Integer version) {this.version = version;}
}

一、不做任何处理的高并发秒杀实现(错误演示):

1.Controller层,模拟500个并发调用:

package com.mybatis.controller;import com.mybatis.domain.BaseResponse;
import com.mybatis.domain.MiaoshaRequest;
import com.mybatis.service.MiaoshaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;@Controller
@RequestMapping(value="/miaoshagoods")
public class MiaoshaController {@Autowiredpublic MiaoshaService miaoshaService;@PostMapping("/miaosha_java_sql_lock")public @ResponseBody BaseResponse miaoshaJavaSqlLock(@RequestBody MiaoshaRequest request){BaseResponse response=new BaseResponse();for(int i=0;i<500;i++){Thread thread=new Thread(new Runnable() {@Overridepublic void run() {//不做任何处理的秒杀实现miaoshaService.miaoshaGoods(request,response);              }});thread.start();}return response;}
}

2.Service层,每个请求进来就去数据库里查剩余的库存量,并且抢购成功后,就减1个库存:

package com.mybatis.service.Impl;import com.mybatis.dao.MiaoShaGoodsDao;
import com.mybatis.domain.BaseResponse;
import com.mybatis.domain.MiaoshaRequest;
import com.mybatis.model.MiaoShaGoods;
import com.mybatis.service.MiaoshaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;@Service
public class MiashaServiceImpl implements MiaoshaService{@AutowiredMiaoShaGoodsDao miaoShaGoodsDao;private Lock lock = new ReentrantLock();@Autowiredprivate RedisTemplate<String,String> redisTemplate;/*** 不做任何处理的秒杀实现* @param request* @return*/@Overridepublic BaseResponse miaoshaGoods(MiaoshaRequest request, BaseResponse response) {int countSuc=0;MiaoShaGoods miaoShaGoods=miaoShaGoodsDao.getGoods(request.getGoodNames());if(miaoShaGoods.getGoodsSum()>0){miaoShaGoods.setGoodsSum(miaoShaGoods.getGoodsSum()-1);countSuc= miaoShaGoodsDao.updateMsGoods(miaoShaGoods);}if(countSuc==1){System.out.println("抢到iphoneX,成功!");}else{System.out.println("抢到iphoneX,失败!");}return response;}
}

3.dao层(mybatis的xml文件):

 <select id="getGoods" parameterType="java.lang.String" resultMap="BaseResultMap">select<include refid="Base_Column_List" />from miao_sha_goodswhere goods_name = #{goodsName,jdbcType=VARCHAR}</select><update id="updateMsGoods" parameterType="com.mybatis.model.MiaoShaGoods">update miao_sha_goodsset goods_sum = #{goodsSum,jdbcType=INTEGER}where goods_name = #{goodsName,jdbcType=VARCHAR}</update>

4.测试结果:

截图表明,居然有500个人抢购成功,而且库存量却只减少了12个,这是明显是错误的。

 

二、数据库乐观锁处理的高并发秒杀实现:

1.Controller层,模拟500个并发调用:

package com.mybatis.controller;import com.mybatis.domain.BaseResponse;
import com.mybatis.domain.MiaoshaRequest;
import com.mybatis.service.MiaoshaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;@Controller
@RequestMapping(value="/miaoshagoods")
public class MiaoshaController {@Autowiredpublic MiaoshaService miaoshaService;@PostMapping("/miaosha_java_sql_lock")public @ResponseBody BaseResponse miaoshaJavaSqlLock(@RequestBody MiaoshaRequest request){BaseResponse response=new BaseResponse();for(int i=0;i<500;i++){Thread thread=new Thread(new Runnable() {@Overridepublic void run() {//不做任何处理的秒杀实现//miaoshaService.miaoshaGoods(request,response);//数据库乐观锁秒杀miaoshaService.miaoshaGoods_sql_optimistic_lock(request,response);}});thread.start();}return response;}
}

2.Service层,每个请求进来就去数据库里查剩余的库存量,并且抢购成功后,就减1个库存:

package com.mybatis.service.Impl;import com.mybatis.dao.MiaoShaGoodsDao;
import com.mybatis.domain.BaseResponse;
import com.mybatis.domain.MiaoshaRequest;
import com.mybatis.model.MiaoShaGoods;
import com.mybatis.service.MiaoshaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;@Service
public class MiashaServiceImpl implements MiaoshaService{@AutowiredMiaoShaGoodsDao miaoShaGoodsDao;private Lock lock = new ReentrantLock();@Autowiredprivate RedisTemplate<String,String> redisTemplate;/*** 不做任何处理的秒杀实现* @param request* @return*/@Overridepublic BaseResponse miaoshaGoods(MiaoshaRequest request, BaseResponse response) {int countSuc=0;MiaoShaGoods miaoShaGoods=miaoShaGoodsDao.getGoods(request.getGoodNames());if(miaoShaGoods.getGoodsSum()>0){miaoShaGoods.setGoodsSum(miaoShaGoods.getGoodsSum()-1);countSuc= miaoShaGoodsDao.updateMsGoods(miaoShaGoods);}if(countSuc==1){System.out.println("抢到iphoneX,成功!");}else{System.out.println("抢到iphoneX,失败!");}return response;}/*** 数据库乐观锁实现秒杀* @param request* @return*/@Overridepublic BaseResponse miaoshaGoods_sql_optimistic_lock(MiaoshaRequest request,BaseResponse response) {int countSuc=0;MiaoShaGoods miaoShaGoods=miaoShaGoodsDao.getGoods_lgs(request.getGoodNames());if(miaoShaGoods.getGoodsSum()>0){miaoShaGoods.setGoodsSum(miaoShaGoods.getGoodsSum()-1);countSuc= miaoShaGoodsDao.updateMsGoods_lgs(miaoShaGoods);}if(countSuc==1){System.out.println("抢到iphoneX,成功!");//做出相应的逻辑(记录抢购成功的用户名什么的....}else{System.out.println("抢到iphoneX,失败!");//重试或者返回友好的提示什么的....}return response;}
}

3.dao层(mybatis的xml文件)[在SQL层面改为数据库乐观锁]: 

<select id="getGoods_lgs" parameterType="java.lang.String" resultMap="BaseResultMap">select<include refid="Base_Column_List" />from miao_sha_goodswhere goods_name = #{goodsName,jdbcType=VARCHAR}</select><update id="updateMsGoods_lgs" parameterType="com.mybatis.model.MiaoShaGoods">update miao_sha_goodsset goods_sum = #{goodsSum,jdbcType=INTEGER},version=version+1where goods_name = #{goodsName,jdbcType=VARCHAR} and version = #{version,jdbcType=VARCHAR}</update>

4.测试结果:

截图表明,总共有500个人抢,有29个人抢购成功,而且库存量减少了29个,这保证了库存的正确性。但却会有抢购不成功的请求,需要我们后续去处理。

 

三、数据库悲观锁处理的高并发秒杀实现:

1.Controller层,模拟500个并发调用:

package com.mybatis.controller;import com.mybatis.domain.BaseResponse;
import com.mybatis.domain.MiaoshaRequest;
import com.mybatis.service.MiaoshaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;@Controller
@RequestMapping(value="/miaoshagoods")
public class MiaoshaController {@Autowiredpublic MiaoshaService miaoshaService;@PostMapping("/miaosha_java_sql_lock")public @ResponseBody BaseResponse miaoshaJavaSqlLock(@RequestBody MiaoshaRequest request){BaseResponse response=new BaseResponse();for(int i=0;i<500;i++){Thread thread=new Thread(new Runnable() {@Overridepublic void run() {//不做任何处理的秒杀实现//miaoshaService.miaoshaGoods(request,response);//数据库乐观锁秒杀//miaoshaService.miaoshaGoods_sql_optimistic_lock(request,response);//数据库悲观锁秒杀miaoshaService.miaoshaGoods_sql_pessimistic_lock(request,response);}});thread.start();}return response;}
}

2.Service层,每个请求进来就去数据库里查剩余的库存量,并且抢购成功后,就减1个库存(查询和更新必须在同一个事务):

package com.mybatis.service.Impl;import com.mybatis.dao.MiaoShaGoodsDao;
import com.mybatis.domain.BaseResponse;
import com.mybatis.domain.MiaoshaRequest;
import com.mybatis.model.MiaoShaGoods;
import com.mybatis.service.MiaoshaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;@Service
public class MiashaServiceImpl implements MiaoshaService{@AutowiredMiaoShaGoodsDao miaoShaGoodsDao;private Lock lock = new ReentrantLock();@Autowiredprivate RedisTemplate<String,String> redisTemplate;/*** 不做任何处理的秒杀实现* @param request* @return*/@Overridepublic BaseResponse miaoshaGoods(MiaoshaRequest request, BaseResponse response) {int countSuc=0;MiaoShaGoods miaoShaGoods=miaoShaGoodsDao.getGoods(request.getGoodNames());if(miaoShaGoods.getGoodsSum()>0){miaoShaGoods.setGoodsSum(miaoShaGoods.getGoodsSum()-1);countSuc= miaoShaGoodsDao.updateMsGoods(miaoShaGoods);}if(countSuc==1){System.out.println("抢到iphoneX,成功!");}else{System.out.println("抢到iphoneX,失败!");}return response;}/*** 数据库乐观锁实现秒杀* @param request* @return*/@Overridepublic BaseResponse miaoshaGoods_sql_optimistic_lock(MiaoshaRequest request,BaseResponse response) {int countSuc=0;MiaoShaGoods miaoShaGoods=miaoShaGoodsDao.getGoods_lgs(request.getGoodNames());if(miaoShaGoods.getGoodsSum()>0){miaoShaGoods.setGoodsSum(miaoShaGoods.getGoodsSum()-1);countSuc= miaoShaGoodsDao.updateMsGoods_lgs(miaoShaGoods);}if(countSuc==1){System.out.println("抢到iphoneX,成功!");//做出相应的逻辑(记录抢购成功的用户名什么的....}else{System.out.println("抢到iphoneX,失败!");//重试或者返回友好的提示什么的....}return response;}/*** 数据库悲观锁实现秒杀* @param request* @return*/@Override@Transactionalpublic BaseResponse miaoshaGoods_sql_pessimistic_lock(MiaoshaRequest request,BaseResponse response) {int countSuc=0;MiaoShaGoods miaoShaGoods=miaoShaGoodsDao.getGoods_bgs(request.getGoodNames());if(miaoShaGoods.getGoodsSum()>0){miaoShaGoods.setGoodsSum(miaoShaGoods.getGoodsSum()-1);countSuc= miaoShaGoodsDao.updateMsGoods_bgs(miaoShaGoods);}if(countSuc==1){System.out.println("抢到iphoneX,成功!");}else{System.out.println("抢到iphoneX,失败!");}return response;}
}

 3.dao层(mybatis的xml文件)[在SQL层面改为数据库悲观锁]: 

<select id="getGoods_bgs" parameterType="java.lang.String" resultMap="BaseResultMap">select<include refid="Base_Column_List" />from miao_sha_goodswhere goods_name = #{goodsName,jdbcType=VARCHAR} FOR UPDATE</select><update id="updateMsGoods_bgs" parameterType="com.mybatis.model.MiaoShaGoods">update miao_sha_goodsset goods_sum = #{goodsSum,jdbcType=INTEGER}where goods_name = #{goodsName,jdbcType=VARCHAR}</update>

4.测试结果:

 截图表明,总共有500个人抢,有100个人抢购成功,而且库存量减少了100个,这保证了库存的正确性。

 

四、java线程同步锁处理的高并发秒杀实现:

1.Controller层,模拟500个并发调用:

package com.mybatis.controller;import com.mybatis.domain.BaseResponse;
import com.mybatis.domain.MiaoshaRequest;
import com.mybatis.service.MiaoshaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;@Controller
@RequestMapping(value="/miaoshagoods")
public class MiaoshaController {@Autowiredpublic MiaoshaService miaoshaService;@PostMapping("/miaosha_java_sql_lock")public @ResponseBody BaseResponse miaoshaJavaSqlLock(@RequestBody MiaoshaRequest request){BaseResponse response=new BaseResponse();for(int i=0;i<500;i++){Thread thread=new Thread(new Runnable() {@Overridepublic void run() {//不做任何处理的秒杀实现//miaoshaService.miaoshaGoods(request,response);//数据库乐观锁秒杀//miaoshaService.miaoshaGoods_sql_optimistic_lock(request,response);//数据库悲观锁秒杀//miaoshaService.miaoshaGoods_sql_pessimistic_lock(request,response);//java线程同步锁秒杀miaoshaService.miaoshaGoods_java_synchronized_lock(request,response);}});thread.start();}return response;}
}

2.Service层,每个请求进来就去数据库里查剩余的库存量,并且抢购成功后,就减1个库存:

package com.mybatis.service.Impl;import com.mybatis.dao.MiaoShaGoodsDao;
import com.mybatis.domain.BaseResponse;
import com.mybatis.domain.MiaoshaRequest;
import com.mybatis.model.MiaoShaGoods;
import com.mybatis.service.MiaoshaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;@Service
public class MiashaServiceImpl implements MiaoshaService{@AutowiredMiaoShaGoodsDao miaoShaGoodsDao;private Lock lock = new ReentrantLock();@Autowiredprivate RedisTemplate<String,String> redisTemplate;/*** 不做任何处理的秒杀实现* @param request* @return*/@Overridepublic BaseResponse miaoshaGoods(MiaoshaRequest request, BaseResponse response) {int countSuc=0;MiaoShaGoods miaoShaGoods=miaoShaGoodsDao.getGoods(request.getGoodNames());if(miaoShaGoods.getGoodsSum()>0){miaoShaGoods.setGoodsSum(miaoShaGoods.getGoodsSum()-1);countSuc= miaoShaGoodsDao.updateMsGoods(miaoShaGoods);}if(countSuc==1){System.out.println("抢到iphoneX,成功!");}else{System.out.println("抢到iphoneX,失败!");}return response;}/*** 数据库乐观锁实现秒杀* @param request* @return*/@Overridepublic BaseResponse miaoshaGoods_sql_optimistic_lock(MiaoshaRequest request,BaseResponse response) {int countSuc=0;MiaoShaGoods miaoShaGoods=miaoShaGoodsDao.getGoods_lgs(request.getGoodNames());if(miaoShaGoods.getGoodsSum()>0){miaoShaGoods.setGoodsSum(miaoShaGoods.getGoodsSum()-1);countSuc= miaoShaGoodsDao.updateMsGoods_lgs(miaoShaGoods);}if(countSuc==1){System.out.println("抢到iphoneX,成功!");//做出相应的逻辑(记录抢购成功的用户名什么的....}else{System.out.println("抢到iphoneX,失败!");//重试或者返回友好的提示什么的....}return response;}/*** 数据库悲观锁实现秒杀* @param request* @return*/@Override@Transactionalpublic BaseResponse miaoshaGoods_sql_pessimistic_lock(MiaoshaRequest request,BaseResponse response) {int countSuc=0;MiaoShaGoods miaoShaGoods=miaoShaGoodsDao.getGoods_bgs(request.getGoodNames());if(miaoShaGoods.getGoodsSum()>0){miaoShaGoods.setGoodsSum(miaoShaGoods.getGoodsSum()-1);countSuc= miaoShaGoodsDao.updateMsGoods_bgs(miaoShaGoods);}if(countSuc==1){System.out.println("抢到iphoneX,成功!");}else{System.out.println("抢到iphoneX,失败!");}return response;}/*** java同步锁实现秒杀* @param request* @return*/@Overridepublic BaseResponse miaoshaGoods_java_synchronized_lock(MiaoshaRequest request,BaseResponse response) {synchronized(this){int countSuc=0;MiaoShaGoods miaoShaGoods=miaoShaGoodsDao.getGoods(request.getGoodNames());if(miaoShaGoods.getGoodsSum()>0){miaoShaGoods.setGoodsSum(miaoShaGoods.getGoodsSum()-1);countSuc= miaoShaGoodsDao.updateMsGoods(miaoShaGoods);}if(countSuc==1){System.out.println("抢到iphoneX,成功!");}else{System.out.println("抢到iphoneX,失败!");}}return response;}
}

3.dao层(mybatis的xml文件):

<select id="getGoods" parameterType="java.lang.String" resultMap="BaseResultMap">select<include refid="Base_Column_List" />from miao_sha_goodswhere goods_name = #{goodsName,jdbcType=VARCHAR}</select><update id="updateMsGoods" parameterType="com.mybatis.model.MiaoShaGoods">update miao_sha_goodsset goods_sum = #{goodsSum,jdbcType=INTEGER}where goods_name = #{goodsName,jdbcType=VARCHAR}</update>

4.测试结果:

截图表明,总共有500个人抢,有100个人抢购成功,而且库存量减少了100个,这保证了库存的正确性。

 

五、java线程可重入锁处理的高并发秒杀实现:

1.Controller层,模拟500个并发调用:

package com.mybatis.controller;import com.mybatis.domain.BaseResponse;
import com.mybatis.domain.MiaoshaRequest;
import com.mybatis.service.MiaoshaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;@Controller
@RequestMapping(value="/miaoshagoods")
public class MiaoshaController {@Autowiredpublic MiaoshaService miaoshaService;@PostMapping("/miaosha_java_sql_lock")public @ResponseBody BaseResponse miaoshaJavaSqlLock(@RequestBody MiaoshaRequest request){BaseResponse response=new BaseResponse();for(int i=0;i<500;i++){Thread thread=new Thread(new Runnable() {@Overridepublic void run() {//不做任何处理的秒杀实现//miaoshaService.miaoshaGoods(request,response);//数据库乐观锁秒杀//miaoshaService.miaoshaGoods_sql_optimistic_lock(request,response);//数据库悲观锁秒杀//miaoshaService.miaoshaGoods_sql_pessimistic_lock(request,response);//java线程同步锁秒杀//miaoshaService.miaoshaGoods_java_synchronized_lock(request,response);//java线程可重入锁秒杀miaoshaService.miaoshaGoods_java_reentrant_lock(request,response);}});thread.start();}return response;}
}

2.Service层,每个请求进来就去数据库里查剩余的库存量,并且抢购成功后,就减1个库存: 

package com.mybatis.service.Impl;import com.mybatis.dao.MiaoShaGoodsDao;
import com.mybatis.domain.BaseResponse;
import com.mybatis.domain.MiaoshaRequest;
import com.mybatis.model.MiaoShaGoods;
import com.mybatis.service.MiaoshaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;@Service
public class MiashaServiceImpl implements MiaoshaService{@AutowiredMiaoShaGoodsDao miaoShaGoodsDao;private Lock lock = new ReentrantLock();@Autowiredprivate RedisTemplate<String,String> redisTemplate;/*** 不做任何处理的秒杀实现* @param request* @return*/@Overridepublic BaseResponse miaoshaGoods(MiaoshaRequest request, BaseResponse response) {int countSuc=0;MiaoShaGoods miaoShaGoods=miaoShaGoodsDao.getGoods(request.getGoodNames());if(miaoShaGoods.getGoodsSum()>0){miaoShaGoods.setGoodsSum(miaoShaGoods.getGoodsSum()-1);countSuc= miaoShaGoodsDao.updateMsGoods(miaoShaGoods);}if(countSuc==1){System.out.println("抢到iphoneX,成功!");}else{System.out.println("抢到iphoneX,失败!");}return response;}/*** 数据库乐观锁实现秒杀* @param request* @return*/@Overridepublic BaseResponse miaoshaGoods_sql_optimistic_lock(MiaoshaRequest request,BaseResponse response) {int countSuc=0;MiaoShaGoods miaoShaGoods=miaoShaGoodsDao.getGoods_lgs(request.getGoodNames());if(miaoShaGoods.getGoodsSum()>0){miaoShaGoods.setGoodsSum(miaoShaGoods.getGoodsSum()-1);countSuc= miaoShaGoodsDao.updateMsGoods_lgs(miaoShaGoods);}if(countSuc==1){System.out.println("抢到iphoneX,成功!");//做出相应的逻辑(记录抢购成功的用户名什么的....}else{System.out.println("抢到iphoneX,失败!");//重试或者返回友好的提示什么的....}return response;}/*** 数据库悲观锁实现秒杀* @param request* @return*/@Override@Transactionalpublic BaseResponse miaoshaGoods_sql_pessimistic_lock(MiaoshaRequest request,BaseResponse response) {int countSuc=0;MiaoShaGoods miaoShaGoods=miaoShaGoodsDao.getGoods_bgs(request.getGoodNames());if(miaoShaGoods.getGoodsSum()>0){miaoShaGoods.setGoodsSum(miaoShaGoods.getGoodsSum()-1);countSuc= miaoShaGoodsDao.updateMsGoods_bgs(miaoShaGoods);}if(countSuc==1){System.out.println("抢到iphoneX,成功!");}else{System.out.println("抢到iphoneX,失败!");}return response;}/*** java同步锁实现秒杀* @param request* @return*/@Overridepublic BaseResponse miaoshaGoods_java_synchronized_lock(MiaoshaRequest request,BaseResponse response) {synchronized(this){int countSuc=0;MiaoShaGoods miaoShaGoods=miaoShaGoodsDao.getGoods(request.getGoodNames());if(miaoShaGoods.getGoodsSum()>0){miaoShaGoods.setGoodsSum(miaoShaGoods.getGoodsSum()-1);countSuc= miaoShaGoodsDao.updateMsGoods(miaoShaGoods);}if(countSuc==1){System.out.println("抢到iphoneX,成功!");}else{System.out.println("抢到iphoneX,失败!");}}return response;}/*** java可重入锁实现秒杀* @param request* @return*/@Overridepublic BaseResponse miaoshaGoods_java_reentrant_lock(MiaoshaRequest request,BaseResponse response) {lock.lock();int countSuc=0;MiaoShaGoods miaoShaGoods=miaoShaGoodsDao.getGoods(request.getGoodNames());if(miaoShaGoods.getGoodsSum()>0){miaoShaGoods.setGoodsSum(miaoShaGoods.getGoodsSum()-1);countSuc= miaoShaGoodsDao.updateMsGoods(miaoShaGoods);}if(countSuc==1){System.out.println(request.getGoodNames()+"抢到iphoneX,成功!");}else{System.out.println("抢到iphoneX,失败!");}lock.unlock();return response;}
}

3.dao层(mybatis的xml文件): 

<select id="getGoods" parameterType="java.lang.String" resultMap="BaseResultMap">select<include refid="Base_Column_List" />from miao_sha_goodswhere goods_name = #{goodsName,jdbcType=VARCHAR}</select><update id="updateMsGoods" parameterType="com.mybatis.model.MiaoShaGoods">update miao_sha_goodsset goods_sum = #{goodsSum,jdbcType=INTEGER}where goods_name = #{goodsName,jdbcType=VARCHAR}</update>

4.测试结果:

 截图表明,总共有500个人抢,有100个人抢购成功,而且库存量减少了100个,这保证了库存的正确性。

 

六、redis单线程处理的高并发秒杀实现(推荐):

1.Controller层,模拟500个并发调用:

package com.mybatis.controller;import com.mybatis.domain.BaseResponse;
import com.mybatis.domain.MiaoshaRequest;
import com.mybatis.service.MiaoshaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;@Controller
@RequestMapping(value="/miaoshagoods")
public class MiaoshaController {@Autowiredpublic MiaoshaService miaoshaService;@Autowiredprivate RedisTemplate<String,String> redisTemplate;@PostMapping("/miaosha_java_sql_lock")public @ResponseBody BaseResponse miaoshaJavaSqlLock(@RequestBody MiaoshaRequest request){BaseResponse response=new BaseResponse();for(int i=0;i<500;i++){Thread thread=new Thread(new Runnable() {@Overridepublic void run() {//不做任何处理的秒杀实现//miaoshaService.miaoshaGoods(request,response);//数据库乐观锁秒杀//miaoshaService.miaoshaGoods_sql_optimistic_lock(request,response);//数据库悲观锁秒杀//miaoshaService.miaoshaGoods_sql_pessimistic_lock(request,response);//java线程同步锁秒杀//miaoshaService.miaoshaGoods_java_synchronized_lock(request,response);//java线程可重入锁秒杀miaoshaService.miaoshaGoods_java_reentrant_lock(request,response);}});thread.start();}return response;}@PostMapping("/miaosha_redis_lock")public @ResponseBody BaseResponse miaoshaRedisLock(@RequestBody MiaoshaRequest request){BaseResponse response=new BaseResponse();//初始化商品数量Integer goodsSum=miaoshaService.getGoodsSum(request);redisTemplate.opsForValue().set(request.getGoodNames()+":goodsSum",goodsSum+"");System.out.println("总共的库存量:"+goodsSum);for(int i=0;i<500;i++){Thread thread=new Thread(new Runnable() {@Overridepublic void run() {miaoshaService.miaoshaGoods_redis(request,response);}});thread.start();}return response;}
}

2.Service层,先把参与秒杀的总库存量写入redis里,然后再利用redis的增量方法去递减:

package com.mybatis.service.Impl;import com.mybatis.dao.MiaoShaGoodsDao;
import com.mybatis.domain.BaseResponse;
import com.mybatis.domain.MiaoshaRequest;
import com.mybatis.model.MiaoShaGoods;
import com.mybatis.service.MiaoshaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;@Service
public class MiashaServiceImpl implements MiaoshaService{@AutowiredMiaoShaGoodsDao miaoShaGoodsDao;private Lock lock = new ReentrantLock();@Autowiredprivate RedisTemplate<String,String> redisTemplate;/*** 不做任何处理的秒杀实现* @param request* @return*/@Overridepublic BaseResponse miaoshaGoods(MiaoshaRequest request, BaseResponse response) {int countSuc=0;MiaoShaGoods miaoShaGoods=miaoShaGoodsDao.getGoods(request.getGoodNames());if(miaoShaGoods.getGoodsSum()>0){miaoShaGoods.setGoodsSum(miaoShaGoods.getGoodsSum()-1);countSuc= miaoShaGoodsDao.updateMsGoods(miaoShaGoods);}if(countSuc==1){System.out.println("抢到iphoneX,成功!");}else{System.out.println("抢到iphoneX,失败!");}return response;}/*** 数据库乐观锁实现秒杀* @param request* @return*/@Overridepublic BaseResponse miaoshaGoods_sql_optimistic_lock(MiaoshaRequest request,BaseResponse response) {int countSuc=0;MiaoShaGoods miaoShaGoods=miaoShaGoodsDao.getGoods_lgs(request.getGoodNames());if(miaoShaGoods.getGoodsSum()>0){miaoShaGoods.setGoodsSum(miaoShaGoods.getGoodsSum()-1);countSuc= miaoShaGoodsDao.updateMsGoods_lgs(miaoShaGoods);}if(countSuc==1){System.out.println("抢到iphoneX,成功!");//做出相应的逻辑(记录抢购成功的用户名什么的....}else{System.out.println("抢到iphoneX,失败!");//重试或者返回友好的提示什么的....}return response;}/*** 数据库悲观锁实现秒杀* @param request* @return*/@Override@Transactionalpublic BaseResponse miaoshaGoods_sql_pessimistic_lock(MiaoshaRequest request,BaseResponse response) {int countSuc=0;MiaoShaGoods miaoShaGoods=miaoShaGoodsDao.getGoods_bgs(request.getGoodNames());if(miaoShaGoods.getGoodsSum()>0){miaoShaGoods.setGoodsSum(miaoShaGoods.getGoodsSum()-1);countSuc= miaoShaGoodsDao.updateMsGoods_bgs(miaoShaGoods);}if(countSuc==1){System.out.println("抢到iphoneX,成功!");}else{System.out.println("抢到iphoneX,失败!");}return response;}/*** java同步锁实现秒杀* @param request* @return*/@Overridepublic BaseResponse miaoshaGoods_java_synchronized_lock(MiaoshaRequest request,BaseResponse response) {synchronized(this){int countSuc=0;MiaoShaGoods miaoShaGoods=miaoShaGoodsDao.getGoods(request.getGoodNames());if(miaoShaGoods.getGoodsSum()>0){miaoShaGoods.setGoodsSum(miaoShaGoods.getGoodsSum()-1);countSuc= miaoShaGoodsDao.updateMsGoods(miaoShaGoods);}if(countSuc==1){System.out.println("抢到iphoneX,成功!");}else{System.out.println("抢到iphoneX,失败!");}}return response;}/*** java可重入锁实现秒杀* @param request* @return*/@Overridepublic BaseResponse miaoshaGoods_java_reentrant_lock(MiaoshaRequest request,BaseResponse response) {lock.lock();int countSuc=0;MiaoShaGoods miaoShaGoods=miaoShaGoodsDao.getGoods(request.getGoodNames());if(miaoShaGoods.getGoodsSum()>0){miaoShaGoods.setGoodsSum(miaoShaGoods.getGoodsSum()-1);countSuc= miaoShaGoodsDao.updateMsGoods(miaoShaGoods);}if(countSuc==1){System.out.println(request.getGoodNames()+"抢到iphoneX,成功!");}else{System.out.println("抢到iphoneX,失败!");}lock.unlock();return response;}@Overridepublic Integer getGoodsSum(MiaoshaRequest request) {MiaoShaGoods miaoShaGoods=miaoShaGoodsDao.getGoods(request.getGoodNames());return miaoShaGoods.getGoodsSum();}/*** redis实现秒杀* @param response* @return*/@Overridepublic BaseResponse miaoshaGoods_redis(MiaoshaRequest request,BaseResponse response) {//增量计算剩余库存(利用redis的单线程特性)double goodsSurplusSum=redisTemplate.opsForValue().increment(request.getGoodNames()+":goodsSum",-1);if(goodsSurplusSum>=0){System.out.println("抢到iphoneX,成功!还剩下:"+goodsSurplusSum);}else {System.out.println("抢到iphoneX,失败!");}return response;}
}

3.测试结果:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

截图表明,总共有500个人抢,有100个人抢购成功,而且库存量减少了100个,这保证了库存的正确性,抢后redis显示是-400个,说明有500个人进来了,有400个人抢不到。

综上所述,要控制库存量,一般要用锁机制。但是一般加锁的话会比较影响性能(只能用于单服务),推荐大家使用redis自带的线程安全属性来实现(可实现分布式锁)。


http://chatgpt.dhexx.cn/article/0rngJD4D.shtml

相关文章

Java 高并发解决方案(电商的秒杀和抢购)

电商的秒杀和抢购&#xff0c;对我们来说&#xff0c;都不是一个陌生的东西。然而&#xff0c;从技术的角度来说&#xff0c;这对于Web系统是一个巨大的考验。当一个Web系统&#xff0c;在一秒钟内收到数以万计甚至更多请求时&#xff0c;系统的优化和稳定至关重要。这次我们会…

【转存】java高并发解决方案

知识点 线程安全&#xff0c;线程封闭&#xff0c;线程调度&#xff0c;同步容器&#xff0c;并发容器&#xff0c;AQS&#xff0c;J.U.C&#xff0c;等等 高并发解决思路与手段 扩容&#xff1a;水平扩容、垂直扩容 缓存&#xff1a;Redis、Memcache、GuavaCache等 队列&…

Java 高并发编程详解:多线程与架构设计

内容简介 本书主要包含四个部分&#xff1a; 部分主要阐述 Thread 的基础知识&#xff0c;详细介绍线程的 API 使用、线程安全、线程间数据通信&#xff0c;以及如何保护共享资源等内容&#xff0c;它是深入学习多线程内容的基础。 第二部分引入了 ClassLoader&#xff0c;这…

Java高并发之Redis批量提交数据库

随着系统并发请求激增&#xff0c;参考电商秒杀、当下集中核酸采取等业务场景&#xff0c;如果突然大量数据请求业务系统。此时如果没有做任何缓存措施&#xff0c;直接保存数据库&#xff0c;即使你的数据库做了集群和分库分表&#xff0c;也会由于扛不住并发压力崩溃的。基于…

Java高并发累加器Striped64

原子类 在多线程环境下&#xff0c;常用累加操作方式是使用原子类进行累加&#xff0c;例如AtomicInteger、AtomicLong。但是使用原子类在多线程高竞争的情况下&#xff0c;CAS会经常失败&#xff0c;并发效率会大大降低。 因为CAS操作失败后要自旋再次进行替换&#xff0c;这…

Java高并发编程实战8,同步容器与并发容器

目录 一、为什么这种方式不能实现线程安全性?二、组合三、同步容器类四、隐藏迭代器五、并发容器六、ConcurrentHashMap一、为什么这种方式不能实现线程安全性? 分析一段代码: package com.guor.util;import java.util.

Java高并发项目案例,Java开发指南

一、前言 最近刚读完一本书&#xff1a;《Netty、Zookeeper、Redis 并发实战》&#xff0c;个人觉得 Netty 部分是写得很不错的&#xff0c;读完之后又对 Netty 进行了一波很好的复习&#xff08;之前用 spring boot netty zookeeper 模仿 dubbo 做 rpc 框架&#xff0c;那时…

Java高并发三部曲

疯狂创客圈为小伙伴奉上以下珍贵的学习资源&#xff1a; 疯狂创客圈 经典极品 &#xff1a; 极致经典《 Java 高并发 三部曲 》 面试必备 大厂必备 涨薪必备 疯狂创客圈 经典图书 &#xff1a; 《Netty Zookeeper Redis 高并发实战》 面试必备 大厂必备 涨薪必备 免费领 …

java队列处理高并发_Java高并发--消息队列

Java高并发--消息队列 举个例子&#xff1a;在购物商城下单后&#xff0c;希望购买者能收到短信或者邮件通知。有一种做法时在下单逻辑执行后调用短信发送的API&#xff0c;如果此时服务器响应较慢、短信客户端出现问题等诸多原因购买者不能正常收到短信&#xff0c;那么此时是…

Java如何解决高并发的问题? 可以试试这些方法

大家好&#xff0c;我是小武&#xff0c;一个工作10年的程序员&#xff0c;就职于鹅厂&#xff0c;平时喜欢搞搞副业。 在工作中&#xff0c;我们经常会遇到高并发的问题&#xff0c;这个是很常见的&#xff0c;只要用户访问量一多的情况下&#xff0c;那么我们的网站就会变慢&…

单例模式的五种写法

设计模式&#xff08;Design pattern&#xff09;&#xff0c;提供了在软件开发过程中面临的一些问题的最佳解决方案&#xff0c;是Java开发者必修的一门课程。主要分创建型模式、结构型模式和行为型模式。其中接下来我们要写的是单例模式&#xff0c;属于创建型模式。 单例模式…

JAVA单例模式代码实现

JAVA常见的设计模式之单例模式 懒汉模式 懒汉式是典型的时间换空间&#xff0c;也就是每次获取实例都会进行判断&#xff0c;看是否需要创建实例&#xff0c;浪费判断的时间。当然&#xff0c;如果一直没有人使用的话&#xff0c;那就不会创建实例&#xff0c;则节约内存空间(…

单例模式编写

单例">什么是单例 单例是保证一个内存/进程里只有一个类的实例&#xff0c;并提供一个访问它的全局访问点。 内存/进程中只有一个实例线程安全性能优化防止序列化产生新对象 写一个单例模式 1、饿汉模式 public class Singleton {//饿汉模式private static Single…

设计模式——单例模式八种方式实现与分析(附代码示例)

一. 概念 所谓类的单例设计模式&#xff0c;就是采取一定的方法保证在整个的软件系统中&#xff0c;对某个类只能存在一个对象实例&#xff0c;并且该类只提供一个取得其对象实例的方法&#xff08;静态方法&#xff09;。 单例模式保证了系统内存中该类只存在一个对象&#xf…

C++ 单例模式 代码详解

单例模式 单例模式&#xff08;Singleton Pattern&#xff09;是 最简单的设计模式之一。这种类型的设计模式属于创建型模式&#xff0c;它提供了一种创建对象的最佳方式。 这种模式涉及到一个单一的类&#xff0c;该类负责创建自己的对象&#xff0c;同时确保只有单个对象被…

[设计模式] -- 单例模式

Emai : hahayacodergmail.com 背景 最近在公司的项目中&#xff0c;经常会用到单例模式&#xff0c;由于之前没有想过怎么正确使用单例模式&#xff0c;导致写成的程序中有BUG。在学习Cocos2d-x时&#xff0c;导演类CCDirector等都是单例类。所以从头开始学习单例模式。 介绍 …

单例模式介绍

目录 1 前言 2 单例模式类型 2.1 饿汉式&#xff1a; 2.2 懒汉式&#xff1a; 2.2.1 双重检查锁 2.2.2 volatile防止指令重排 2.3 静态内部类 3 破坏单例 1 前言 单例模式是指在内存中有且只会创建一次对象的设计模式&#xff0c;在程序中多次使用同一个对象且作用相同…

单例模式详解(附常见的7种单例模式源码)

单例模式&#xff08;Singleton Pattern&#xff09;:保证一个类仅有一个对象&#xff0c;并提供一个访问它的全局访问点。(Ensure a class only has one instance,and provide a globe point of access to it.) 常见应用场景&#xff1a; Windows的Task Manager&#xff08;…

设计模式(一)—单例模式(附Java代码)

单例模式&#xff08;Singleton Pattern&#xff09;:采取一定的方法保证在整个的软件系统中&#xff0c;对于某个类只能存在一个对象实例&#xff0c;并且该类只提供一个取得其实例对象的方法。 比如Hibernate的SessionFactory&#xff0c;它充当数据存储源的代理&#xff0c;…

线程的运行状态

不管是多线程还是多进程&#xff0c;实际上都不太可能一直占用CPU资源&#xff0c;所有多线程的几种状态一定要掌握。 多线程的状态如下图&#xff1a; 所有的系统费资源是有限的&#xff0c;不管是多线程还是多进程都必须在执行一段时间后让出资源&#xff0c;交由其他的线程…