搭建增删改查服务
还是用昨天的注册中心和聚合中心,编写服务C,服务B也需要一些修改
数据库搭建了一个简单的user,数据是id,username,password
总体结构
依赖文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</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-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</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>
启动项
package com.xfgg.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableHystrixDashboard
@EnableHystrix
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
配置文件
server.port=8092
spring.application.name=turbine-c
eureka.instance.prefer-ip-address=true
eureka.instance.hostname=${spring.cloud.client.ip-address}
eureka.instance.instance-id=${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
eureka.client.service-url.defaultZone= http://${eureka.instance.hostname}:8761/eureka/
management.endpoints.web.exposure.include=*
feign.hystrix.enabled=true
#数据源相关配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/kgc?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true
spring.datasource.username=root
spring.datasource.password=123456
#映射xml文件
mybatis.mapper-locations=mapper/*.xml
mybatis.type-aliases-package=com.xfgg.demo
实体类编写
package com.xfgg.demo.entity;
import lombok.*;
import java.io.Serializable;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class User implements Serializable {
private Integer id;
private String username;
private String password;
}
dao层编写
package com.xfgg.demo.mapper;
import com.xfgg.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface UserRepository{
List<User> getList();
User getUserById(int id);
void delete(int id);
void update(User user);
void newp(User user);
}
service接口层编写
package com.xfgg.demo.service;
import com.xfgg.demo.entity.User;
import java.util.List;
public interface UserService {
List<User> getList();
User getUserById(int id);
void delete(int id);
void update(User user);
void newp(User user);
}
service实现层编写
package com.xfgg.demo.service.impl;
import com.xfgg.demo.entity.User;
import com.xfgg.demo.mapper.UserRepository;
import com.xfgg.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Override
public List<User> getList() {
return userRepository.getList();
}
@Override
public User getUserById(int id) {
return userRepository.getUserById(id);
}
@Override
public void delete(int id) {
userRepository.delete(id);
}
@Override
public void update(User user) {
userRepository.update(user);
}
@Override
public void newp(User user) {
userRepository.newp(user);
}
}
controller层编写
package com.xfgg.demo.controller;
import com.xfgg.demo.entity.User;
import com.xfgg.demo.service.UserService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
@RestController
public class UserAdminController {
@Resource
private UserService userService;
@GetMapping(value = "/getList")
public List<User> getList(){
List<User> list = userService.getList();
System.out.println(list);
return list;
}
@RequestMapping(value = "/getUser/{id}")
public User getUserById(@PathVariable(value = "id") int id){
User user = userService.getUserById(id);
System.out.println(user);
return userService.getUserById(id);
}
@RequestMapping(value = "/deleteUser/{id}")
public void delete(@PathVariable(value = "id") int id){
userService.delete(id);
System.out.println("success");
}
@RequestMapping(value = "/updateUser/{id}/{username}/{password}")
public void update(@PathVariable(value = "id") int id,
@PathVariable(value = "username") String username,
@PathVariable(value = "password") String password){
User user = new User();
user.setUsername(username);
user.setPassword(password);
userService.update(user);
System.out.println("更改用户"+user+"成功");
}
@RequestMapping(value = "/newp/{id}/{username}/{password}")
public void newp(@PathVariable(value = "id") int id,
@PathVariable(value = "username") String username,
@PathVariable(value = "password") String password){
User user = new User();
user.setId(id);
user.setUsername(username);
user.setPassword(password);
userService.newp(user);
System.out.println("添加用户"+user+"成功");
}
}
mapper编写
<?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.xfgg.demo.mapper.UserRepository">
<!-- CodeBuilder Generated -->
<resultMap id="UserMap" type="com.xfgg.demo.entity.User">
<id column="id" property="id" jdbcType="INTEGER" />
<result column="username" property="username" jdbcType="VARCHAR" />
<result column="password" property="password" jdbcType="VARCHAR" />
</resultMap>
<sql id="Base_List">
id,username,password
</sql>
<select id="getList" resultMap="UserMap">
select
<include refid="Base_List"></include>
from user
</select>
<select id="getUserById" resultMap="UserMap">
select * from user
where id=#{id}
</select>
<insert id="newp" parameterType="com.xfgg.demo.entity.User">
insert into
user
(id,username,password)
values
(#{id},#{username},#{password})
</insert>
<update id="update" parameterType="com.xfgg.demo.entity.User">
update
user
set
username=#{username},password=#{password}
where
id=#{id}
</update>
<delete id="delete" parameterType="com.xfgg.demo.entity.User">
delete from
user
where
id=#{id}
</delete>
</mapper>
依次启动注册中心,聚合中心,服务ABC
如图
hystrix dashboard效果图
使用postman将各个请求运行100次
仪表盘效果
可以看到一切正常
这次我们将删除用户去掉,理想状况应该是会导致newp错误率达到100%
断路器并不是马上打开,可以看到失败了20个请求,80个请求使用了熔断器
delete服务的请求曲线平缓
Redis
因为之前有学过,所以这里只是大概过一下概念和常用的数据结构,手动构造一个数据
基本概念
Redis 是完全开源的,遵守 BSD 协议,是一个高性能的 key-value 数据库。
- Redis 与其他 key - value 缓存产品有以下三个特点:
- Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
- Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
- Redis支持数据的备份,即master-slave模式的数据备份。
常用的数据结构
语法
127.0.0.1:6379> COMMAND KEY_NAME
- String
Redis 字符串数据类型的相关命令用于管理 redis 字符串值,基本语法如下:
127.0.0.1:6379> set xf redis
OK
127.0.0.1:6379> get xf
"redis"
127.0.0.1:6379> getrange xf 1 3
"edi"
127.0.0.1:6379> getset xf redis
"redis"
127.0.0.1:6379> get xf
"redis"
127.0.0.1:6379> getbit key 1
(integer) 0
127.0.0.1:6379> getbit key 2
(integer) 0
127.0.0.1:6379> mget xf xf
1) "redis"
2) "redis"
127.0.0.1:6379> setnx xf redis
(integer) 0
127.0.0.1:6379> setex xf 100 redis
OK
详情见:https://www.runoob.com/redis/redis-strings.html
- Hash
Redis hash 是一个 string 类型的 field(字段) 和 value(值) 的映射表,hash 特别适合用于存储对象。
Redis 中每个 hash 可以存储 232 - 1 键值对(40多亿)。
127.0.0.1:6379> hmset xf name xfgg like ball age 20
OK
127.0.0.1:6379> hgetall xf
1) "name"
2) "xfgg"
3) "like"
4) "ball"
5) "age"
6) "20"
127.0.0.1:6379> hdel xf name xfgg
(integer) 1
127.0.0.1:6379> hgetall xf
1) "like"
2) "ball"
3) "age"
4) "20"
127.0.0.1:6379> hexists xf age
(integer) 1
127.0.0.1:6379> hget xf age
"20"
127.0.0.1:6379> hincrby xf age 1
(integer) 21
127.0.0.1:6379> hkeys xf
1) "like"
2) "age"
127.0.0.1:6379> hlen xf
(integer) 2
127.0.0.1:6379> hvals xf
1) "ball"
2) "21"
具体:https://www.runoob.com/redis/redis-hashes.html
- List
Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)
一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。
127.0.0.1:6379> lpush xf redis
(integer) 1
127.0.0.1:6379> lpush xf mysql
(integer) 2
127.0.0.1:6379> lpush xf mybatis
(integer) 3
127.0.0.1:6379> lrange xf 0 10
1) "mybatis"
2) "mysql"
3) "redis"
具体:https://www.runoob.com/redis/redis-lists.html
- Set
Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。
127.0.0.1:6379> sadd xf reids
(integer) 1
127.0.0.1:6379> sadd xf mysql
(integer) 1
127.0.0.1:6379> sadd xf mysql
(integer) 0
127.0.0.1:6379> sadd xf mybatis
(integer) 1
127.0.0.1:6379> smembers xf
1) "reids"
2) "mybatis"
3) "mysql"
127.0.0.1:6379>
具体:https://www.runoob.com/redis/redis-sets.html
- zset
Redis 有序集合和集合一样也是 string 类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序。
有序集合的成员是唯一的,但分数(score)却可以重复。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。 集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。
127.0.0.1:6379> zadd xf 1 redis
(integer) 1
127.0.0.1:6379> zadd xf 2 mybatis
(integer) 1
127.0.0.1:6379> zadd xf 3 mysql
(integer) 1
127.0.0.1:6379> zadd xf 3 mysql
(integer) 0
127.0.0.1:6379> zadd xf 4 mysql
(integer) 0
127.0.0.1:6379> zrange xf 0 10 withscores
1) "redis"
2) "1"
3) "mybatis"
4) "2"
5) "mysql"
6) "4"
127.0.0.1:6379> zrange xf 0 10
1) "redis"
2) "mybatis"
3) "mysql"
127.0.0.1:6379>
具体:https://www.runoob.com/redis/redis-sorted-sets.html
通过template模拟取数据
使用网络上大佬的RedisUtils工具类
package com.xfgg.demo.utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Service;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@Service
public class RedisUtils {
@Autowired
private RedisTemplate redisTemplate;
private static double size = Math.pow(2, 32);
/**
* 写入缓存
*
* @param key
* @param offset 位 8Bit=1Byte
* @return
*/
public boolean setBit(String key, long offset, boolean isShow) {
boolean result = false;
try {
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
operations.setBit(key, offset, isShow);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 写入缓存
*
* @param key
* @param offset
* @return
*/
public boolean getBit(String key, long offset) {
boolean result = false;
try {
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
result = operations.getBit(key, offset);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 写入缓存
*
* @param key
* @param value
* @return
*/
public boolean set(final String key, Object value) {
boolean result = false;
try {
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 写入缓存设置时效时间
*
* @param key
* @param value
* @return
*/
public boolean set(final String key, Object value, Long expireTime) {
boolean result = false;
try {
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 批量删除对应的value
*
* @param keys
*/
public void remove(final String... keys) {
for (String key : keys) {
remove(key);
}
}
/**
* 删除对应的value
*
* @param key
*/
public void remove(final String key) {
if (exists(key)) {
redisTemplate.delete(key);
}
}
/**
* 判断缓存中是否有对应的value
*
* @param key
* @return
*/
public boolean exists(final String key) {
return redisTemplate.hasKey(key);
}
/**
* 读取缓存
*
* @param key
* @return
*/
public Object get(final String key) {
Object result = null;
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
result = operations.get(key);
return result;
}
/**
* 哈希 添加
*
* @param key
* @param hashKey
* @param value
*/
public void hmSet(String key, Object hashKey, Object value) {
HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
hash.put(key, hashKey, value);
}
/**
* 哈希获取数据
*
* @param key
* @param hashKey
* @return
*/
public Object hmGet(String key, Object hashKey) {
HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
return hash.get(key, hashKey);
}
/**
* 列表添加
*
* @param k
* @param v
*/
public void lPush(String k, Object v) {
ListOperations<String, Object> list = redisTemplate.opsForList();
list.rightPush(k, v);
}
/**
* 列表获取
*
* @param k
* @param l
* @param l1
* @return
*/
public List<Object> lRange(String k, long l, long l1) {
ListOperations<String, Object> list = redisTemplate.opsForList();
return list.range(k, l, l1);
}
/**
* 集合添加
*
* @param key
* @param value
*/
public void add(String key, Object value) {
SetOperations<String, Object> set = redisTemplate.opsForSet();
set.add(key, value);
}
/**
* 集合获取
*
* @param key
* @return
*/
public Set<Object> setMembers(String key) {
SetOperations<String, Object> set = redisTemplate.opsForSet();
return set.members(key);
}
/**
* 有序集合添加
*
* @param key
* @param value
* @param scoure
*/
public void zAdd(String key, Object value, double scoure) {
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
zset.add(key, value, scoure);
}
/**
* 有序集合获取
*
* @param key
* @param scoure
* @param scoure1
* @return
*/
public Set<Object> rangeByScore(String key, double scoure, double scoure1) {
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
redisTemplate.opsForValue();
return zset.rangeByScore(key, scoure, scoure1);
}
//第一次加载的时候将数据加载到redis中
public void saveDataToRedis(String name) {
double index = Math.abs(name.hashCode() % size);
long indexLong = new Double(index).longValue();
boolean availableUsers = setBit("availableUsers", indexLong, true);
}
//第一次加载的时候将数据加载到redis中
public boolean getDataToRedis(String name) {
double index = Math.abs(name.hashCode() % size);
long indexLong = new Double(index).longValue();
return getBit("availableUsers", indexLong);
}
/**
* 有序集合获取排名
*
* @param key 集合名称
* @param value 值
*/
public Long zRank(String key, Object value) {
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
return zset.rank(key,value);
}
/**
* 有序集合获取排名
*
* @param key
*/
public Set<ZSetOperations.TypedTuple<Object>> zRankWithScore(String key, long start,long end) {
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
Set<ZSetOperations.TypedTuple<Object>> ret = zset.rangeWithScores(key,start,end);
return ret;
}
/**
* 有序集合添加
*
* @param key
* @param value
*/
public Double zSetScore(String key, Object value) {
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
return zset.score(key,value);
}
/**
* 有序集合添加分数
*
* @param key
* @param value
* @param scoure
*/
public void incrementScore(String key, Object value, double scoure) {
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
zset.incrementScore(key, value, scoure);
}
/**
* 有序集合获取排名
*
* @param key
*/
public Set<ZSetOperations.TypedTuple<Object>> reverseZRankWithScore(String key, long start, long end) {
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
Set<ZSetOperations.TypedTuple<Object>> ret = zset.reverseRangeByScoreWithScores(key,start,end);
return ret;
}
/**
* 有序集合获取排名
*
* @param key
*/
public Set<ZSetOperations.TypedTuple<Object>> reverseZRankWithRank(String key, long start, long end) {
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
Set<ZSetOperations.TypedTuple<Object>> ret = zset.reverseRangeWithScores(key, start, end);
return ret;
}
}
发现是一些自定义的存取操作,如果想要使用需要改动大量的代码,所以感觉今天的方向错了,浪费了一个多小时来研究,造孽呀!!!!
多次尝试都达不到理想的redis存取,还是不够大佬