亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

1、Redis簡介

Redis是一個開源的key-value存儲系統(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)用場景為配合關(guān)系型數(shù)據(jù)庫做高速緩存,降低數(shù)據(jù)庫IO

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

2、實現(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ù)庫索引(默認(rèn)為0)
spring.redis.database=0
#連接超時時間(毫秒)
spring.redis.timeout=1800000
#連接池最大連接數(shù)(使用負(fù)值表示沒有限制)
spring.redis.lettuce.pool.max-active=20
#最大阻塞等待時間(負(fù)數(shù)表示沒限制)
spring.redis.lettuce.pool.max-wait=-1
#連接池中的最大空閑連接
spring.redis.lettuce.pool.max-idle=5
#連接池中的最小空閑連接
spring.redis.lettuce.pool.min-idle=0
# 關(guān)閉超時時間
#pring.redis.lettuce.shutdown-timeout=100
#配置spring啟動端口號
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>
<!-- 開發(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ā)生錯誤");
                });

            },

            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)換異常的問題
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // 配置序列化(解決亂碼的問題),過期時間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ù)時出現(xià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: 解決跨域問題(接口是http,而axios一般請求的是https。從https到http是跨域,因此要配置跨域請求)
 */

@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()); //注冊
        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";   //庫存
        String userKey = "sk:" + productId + ":user";  //秒殺成功的用戶

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

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

        //6、秒殺過程
        redisTemplate.opsForValue().decrement(kcKey);  //庫存數(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  //自動返回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);  //使用隨機數(shù)生成用戶ID
        String uid = String.valueOf(id) + " ";
        boolean flag = secKillService.doSecKill(uid, productId+index);
        System.out.println(flag);
        return flag;
    }
}

啟動類

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、啟動步驟

因為一共有三件商品要秒殺,所以在redis里面設(shè)置三個商品的庫存數(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能夠被訪問,要確保關(guān)閉linux的防火墻,以及關(guān)閉redis的保護(hù)模式。

vim redis.conf   --打開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"

啟動springboot項目

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

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

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

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

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

yum install httpd-tools

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

在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這個商品庫存變?yōu)?了

5、線程安全

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

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

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

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

6、總結(jié)

redis作為一種Nosql的非關(guān)系型數(shù)據(jù)庫,因為其單實例,簡單高效的特性通常會被作為其他關(guān)系型數(shù)據(jù)庫的高速緩存。尤其是在秒殺這樣的高并發(fā)操作。先將要秒殺的商品信息從數(shù)據(jù)庫讀入到redis中,秒殺的過程實際上是在與redis進(jìn)行交互。等秒殺完成后再將秒殺的結(jié)果存入數(shù)據(jù)庫。可以有效降低降低數(shù)據(jù)庫IO,防止數(shù)據(jù)庫宕機。

7、參考資料

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

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

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

相關(guān)文章

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

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

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

    Springboot源碼 TargetSource解析

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

    Jackson序列化丟失泛型的解決

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

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

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

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

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

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

    這篇文章主要介紹了SpringBoot對Druid配置SQL監(jiān)控功能失效問題的解決方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    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,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • 簡單了解Spring中常用工具類

    簡單了解Spring中常用工具類

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

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

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

最新評論