mysql乐观锁 秒杀_redis 乐观锁实践秒杀

需求:有一个标(理解成抢红包也行,accountBalance预赋值1000元),大家可以抢购,每个用户抢购成功后,更新最后标的总数,在并发情况下,使用redis的乐观锁,保证更新标总值正确性,先往redis放一个标的金额:

set accountBalance "1000"

实现方式如下:

pom.xml

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

mybatisPage

page

1.0-SNAPSHOT

war

PageHelperSample

http://git.oschina.net/free/Mybatis-Sample

UTF-8

jstl

jstl

1.1.2

taglibs

standard

1.1.2

commons-pool

commons-pool

1.6

org.slf4j

slf4j-log4j12

1.7.5

org.slf4j

slf4j-api

1.7.5

com.alibaba

fastjson

1.2.5

com.alibaba

fastjson

1.2.4

javax.servlet

servlet-api

2.5

provided

javax.servlet.jsp

jsp-api

2.1

provided

taglibs

standard

1.1.2

javax.servlet

jstl

1.2

com.github.pagehelper

pagehelper

3.7.4

com.github.jsqlparser

jsqlparser

0.9.1

junit

junit

4.11

test

log4j

log4j

1.2.17

org.mybatis

mybatis

3.2.5

org.apache.commons

commons-lang3

3.1

mysql

mysql-connector-java

5.1.35

redis.clients

jedis

2.1.0

jar

org.apache.maven.plugins

maven-compiler-plugin

1.6

1.6

utf-8

org.mortbay.jetty

jetty-maven-plugin

8.0.0.M3

web.xml

xmlns="http://java.sun.com/xml/ns/javaee"

xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"

version="3.0">

index.jsp

bid

com.heli.mybatis.page.servlet.ReidsMatchServlet

bid

/bid

list

com.heli.mybatis.page.servlet.ReidsMatchListServlet

list

/list

servlet

package com.heli.mybatis.page.servlet;

import java.io.IOException;

import java.util.List;

import java.util.Random;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;

import com.commnon.RedisAPI;

import redis.clients.jedis.Jedis;

import redis.clients.jedis.JedisPool;

import redis.clients.jedis.Transaction;

public class ReidsMatchServlet extends HttpServlet {

public static JedisPool pool = RedisAPI.getPool();

// RedisAPI.set("accountBalance", "999999999");// 标还剩999999999块钱

private static final long serialVersionUID = 1L;

protected void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

Jedis jedis = pool.getResource();

long start = System.currentTimeMillis();

int flag = 0;

try {

flag = bid(request, response, jedis);

} catch (Exception e) {

e.printStackTrace();

response.getWriter().write("fail buy");

} finally {

pool.returnBrokenResource(jedis);

RedisAPI.returnResource(pool, jedis);

}

if (flag == 1) {

response.getWriter().write("success buy");

} else if (flag == 2) {

response.getWriter().write("have buy");

} else if (flag == 0) {

response.getWriter().write("bid is zero ,you can not buy");

}else{

response.getWriter().write("fail buy");

}

long end = System.currentTimeMillis();

System.out.println("--------------------------------------------请求耗时:" + (end - start) + "毫秒");

}

protected void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

private int bid(HttpServletRequest request, HttpServletResponse response, Jedis jedis) throws Exception {

int flag = 0;// 1,成功,2已经购买,3已经没钱了,其他異常

// 每个请求对应一个userId

int userId = new Random().nextInt(999999);

// 观察 总标值,每人抢购一元

while ("OK".equals(jedis.watch("accountBalance"))) {

// 判断是否购买过

Boolean isBuy = RedisAPI.sismember("userIdSet", userId + "");

if (isBuy) {

flag = 2;

return flag;

}

//投资额

int r = 1;// new Random().nextInt(2);

int lastAccount = 0;

String balance = RedisAPI.get("accountBalance");

if (StringUtils.isNotBlank(balance)) {

lastAccount = Integer.valueOf(balance) - r;

}

if (lastAccount 

flag = 3;

break;

}

Transaction tx = jedis.multi();

tx.set("accountBalance", lastAccount + "");

List result = tx.exec();

if (result == null || result.isEmpty()) {

jedis.unwatch();

} else {

System.out.println("恭喜您," + userId + "已经中标" + r + "元,标余额" + lastAccount + "元");

RedisAPI.set(Thread.currentThread().getName(), r + "");

RedisAPI.sadd("userIdSet", userId + "");

flag = 1;

break;

}

}

return flag;

}

}

package com.heli.mybatis.page.servlet;

import java.io.IOException;

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map;

import java.util.Set;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import com.commnon.RedisAPI;

import redis.clients.jedis.Jedis;

import redis.clients.jedis.JedisPool;

public class ReidsMatchListServlet extends HttpServlet {

public static JedisPool pool= RedisAPI.getPool();;

public static Jedis jedis;

static {

jedis = pool.getResource();

}

private static final long serialVersionUID = 1L;

protected void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

list(request, response);

try {

response.sendRedirect("list.jsp");

} catch (IOException e) {

e.printStackTrace();

}

}

protected void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

private void list(HttpServletRequest request, HttpServletResponse response) {

Set set = jedis.smembers("userIdSet");

Iterator ite = set.iterator();

System.out.println("中标名单-------------------------");

int i = 0;

Map map = new HashMap();

while (ite.hasNext()) {

i++;

Object obj1 = ite.next();

System.out.println("第" + i + "名:" + obj1);

map.put("第" + i + "名:", obj1 + "");

}

request.getSession().setAttribute("user", map);

System.out.println("中标名单-------------------------");

}

}

工具类

package com.commnon;

import java.util.ResourceBundle;

import redis.clients.jedis.Jedis;

import redis.clients.jedis.JedisPool;

import redis.clients.jedis.JedisPoolConfig;

/**

* Redis操作接口

*

* @author 林计钦

* @version 1.0 2013-6-14 上午08:54:14

*/

public class RedisAPI {

private static JedisPool pool = null;

private static ThreadLocal poolThreadLocal = new ThreadLocal();

/**

* 构建redis连接池

*

* @param ip

* @param port

* @return JedisPool

*/

public static JedisPool getPool() {

if (pool == null) {

ResourceBundle bundle = ResourceBundle.getBundle("redis");

if (bundle == null) {

throw new IllegalArgumentException(

"[redis.properties] is not found!");

}

JedisPoolConfig config = new JedisPoolConfig();

config.setMaxActive(Integer.valueOf(bundle

.getString("redis.pool.maxActive")));

config.setMaxIdle(Integer.valueOf(bundle

.getString("redis.pool.maxIdle")));

config.setMaxWait(Long.valueOf(bundle.getString("redis.pool.maxWait")));

config.setTestOnBorrow(Boolean.valueOf(bundle

.getString("redis.pool.testOnBorrow")));

config.setTestOnReturn(Boolean.valueOf(bundle

.getString("redis.pool.testOnReturn")));

pool = new JedisPool(config, bundle.getString("redis.ip"),

Integer.valueOf(bundle.getString("redis.port")));

}

return pool;

}

public static JedisPool getConnection() {

// ②如果poolThreadLocal没有本线程对应的JedisPool创建一个新的JedisPool,将其保存到线程本地变量中。

if (poolThreadLocal.get() == null) {

pool = RedisAPI.getPool();

poolThreadLocal.set(pool);

return pool;

} else {

return poolThreadLocal.get();// ③直接返回线程本地变量

}

}

/**

* 返还到连接池

*

* @param pool

* @param redis

*/

public static void returnResource(JedisPool pool, Jedis redis) {

if (redis != null) {

pool.returnResource(redis);

}

}

/**

* 获取数据

*

* @param key

* @return

*/

public static String get(String key) {

String value = null;

JedisPool pool = null;

Jedis jedis = null;

try {

pool = getPool();

jedis = pool.getResource();

value = jedis.get(key);

} catch (Exception e) {

e.printStackTrace();

} finally {

// 释放redis对象

pool.returnBrokenResource(jedis);

// 返还到连接池

returnResource(pool, jedis);

}

return value;

}

/**

* 赋值数据

*

* @param key

* @return

*/

public static String set(String key, String value) {

String result = null;

JedisPool pool = null;

Jedis jedis = null;

try {

pool = getPool();

jedis = pool.getResource();

result = jedis.set(key, value);

} catch (Exception e) {

e.printStackTrace();

} finally {

// 释放redis对象

pool.returnBrokenResource(jedis);

// 返还到连接池

returnResource(pool, jedis);

}

return result;

}

/**

* 赋值数据

*

* @param key

* @return

*/

public static Long sadd(String key, String value) {

Long result = null;

JedisPool pool = null;

Jedis jedis = null;

try {

pool = getPool();

jedis = pool.getResource();

result = jedis.sadd(key, value);

} catch (Exception e) {

e.printStackTrace();

} finally {

// 释放redis对象

pool.returnBrokenResource(jedis);

// 返还到连接池

returnResource(pool, jedis);

}

return result;

}

/**

* 判断set中是否有值

*

* @param key

* @return

*/

public static Boolean sismember(String key, String member) {

Boolean result = null;

JedisPool pool = null;

Jedis jedis = null;

try {

pool = getPool();

jedis = pool.getResource();

result = jedis.sismember(key, member);

} catch (Exception e) {

e.printStackTrace();

} finally {

// 释放redis对象

pool.returnBrokenResource(jedis);

// 返还到连接池

returnResource(pool, jedis);

}

return result;

}

}

redis.properties

#\u6700\u5927\u5206\u914d\u7684\u5bf9\u8c61\u6570

redis.pool.maxActive=1024

#\u6700\u5927\u80fd\u591f\u4fdd\u6301idel\u72b6\u6001\u7684\u5bf9\u8c61\u6570

redis.pool.maxIdle=200

#\u5f53\u6c60\u5185\u6ca1\u6709\u8fd4\u56de\u5bf9\u8c61\u65f6\uff0c\u6700\u5927\u7b49\u5f85\u65f6\u95f4

redis.pool.maxWait=1000

#\u5f53\u8c03\u7528borrow Object\u65b9\u6cd5\u65f6\uff0c\u662f\u5426\u8fdb\u884c\u6709\u6548\u6027\u68c0\u67e5

redis.pool.testOnBorrow=true

#\u5f53\u8c03\u7528return Object\u65b9\u6cd5\u65f6\uff0c\u662f\u5426\u8fdb\u884c\u6709\u6548\u6027\u68c0\u67e5

redis.pool.testOnReturn=true

#IP

redis.ip=127.0.0.1

#Port

redis.port=6379

bid.jsp

pageEncoding="utf-8"%>

html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

抢标秒杀

* {

margin: 0;

}

html, body {

height: 100%;

}

.wrapper {

min-height: 100%;

height: auto !important;

height: 100%;

margin: 0 auto -155px;

}

.footer, .push {

height: 155px;

}

.middle {

text-align: center;

margin: 0 auto;

width: 600px;

height: auto;

}

秒标

style="width: 600px; height: 200px" value="秒杀" /> 

type="submit" style="width: 200px; height: 50px" value="查看秒杀结果" />

list.jsp

pageEncoding="utf-8"%>

html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

抢标秒杀

* {

margin: 0;

}

html, body {

height: 100%;

}

.wrapper {

min-height: 100%;

height: auto !important;

height: 100%;

margin: 0 auto -155px;

}

.footer, .push {

height: 155px;

}

.middle {

text-align: center;

margin: 0 auto;

width: 600px;

height: auto;

}

java.util.Map mapBean = (java.util.Map) request.getSession()

.getAttribute("user");

%>

中奖名单

if (mapBean != null) {

%>

}

%>

if (mapBean != null) {

for (String key : mapBean.keySet()) {

%>

--

}

}

%>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值