商品详情页系统 -- day08 库存服务项目搭建

一、库存服务项目搭建

 

1、配置Maven环境,创建Maven工程

 

2、pom.xml中导入jar包坐标

<?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>

    <groupId>com.wingzhe.cache</groupId>
    <artifactId>es_cache</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.5.RELEASE</version>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.2.8</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.1.43</version>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.7</version>
            <scope>test</scope>
        </dependency>
    </dependencies>


</project>

 

3、编写Springboot启动引导类

package com.wingzhe.cache;

import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;

import java.util.HashSet;
import java.util.Set;

/**
 * 库存服务启动引导类
 */
@EnableAutoConfiguration // 开启自动配置
@SpringBootApplication  // 标记为springboot启动引导类
@ComponentScan // 开启组件扫描
@MapperScan("com.wingzhe.cache.mapper") // 配置mapper配置接口扫描路径
public class MainApp {

    /**
     * 启动引导类
     */
    public static void main(String[] args) {
        SpringApplication.run(MainApp.class, args);
    }

    /**
     * 创建数据源
     *
     * @return
     */
    @Bean
    @ConfigurationProperties("spring.datasource")
    public DataSource dataSource() {
        return new DataSource();
    }

    /**
     * 创建Mybatis的sessionFactory
     *
     * @return
     * @throws Exception
     */
    @Bean
    public SqlSessionFactory sqlSessionFactoryBean() throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource());
        // 创建对象用来解析资源文件,需要在classpath下创建templates文件夹,其中放置任意ftl结尾文件即可
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath:/mybatis/*.xml"));
        return sqlSessionFactoryBean.getObject();
    }

    /**
     * 配置事务管理器
     */
    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource());
    }

    /**
     * 配置JedisCluster
     */
    @Bean
    public JedisCluster jedisClusterFactory() {
        Set<HostAndPort> jedisClusterNodes = new HashSet<>();
        jedisClusterNodes.add(new HostAndPort("192.168.20.128", 7001));
        jedisClusterNodes.add(new HostAndPort("192.168.20.128", 7002));
        jedisClusterNodes.add(new HostAndPort("192.168.20.129", 7003));
        JedisCluster jedisCluster = new JedisCluster(jedisClusterNodes);
        return jedisCluster;
    }
}

 

4、创建数据库、用户、表

 

5、编写springboot主配置文件

spring.datasource.url=jdbc:mysql://192.168.20.131:3306/cache
spring.datasource.username=wingzhe
spring.datasource.password=wingzhe
spring.datasource.driverClassName=com.mysql.jdbc.Driver

 

6、整合mybatis|springmvc|springboot,并编写测试类进行测试数据库以及redisCluster功能

User.java

package com.wingzhe.cache.model;

public class User {
    private String name;
    private Integer age;

    public User() {
    }

    public User(String name, Integer age) {

        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wingzhe.cache.mapper.UserMapper">
    <select id="findUserInfo" resultType="com.wingzhe.cache.model.User">
        select name, age from user;
    </select>
</mapper>

UserMapper.java

package com.wingzhe.cache.mapper;

import com.wingzhe.cache.model.User;

public interface UserMapper {

    public User findUserInfo();
}

RedisDao.java

package com.wingzhe.cache.dao;

/**
 * RedisDao
 *
 */
public interface RedisDao {
    public void setKey(String key, String value);

    public String getKey(String key);
}

RedisDaoImpl.java

package com.wingzhe.cache.dao.impl;

import com.wingzhe.cache.dao.RedisDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import redis.clients.jedis.JedisCluster;

@Repository
public class RedisDaoImpl implements RedisDao {

    @Autowired
    private JedisCluster jedisCluster;

    @Override
    public void setKey(String key, String value) {
        jedisCluster.set(key, value);
    }

    @Override
    public String getKey(String key) {
        return jedisCluster.get(key);
    }
}

UserService.java

package com.wingzhe.cache.service;

import com.wingzhe.cache.model.User;

public interface UserService {

    public User findUserInfo();

    public User findCacheUserInfoFromRedis();
}

UserServiceImpl.java

package com.wingzhe.cache.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.wingzhe.cache.dao.RedisDao;
import com.wingzhe.cache.mapper.UserMapper;
import com.wingzhe.cache.model.User;
import com.wingzhe.cache.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.JedisCluster;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisDao redisDao;

    public User findUserInfo() {
        return userMapper.findUserInfo();
    }

    @Override
    public User findCacheUserInfoFromRedis() {
        redisDao.setKey("user_cache", "{name:\"李四\",age:\"23\"}");
        String jsonStr = redisDao.getKey("user_cache");
        JSONObject object = JSONObject.parseObject(jsonStr);

        User user = new User(object.getString("name"), object.getInteger("age"));
        return user;
    }
}

UserController.java

package com.wingzhe.cache.controller;

import com.wingzhe.cache.model.User;
import com.wingzhe.cache.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping("/getUserInfo")
    @ResponseBody
    public User getUserInfo(){
        return userService.findUserInfo();
    }

    @RequestMapping("/getCacheUserInfoFromRedis")
    @ResponseBody
    public User getCacheUserInfoFromRedis(){
        return userService.findCacheUserInfoFromRedis();
    }
}

 

二、在库存服务中实现缓存与数据的双写一致保障方案

 

1、线程池+内存队列初始化操作

 

(1)、创建单例请求处理的线程池以及执行工作请求的线程类

 

RequestProcessorThread.java

package com.wingzhe.cache.thread;

import com.wingzhe.cache.request.Request;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Callable;

/**
 * 执行请求的工作线程
 */
public class RequestProcessorThread implements Callable<Boolean> {

    /**
     * 内存队列
     */
    private ArrayBlockingQueue<Request> queue;

    public RequestProcessorThread(ArrayBlockingQueue<Request> queue) {
        this.queue = queue;
    }

    @Override
    public Boolean call() throws Exception {
        while(true){
            break;
        }
        return true;
    }
}

 

RequestProcessorThreadPool.java

package com.wingzhe.cache.thread;

import com.wingzhe.cache.request.Request;
import com.wingzhe.cache.request.RequestQueue;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 单例模式的请求处理线程池
 */
public class RequestProcessorThreadPool {

    // 初始化长度为10的自定义线程池
    private ExecutorService threadPool = Executors.newFixedThreadPool(10);

    public RequestProcessorThreadPool() {
        RequestQueue requestQueue = RequestQueue.getInstance();

        for (int i = 0; i < 10; i++) {
            ArrayBlockingQueue<Request> queue = new ArrayBlockingQueue<>(100);
            requestQueue.addQueue(queue);
            threadPool.submit(new RequestProcessorThread(queue));
        }
    }

    /**
     * 使用静态内部类的方式实现初始化单例
     * 优点:绝对安全
     */
    private static class Singleton {
        private static RequestProcessorThreadPool instance;

        static {
            instance = new RequestProcessorThreadPool();
        }

        public static RequestProcessorThreadPool getInstance() {
            return instance;
        }
    }

    /**
     * 静态方法能够通过JVM的机制去保证多线程下的并发安全
     * 不管多少个线程去并发初始化当前的内存队列,内部类初始化只会发生一次,因此只会创建一个内存队列
     * 从而保证所有的线程用到的都是同一个内存队列
     *
     * @return
     */
    public static RequestProcessorThreadPool getInstance() {
        return Singleton.getInstance();
    }

    /**
     * 初始化入口方法
     */
    public static void init() {
        getInstance();
    }
}

 

(2)、编写自定义请求队列以及请求接口类

Request.java

package com.wingzhe.cache.request;

/**
 * 自定义封装请求的接口
 */
public interface Request {
}

 

RequestQueue.java

package com.wingzhe.cache.request;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;

/**
 * 使用单例方式自定义请求内存队列
 */
public class RequestQueue {

    /**
     * 初始化内存队列
     */
    private List<ArrayBlockingQueue<Request>> queues = new ArrayList<ArrayBlockingQueue<Request>>();

    /**
     * 使用静态内部类的方式实现初始化单例
     * 优点:绝对安全
     */
    private static class Singleton {
        private static RequestQueue instance;

        static {
            instance = new RequestQueue();
        }

        public static RequestQueue getInstance() {
            return instance;
        }
    }

    /**
     * 静态方法能够通过JVM的机制去保证多线程下的并发安全
     * 不管多少个线程去并发初始化当前的内存队列,内部类初始化只会发生一次,因此只会创建一个内存队列
     * 从而保证所有的线程用到的都是同一个内存队列
     *
     * @return
     */
    public static RequestQueue getInstance() {
        return Singleton.getInstance();
    }

    /**
     * 添加一个内存队列
     *
     * @param queue
     */
    public void addQueue(ArrayBlockingQueue<Request> queue) {
        this.queues.add(queue);
    }

}

 

(3)、编写自定义的初始化监听类,并在启动引导类中加入线程池监听

2、两种请求对象的封装

 

3、请求异步执行Service封装

 

4、两种请求Controller接口封装

 

5、读请求去重优化

 

6、空数据读请求过滤优化

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值