MySQL悲观锁 select for update实现秒杀案例(jfinal框架)

发布时间:2018-08-17作者:laosun阅读(2069)

MySQL悲观锁

    为了方便测试,博主使用最新的jfinal框架,里边的东西就修改了一下a_little_config.txt,配置数据库链接的,启动直接打开DemoConfig.java,main方法启动即可(记得修改端口),这样就不用再去写jdbc了。感兴趣的朋友可以去了解一下:

    项目下载地址:Jfinal 3.4        本次测试例子下载 :jfinal_demo_for_maven.zip

    主要源码(模拟120人同时抢购100件商品):

    package com.demo.index;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    import com.jfinal.core.Controller;
    import com.jfinal.plugin.activerecord.Db;
    
    /**
     * 秒杀/MySQL 悲观锁实现方式
     * 
     * @author sun
     */
    public class SecKillForPLController extends Controller {
    	
    	public static int goodsTotalNum = 100;
    
    	public void index() {
    		//每一次新的请求都会模拟抢购100件商品,所以先恢复商品的数量,这个可以不要,也可以手动去更新数据库
    		Db.update("update t_goods set num = ? where id = 1", goodsTotalNum);
    		
    		SecKillPL sk = new SecKillPL();
    		// 模拟120个人抢购
    		for (int i = 1; i <= 120; i++) {
    			new Thread(sk, i + " 号人").start();
    		}
    		renderHtml("<center><h2>抢购成功!</h2></center>");
    	}
    }
    
    /**
     * 这里我们只是演示数据库悲观锁的实现方式,至于事务等其他的都不添加了。
     * 
     * @author sun
     */
    class SecKillPL implements Runnable {
    
    	@Override
    	public void run() {
    		Connection conn = null;
    		PreparedStatement ps = null;
    		try {
    			conn = Db.use().getConfig().getConnection();
    			conn.setAutoCommit(false);
    			ps = conn.prepareStatement("select * from t_goods where id = 1 for update");
    			ResultSet rs = ps.executeQuery();
    			Integer num = 0;
    			while (rs.next()) {
    				num = rs.getInt("num");
    			}
    			if (num > 0) {
    				PreparedStatement ps2 = conn.prepareStatement("update t_goods set num=num-1 where id = 1");
    				ps2.execute();
    				System.out.println(Thread.currentThread().getName() + " 抢到了第" + (SecKillForPLController.goodsTotalNum - num + 1) + "商品");
    				conn.commit();
    			}else{
    				System.err.println(Thread.currentThread().getName() + " 太悲剧了,没抢到商品...");
    			}
    		} catch (SQLException e1) {
    			e1.printStackTrace();
    		} finally {
    			try {
    				ps.close();
    			} catch (SQLException e) {}
    			try {
    				conn.close();
    			} catch (SQLException e) {}
    		}
    	}
    }

    代码里有些jfinal的东西,看不懂的不要紧,只要知道是操作sql就行。

    输出结果:

    3 号人 抢到了第1商品
    2 号人 抢到了第2商品
    1 号人 抢到了第3商品
    4 号人 抢到了第4商品
    9 号人 抢到了第5商品
    6 号人 抢到了第6商品
    5 号人 抢到了第7商品
    ......
    95 号人 抢到了第92商品
    94 号人 抢到了第93商品
    97 号人 抢到了第94商品
    98 号人 抢到了第95商品
    99 号人 抢到了第96商品
    100 号人 抢到了第97商品
    80 号人 抢到了第98商品
    83 号人 抢到了第99商品
    102 号人 抢到了第100商品
    96 号人 太悲剧了,没抢到商品...
    101 号人 太悲剧了,没抢到商品...
    103 号人 太悲剧了,没抢到商品...
    104 号人 太悲剧了,没抢到商品...
    105 号人 太悲剧了,没抢到商品...
    106 号人 太悲剧了,没抢到商品...
    107 号人 太悲剧了,没抢到商品...
    108 号人 太悲剧了,没抢到商品...
    109 号人 太悲剧了,没抢到商品...
    110 号人 太悲剧了,没抢到商品...
    111 号人 太悲剧了,没抢到商品...
    112 号人 太悲剧了,没抢到商品...
    113 号人 太悲剧了,没抢到商品...
    114 号人 太悲剧了,没抢到商品...
    115 号人 太悲剧了,没抢到商品...
    116 号人 太悲剧了,没抢到商品...
    117 号人 太悲剧了,没抢到商品...
    118 号人 太悲剧了,没抢到商品...
    119 号人 太悲剧了,没抢到商品...
    120 号人 太悲剧了,没抢到商品...

    t_goods表结构:

    CREATE TABLE `d_sunjs_test`.`t_goods`  (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      `num` int(11) NULL DEFAULT NULL,
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;


    下一篇文章: 用MySQL乐观锁来实现秒杀

5 +1

版权声明

 Java  源码  多线程

 请文明留言

0 条评论