基于mysql樂觀鎖實現(xiàn)秒殺的示例代碼
說明
如果你的項目流量非常小,完全不用擔(dān)心有并發(fā)的購買請求,那么做這樣一個系統(tǒng)意義不大。但如果你的系統(tǒng)要像12306那樣,接受高并發(fā)訪問和下單的考驗,那么你就需要一套完整的流程保護(hù)措施,來保證你系統(tǒng)在用戶流量高峰期不會被搞掛了。
進(jìn)階redis+mq實現(xiàn):參考springboot + rabbitmq + redis實現(xiàn)秒殺
嚴(yán)格防止超賣
保證用戶體驗:高并發(fā)下,別網(wǎng)頁打不開了,支付不成功了,購物車進(jìn)不去了,地址改不了了
防止黑產(chǎn):防止不懷好意的人群通過各種技術(shù)手段把你本該下發(fā)給群眾的利益全收入了囊中
具體實現(xiàn)
1、核心
mysql樂觀鎖防止超賣
樂觀鎖是指操作數(shù)據(jù)庫時(更新操作),想法很樂觀,認(rèn)為這次的操作不會導(dǎo)致沖突,在操作數(shù)據(jù)時,并不進(jìn)行任何其他的特殊處理(也就是不加鎖),而在進(jìn)行更新后,再去判斷是否有沖突了。
這里是引用通常實現(xiàn)是這樣的:在表中的數(shù)據(jù)進(jìn)行操作時(更新),先給數(shù)據(jù)表加一個版本(version)字段,每操作一次,將那條記錄的版本號加1。也就是先查詢出那條記錄,獲取出version字段,如果要對那條記錄進(jìn)行操作(更新),則先判斷此刻version的值是否與剛剛查詢出來時的version的值相等,如果相等,則說明這段期間,沒有其他程序?qū)ζ溥M(jìn)行操作,則可以執(zhí)行更新,將version字段的值加1;如果更新時發(fā)現(xiàn)此刻的version值與剛剛獲取出來的version的值不相等,則說明這段期間已經(jīng)有其他程序?qū)ζ溥M(jìn)行操作了,則不進(jìn)行更新操作。
2、建表語句
stock商品表
-- ---------------------------- -- Table structure for stock -- ---------------------------- DROP TABLE IF EXISTS `stock`; CREATE TABLE `stock` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL DEFAULT '' COMMENT '名稱', `count` int(11) NOT NULL COMMENT '庫存', `sale` int(11) NOT NULL COMMENT '已售', `version` int(11) NOT NULL COMMENT '樂觀鎖,版本號', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
初始化數(shù)據(jù):
stock_order訂單表
-- ---------------------------- -- Table structure for stock_order -- ---------------------------- DROP TABLE IF EXISTS `stock_order`; CREATE TABLE `stock_order` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `sid` int(11) NOT NULL COMMENT '庫存ID', `name` varchar(30) NOT NULL DEFAULT '' COMMENT '商品名稱', `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '創(chuàng)建時間', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
3、業(yè)務(wù)流程
代碼實現(xiàn)
1、pom
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--mysql--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--druid--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.2.0</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.8</version> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>5.8.2</version> <scope>test</scope> </dependency>
2、model
可通過逆向工程進(jìn)行配置,參考idea+mybatis逆向工程
4、dao
public interface StockMapper { Stock checkStock(Integer id);//校驗庫存 int updateSale(Stock stock);//扣除庫存 }
public interface StockOrderMapper { //創(chuàng)建訂單 void createOrder(StockOrder order); }
5、sql
商品校驗和減庫存
<select id="checkStock" parameterType="java.lang.Integer" resultType="com.yy.msserver.model.vo.Stock"> select * from stock where id = #{id} </select> <update id="updateSale" parameterType="com.yy.msserver.model.vo.Stock" > update stock set sale = #{sale,jdbcType=INTEGER} + 1, version = #{version,jdbcType=INTEGER} + 1, count = #{count,jdbcType=INTEGER} - 1 where id = #{id,jdbcType=INTEGER} AND count > 0 AND version = #{version} </update>
下訂單
<insert id="createOrder" parameterType="com.yy.msserver.model.vo.StockOrder"> insert into stock_order (sid, name, create_time) values (#{sid,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{createTime,jdbcType=TIMESTAMP}) </insert>
6、service
public interface StockOrderService { public Integer createOrder(Integer id); }
7、實現(xiàn)
/** * @author code * @Date 2022/6/24 9:25 * Description 訂單實現(xiàn) * Version 1.0 */ @Service public class StockOrderServiceImpl implements StockOrderService { @Autowired private StockOrderMapper stockOrderMapper; @Autowired private StockMapper stockMapper; @Override @Transactional(rollbackFor = Exception.class) public Integer createOrder(Integer id) { //校驗庫存 Stock stock = checkStock(id); if(stock.getCount()>0){ System.out.println("當(dāng)前庫存:" + stock.getCount()); //扣庫存 if(updateSale(stock) == 1){ return createOrder(stock); }else { return 0; } } return 0; } //校驗庫存 private Stock checkStock(Integer id) { return stockMapper.checkStock(id); } //扣庫存 private int updateSale(Stock stock){ return stockMapper.updateSale(stock); } //下訂單 private Integer createOrder(Stock stock){ StockOrder order = new StockOrder(); order.setSid(stock.getId()); order.setCreateTime(new Date()); order.setName(stock.getName()); stockOrderMapper.createOrder(order); return order.getId(); } }
8、測試
模擬100人參與活動
@SpringBootTest class MsServerApplicationTests { @Autowired private StockOrderService stockOrderService; @Test void contextLoads() throws InterruptedException { // 庫存初始化為10,這里通過CountDownLatch和線程池模擬100個并發(fā) int threadTotal = 100; ExecutorService executorService = Executors.newCachedThreadPool(); final CountDownLatch countDownLatch = new CountDownLatch(threadTotal); for (int i = 0; i < threadTotal ; i++) { int uid = i; executorService.execute(() -> { try { stockOrderService.createOrder(1); } catch (Exception e) { e.printStackTrace(); } countDownLatch.countDown(); }); } countDownLatch.await(); executorService.shutdown(); } }
9、結(jié)果
商品表
訂單表
到此這篇關(guān)于基于mysql樂觀鎖實現(xiàn)秒殺的示例代碼的文章就介紹到這了,更多相關(guān)mysql樂觀鎖秒殺內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
mysql數(shù)據(jù)庫常見基本操作實例分析【創(chuàng)建、查看、修改及刪除數(shù)據(jù)庫】
這篇文章主要介紹了mysql數(shù)據(jù)庫常見基本操作,結(jié)合實例形式分析了mysql創(chuàng)建、查看、修改及刪除數(shù)據(jù)庫實現(xiàn)方法與操作注意事項,需要的朋友可以參考下2020-04-04VS2019連接mysql8.0數(shù)據(jù)庫的教程圖文詳解
這篇文章主要介紹了VS2019連接mysql8.0數(shù)據(jù)庫的教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-05-05MySQL實現(xiàn)批量更新不同表中的數(shù)據(jù)
這篇文章主要介紹了MySQL實現(xiàn)批量更新不同表中的數(shù)據(jù),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-05-05