• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

redis 乐观锁实践秒杀

php 搞代码 4年前 (2022-01-04) 23次浏览 已收录 0个评论

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

set accountBalance "1000"

实现方式如下:

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">	<modelVersion>4.0.0</modelVersion>	<groupId>mybatisPage</groupId>	<artifactId>page</artifactId>	<version>1.0-SNAPSHOT</version>	<packaging>war</packaging>	<name>PageHelperSample</name>	<url>http://git.oschina.net/free/Mybatis-Sample</url>	<properties>		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>	</properties>	<dependencies>		<!-- jstl -->		<dependency>			<groupId>jstl</groupId>			<artifactId>jstl</artifactId>			<version>1.1.2</version>		</dependency>		<dependency>			<groupId>taglibs</groupId>			<artifactId>standard</artifactId>			<version>1.1.2</version>		</dependency>		<!-- jstl -->		<dependency>			<groupId>commons-pool</groupId>			<artifactId>commons-pool</artifactId>			<version>1.6</version>		</dependency>		<!-- log mybatis sql -->		<dependency>			<groupId>org.slf4j</groupId>			<artifactId>slf4j-log4j12</artifactId>			<version>1.7.5</version>		</dependency>		<dependency>			<groupId>org.slf4j</groupId>			<artifactId>slf4j-api</artifactId>			<version>1.7.5</version>		</dependency>		<!-- log mybatis sql -->		<!-- fastjson -->		<dependency>			<groupId>com.alibaba</groupId>			<artifactId>fastjson</artifactId>			<version>1.2.5</version>		</dependency>		<dependency>			<groupId>com.alibaba</groupId>			<artifactId>fastjson</artifactId>			<version>1.2.4</version>		</dependency>		<!-- web -->		<dependency>			<groupId>javax.servlet</groupId>			<artifactId>servlet-api</artifactId>			<version>2.5</version>			<scope>provided</scope>		</dependency>		<dependency>			<groupId>javax.servlet.jsp</groupId>			<artifactId>jsp-api</artifactId>			<version>2.1</version>			<scope>provided</scope>		</dependency>		<dependency>			<groupId>taglibs</groupId>			<artifactId>standard</artifactId>			<version>1.1.2</version>		</dependency>		<dependency>			<groupId>javax.servlet</groupId>			<artifactId>jstl</artifactId>			<version>1.2</version>		</dependency>		<dependency>			<groupId>com.github.pagehelper</groupId>			<artifactId>pagehelper</artifactId>			<version>3.7.4</version>		</dependency>		<dependency>			<groupId>com.github.jsqlparser</groupId>			<artifactId>jsqlparser</artifactId>			<version>0.9.1</version>		</dependency>		<dependency>			<groupId>junit</groupId>			<artifactId>junit</artifactId>			<version>4.11</version>			<scope>test</scope>		</dependency>		<dependency>			<groupId>log4j</groupId>			<artifactId>log4j</artifactId>			<version>1.2.17</version>		</dependency>		<dependency>			<groupId>org.mybatis</groupId>			<artifactId>mybatis</artifactId>			<version>3.2.5</version>		</dependency>		<!-- util -->		<dependency>			<groupId>org.apache.commons</groupId>			<artifactId>commons-lang3</artifactId>			<version>3.1</version>		</dependency>		<!-- mysql -->		<dependency>			<groupId>mysql</groupId>			<artifactId>mysql-connector-java</artifactId>			<version>5.1.35</version>		</dependency>		<!-- redis -->		<dependency>			<groupId>redis.clients</groupId>			<artifactId>jedis</artifactId>			<version>2.1.0</version>			<type>jar</type>		</dependency>	</dependencies>	<build>		<plugins>			<plugin>				<groupId>org.apache.maven.plugins</groupId>				<artifactId>maven-compiler-plugin</artifactId>				<configuration>					<source>1.6</source>					<target>1.6</target>					<encoding>utf-8</encoding>				</configuration>			</plugin>			<plugin>				<groupId>org.mortbay.jetty</groupId>				<artifactId>jetty-maven-plugin</artifactId>				<version>8.0.0.M3</version>			</plugin>		</plugins>	</build></project>

web.xml

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"	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">	<welcome-file-list>		<welcome-file>index.jsp</welcome-file>	</welcome-file-list>		<servlet>		<servlet-name>bid</servlet-name>		<servlet-class>com.heli.mybatis.page.servlet.ReidsMatchServlet</servlet-class>	</servlet>	<servlet-mapping>		<servlet-<i style="color:transparent">来源gaodai$ma#com搞$代*码网</i>name>bid</servlet-name>		<url-pattern>/bid</url-pattern>	</servlet-mapping>	<servlet>		<servlet-name>list</servlet-name>		<servlet-class>com.heli.mybatis.page.servlet.ReidsMatchListServlet</servlet-class>	</servlet>	<servlet-mapping>		<servlet-name>list</servlet-name>		<url-pattern>/list</url-pattern>	</servlet-mapping></web-app>

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 < 0) {				flag = 3;				break;			}			Transaction tx = jedis.multi();			tx.set("accountBalance", lastAccount + "");			List<Object> 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<String, String> map = new HashMap<String, String>();		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<JedisPool> poolThreadLocal = new ThreadLocal<JedisPool>();	/**	 * 构建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\u6570redis.pool.maxActive=1024#\u6700\u5927\u80fd\u591f\u4fdd\u6301idel\u72b6\u6001\u7684\u5bf9\u8c61\u6570redis.pool.maxIdle=200#\u5f53\u6c60\u5185\u6ca1\u6709\u8fd4\u56de\u5bf9\u8c61\u65f6\uff0c\u6700\u5927\u7b49\u5f85\u65f6\u95f4redis.pool.maxWait=1000#\u5f53\u8c03\u7528borrow Object\u65b9\u6cd5\u65f6\uff0c\u662f\u5426\u8fdb\u884c\u6709\u6548\u6027\u68c0\u67e5redis.pool.testOnBorrow=true#\u5f53\u8c03\u7528return Object\u65b9\u6cd5\u65f6\uff0c\u662f\u5426\u8fdb\u884c\u6709\u6548\u6027\u68c0\u67e5redis.pool.testOnReturn=true#IPredis.ip=127.0.0.1#Portredis.port=6379

bid.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"	pageEncoding="utf-8"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>抢标秒杀</title><style type="text/css">* {	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></head><body>	<form name="formBid" action="bid" method="get">		<div class="wrapper">			<div class="middle">				<h1 style="padding: 0px 0 10px;">秒标</h1>				<br> <br> <br> <br> <br> <br> <br>				<br> <br> <br> <input type="submit"					style="width: 600px; height: 200px" value="秒杀" /> <br> <br>				<br> <br> <br>			</div>		</div>	</form>	<form name="formList" action="list" method="post">		<div class="wrapper">			<div class="middle">				<br> <br> <br> <br> <br> <input					type="submit" style="width: 200px; height: 50px" value="查看秒杀结果" />			</div>		</div>	</form></body></html>

list.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"	pageEncoding="utf-8"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>抢标秒杀</title><style type="text/css">* {	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></head><body>	<%		java.util.Map<String, String> mapBean = (java.util.Map<String, String>) request.getSession()				.getAttribute("user");	%>	<form name="formList" action="list" method="post">		<div class="wrapper">			<div class="middle">				<br> <br> <br> <br> <br> <br> <br>				<br>				<h1 style="padding: 0px 0 10px;">					中奖名单<%					if (mapBean != null) {				%>					<%=mapBean.size()%></h1>				<%					}				%>				<br>				<%					if (mapBean != null) {						for (String key : mapBean.keySet()) {				%>				<%=key%>--<%=mapBean.get(key)%><br>				<%					}					}				%>			</div>		</div>	</form></body></html>

搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:redis 乐观锁实践秒杀

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址