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

一、库存服务项目搭建

 

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

 

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



    4.0.0

    com.wingzhe.cache
    es_cache
    1.0-SNAPSHOT

    
        org.springframework.boot
        spring-boot-starter-parent
        1.2.5.RELEASE
    

    
        UTF-8
        1.8
    

    
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        
        
            org.springframework.boot
            spring-boot-starter-jdbc
        
        
            org.springframework.boot
            spring-boot-starter-actuator
        
        
            org.mybatis
            mybatis-spring
            1.2.2
        
        
            org.mybatis
            mybatis
            3.2.8
        
        
            org.apache.tomcat
            tomcat-jdbc
        
        
            mysql
            mysql-connector-java
        
        
            com.alibaba
            fastjson
            1.1.43
        
        
            redis.clients
            jedis
        
        
            junit
            junit
            4.7
            test
        
    


 

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




    

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 {

    /**
     * 内存队列
     */
    private ArrayBlockingQueue queue;

    public RequestProcessorThread(ArrayBlockingQueue 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 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> queues = new ArrayList>();

    /**
     * 使用静态内部类的方式实现初始化单例
     * 优点:绝对安全
     */
    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 queue) {
        this.queues.add(queue);
    }

}

 

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

2、两种请求对象的封装

 

3、请求异步执行Service封装

 

4、两种请求Controller接口封装

 

5、读请求去重优化

 

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

 

 

你可能感兴趣的:(高并发解决方案)