¸üÐÂʱ¼ä:2018Äê12ÔÂ13ÈÕ14ʱ24·Ö À´Ô´:ÀÖÓã²¥¿Í ä¯ÀÀ´ÎÊý:
¡¡¡¡Ò»¡¢Ç°ÑÔ1. Ãëɱ½éÉÜ
¡¡¡¡ÃëɱÊǵçÉÌϵͳ·Ç³£³£¼ûµÄ¹¦ÄÜÄ£¿é£¬ÊÇÉ̼ҽøÐÐÏà¹Ø´ÙÏúÍÆ¹ãµÄ³£Ó÷½Ê½¡£Ö÷ÒªÌØµãÊÇÉÌÆ·¿â´æÓÐÏÞ£¬ÇÀ¹ºÊ±¼äÓÐÏÞ¡£ÄÇôÔÚϵͳÉè¼ÆÖ®³õ¾ÍÓ¦¸Ã¿¼ÂÇÔÚÊýÁ¿ºÍʱ¼äÓÐÏÞµÄÇé¿öϵ¼ÖµÄÒ»¸ö¸ß²¢·¢ÒÔ¼°¸ß²¢·¢Ëù´øÀ´µÄ¿â´æ³¬ÂôµÄÎÊÌâ¡£
¡¡¡¡ÃëɱÐèÒª½â¾öµÄÎÊÌ⣺
¡¡¡¡1) ¿â´æ³¬Âô
¡¡¡¡½â¾ö·½°¸£º
¡¡¡¡1) ±¯¹ÛËø£ºsynchronize ¡¢ Lock
¡¡¡¡2) ÀÖ¹ÛËø£ºÊý¾Ý¿âÀÖ¹ÛËø°æ±¾ºÅ¿ØÖÆ
¡¡¡¡2) ¸ß²¢·¢Çé¿öÏÂϵͳѹÁ¦ÒÔ¼°Óû§ÌåÑé
¡¡¡¡½â¾ö·½°¸£º redis
¡¡¡¡±¾½Ì³Ì²ÉÓãºredisÖÐlistÀàÐÍ´ïµ½ÁîÅÆ»úÖÆÍê³ÉÃëɱ¡£Óû§ÇÀredisÖеÄÁîÅÆ£¬ÇÀµ½ÁîÅÆµÄÓû§²ÅÄܽøÐÐÖ§¸¶£¬Ö§¸¶³É¹¦Ö®ºó¿ÉÒÔÉú³É¶©µ¥£¬Èç¹ûÒ»¶¨Ê±¼äÖ®ÄÚûÓÐÖ§¸¶ÄÇô¾ÍÓɶ¨Ê±ÈÎÎñÀ´¹é»¹ÁîÅÆ
¡¡¡¡2. ¿ª·¢½éÉÜ
¡¡¡¡1) ¿ª·¢¹¤¾ß: IntelliJ IDEA2017.3.5
¡¡¡¡2) JDK°æ±¾£º1.7+
¡¡¡¡3) Êý¾Ý¿â£º mysql5.7 ¡¢ Redis
¡¡¡¡4) ¼¼Êõ£ºSpring¡¢Spring Data Redis¡¢mybatis
¡¡¡¡¶þ¡¢»·¾³´î½¨1. Êý¾Ý¿â±í´´½¨
/*ÉÌÆ·±í */CREATE TABLE `goods` ( `goods_id` int(11) NOT NULL AUTO_INCREMENT, `num` int(11) DEFAULT NULL, `goods_name` varchar(50) DEFAULT NULL, PRIMARY KEY (`goods_id`)) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;insert into `goods`(`goods_id`,`num`,`goods_name`) values (1,100,'iphone X'); /*¶©µ¥±í */CREATE TABLE `orders` ( `order_id` int(11) NOT NULL AUTO_INCREMENT, `good_id` int(11) DEFAULT NULL, `user` varchar(50) DEFAULT NULL, PRIMARY KEY (`order_id`)) ENGINE=InnoDB AUTO_INCREMENT=1163 DEFAULT CHARSET=utf8;¡¡2. redis°²×° ( ÂÔ )
¡¡3. ´´½¨mavneÏîÄ¿,´ò°ü·½Ê½jar,pom.xmlÈçÏÂ
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <junit.version>4.12</junit.version> <spring.version>4.2.4.RELEASE</spring.version> <pagehelper.version>4.0.0</pagehelper.version> <mybatis.version>3.2.8</mybatis.version> <mybatis.spring.version>1.2.2</mybatis.spring.version> <mybatis.paginator.version>1.2.15</mybatis.paginator.version> <mysql.version>5.1.32</mysql.version> <druid.version>1.0.9</druid.version></properties><dependencies> <!-- Spring --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jms</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.9</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.28</version> </dependency> <dependency> <groupId>javassist</groupId> <artifactId>javassist</artifactId> <version>3.11.0.GA</version> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.10</version> </dependency> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>${pagehelper.version}</version> </dependency> <!-- Mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>${mybatis.version}</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>${mybatis.spring.version}</version> </dependency> <dependency> <groupId>com.github.miemiedev</groupId> <artifactId>mybatis-paginator</artifactId> <version>${mybatis.paginator.version}</version> </dependency> <!-- MySql --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <!-- Á¬½Ó³Ø --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>${druid.version}</version> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.8.1</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.7.2.RELEASE</version> </dependency> <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>xml-apis</groupId> <artifactId>xml-apis</artifactId> <version>1.4.01</version> </dependency></dependencies>¡¡¡¡4. Êý¾Ý·ÃÎʲã
¡¡¡¡ÀûÓÃmybatisÄæÏò¹¤³ÌÉú³ÉPOJO£¬ÒÔ¼°mapper½Ó¿ÚºÍmapperÓ³ÉäÎļþ¡£¸Ã²¿·Ö×ÔÐвÙ×÷
¡¡¡¡mybatisºËÐÄÅäÖÃÎļþSqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration> <plugins> <!-- com.github.pagehelper Ϊ PageHelper ÀàËùÔÚ°üÃû --> <plugin interceptor="com.github.pagehelper.PageHelper"> <!-- ÉèÖÃÊý¾Ý¿âÀàÐÍ Oracle,Mysql,MariaDB,SQLite,Hsqldb,PostgreSQL ÁùÖÖÊý¾Ý¿â--> <property name="dialect" value="mysql"/> </plugin> </plugins></configuration>jdbc.driver=com.mysql.jdbc.Driverjdbc.url=jdbc:mysql://localhost:3306/miaosha?characterEncoding=utf-8jdbc.username=rootjdbc.password=rootredisÅäÖÃÊôÐÔÎļþredis-config.propertiesproperties
# Redis settings # server IP redis.host=127.0.0.1 # server port redis.port=6379 # server pass redis.pass= # use dbIndex redis.database=0 redis.maxIdle=1000 redis.maxWait=3000¡¡¡¡5. springÅäÖÃÎļþ
¡¡¡¡applicationContext-dao.xml
<!-- ¼ÓÔØÅäÖÃÎļþ --> <context:property-placeholder location="classpath*:properties/*.properties" /> <!-- Êý¾Ý¿âÁ¬½Ó³Ø --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <property name="driverClassName" value="${jdbc.driver}" /> <property name="maxActive" value="10" /> <property name="minIdle" value="5" /> </bean> <!-- ÈÃspring¹ÜÀísqlsessionfactory ʹÓÃmybatisºÍspringÕûºÏ°üÖÐµÄ --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- Êý¾Ý¿âÁ¬½Ó³Ø --> <property name="dataSource" ref="dataSource" /> <!-- ¼ÓÔØmybatisµÄÈ«¾ÖÅäÖÃÎļþ --> <property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml" /> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.miaosha.demo.mapper" /> </bean>¡¡¡¡applicationContext-redis.xml
<context:property-placeholder location="classpath*:properties/*.properties" ignore-unresolvable="true" /> <!-- redis Ïà¹ØÅäÖà --> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxIdle" value="${redis.maxIdle}" /> <property name="maxTotal" value="2000" /> <property name="maxWaitMillis" value="${redis.maxWait}" /> <property name="testOnBorrow" value="true" /> </bean> <bean id="JedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.pass}" p:pool-config-ref="poolConfig"/> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <!--<!–¿ªÆôÊÂÎñÖ§³Ö–>--> <!--<property name="enableTransactionSupport" value="true"/>--> <property name="connectionFactory" ref="JedisConnectionFactory" /> <!-- ÐòÁл¯·½Ê½ ½¨Òékey/hashKey²ÉÓÃStringRedisSerializer¡£ --> <property name="keySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/> </property> <property name="hashKeySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/> </property> <property name="valueSerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/> </property> <property name="hashValueSerializer"> <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/> </property></bean>¡¡¡¡Èý¡¢´úÂëʵÏÖ
¡¡¡¡1.¶¨ÒåÃëɱҵÎñ½Ó¿Ú
/** * ÃëɱµÄ½Ó¿Ú */ public interface MiaoShaService { /** * ³õʼ»¯ËùÓÐÉÌÆ·µÄÁîÅÆ * @return */ public boolean initTokenToRedis(); /** * ÇÀ¹ºÁîÅÆ * @param goodsId * @param user * @param num * @return */ public boolean miaoshaTokenFromRedis(Integer goodsId,String user,Integer num); /** * Óû§Î´Ö§¸¶ ÍË»¹ÁîÅÆ * @param user * @return */ public boolean returnToken(String user); /** * Ö§¸¶Éú³É¶©µ¥±£´æµ½Êý¾Ý¿â * @param user * @return */ public boolean payTokenToOrder(String user); }¡¡¡¡2.ÃëɱҵÎñʵÏÖÀà
@Service public class MiaoShaServiceImpl implements MiaoShaService{ @Autowired private GoodsMapper goodsMapper; @Autowired private OrderMapper orderMapper; @Autowired RedisTemplate redisTemplate; @Override public boolean initTokenToRedis() { //²éѯËùÓÐÉÌÆ· //¸ù¾Ýʱ¼ä startTime<=now<=endTime //¸ù¾Ý״̬ ÒÑÉóºË״̬ List<Goods> goodsList= goodsMapper.selectByExample(null); for(Goods goods : goodsList){ for(int i=0;i<goods.getNum();i++) { //token_goods_1:[token_1_0,token_1_1,token_1_2 ... token_1_99] //token_goods_2:[token_2_0,token_2_1,token_2_2 ... token_2_99] redisTemplate.boundListOps("token_goods_" + goods.getGoodsId()).leftPush("token_" + goods.getGoodsId() + "_" +i); } } return false; } @Override public boolean miaoshaTokenFromRedis(Integer goodsId, String user, Integer num) { // »ñÈ¡ÁîÅÆ String token = (String)redisTemplate.boundListOps("token_goods_"+goodsId).rightPop(); if(token == null || token.equals("")){ return false; }else{ //¼Ç¼µ±Ç°Óû§ÒѾÇÀ¹ºµ½ÁîÅÆ£¬Ö¤Ã÷µ±Ç°Õâ¸öÓû§¿ÉÒÔȡ֧¸¶ //ÓÃredis¼Ç¼ String yes = (String)redisTemplate.boundValueOps(token).get(); if(yes != null && yes.equals("yes")) { System.out.println("µ±Ç°tokenÒѾ±»Ö§¸¶£¬²»ÄÜÔÙÇÀ¹º"); redisTemplate.boundListOps("token_goods_"+goodsId).remove(1,token); return false; } System.out.println(user); redisTemplate.boundHashOps("user_token").put(user,token); return true; } } @Override public boolean returnToken(String user) { //»ñµÃµ±Ç°Óû§µÄÁîÅÆ String token = (String) redisTemplate.boundHashOps("user_token").get(user); if(token == null || token.equals("")){ return false; }else { //µÃµ½ÉÌÆ·id String goodsId = token.split("_")[1]; redisTemplate.boundListOps("token_goods_"+goodsId).leftPush(token); return true; } } @Override public boolean payTokenToOrder(String user) { //»ñµÃµ±Ç°Óû§µÄÁîÅÆ String token = (String) redisTemplate.boundHashOps("user_token").get(user); if(token == null || token.equals("")){ return false; }else { //Èç¹ûÔÚµ±Ç°tokenÒѾ±»¹ºÂò¹ý£¬ÄÇô±ðÈ˾Ͳ»ÄÜÇÀµ±Ç°µÄtoken»òÕß²»ÄÜÔÙ¶Ô¸Ãtoken½øÐÐÖ§¸¶ //²ÉÓÃredis¼Ç¼µ±Ç°tokenÒѾ±»Ö§¸¶ //redisTemplate.boundValueOps("key").setIfAbsent("value") //Èç¹ûµ±Ç°Õâ¸ökeyÓÐÖµ£¬¸Ã·½·¨¾Í»á·µ»Øfalse,Èç¹ûûÓÐÖµ£¬¾Í»ásÉèÖÃΪ¶ÔÓ¦value£¬Í¬Ê±·µ»Øtrue boolean flag = redisTemplate.boundValueOps(token).setIfAbsent("yes"); //µ±Ç°tokenµÚÒ»´Î±»Ö§¸¶ flag=true if(flag) { //µÃµ½ÉÌÆ·id String goodsId = token.split("_")[1]; Order order = new Order(); order.setUser(user); order.setGoodId(Integer.parseInt(goodsId)); orderMapper.insert(order); //Óû§¸ÕºÃÔÚÖ§¸¶Ê±£¬¶¨Ê±ÈÎÎñÖ´ÐÐ redisTemplate.boundHashOps("user_token").delete(user);//ÓпÉÄÜÒѾ¹é»¹token redisTemplate.boundListOps("token_goods_" + goodsId).remove(1, token);//ÒÆ³ýtoken, ÓпÉÄܱ»±ðÈËÇÀµ½ } return true; } } }package com.miaosha.test; import com.miaosha.demo.service.MiaoShaService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:spring/applicationContext-*.xml"}) public class MiaoShaTest { @Autowired private MiaoShaService miaoShaService; //²¢·¢ÊýÁ¿ public static int bfCount = 1000; //¼Ç¼³É¹¦¸öÊý public int count =0; //¶àÏ̸߳¨ÖúÀ࣬¿ØÖƲ¢·¢·ÃÎÊÊýÁ¿ CountDownLatch countDownLatch = new CountDownLatch(bfCount); @Test public void miaoshaToOrder() throws Exception{ boolean flag = miaoShaService.initTokenToRedis(); if(flag){ System.out.println("³õʼ»¯token³É¹¦"); } long startTime = System.currentTimeMillis(); List<Thread> tList = new ArrayList<>(); for(int i=0;i<bfCount;i++){ MiaoShaThread miaoShaThread = new MiaoShaThread(1,"user_"+i,1); Thread thread = new Thread(miaoShaThread); thread.start(); tList.add(thread); countDownLatch.countDown(); } for (Thread t : tList){ t.join(); } long endTime = System.currentTimeMillis(); System.out.println("Ö´ÐÐʱ¼ä£º"+(endTime-startTime) ); System.out.println("³É¹¦µÄ¸öÊý:"+count); } @Autowired RedisTemplate redisTemplate; @Test public void getTokenFromRefis(){ Long count = redisTemplate.boundListOps("token_goods_" + 1).size(); System.out.println("ÁîÅÆÊýÁ¿£º"+count); } @Test public void payToOrder(){ int count_ = 1; for(int i=0;i<200;i++){ boolean b = miaoShaService.payTokenToOrder("user_"+i); if(b){ count_++; } } System.out.println("Ö§¸¶³É¹¦µÄÈËÊý£º"+count_); } //¶¨Ê±ÈÎÎñÿÃëÖ´ÐÐÍË»¹ÁîÅÆµÄ²Ù×÷ // Èç¹ûÔڹ涨ʱ¼ä5·ÖÖÓÖ®ÄÚûÓÐÖ§¸¶¾ÍÐèÒªÍË»¹ @Test public void returnToken(){ for(int i=0;i<1000;i++) { boolean flag = miaoShaService.returnToken("user_"+i); if(flag){ System.out.println("ÍË»¹ÁîÅÆ³É¹¦"); } } } class MiaoShaThread implements Runnable{ private Integer goodsId; private String user; private Integer num; public MiaoShaThread(Integer goodsId,String user,Integer num){ this.goodsId=goodsId; this.user=user; this.num=num; } public void run() { try { countDownLatch.await(); //²Ù×÷redis ÇÀ¹ºtoken boolean flag = miaoShaService.miaoshaTokenFromRedis(goodsId, user, num); if(flag){ synchronized (this){ count++; } } }catch (Exception e){ e.printStackTrace(); } } } }¡¡¡¡×¢Òâ:Ëæ×ÅCountDownLatchÉèÖò¢·¢ÊýÁ¿Ô½¸ß£¬ÐèÒªµ÷Õûredis-config.propertiesÊôÐÔÖеÄredis.maxIdleÊôÐÔ
¡¡¡¡ËÄ¡¢×ܽá
¡¡¡¡±¾ÎĽéÉÜÁËÀûÓÃredisµÄlistÊý¾ÝÀàÐÍÄ£ÄâÁîÅÆ¶ÓÁÐÀ´Íê³ÉÃëɱ£¬Ö÷Òª½â¾ö¿â´æ³¬Âô¡¢¸ß²¢·¢½µµÍϵͳѹÁ¦Ìá¸ßÓû§ÌåÑé¡¢½â¾öÀÖ¹ÛËø²»ÄÜÏȵ½ÏȵõÄÎÊÌâ¡£ÔÚµ¥»úÉÏÔËÐÐÄܹ»¹¹½¨ÉÏÍòµÄÇëÇóÀûÓÃredisÇÀ¹º100¸öÉÌÆ·ÔÚ¼¸ÃëÖ®ÄÚ´¦ÀíÍê³É¡£±¾ÎIJ¢²»ÊÇÕæÊǵÄÃëɱҵÎñ³¡¾°£¬ÖÁÉÙÌṩһÖÖÃëɱµÄ½â¾ö˼·£¬Èç¹ûÒµÎñ´æÔÚijЩ²»È·Çеĵط½£¬»¶ÓÁôÑÔ½»Á÷£¬Ï໥ѧϰ¡£
×÷ÕߣºÀÖÓã²¥¿ÍJavaEEÅàѵѧԺ
Ê×·¢£ºhttp://java.itcast.cn
±±¾©Ð£Çø