需求:有一個標(理解成搶紅包也行,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-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 bid.jsp
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; } }
list.jsp
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("中标名单-------------------------"); } }