java秒杀系统优化方案

编程入门 行业动态 更新时间:2024-10-25 10:34:25

java秒杀<a href=https://www.elefans.com/category/jswz/34/1744926.html style=系统优化方案"/>

java秒杀系统优化方案

首先先把 springboot +thymeleaf 搞起来 ,参考 springboot 官方文档

本次学习 使用 springboot + thymeleaf+mybatis+redis+RabbitMQ 等实现,未完待继续补充

开发环境: IDEA

接口测试: PostMan

鸭梨测试:JMeter

整体结构

那么使用 idea ——>file -->new project --> maven project

修改 pom.xml 添加依赖

xmlns:xsi=""

xsi:schemaLocation=".0.0 .0.0.xsd">

4.0.0

springbootdemo

springbootdemo

1.0-SNAPSHOT

org.springframework.boot

spring-boot-starter-parent

1.5.2.RELEASE

org.springframework.boot

spring-boot-starter-web

org.springframework.boot

spring-boot-starter-thymeleaf

UTF-8

3.0.0.RELEASE

2.0.0

为 项目 书写一个 启动类

package com.ghc.starter; // 千万注意,这里将启动类放置在 starter 这个 root 目录下,后面 controller, service,dao 等就不用写注解去 @ComponentScan 了

import org.springframework.boot.*;

import org.springframework.boot.autoconfigure.*;

import org.springframework.web.bind.annotation.*;

@RestController

@SpringBootApplication

public class Example {

@RequestMapping("/")

String home() {

return "Hello World!";

}

public static void main(String[] args) throws Exception {

SpringApplication.run(Example.class, args);

}

}

这里 ,一个官方 简单的 快速搭建就已经实现了

手动输入 http://localhost:8080 即可访问 返回 页面 Hello World!

接下来,正常开发 是 分离 starter 与 controller 的

springboot 默认会有一个 application.properties 文件,我们可以在 resources 下 手动创建一个,为其添加 thymeleaf 的配置,实际上,数据源(spring.datasource.name)等都可以在此配置

#thymelea模板配置

spring.thymeleaf.prefix=classpath:/templates/

spring.thymeleaf.suffix=.html

spring.thymeleaf.mode=HTML5

spring.thymeleaf.encoding=UTF-8

#热部署文件,页面不产生缓存,及时更新

spring.thymeleaf.cache=false

spring.resources.chain.strategy.content.enabled=true

spring.resources.chain.strategy.content.paths=/**

扩展 数据源的配置

server.port=8888

spring.datasource.driver-class-name=com.amazon.redshift.jdbc41.Driver

spring.datasource.url=jdbc:xxx

spring.datasource.username= xxx

spring.datasource.password= xxx

#自动提交

spring.datasource.default-auto-commit=true

spring.datasource.initialSize=5

spring.datasource.minIdle=5

spring.datasource.maxActive=100

# 配置获取连接等待超时的时间

spring.datasource.maxWait=60000

# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒

spring.datasource.timeBetweenEvictionRunsMillis=60000

# 配置一个连接在池中最小生存的时间,单位是毫秒

spring.datasource.minEvictableIdleTimeMillis=300000

spring.datasource.validationQuery=SELECT 1

spring.datasource.testWhileIdle=true

spring.datasource.testOnBorrow=false

spring.datasource.testOnReturn=false

# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙

spring.datasource.filters=stat,wall,log4j

spring.datasource.logSlowSql=true

mybatis.config-locations=classpath:mybatis/mybatis-config.xml

mybatis.mapper-locations=classpath:mapper/*.xml

mybatis.type-aliases-package=com.middleplugin.pojo

在 resources 下 创建一个 templates 用来做 视图渲染的 view 层,这里可以是 html,不是 jsp 哦,不要太爽。。

特别注意这里 需要写上 namespace

hello

创建一个 controller 类,用来验证 thymeleaf 模板引擎起作用了。

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

@Controller

@RequestMapping("/center")

public class centercontroller {

@RequestMapping("/sayhello")

public String hello(Model model){

model.addAttribute("name","frank");

return "hello";

}

}

至此,我们可以验证一下,启动 Example 类,在 浏览器端输入 http://localhost:8080/center/sayhello 如果你有自定义 server.port 那么 就用自定义那个端口访问

整合 mybatis ,参考mybatis 官方文档其实 也没啥整合的 ,比 springmvc 容易整合。。。

准备我们的 sql 脚本

create database miaosha;

use miaosha;

create table user(id int not null auto_increment primary key,name varchar(10));

insert into user(name) values('frank');

select * from user;

修改 pom.xml 添加依赖 springboot-mybatis 整合依赖包, druid 连接池, mysql jdbc 连接驱动

com.alibaba

druid

1.1.12

org.mybatis.spring.boot

mybatis-spring-boot-starter

1.3.2

mysql

mysql-connector-java

8.0.12

修改 application.properties ,添加 mybatis, druid 等配置 注意 mybatis.mapper-locations=classpath:dao/*.xml 这个 mapper 文件指定很重要,当然后面会用注解来一次

# mybatis

# application.properties

#mybatis.type-aliases-package=com.ghc.starter.domain.model

#mybatis.type-handlers-package=com.example.typehandler

mybatis.configuration.map-underscore-to-camel-case=true

mybatis.configuration.default-fetch-size=100

mybatis.configuration.default-statement-timeout=3000

mybatis.mapper-locations=classpath:dao/*.xml

# druid

spring.datasource.url=jdbc:mysql://localhost/miaosha?useUnicode=true&characterEncoding=utf-8

spring.datasource.username=root

spring.datasource.password=xxx

spring.datasource.driver-class-name=com.mysql.jdbc.Driver

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

spring.datasource.filters=stat

spring.datasource.maxActive=2

spring.datasource.initialSize=1

spring.datasource.maxWait=60000

spring.datasource.minldle=1

spring.datasource.timeBetweenEvictionRunsMillis=60000

spring.datasource.minEvictableldleTimeMillis=300000

spring.datasource.validationQuery=select 'x'

spring.datasource.testWhileldle=true

spring.datasouce.testOnBorrow=false

spring.datasource.poolPreparedStatements=true

spring.datasource.maxOpenPreparedStatements=20

接下来做个 简单测试

pojo

package com.ghc.starter.domain.model;

import org.springframework.stereotype.Component;

@Component

public class User {

private int id;

private String name;

public int getId() {

return id;

}

public void setId(int id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

}

dao

package com.ghc.starter.dao;

import com.ghc.starter.domain.model.User;

import org.apache.ibatis.annotations.Mapper;

import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper

public interface UserDao {

@Select("select * from user")

List getAllUsers();

}

service 接口

package com.ghc.starter.service;

import com.ghc.starter.domain.model.User;

import java.util.List;

public interface UserService {

List getAllUsers();

}

service 实现类

package com.ghc.starter.service.Impl;

import com.ghc.starter.dao.UserDao;

import com.ghc.starter.domain.model.User;

import com.ghc.starter.service.UserService;

import org.apache.log4j.Logger;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.dao.DataAccessException;

import org.springframework.stereotype.Service;

import java.util.List;

@Service

public class UserServiceImpl implements UserService{

@Autowired

private UserDao userDao;

private final Logger logger = Logger.getLogger(UserServiceImpl.class);

@Override

public List getAllUsers() {

List userList = null;

try{userList = userDao.getAllUsers();

}catch(DataAccessException de){

logger.error(de);

throw new RuntimeException("数据库访问不到");

}

return userList;

}

}

优雅地 使用 枚举+泛型 封装 返回值类型 Result

code msg 基接口

package com.ghc.starter.result;

public interface BaseCodeMsg {

String msg=null;

int code=500;

}

code msg 实现类

package com.ghc.starter.result;

public enum CodeMsg implements BaseCodeMsg{

SUCCESS("SUCCESS",200),ERROR("ERROR",500);

private final String msg;

private final int code;

CodeMsg(String msg,int code){

this.msg = msg;

this.code = code;

}

public String getMsg() {

return msg;

}

public int getCode() {

return code;

}

}

最后 Result 类

package com.ghc.starter.result;

public class Result {

private String msg;

private int code;

private T data;

public static Result success(T data){

return new Result(data);

}

public static Result error(){

Result result = new Result(null);

result.code = CodeMsg.ERROR.getCode();

result.msg = CodeMsg.ERROR.getMsg();

return result;

}

private Result(T data){

this.data = data;

this.msg = CodeMsg.SUCCESS.getMsg();

this.code = CodeMsg.SUCCESS.getCode();

}

public String getMsg() {

return msg;

}

public int getCode() {

return code;

}

public T getData() {

return data;

}

}

controller 层

package com.ghc.starter.controller;

import com.ghc.starter.domain.model.User;

import com.ghc.starter.result.Result;

import com.ghc.starter.service.UserService;

import org.mybatis.spring.annotation.MapperScan;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController

@RequestMapping("/center")

public class centercontroller {

@Autowired

private UserService userService;

@RequestMapping("/sayhello")

public String hello(Model model){

model.addAttribute("name","frank");

return "hello";

}

@RequestMapping("/getAllUsers")

public Result> getAllUsers(){

List userList = null;

Result> listResult=null;

try{userList = userService.getAllUsers();

// int a = 1/0; //测试下异常

listResult = Result.success(userList);

}catch(Exception e){

listResult = Result.error();

}

return listResult;

}

}

Postman测试访问

引入 redis 缓存

基于 redis api 封装自己的 redis 操作类

修改 application.properties 文件 添加 redis 相关配置

#redis

redis.host=192.168.32.129

redis.port=6379

redis.timeout=3

redis.password=frank

redis.poolMaxTotal=10

redis.poolMaxldle=10

# 秒 = ms * 1000

redis.poolMaxWait=3

读取 application.properties 文件 redis 部分 配置。

package com.ghc.starter.redis;

import org.springframework.boot.context.properties.ConfigurationProperties;

import org.springframework.stereotype.Component;

@Component

@ConfigurationProperties(prefix = "redis")

public class RedisConfig {

private String host;

private int port;

private int timeout;

private String password;

private int poolMaxTotal;

private int poolMaxldle;

private int poolMaxWait;

public String getHost() {

return host;

}

public void setHost(String host) {

this.host = host;

}

public int getPort() {

return port;

}

public void setPort(int port) {

this.port = port;

}

public int getTimeout() {

return timeout;

}

public void setTimeout(int timeout) {

this.timeout = timeout;

}

public String getPassword() {

return password;

}

public void setPassword(String password) {

this.password = password;

}

public int getPoolMaxTotal() {

return poolMaxTotal;

}

public void setPoolMaxTotal(int poolMaxTotal) {

this.poolMaxTotal = poolMaxTotal;

}

public int getPoolMaxldle() {

return poolMaxldle;

}

public void setPoolMaxldle(int poolMaxldle) {

this.poolMaxldle = poolMaxldle;

}

public int getPoolMaxWait() {

return poolMaxWait;

}

public void setPoolMaxWait(int poolMaxWait) {

this.poolMaxWait = poolMaxWait;

}

}

redis 连接池 工厂类

package com.ghc.starter.redis;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.Bean;

import org.springframework.stereotype.Service;

import redis.clients.jedis.JedisPool;

import redis.clients.jedis.JedisPoolConfig;

@Service

public class RedisPoolFactory {

@Autowired

private RedisConfig redisConfig;

@Bean

public JedisPool jedisPoolFactory(){

JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();

jedisPoolConfig.setMaxWaitMillis(redisConfig.getPoolMaxWait()*1000); // 配置文件里是秒

jedisPoolConfig.setMaxTotal(redisConfig.getPoolMaxTotal());

jedisPoolConfig.setMaxIdle(redisConfig.getPoolMaxldle());

JedisPool jedisPool = new JedisPool(jedisPoolConfig,redisConfig

.getHost(),redisConfig.getPort(),

redisConfig.getTimeout(),redisConfig.getPassword(),0);

return jedisPool;

}

}

自定义封装的 redis 操作类,主要实现 set / get 方法

package com.ghc.starter.redis;

import com.alibaba.fastjson.JSON;

import org.springframework.beans.factory.annotation.Autowired;

import redis.clients.jedis.Jedis;

import redis.clients.jedis.JedisPool;

public class RedisService {

@Autowired

private JedisPool jedisPool;

public T get(String key,Class clazz){

Jedis jedis = null;

T t;

try{jedis = jedisPool.getResource();

String value = jedis.get(key);

t = str2Bean(value,clazz);

}finally{

return2Pool(jedis);

}

return t;

}

public boolean set(String key,T value){

Jedis jedis = null;

try{jedis = jedisPool.getResource();

String str = bean2Str(value);

if(str==null||str.length()<=0){

return false;

}else{ jedis.set(key,str);

return true;

}

}finally{

return2Pool(jedis);

}

}

@SuppressWarnings("unchecked")

private String bean2Str(T value){

Class> clazz = value.getClass();

if(value == null){

return null;

}

else if(clazz == int.class||clazz == Integer.class){

return ""+value;

}else if(clazz == String.class){

return (String)value;

}else if(clazz == long.class||clazz == Long.class){

return ""+value;

}else{

return JSON.toJSONString(value);

}

}

@SuppressWarnings("unchecked")

private T str2Bean(String value, Class clazz) {

if(value==null||value.length()<=0||clazz==null){

return null;

}else if(clazz==int.class||clazz == Integer.class){

return (T)Integer.valueOf(value);

}else if(clazz==long.class||clazz == Long.class){

return (T)Long.valueOf(value);

}else if(clazz==String.class){

return (T)value;

}else{ return JSON.toJavaObject(JSON.parseObject(value),clazz);}

}

private void return2Pool(Jedis jedis) {

if(jedis!=null){

jedis.close();

}

}

}

junit Test 测试一下

package com.ghc.starter;

import com.ghc.starter.redis.RedisService;

import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.test.context.SpringBootTest;

import org.springframework.context.annotation.Configuration;

import org.springframework.test.context.junit4.SpringRunner;

@Configuration

@RunWith(SpringRunner.class)

@SpringBootTest

public class Test {

@Autowired

private RedisService redisService;

@org.junit.Test

public void testRedisService(){

redisService.set("key1","value1");

String value = (String)redisService.get("key1",String.class);

System.out.println("value: "+value);

}

}

发现报 异常如下:

Exception in thread "main" redis.clients.jedis.exceptions.JedisConnectionException: java.SocketTimeoutException: Read timed out

那么经过查询得知需要关闭防火墙

1、关闭firewall:

systemctl stop firewalld.service #停止firewall

systemctl disable firewalld.service #禁止firewall开机启动

firewall-cmd --state #查看默认防火墙状态(关闭后显示notrunning,开启后显示running)

firewall-cmd --zone=public --add-port=6379/tcp --permanent #开放 6379 端口

为了防止 key 混淆 比如 User 的 key 与 Order 的 key ,最好绑定类名以及 id 或 name 的方式 存储一起做key ,也就是 把类名 做成 前缀

前缀 接口

package com.ghc.starter.prefix;

public interface KeyPrefix {

int expireSeconds();

String getPrefix();

}

前缀接口实现的 抽象类

package com.ghc.starter.prefix;

public abstract class BaseKeyPrefix implements KeyPrefix {

BaseKeyPrefix(String prefix){

this(0,prefix);

}

private BaseKeyPrefix(int expireSeconds,String prefix){

this.expireSeconds = expireSeconds;

this.prefix = prefix;

}

private String prefix;

private int expireSeconds;

@Override

public int expireSeconds() { // 默认 0 代表永不过期

return expireSeconds;

}

@Override

public String getPrefix() {

return getClass().getSimpleName()+":"+prefix;

}

}

前缀抽象类的 具体子类之一, 还可以有 OrderKey

package com.ghc.starter.prefix;

public class UserKey extends BaseKeyPrefix {

private UserKey(String prefix) {

super(prefix);

}

public static UserKey getById = new UserKey("id");

public static UserKey getByName = new UserKey("name");

}

此时,我们需要对 RedisService 里面的 set , get 方法增加 输入参数 Prefix

public T get(KeyPrefix keyPrefix,String key, Class clazz){

Jedis jedis = null;

T t;

try{jedis = jedisPool.getResource();

String realKey = keyPrefix.getPrefix() + key;

String value = jedis.get(realKey);

t = str2Bean(value,clazz);

}finally{

return2Pool(jedis);

}

return t;

}

public boolean set(KeyPrefix keyPrefix,String key,T value){

Jedis jedis = null;

try{jedis = jedisPool.getResource();

String str = bean2Str(value);

if(str==null||str.length()<=0){

return false;

}else{

String realKey = keyPrefix.getPrefix() + key;

int expireSeconds = keyPrefix.expireSeconds();

if(expireSeconds>0){

jedis.setex(realKey,expireSeconds,str);

}

else{

jedis.set(realKey,str);

}

return true;

}

}finally{

return2Pool(jedis);

}

}

接下来,再做一次 JUnit 测试

package com.ghc.starter;

import com.ghc.starter.domain.model.User;

import com.ghc.starter.prefix.UserKey;

import com.ghc.starter.redis.RedisService;

import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.test.context.SpringBootTest;

import org.springframework.context.annotation.Configuration;

import org.springframework.test.context.junit4.SpringRunner;

@Configuration

@RunWith(SpringRunner.class)

@SpringBootTest

public class Test {

@Autowired

private RedisService redisService;

@org.junit.Test

public void testRedisService(){

User user = new User();

user.setId(2);

user.setName("frank2");

redisService.set(UserKey.getById,"1",user);

User getUser = (User)redisService.get(UserKey.getById,"1",User.class);

System.out.println(getUser.getName());

}

}

更多推荐

java秒杀系统优化方案

本文发布于:2024-02-10 15:25:44,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1676050.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:系统优化   方案   秒杀   java

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!