Java零基础——秒杀篇

news2024/11/22 19:05:28

1.【秒杀】
1.1. 技术选择型
Ø Springboot

Ø Redis

Ø Rocketmq

Ø Mysql

Ø MybatisPlus

1.2. 架构图
在这里插入图片描述

1.3. 准备工作-数据库
在这里插入图片描述

SET NAMES utf8mb4;

SET FOREIGN_KEY_CHECKS = 0;



-- ----------------------------

-- Table structure for goods

-- ----------------------------

DROP TABLE IF EXISTS `goods`;

CREATE TABLE `goods`  (

  `goods_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '商品ID',

  `goods_name` varchar(300) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '商品名称',

  `price` decimal(15, 2) DEFAULT NULL COMMENT '现价',

  `content` text CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT '详细描述',

  `status` int(1) DEFAULT 0 COMMENT '默认是1,表示正常状态, -1表示删除, 0下架',

  `total_stocks` int(11) DEFAULT 0 COMMENT '总库存',

  `create_time` datetime(0) DEFAULT NULL COMMENT '录入时间',

  `update_time` datetime(0) DEFAULT NULL COMMENT '修改时间',

  `spike` int(11) DEFAULT 0 COMMENT '是否参与秒杀1是0否',

  PRIMARY KEY (`goods_id`) USING BTREE

) ENGINE = InnoDB AUTO_INCREMENT = 95 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '商品' ROW_FORMAT = Dynamic;



-- ----------------------------

-- Records of goods

-- ----------------------------

INSERT INTO `goods` VALUES (18, 'Apple iPhone XS Max 移动联通电信4G手机 ', 1.01, '<div style=\"margin: 0px; padding: 0px; color: #666666; font-family: tahoma, arial, \'Microsoft YaHei\', \'Hiragino Sans GB\', u5b8bu4f53, sans-serif; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;\" align=\"center\">\n<table id=\"__01\" style=\"text-align: center;\" border=\"0\" width=\"750\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td><img class=\"\" style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: middle;\" src=\"https://img30.360buyimg.com/cms/jfs/t1/4626/32/3475/220504/5b997365E80a1373f/279c244f12161cb3.jpg\" alt=\"\" width=\"750\" height=\"1991\" /></td>\n</tr>\n<tr>\n<td><img class=\"\" style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: middle;\" src=\"https://img12.360buyimg.com/cms/jfs/t1/3397/21/3533/236322/5b99759aE73795787/f782e04a140c8f16.jpg\" alt=\"\" width=\"750\" height=\"2052\" /></td>\n</tr>\n<tr>\n<td><img class=\"\" style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: middle;\" src=\"https://img11.360buyimg.com/cms/jfs/t1/5274/3/3465/245167/5b997365E16b81bc9/93e07e40f3af5e62.jpg\" alt=\"\" width=\"750\" height=\"2250\" /></td>\n</tr>\n<tr>\n<td><img class=\"\" style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: middle;\" src=\"https://img30.360buyimg.com/cms/jfs/t1/2322/11/3524/269574/5b997365E26f81a7a/e01fc9486da9eda1.jpg\" alt=\"\" width=\"750\" height=\"2327\" /></td>\n</tr>\n<tr>\n<td><img class=\"\" style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: middle;\" src=\"https://img13.360buyimg.com/cms/jfs/t1/5074/21/3432/296470/5b997364Ee966f7a0/7f424d41479db45d.jpg\" alt=\"\" width=\"750\" height=\"2561\" /></td>\n</tr>\n<tr>\n<td><img class=\"\" style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: middle;\" src=\"https://img13.360buyimg.com/cms/jfs/t1/5770/18/3580/288371/5b997365Ea2c58cb4/176b9a40ccd4e56b.jpg\" alt=\"\" width=\"750\" height=\"2668\" /></td>\n</tr>\n<tr>\n<td><img class=\"\" style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: middle;\" src=\"https://img11.360buyimg.com/cms/jfs/t1/227/21/3811/268132/5b997364E3d6c51b2/92d2a3a559e3baa8.jpg\" alt=\"\" width=\"750\" height=\"2850\" /></td>\n</tr>\n<tr>\n<td><img class=\"\" style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: middle;\" src=\"https://img20.360buyimg.com/cms/jfs/t1/3787/5/3493/125020/5b997363E3c9f5910/ddbd08a556744630.jpg\" alt=\"\" width=\"750\" height=\"1486\" /></td>\n</tr>\n<tr>\n<td><img class=\"\" style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: middle;\" src=\"https://img30.360buyimg.com/cms/jfs/t1/1687/5/3327/266718/5b997366E9cc80e69/9e40ceae1fef4466.jpg\" alt=\"\" width=\"750\" height=\"3376\" /></td>\n</tr>\n<tr>\n<td><img class=\"\" style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: middle;\" src=\"https://img30.360buyimg.com/cms/jfs/t1/457/6/3849/283318/5b997363E0c5ab7a9/6f636f0a286bc87c.jpg\" alt=\"\" width=\"750\" height=\"2455\" /></td>\n</tr>\n<tr>\n<td><img class=\"\" style=\"margin: 0px; padding: 0px; border: 0px; vertical-align: middle;\" src=\"https://img10.360buyimg.com/cms/jfs/t1/397/25/3796/217624/5b9975a8E5ee578af/4d8f05a606fa5c4a.jpg\" alt=\"\" width=\"750\" height=\"2703\" /></td>\n</tr>\n</tbody>\n</table>\n</div>', 1, 10, '2019-03-29 14:40:00', '2019-06-22 18:28:32', 1);

INSERT INTO `goods` VALUES (59, '兰蔻粉水清滢柔肤水400ml 爽肤水女保湿舒缓滋润嫩肤', 420.00, '<p><img src=\"http://img-test.gz-yami.com/2019/04/71f54ee20ef34872b1e0aa53cb75b7b6.jpg\" alt=\"\" width=\"790\" height=\"1110\" /></p>', 1, 10, '2019-04-21 19:15:34', '2019-04-29 14:30:44', 1);

INSERT INTO `goods` VALUES (68, '【Dole都乐】菲律宾都乐非转基因木瓜1只 单只约410g', 26.00, '<p style=\"text-align: justify;\"><img src=\"http://img-test.gz-yami.com/2019/04/e7536a53a83d450e8635ce1e9819faf6.jpg\" alt=\"\" width=\"790\" height=\"350\" /></p>', 1, 10, '2019-04-21 21:56:38', '2019-05-22 10:30:37', 0);

INSERT INTO `goods` VALUES (69, '阿迪达斯官方 adidas 三叶草 NITE JOGGER 男子经典鞋BD7956', 1199.00, '<p><img src=\"http://img-test.gz-yami.com/2019/04/6d0bea4a0be54423999136bcd1158897.jpg\" alt=\"\" width=\"790\" height=\"2232\" /></p>', 1, 10, '2019-04-21 22:10:04', '2019-05-23 20:17:03', 0);

INSERT INTO `goods` VALUES (70, '【Dole都乐】比利时Truval啤梨12只 进口水果新鲜梨 单果120g左右', 38.00, '<p><img src=\"http://img-test.gz-yami.com/2019/04/67ce2251e9b14ea08b87752ef7b30207.jpg\" alt=\"\" width=\"760\" height=\"488\" /></p>', 1, 10, '2019-04-22 16:43:33', '2019-06-22 09:40:24', 0);

INSERT INTO `goods` VALUES (71, '旗舰店官网 自拍神器 梵高定制', 6998.00, '<p><img src=\"http://img-test.gz-yami.com/2019/04/fa35b300102e45f3a57d7c5c775ebf6d.jpg\" alt=\"\" width=\"790\" height=\"853\" /></p>\n<p><img src=\"http://img-test.gz-yami.com/2019/04/f8fd168ddb8a437dbb5b742691bd1d02.jpg\" alt=\"\" width=\"800\" height=\"800\" /><img src=\"http://img-test.gz-yami.com/2019/04/db46108466264b48841b18437940e0b3.jpg\" alt=\"\" width=\"800\" height=\"800\" /></p>', 1, 10, '2019-04-23 15:43:26', '2019-05-21 11:01:59', 0);



-- ----------------------------

-- Table structure for order

-- ----------------------------

DROP TABLE IF EXISTS `order`;

CREATE TABLE `order`  (

  `id` int(11) NOT NULL AUTO_INCREMENT,

  `userid` int(11) DEFAULT NULL,

  `goodsid` int(11) DEFAULT NULL,

  `createtime` datetime(0) DEFAULT NULL,

  PRIMARY KEY (`id`) USING BTREE

) ENGINE = InnoDB AUTO_INCREMENT = 23 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;



SET FOREIGN_KEY_CHECKS = 1;

1.4. 创建项目选择依赖spike-web(接受用户秒杀请求)

1.4.1. 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 https://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.6.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.powernode</groupId>
    <artifactId>seckill-web</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>04-seckill-web</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <!-- rocketmq的依赖 -->
        <dependency>
            <groupId>org.apache.rocketmq</groupId>
            <artifactId>rocketmq-spring-boot-starter</artifactId>
            <version>2.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.3.9</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
 

1.4.2. 修改配置文件

server:
    port: 7001
spring:
    application:
        name: spike-web
    redis:
        host: 192.168.47.128
        port: 6380
        database: 0
rocketmq:
    name-server: 127.0.0.1:9876     # rocketMq的nameServer地址
    producer:
        group: powernode-group        # 生产者组别
        send-message-timeout: 3000  # 消息发送的超时时间
        retry-times-when-send-async-failed: 2  # 异步消息发送失败重试次数
        max-message-size: 4194304       # 消息的最大长度

1.4.3. 添加布隆过滤器的配置

@Bean
public BitMapBloomFilter bitMapBloomFilter() {
    return new BitMapBloomFilter(100);
}

1.4.4. 创建SpikeController

@RestController
public class SeckillController {


    @Autowired
    private BitMapBloomFilter bitMapBloomFilter;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    /**
     * 因为我们没有做登录 安全框架
     * 1.先判断当前用户对这个商品有没有买过
     * 2.看这个商品的库存够不够
     * 3.组装数据放mq
     *
     * @return
     */
    @GetMapping("doSeckill")
    public String doSeckill(Integer goodsId, Integer userId) {
        // 使用布隆过滤器来判断用户是否买过这个商品 (只要是去重操作 都可以使用)
        // 一个用户针对一个商品只能买一次  双主键
        String secKillId = userId + "-" + goodsId;
        if (bitMapBloomFilter.contains(secKillId)) {
            return "您已经参与过该商品的抢购,请参与其他商品(*^▽^*)";
        }
        bitMapBloomFilter.add(secKillId);
        // 判断该商品的库存是否足够
        // 需要将mysql的数据 要同步到redis去
        // 直接通过redis来做减法  因为redis是单线程的 所以是安全的
        Long count = redisTemplate.opsForValue().decrement("secKill:" + goodsId);
        // 我不是只放10个人进来操作 而是多放10%-30%的请求进来
        // 为了防止有的请求报错 失败了
        if (count < -3) {
            return "该商品已经卖完了,下次早点来";
        }
        // 走到这里的人 就有机会买到
        // 组装数据 放mq 操作数据库的代码 异步执行  让这里的线程return回收 提高服务器并发量
        HashMap<String, Integer> map = new HashMap<>(4);
        // 如果你知道你的map要放多少数据进去 直接在定义的时候就写好
        map.put("userId", userId);
        map.put("goodsId", goodsId);
        // 通过mq来做数据传输 最好放什么类型的数据  Integer Map Obj   String是万能的 json
        rocketMQTemplate.syncSend("secKillTopic", JSONUtil.toJsonStr(map));
        return "正在拼命抢购中,请稍后查看";
    }
}

1.5. 创建项目选择依赖spike-service(处理秒杀)

<?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 https://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.6.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.powernode</groupId>
    <artifactId>seckill-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>05-seckill-service</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <!-- rocketmq的依赖 -->
        <dependency>
            <groupId>org.apache.rocketmq</groupId>
            <artifactId>rocketmq-spring-boot-starter</artifactId>
            <version>2.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.3.9</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

1.5.1. 修改yml文件

server:
    port: 7002
spring:
    application:
        name: spike-service
    datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/spike?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
        username: root
        password: root
    redis:
        host: 192.168.47.128
        port: 6380
        database: 0
mybatis-plus:
    configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    mapper-locations: classpath*:mapper/*.xml
rocketmq:
    name-server: 127.0.0.1:9876

1.5.2. 逆向生成实体类等
在这里插入图片描述

1.5.3. 修改启动类

@SpringBootApplication
@MapperScan(basePackages = {"com.bjpowernode.mapper"})
public class SpikeServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpikeServiceApplication.class, args);
    }

}

1.5.4. 同步mysql数据到redis

/**
 * 实现CommandLineRunner 项目启动后会执行里面的run方法
 */
@Component
public class MysqlToRedis implements CommandLineRunner {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private GoodsMapper goodsMapper;

    /**
     * 查询数据库中参与秒杀的商品
     * 将商品id和数量存入redis
     */
    public void goods2Redis() {
        List<Goods> goodsList = goodsMapper.selectList(new LambdaQueryWrapper<Goods>()
                .eq(Goods::getSpike, 1)
                .eq(Goods::getStatus, 1)
        );
        if (CollectionUtils.isEmpty(goodsList)) {
            return;
        }
        goodsList.forEach(goods -> {
            redisTemplate.opsForValue().set("goods_stock:" + goods.getGoodsId(), goods.getTotalStocks().toString());
        });
    }

    @Override
    public void run(String... args) throws Exception {
        goods2Redis();
    }
}

1.5.5. 创建秒杀监听

@Component
@RocketMQMessageListener(topic = "secKillTopic",
        consumerGroup = "secKill-group",
        messageModel = MessageModel.CLUSTERING,
        consumeThreadMax = 64
)
@Slf4j
public class SpikeListener implements RocketMQListener<MessageExt> {

    @Autowired
    private OrderService orderService;

    /**
     * 处理秒杀
     *
     * @param message
     */
    @Override
    public void onMessage(MessageExt message) {
        String spikeStr = new String(message.getBody());
        JSONObject jsonObject = JSONUtil.parseObj(spikeStr);
        Integer userId = jsonObject.getInt("userId");
        Integer goodsId = jsonObject.getInt("goodsId");
        try {
            orderService.realDoSpike(userId, goodsId);
        } catch (Exception e) {
            log.error("抢购失败,用户id为{},商品id为{}", userId, goodsId);
        }
    }
}

1.5.6. 修改OrderService

public interface OrderService extends IService<Order> {


    /**
     * 做秒杀
     *
     * @param userId
     * @param goodsId
     */
    void realDoSpike(Integer userId, Integer goodsId);
}

1.5.7. 修改OrderServiceImpl

@Service
public class OrderServiceImpl implements OrderService {

    @Resource
    private OrderMapper orderMapper;

    @Autowired
    private GoodsMapper goodsMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    // 定义一个时间
    private Long allTime = 1000L;

    @Autowired
    private RedissonClient redissonClient;



    @Override
    public int deleteByPrimaryKey(Integer id) {
        return orderMapper.deleteByPrimaryKey(id);
    }

    @Override
    public int insert(Order record) {
        return orderMapper.insert(record);
    }

    @Override
    public int insertSelective(Order record) {
        return orderMapper.insertSelective(record);
    }

    @Override
    public Order selectByPrimaryKey(Integer id) {
        return orderMapper.selectByPrimaryKey(id);
    }

    @Override
    public int updateByPrimaryKeySelective(Order record) {
        return orderMapper.updateByPrimaryKeySelective(record);
    }

    @Override
    public int updateByPrimaryKey(Order record) {
        return orderMapper.updateByPrimaryKey(record);
    }


    /**
     * 减库存和写订单表
     * 有线程安全问题
     * A线程执行到 goodsMapper.selectByPrimaryKey(goodsId);  B 也执行这行代码  都查到有1件商品
     * 加锁
     * <p>
     * 分布式锁
     * mysql的版本号做 乐观锁
     * update goods set stock = stock ,version = version + 1  where goodsId = goodsId and version = version
     * 如果有两个人同时查询到 库存足够 并且version 相同
     * 此时去操作数据库 只能有一个人成功  体验不好
     * <p>
     * redis来做分布式锁
     * setnx   set if not exist  如果这个key不存在 就能设置成功 返回true   通过业务来判断 加锁
     *
     * @param goodsId
     * @param userId
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void realSpike(Integer goodsId, Integer userId) {
//        RLock lock = redissonClient.getLock("goods_lock:" + goodsId);
//        lock.lock();
        // 写一个自旋 来重试
        long time = 0;
        while (time < allTime) {
            // setnx = setIfAbsent(缺席)  给一个过期时间 方式卡死 别的线程永远进不来了   时间不要写死   定义变量 更新
            // 锁续命  long id = Thread.currentThread().getId(); 拿到当前获取锁的一个线程id
            // 搞一个任务调度 每隔2/3的时间 去判断一下 获取锁的线程是否是当前线程 如果是 就将时间 加 1/3 的时间
            Boolean flag = redisTemplate.opsForValue().setIfAbsent("goods_lock:" + goodsId, "", Duration.ofSeconds(30));
//            redisTemplate.expire("goods_lock:" + goodsId, Duration.ofSeconds(10));
            if (flag) {
                try {
                    Goods goods = goodsMapper.selectByPrimaryKey(goodsId);
                    // 只能锁住本地jvm 在分布式环境中 不能起作用
                    int finalStock = goods.getTotalStocks() - 1;
                    if (finalStock < 0) {
                        throw new RuntimeException("商品的库存不足,id为" + goods.getGoodsId());
                    }
                    goods.setTotalStocks(finalStock);
                    goods.setUpdateTime(new Date());
                    int i = goodsMapper.updateByPrimaryKey(goods);
                    if (i > 0) {
                        writeOrder(goodsId, userId);
                        return;
                    }
                } finally {
                    // 删掉这个锁 不然别人就获取不到锁了
                    redisTemplate.delete("goods_lock:" + goodsId);
//                    lock.unlock();
                }
            } else {
                time += 300;
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 写订单表
     *
     * @param goodsId
     * @param userId
     */
    private void writeOrder(Integer goodsId, Integer userId) {
        Order order = new Order();
        order.setCreatetime(new Date());
        order.setUserid(userId);
        order.setGoodsid(goodsId);
        orderMapper.insert(order);
    }
}

1.5.8. pom.xml

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.13.6</version>
</dependency>

1.5.9. 启动类

@Bean
public RedissonClient redissonClient() {
    Config config = new Config();
    config.useSingleServer().setAddress("localhost:6379");
    return Redisson.create(config);
} 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1288484.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【labview报错,缺少GOOP Development Suite】

操作 当labview报此错误时&#xff0c;第一类情况为缺少包&#xff0c;第二类为所使用的GPU包已失效 以下为第一类缺包的解决方式 登录VIPM&#xff0c;如何安装VIPM查看此贴&#xff1a;VIPM安装 打开VIPM后&#xff0c;右上角输入goop,双击搜索出的安装包 勾选需要安装的包…

Java_ArrayList顺序表详解

目录 前言 顺序表 ​编辑 顺序表和数组 ArrayList简介 说明 ArrayList使用​编辑 ArrayList常见操作 ArrayList实现二维数组 ArrayList的遍历 ArrayList的扩容机制 总结 前言 一个高端的程序员,往往都是数据结构学的很好,判断一个程序的优劣也是看数据结构学的好与坏.…

Mysql-全外连接-Union和Union ALL的辨析及练习

mysql不支持FULL JOIN&#xff0c;但是可以用 &#xff08;select 语句1&#xff09; union &#xff08;select 语句2&#xff09;代替 &#x1f436;1. SQL UNION 操作符 UNION 操作符用于合并两个或多个 SELECT 语句的结果集。 请注意&#xff0c;UNION 内部的 SELECT 语句…

使用git出现的问题

保证 首先保证自己的git已经下载 其次保证自己的gitee账号已经安装并且已经生成ssh公钥 保证自己要push的代码在要上传的文件夹内并且配置文件等都在父文件夹&#xff08;也就是文件没有套着文件&#xff09; 问题 1 $ git push origin master gitgitee.com: Permission de…

Vue混淆与还原

Vue混淆与还原 引言 Vue是一种流行的JavaScript框架&#xff0c;用于构建用户界面。它简单易用且功能强大&#xff0c;备受开发者喜爱。然而&#xff0c;在传输和存储过程中&#xff0c;我们需要保护Vue代码的安全性。混淆是一种有效的保护措施&#xff0c;可以加密和压缩代码…

简单构造好题

没啥思路&#xff0c;看到题解&#xff0c;先处理最大值&#xff0c;发现非常的nice // Problem: C. Polycarp Recovers the Permutation // Contest: Codeforces - Codeforces Round 756 (Div. 3) // URL: https://codeforces.com/problemset/problem/1611/C // Memory Limit:…

window下安装RocketMQ

本文以window11、JDK1.8、RocketMQ4.9.7版本为例 1.下载安装 1.1.官网 官网官网文档官网下载 1.2.下载 1.3.解压 2.配置 2.1.环境变量添加ROCKETMQ_HOME 2.2.环境变量添加JAVA_HOME 安装jdk1.8&#xff0c;并配置环境变量JAVA_HOME 3.启动 如果JAVA_HOME未指向jdk1.…

win10下maven安装与配置

1.下载安装 去官网下载最新版的安装包&#xff0c;然后解压到安装目录。 2.配置 右键桌面的计算机图标&#xff0c;属性–>高级系统设置–>环境变量&#xff0c;添加M2_HOME的环境变量&#xff0c;然后将该变量加入的PATH中。 如果想要修改maven的本地仓库位置&…

spring data Redis整合spring cache实战(附源码及源码分析)

这里是weihubeats,觉得文章不错可以关注公众号小奏技术&#xff0c;文章首发。拒绝营销号&#xff0c;拒绝标题党 背景 最近在研究缓存框架&#xff0c;打算写一个多级缓存框架的sdk。所以想借鉴(抄袭)下spring的缓存框架的实现 spring cache reids spring cache对各种缓存进…

台灯哪个品牌更护眼推荐?学生党备考台灯推荐

近些年近视人数持续升高&#xff0c;我们越来越注意个人的健康问题&#xff0c;而对于视力健康&#xff0c;尤其是儿童青少年们&#xff0c;在3-14岁这个年龄段近视机率更高&#xff0c;儿童青少年近视率高达52.7%&#xff0c;随着开学季到来&#xff0c;应该怎么选护眼台灯呢&…

【安装VIPM】

操作 打开VIPM安装包&#xff0c;下载链接&#xff1a;VIPM安装包&#xff0c;双击vipm.exe 点击下一步 勾选VI Package&#xff0c;点击下一步 这时会有弹窗&#xff0c;无需担心&#xff0c;等待即可 点击下一步 选择我接受&#xff0c;点击下一步 这里可选择是否要创…

Linux环境搭建SVN服务器并结合内网穿透实现远程访问

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;网络奇遇记、Cpolar杂谈 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. Ubuntu安装SVN服务二. 修改配置文件2.1 修改svnserve.conf文件2.2 修改pass…

STM32-新建工程(标准库)

目录 STM32F10x新建工程&#xff08;标准库&#xff09; 移植文件夹 新建工程 添加启动文件和必需文件 在工程中加载新添加的文件 在工程中添加文件路径 在工程中添加main函数 添加lib库 添加必需文件 添加宏定义 点亮LED&#xff08;标准库&#xff09; STM32F10x新…

Xshell7和Xftp7的下载、安装2023最新最全

1.下载 1.官网地址&#xff1a; XSHELL - NetSarang Website 选择学校免费版下载 2.将XSHELL和XFTP全都下载下来 2.安装 安装过程就是选择默认选项&#xff0c;然后无脑下一步 3.连接服务器 1.打开Xshell7&#xff0c;然后新建会话 2.填写相关信息 出现Connection establ…

数据库管理-第123期 Oracle相关两个参数(202301205)

数据库管理-第123期 Oracle相关两个参数&#xff08;202301205&#xff09; 最近在群聊中看到俩和Oracle数据库相关的俩参数&#xff0c;一个是Oracle数据库本身的&#xff0c;一个是来自于Weblogic的&#xff0c;挺有趣的&#xff0c;本期研究一下。&#xff08;本期涉及参数…

面试官:说说webpack的热更新是如何做到的?原理是什么?

面试官&#xff1a;说说webpack的热更新是如何做到的&#xff1f;原理是什么&#xff1f; 一、是什么 HMR 全称 Hot Module Replacement&#xff0c;可以理解为模块热替换&#xff0c;指在应用程序运行过程中&#xff0c;替换、添加、删除模块&#xff0c;而无需重新刷新整个应…

振弦采集仪在安全监测中的可靠性与精度分析

振弦采集仪在安全监测中的可靠性与精度分析 振弦采集仪在土体与岩体监测中是一种常见的监测手段&#xff0c;它可以通过采集岩体或土体振动信号来判断其稳定性和变形情况。在实际应用中&#xff0c;振弦采集仪的可靠性和精度是极为重要的&#xff0c;本篇文章将从这两个方面进…

基于SpringBoot实现的毕业设计管理系统

一、 系统架构 前端&#xff1a;html | jquery | vue 后端&#xff1a;springboot | thymeleaf | mybatis 环境&#xff1a;jdk1.8 | mysql | maven 二、代码及数据库 三、功能介绍 01. 登录页 02. 教务管理-控制台 03. 教务管理-选题管理-选题大厅 04. 教务管理-选题…

Python接口自动化测试:断言封装详解!

前言 在进行API接口测试时&#xff0c;断言起着至关重要的作用。断言是用于验证预期结果与实际结果是否一致的过程。在Python中&#xff0c;我们可以利用一些库来实现断言功能。 1. 安装必要的库 在Python中&#xff0c;我们主要会使用两个库&#xff1a;requests和jsonpath…

CSS单位vmin、vmax

在前端项目中使用到图片或者一些其他的需要适应视口宽度的地方时候&#xff0c;我们可以使用vmin或者vmax这两个属性。我们来看一下这两个属性在MDN上面的定义 实例 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8">…