博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
模拟实现一个秒杀减库存的案例
阅读量:6219 次
发布时间:2019-06-21

本文共 4814 字,大约阅读时间需要 16 分钟。

hot3.png

需求:

对商品秒杀,每个用户只能对一个商品买一次

实现思路:

设计三个表,商品详情表,商品总数表,用户订单表

插入订单表和更新总数表放到一个事务里边,更新j库存总数时,受影响行数小于等于0的时候,事务回滚;

对订单表的(user_id,goods_id)加唯一索引,一个用户只能买一笔商品,如果插入的时候报错,事务回滚;

//开启事务

//更新库存数量

update goods set goods_num=goods_num-1  where goods_id=$goods_id and goods_num>0 ;

if(受影响行数<=0)
    抛异常,商品秒完了,回滚。。。

//插入订单

insert into goods_order。。。
if(唯一索引报错?)
    抛异常,已经秒过了,回滚。。。
//最后提交事务

数据库设计:

商品详情表:

DROP TABLE IF EXISTS `goods`;CREATE TABLE `goods` (  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',  `goods_name` varchar(50) NOT NULL,  `add_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,  PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='商品详情表';-- ------------------------------ Records of goods-- ----------------------------INSERT INTO `goods` VALUES ('1', '笔记本', '2016-04-27 10:24:48');

商品总数表:

DROP TABLE IF EXISTS `goods_num`;CREATE TABLE `goods_num` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `goods_id` int(11) NOT NULL COMMENT '货品ID',  `goods_num` int(11) NOT NULL COMMENT '商品总数',  PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='商品总数表';-- ------------------------------ Records of goods_num-- ----------------------------INSERT INTO `goods_num` VALUES ('1', '1', '3');

用户订单表:

DROP TABLE IF EXISTS `goods_order`;CREATE TABLE `goods_order` (  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '订单ID',  `goods_id` int(11) NOT NULL COMMENT '商品ID',  `user_id` int(11) NOT NULL COMMENT '用户ID',  PRIMARY KEY (`id`),  UNIQUE KEY `good_user` (`goods_id`,`user_id`)) ENGINE=InnoDB AUTO_INCREMENT=409 DEFAULT CHARSET=utf8 COMMENT='订单表';

具体实现代码:

package class10;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.SQLException;import java.sql.Statement;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class SnapUp {	/**	 * 	 * 功能说明:数据库连接	 *	 * @return	 *	 */	private static Connection getConn() {		String driver = "com.mysql.jdbc.Driver";		String url = "jdbc:mysql://localhost:3306/study";		String username = "root";		String password = "123456";		Connection conn = null;		try {			Class.forName(driver); //classLoader,加载对应驱动			conn = (Connection) DriverManager.getConnection(url, username, password);		} catch (ClassNotFoundException e) {			e.printStackTrace();		} catch (SQLException e) {			e.printStackTrace();		}		return conn;	}	/**	 * 功能说明:秒杀抢购	 * @param goodsId 商品ID	 * @param userId 用户ID	 *	 */	public static void snapUp(int goodsId, int userId) {		Connection conn = getConn();		Statement stmt = null;		PreparedStatement pst = null;		try {			stmt = conn.createStatement();			//首先,.设置事务的提交方式为非自动提交			conn.setAutoCommit(false);			//更新库存			String sqlUpdate = "update goods_num set goods_num=goods_num-1 where goods_id=" + goodsId					+ " and goods_num>0";			pst = conn.prepareStatement(sqlUpdate);			int count = pst.executeUpdate();			if (count <= 0) {				System.out.println("货物已经被抢空了,明天再来吧");				throw new RuntimeException();			}			// 插入订单			String sqlOrder = "insert into goods_order(goods_id,user_id)values(?,?)";			pst = conn.prepareStatement(sqlOrder);			pst.setInt(1, goodsId);			pst.setInt(2, userId);			pst.executeUpdate();			System.out.println("用户:" + userId + "抢购货物:" + goodsId + "成功!");			conn.commit();		} catch (Exception e) {			System.out.println("用户:" + userId + "抢购货物:" + goodsId + "失败!");			try {				//.在catch块内添加回滚事务,表示操作出现异常,撤销事务:				conn.rollback();			} catch (SQLException e1) {				//e1.printStackTrace();			}			//e.printStackTrace();		} finally {			try {				//设置事务提交方式为自动提交				conn.setAutoCommit(true);				stmt.close();				conn.close();			} catch (SQLException e) {				e.printStackTrace();			}		}	}	public static void main(String[] args) {		// 线程池		ExecutorService exec = Executors.newCachedThreadPool();		// 模拟50个客户端访问		for (int index = 0; index < 50; index++) {			final int userId = index / 9;			Runnable run = new Runnable() {				public void run() {					snapUp(1, userId);				}			};			exec.execute(run);		}		// 退出线程池		exec.shutdown();	}}

结果:

用户:4抢购货物:1成功!用户:3抢购货物:1成功!用户:1抢购货物:1成功!用户:5抢购货物:1失败!用户:5抢购货物:1失败!用户:3抢购货物:1失败!用户:1抢购货物:1失败!用户:1抢购货物:1失败!用户:4抢购货物:1失败!用户:3抢购货物:1失败!用户:1抢购货物:1失败!用户:1抢购货物:1失败!用户:1抢购货物:1失败!用户:3抢购货物:1失败!用户:1抢购货物:1失败!用户:1抢购货物:1失败!用户:3抢购货物:1失败!用户:3抢购货物:1失败!用户:3抢购货物:1失败!用户:4抢购货物:1失败!用户:1抢购货物:1失败!用户:4抢购货物:1失败!用户:3抢购货物:1失败!用户:4抢购货物:1失败!用户:3抢购货物:1失败!用户:4抢购货物:1失败!用户:4抢购货物:1失败!用户:4抢购货物:1失败!用户:0抢购货物:1失败!用户:4抢购货物:1失败!用户:2抢购货物:1失败!用户:2抢购货物:1失败!用户:0抢购货物:1失败!用户:2抢购货物:1失败!用户:0抢购货物:1失败!用户:2抢购货物:1失败!用户:0抢购货物:1失败!用户:2抢购货物:1失败!用户:0抢购货物:1失败!用户:0抢购货物:1失败!用户:2抢购货物:1失败!用户:0抢购货物:1失败!用户:0抢购货物:1失败!用户:0抢购货物:1失败!用户:2抢购货物:1失败!用户:2抢购货物:1失败!用户:2抢购货物:1失败!用户:5抢购货物:1失败!用户:5抢购货物:1失败!用户:5抢购货物:1失败!

最后查看goods_num表,总数变为0, goods_order里边有3条不重复的用户订单记录,说明只有独立的三个人抢购成功。

借鉴了http://www.tuicool.com/articles/Bfa63e6

转载于:https://my.oschina.net/ydsakyclguozi/blog/666920

你可能感兴趣的文章
我的友情链接
查看>>
ToRPC:一个双向RPC的Python实现
查看>>
我的友情链接
查看>>
nginx在reload时候报错invalid PID number
查看>>
神经网络和深度学习-第二周神经网络基础-第二节:Logistic回归
查看>>
Myeclipse代码提示及如何设置自动提示
查看>>
c/c++中保留两位有效数字
查看>>
ElasticSearch 2 (32) - 信息聚合系列之范围限定
查看>>
VS2010远程调试C#程序
查看>>
[MicroPython]TurniBit开发板DIY自动窗帘模拟系统
查看>>
由String类的Split方法所遇到的两个问题
查看>>
Python3.4 12306 2015年3月验证码识别
查看>>
从Handler.post(Runnable r)再一次梳理Android的消息机制(以及handler的内存泄露)
查看>>
自制操作系统Antz day11——实现shell(下)命令响应
查看>>
windows查看端口占用
查看>>
strongswan ikev2 server on ubuntu 14.04
查看>>
Yii用ajax实现无刷新检索更新CListView数据
查看>>
JDBC的事务
查看>>
Io流的概述
查看>>
js功能实现top轮播图
查看>>