欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Springboot+redis+Vue實(shí)現(xiàn)秒殺的項(xiàng)目實(shí)踐

 更新時(shí)間:2022年08月05日 15:13:58   作者:Atlantide  
本文主要介紹了Springboot+redis+Vue實(shí)現(xiàn)秒殺的項(xiàng)目實(shí)踐,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

1、Redis簡(jiǎn)介

Redis是一個(gè)開(kāi)源的key-value存儲(chǔ)系統(tǒng)。

Redis的五種基本類型:String(字符串),list(鏈表),set(集合),zset(有序集合),hash,stream(Redis5.0后的新數(shù)據(jù)結(jié)構(gòu))

這些數(shù)據(jù)類型都支持push/pop、add/remove及取交集并集和差集及更豐富的操作,而且這些操作都是原子性的。

Redis的應(yīng)用場(chǎng)景為配合關(guān)系型數(shù)據(jù)庫(kù)做高速緩存,降低數(shù)據(jù)庫(kù)IO

需要注意的是,Redis是單線程的,如果一次批量處理命令過(guò)多,會(huì)造成Redis阻塞或網(wǎng)絡(luò)擁塞(傳輸數(shù)據(jù)量大)

2、實(shí)現(xiàn)代碼

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>org.example</groupId>
    <artifactId>seckill</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>2.2.1.RELEASE</version>
            <scope>test</scope>
        </dependency>

        <!-- redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <!-- spring2.X集成redis所需common-pool2-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.6.0</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.24</version>
        </dependency>

    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <fork>true</fork>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

application.properties.xml

#Redis服務(wù)器地址
spring.redis.host=192.168.1.2
#Redis服務(wù)器連接端口
spring.redis.port=6379
#Redis數(shù)據(jù)庫(kù)索引(默認(rèn)為0)
spring.redis.database=0
#連接超時(shí)時(shí)間(毫秒)
spring.redis.timeout=1800000
#連接池最大連接數(shù)(使用負(fù)值表示沒(méi)有限制)
spring.redis.lettuce.pool.max-active=20
#最大阻塞等待時(shí)間(負(fù)數(shù)表示沒(méi)限制)
spring.redis.lettuce.pool.max-wait=-1
#連接池中的最大空閑連接
spring.redis.lettuce.pool.max-idle=5
#連接池中的最小空閑連接
spring.redis.lettuce.pool.min-idle=0
# 關(guān)閉超時(shí)時(shí)間
#pring.redis.lettuce.shutdown-timeout=100
#配置spring啟動(dòng)端口號(hào)
server.port=8080

前端界面

seckillpage.html

<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>redis秒殺</title>
</head>
<body>
<!-- 開(kāi)發(fā)環(huán)境版本,包含了有幫助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 官網(wǎng)提供的 axios 在線地址 -->
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.20.0-0/axios.min.js"></script>
<div id="app">
    <h1>商品1元秒殺</h1>
    <!-- 左箭頭 -->
    <input type="button" value="<" v-on:click="prov" v-show="this.index>-1"/>
    <img v-bind:src="imgArr[index]" width="200px" />
    <!-- 右箭頭 -->
    <input type="button" value=">" v-on:click="next" v-show="this.index<2"/><br>
    <input type="button" v-on:click="seckill" value="秒 殺"/>
</div>
<script>
    var app = new Vue({
        el: "#app",
        data: {
            productId: "01234",
            imgArr:[
                "/image/phone1.png",
                "/image/phone2.png",
                "/image/phone3.png",
            ],
            index:0
        },
        methods: {
            seckill: function () {
                let param = new URLSearchParams()
                param.append('productId', this.productId)
                param.append('index', this.index)
                axios({
                    method: 'post',
                    url: 'http://192.168.1.6:8080/index/doSeckill',
                    data: param
                }).then(function (response) {
               
                    if (response.data == true) {
                        alert("秒殺成功");
                    } else {
                        alert("搶光了");
                    }
                 
                },
                    function(error){
                    alert("發(fā)生錯(cuò)誤");
                });

            },

            prov:function(){
                this.index--;
            },
            next:function(){
                this.index++;
            }
        }
    });

</script>
</body>
</html>

相關(guān)配置類

Redis配置類

RedisConfig.java

package com.springboot_redis_seckill.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

/**
 * @author WuL2
 * @create 2021-05-27 14:26
 * @desc
 **/
@EnableCaching
@Configuration
public class RedisConfig extends CachingConfigurerSupport {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        template.setConnectionFactory(factory);
        template.setKeySerializer(redisSerializer); //key序列化方式
        template.setValueSerializer(jackson2JsonRedisSerializer); //value序列化
        template.setHashValueSerializer(jackson2JsonRedisSerializer); //value hashmap序列化
        return template;
    }

    @Bean(name = "cacheManager")
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        //解決查詢緩存轉(zhuǎn)換異常的問(wèn)題
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // 配置序列化(解決亂碼的問(wèn)題),過(guò)期時(shí)間600秒
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(600))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                .disableCachingNullValues();
        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
        return cacheManager;
    }
}

配置Vue獲取后端接口數(shù)據(jù)時(shí)出現(xiàn)的跨域請(qǐng)求問(wèn)題。

CorsConfig.java

package com.springboot_redis_seckill.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;


/**
 * @author: wu linchun
 * @time: 2021/5/28 22:22
 * @description: 解決跨域問(wèn)題(接口是http,而axios一般請(qǐng)求的是https。從https到http是跨域,因此要配置跨域請(qǐng)求)
 */

@Configuration
public class CorsConfig {
    private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*"); //允許任何域名
        corsConfiguration.addAllowedHeader("*"); //允許任何頭
        corsConfiguration.addAllowedMethod("*"); //允許任何方法
        return corsConfiguration;
    }

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", buildConfig()); //注冊(cè)
        return new CorsFilter(source);
    }

}

服務(wù)層

SecKillService.java

package com.springboot_redis_seckill.service;

public interface SecKillService {
    public boolean doSecKill(String uid,String productId);
}

SecKillServiceImpl.java

package com.springboot_redis_seckill.service.impl;

import com.springboot_redis_seckill.service.SecKillService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

/**
 * @author WuL2
 * @create 2021-05-27 14:53
 * @desc
 **/
@Service
public class SecKillServiceImpl implements SecKillService {
    @Autowired
    @Qualifier("redisTemplate")
    private RedisTemplate redisTemplate;

    @Override
    public synchronized boolean doSecKill(String uid, String productId) {
        //1、uid和productId非空判斷
        if (uid == null || productId == null) {
            return false;
        }

        //2、拼接key
        String kcKey = "sk:" + productId + ":qt";   //庫(kù)存
        String userKey = "sk:" + productId + ":user";  //秒殺成功的用戶

        //3、獲取庫(kù)存
        String kc = String.valueOf(redisTemplate.opsForValue().get(kcKey)) ;
        if (kc == null) {
            System.out.println("秒殺還沒(méi)有開(kāi)始,請(qǐng)等待");
            return false;
        }

        //4、判斷用戶是否已經(jīng)秒殺成功過(guò)了
        if (redisTemplate.opsForSet().isMember(userKey, uid)) {
            System.out.println("已秒殺成功,不能重復(fù)秒殺");
            return false;
        }
        //5、如果庫(kù)存數(shù)量小于1,秒殺結(jié)束
        if (Integer.parseInt(kc) <=0) {
            System.out.println("秒殺結(jié)束");
            return false;
        }

        //6、秒殺過(guò)程
        redisTemplate.opsForValue().decrement(kcKey);  //庫(kù)存數(shù)量減1
        redisTemplate.opsForSet().add(userKey, uid);
        System.out.println("秒殺成功。。。");
        return true;
    }
}

控制層

package com.springboot_redis_seckill.controller;

import com.alibaba.fastjson.JSONObject;
import com.springboot_redis_seckill.service.SecKillService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Random;

/**
 * @author WuL2
 * @create 2021-05-27 14:28
 * @desc
 **/
@Controller
@RequestMapping("/index")
public class MyController {
    @Autowired
    @Qualifier("secKillServiceImpl")
    private SecKillService secKillService;

    @RequestMapping(value = {"/seckillpage"}, method = RequestMethod.GET)
    public String seckillpage() {
        return "/html/seckillpage.html";
    }


    @RequestMapping(value = {"/doSeckill"}, method = RequestMethod.POST)
    @ResponseBody  //自動(dòng)返回json格式的數(shù)據(jù)
    public Object doSeckill(HttpServletRequest request, HttpServletResponse response) {
        System.out.println("doSeckill");
        String productId = request.getParameter("productId");  
        String index = request.getParameter("index");
        System.out.println(productId+index);  //拼接成為商品ID
        int id = new Random().nextInt(50000);  //使用隨機(jī)數(shù)生成用戶ID
        String uid = String.valueOf(id) + " ";
        boolean flag = secKillService.doSecKill(uid, productId+index);
        System.out.println(flag);
        return flag;
    }
}

啟動(dòng)類

RunApplication.java

package com.springboot_redis_seckill;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author WuL2
 * @create 2021-05-27 14:32
 * @desc
 **/
@SpringBootApplication
public class RunApplication {
    public static void main(String[] args) {
        SpringApplication.run(RunApplication.class, args);
    }
}

3、啟動(dòng)步驟

因?yàn)橐还灿腥唐芬霘ⅲ栽趓edis里面設(shè)置三個(gè)商品的庫(kù)存數(shù)量。這里數(shù)量都設(shè)置為10。

127.0.0.1:6379> set sk:012340:qt 10
OK
127.0.0.1:6379> set sk:012341:qt 10
OK
127.0.0.1:6379> set sk:012342:qt 10
OK

要確保redis能夠被訪問(wèn),要確保關(guān)閉linux的防火墻,以及關(guān)閉redis的保護(hù)模式。

vim redis.conf   --打開(kāi)redis配置
 
service iptables stop?  --關(guān)閉防火墻
 
 
//關(guān)閉redis保護(hù)模式
redis-cli    --進(jìn)入redis客戶端
config set protected-mode "no"   --配置里面關(guān)閉redis保護(hù)模式(只是進(jìn)入redis.conf把protected-mode變?yōu)閚o是不行的,還要加一句config set protected-mode "no"

啟動(dòng)springboot項(xiàng)目

秒殺成功后,該商品在redis中的數(shù)量就減1。

當(dāng)數(shù)量減為0時(shí),則提示“搶光了”。

4、使用ab進(jìn)行并發(fā)測(cè)試

如果是centOS 6版本的linux都是默認(rèn)按照了ab工具的。

如果沒(méi)有安裝ab工具,可在linux終端用命令聯(lián)網(wǎng)下載安裝。

yum install httpd-tools

安裝完成后,就可以使用ab工具進(jìn)行并發(fā)測(cè)試了。

在linux終端輸入如下命令:

ab -n 2000  -c 200 -p '/root/Desktop/post.txt' -T 'application/x-www-form-urlencoded' 'http://192.168.1.6:8080/index/doSeckill/'

012341這個(gè)商品庫(kù)存變?yōu)?了

5、線程安全

為了防止出現(xiàn)“超買”的現(xiàn)象,需要讓操作redis的方法是線程安全的(即在方法上加上一個(gè)“悲觀鎖”synchronized)。

如果不加synchronized就會(huì)出現(xiàn)“超買”現(xiàn)象,即redis庫(kù)存會(huì)出現(xiàn)負(fù)數(shù)

之所以產(chǎn)生這種現(xiàn)象是由于并發(fā)導(dǎo)致多個(gè)用戶同時(shí)調(diào)用了doSecKill()方法,多個(gè)用戶同時(shí)修改了redis中的sk:012342:qt的值,但暫時(shí)都沒(méi)有提交存入到redis中去。等到后來(lái)一起提交,導(dǎo)致了sk:012342:qt的值被修改了多次,因此會(huì)出現(xiàn)負(fù)數(shù)。

因此在doSecKill()方法加上悲觀鎖,用戶調(diào)用該方法就對(duì)該方法加鎖,修改了sk:012342:qt的值后并提交存入redis中之后,才會(huì)釋放鎖。其他用戶才能得到鎖并操作該方法。

6、總結(jié)

redis作為一種Nosql的非關(guān)系型數(shù)據(jù)庫(kù),因?yàn)槠鋯螌?shí)例,簡(jiǎn)單高效的特性通常會(huì)被作為其他關(guān)系型數(shù)據(jù)庫(kù)的高速緩存。尤其是在秒殺這樣的高并發(fā)操作。先將要秒殺的商品信息從數(shù)據(jù)庫(kù)讀入到redis中,秒殺的過(guò)程實(shí)際上是在與redis進(jìn)行交互。等秒殺完成后再將秒殺的結(jié)果存入數(shù)據(jù)庫(kù)??梢杂行Ы档徒档蛿?shù)據(jù)庫(kù)IO,防止數(shù)據(jù)庫(kù)宕機(jī)。

7、參考資料

https://www.bilibili.com/video/BV1Rv41177Af?p=27

https://www.cnblogs.com/taiyonghai/p/5810150.html

到此這篇關(guān)于Springboot+redis+Vue實(shí)現(xiàn)秒殺的項(xiàng)目實(shí)踐的文章就介紹到這了,更多相關(guān)Springboot+redis+Vue 秒殺內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java如何獲取數(shù)組和字符串的長(zhǎng)度(length還是length())

    Java如何獲取數(shù)組和字符串的長(zhǎng)度(length還是length())

    這篇文章主要介紹了Java如何獲取數(shù)組和字符串的長(zhǎng)度(length還是length()),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • Springboot源碼 TargetSource解析

    Springboot源碼 TargetSource解析

    這篇文章主要介紹了Springboot源碼 TargetSource解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-08-08
  • Jackson序列化丟失泛型的解決

    Jackson序列化丟失泛型的解決

    這篇文章主要介紹了Jackson序列化丟失泛型的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • springboot 異步調(diào)用的實(shí)現(xiàn)方法

    springboot 異步調(diào)用的實(shí)現(xiàn)方法

    這篇文章主要介紹了springboot 異步調(diào)用的實(shí)現(xiàn)方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-04-04
  • 將應(yīng)用程序進(jìn)行Spring6遷移的最佳使用方式

    將應(yīng)用程序進(jìn)行Spring6遷移的最佳使用方式

    這篇文章主要介紹了將應(yīng)用程序進(jìn)行Spring6遷移的最佳方式,以及如何充分利用此升級(jí),需要的朋友可以參考下,如有錯(cuò)誤的地方還請(qǐng)指正
    2023-03-03
  • SpringBoot對(duì)Druid配置SQL監(jiān)控功能失效問(wèn)題及解決方法

    SpringBoot對(duì)Druid配置SQL監(jiān)控功能失效問(wèn)題及解決方法

    這篇文章主要介紹了SpringBoot對(duì)Druid配置SQL監(jiān)控功能失效問(wèn)題的解決方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-05-05
  • 工作中禁止使用Executors快捷創(chuàng)建線程池原理詳解

    工作中禁止使用Executors快捷創(chuàng)建線程池原理詳解

    這篇文章主要為大家介紹了工作中禁止使用Executors快捷創(chuàng)建線程池原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • 詳解在Spring Boot中使用Https

    詳解在Spring Boot中使用Https

    本篇文章主要介紹了詳解在Spring Boot中使用Https,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-05-05
  • 簡(jiǎn)單了解Spring中常用工具類

    簡(jiǎn)單了解Spring中常用工具類

    這篇文章主要介紹了簡(jiǎn)單了解Spring中常用工具類,非常全面,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-10-10
  • Java 時(shí)間格式轉(zhuǎn)換之impleDateFormat與Data API解析與使用

    Java 時(shí)間格式轉(zhuǎn)換之impleDateFormat與Data API解析與使用

    想必大家對(duì) SimpleDateFormat 并不陌生。SimpleDateFormat 是 Java 中一個(gè)非常常用的類,他是以區(qū)域敏感的方式格式化和解析日期的具體類。 它允許格式化 (date -> text)、語(yǔ)法分析 (text -> date)和標(biāo)準(zhǔn)化
    2021-11-11

最新評(píng)論