https://www.cnblogs.com/hunanzp/p/12304622.html
参照这篇博客
并做补充

cd 进入目录
比如: cd /usr
进入目录
cd local
进入文件夹
查看当前所有文件
ls
t

上面那篇帖子
之所以在图形界面看不到
因为没有加载conf文件
./redis-server …/redis.conf
加载redis配置文件
./redis-server …/redis.conf

退出redis
ps aux
查看进程
kill 进程号
结束进程

服务器开放redis 6379端口
开放失败打开防火墙就能开放
查看端口:
$ netstat -tlunp

(1)远程访问redis时,先将远程服务器Redis的端口(6379)放开。
$ firewall-cmd --permanent --zone=public --add-port=6379/tcp
提示:success成功

运行Java代码:Jedis jedis = new Jedis(“193.168.4.47”, 6379);报错:
redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: connect timed out
连接超时

解决:关闭防火墙试试
$ service firewalld stop #停止防火墙
$ systemctl disable firewalld.service #禁止firewall开机启动
$ firewall-cmd --state #查看防火墙状态
再次运行Java代码测试,还是报错:Connection refused: connect 拒绝访问

redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out

解决:修改redis.conf文件内容:
注意:修改是redis-4.0.11目录下的redis.conf,而不是redis-4.0.11/src下的
$ vim redis.conf
注释 # bind 127.0.0.1,并将protected-mode设为no
……
#bind 127.0.0.1
……
protected-mode no
……
#bind 127.0.0.1注释掉该IP地址,表示允许网络访问。
注意:Redis默认只允许本机连接,网络访问不允许。因此注释掉该段代码,允许网络访问。
protected-mode no表示运行时报受保护异常。

重新加载redis.conf启动redis服务:
$ ./redis-server …/redis.conf
…/redis.conf是指上一级的redis.conf,是redis-4.0.11下的,否则是redis-4.0.11/src下的。

再次执行java测试,通过。

1.关系型数据库与非关系型数据库
1.1.关系型数据库
表与表之间的数据存在关系的。
1.2.非关系型数据库——NoSQL
NoSQL(Not Only SQL——不仅仅是数据库),泛指非关系型数据库(mongeDB、Redis)。
Sql server mysql oracle 关系型数据库

1.3.NoSQL的优缺点
优点:
键值对型数据库,读(查询)写性能非常好(因为数据结构简单,没有关系,数据之间无关系);
内存数据库,可以实现数据的持久化;
无需事先为要存储的数据建立字段,随时可以存储自定义的数据格式。

缺点:
存储的数据缺少结构化。
1.4.为什么会出现NoSql数据库?
对数据库高并发读写的需求。
1.5.互联网“三高”
高并发
是指通过设计保证系统能够同时并行处理很多请求。
高并发相关常用的一些指标有响应时间(Response Time),吞吐量(Throughput),每秒查询率QPS(Query Per Second),并发用户数等。
高负载
对海量数据能够高效存储和访问需求的一种性能。
高可用
系统无中断地执行其功能的能力,代表系统的可用性程度。
1.6.为什么要使用Redis?
对数据库高并发读写的需求。每秒上万次的读写请求,硬盘IO无法承受。
对海量数据的高效率存储和访问的需求。
对数据库的高可扩展性和高可用性的需求。
2.Redis简介
2.1.概述
Redis——Remote Dictionary Server(远程数据服务)。
Redis是一个开源的、基于Key-Value方式的内存高速缓存数据库,可持久化(随时把数据备份到硬盘中),保证数据安全。
Redis也通常被称为数据结构服务器。
官  网:http://www.redis.io
中文官网:http://www.redis.cn

Redis数据库有16个数据库实例,编号是0-15。
使用Redis时,默认进入实例0。
2.2.Redis数据类型(结构)
比如:String(字符串)、Hash(哈希)、List(列表)、Sets(集合)和Sorted Sets(有序集合)等类型。
2.3.什么数据适合做缓存?
在Web开发的时候,如果有一些数据在短时间内不会发生变化,而它们还要被频繁的访问,为了提高用户的请求速度和降低网站的负载,就把这些数据放到一个读取速度更快的介质上(或者是通过较少的计算量就可以获得该数据),该行为就称作对该数据的缓存。
该介质可以是文件、数据库、内存。
内存介质经常用于数据缓存。
2.4.Redis缓存案例
同一个select查询SQL语句,每天需要被执行查询100万次,并且每次查询获得的数据还是一样的。为了减轻数据库的负载,就把查询好的数据给缓存起来(存储在内存中),第一个用户执行Select查询时从数据库中获得数据并存储到内存中,第二个到第100万个用户查询就直接从内存中获得数据。

使用缓存减轻数据库的负载。数据库是整个网站资源的“瓶颈”。
2.5.缓存的两种形式
(1)网页缓存经常用在CMS(Content Manage System)内容管理系统中(Smarty缓存)
不发生变化的新闻信息页面适合做“页面缓存”,每个用户就从一个静态页面访问该新闻即可。

(2)数据缓存经常会用在页面的具体数据中使用
京东网站的一个页面从业务上看,数据有分类(推广商品、商品精选、普通商品),这些商品从数据读取出来,为了降低数据库负载,可以给它们设置三个数据缓存,这样独立更新、独立读取。

3.Redis安装与启动、关闭
Redis的安装有两种方式:离线安装和在线安装。
3.1.安装
3.1.1.离线安装
3.1.1.1.官网下载Redis压缩包
下载地址:http://redis.io/download,下载最新文档版本。

3.1.2.通过WinSCP等远程管理工具,将压缩包复制到Linux服务器
这里在Linux中创建目录:/dml/redis,并将压缩包复制到该目录:
$ mkdir /dml/redis

或直接在线下载,再解压。
#在线下载
$ wget http://download.redis.io/releases/redis-5.0.5.tar.gz
3.1.3.解压压缩文件,并执行make对解压后的文件进行编译
在Linux中通过命令方式下载并安装:
$ cd /dml/redis

将redis解压到/dml/redis目录

$ tar -zxvf redis-4.0.11.tar.gz
$ cd redis-4.0.11

编译

$ make

解压:

查看解压后的目录:

进入解压目录查看:

编译:

编译时出现gcc错误:

安装gcc依赖:
$ yum install gcc
安装过程有点长,如不知道选择,全选Y。

再次编译安装:(注意大写)
$ make MALLOC=libc

编译完后,可以看到解压文件redis中会对应的src、conf等文件夹。
3.1.4.在线安装
在CentOS系统在线安装 Redis 服务端可以使用以下命令获得最近的软件包的列表:
$ sudo yum update

安装Redis服务端:
$ sudo yum install redis-server

3.2.启动Redis服务
启动Redis分为直接启动、后台进程方式启动。
3.2.1.直接启动Redis服务
进入/dml/redis/redis-4.0.11/src文件夹,找到Redis服务命令:redis-server

直接启动Redis服务:
$ ./redis-server

出现如下界面表示已启动 Redis服务:

3.2.2.设置后台进程方式启动
redis.conf是一个默认的配置文件。我们可以根据需要使用自己的配置文件。
Redis.conf文件所在位置:redis/redis-4.0.11

第一步:编辑修改redis.conf文件
$ vim redis.conf
将:daemoize no改为daemoize yes,保存并退出(选按ESC,再输入:wq!)。
文档中:databases 16表示Redis中默认的数据库有16个,但没有名字。

第二步:加载redis.conf文件重新启动Redis服务
$ ./redis-server /dml/redis/redis-4.0.11/redis.conf

3.3.启动Redis客户端
在成功启动Redis服务后,即可启动客启端。
注意:这里最好再开一个终端测试。

进入Redis-4.0.11/src目录,启动Redis客户端:
$ ./redis-cli

以上命令将打开以下终端:
127.0.0.1:6379>
127.0.0.1 是本机 IP ,6379 是Redis服务端口。现在我们输入PING命令,测试是否连接成功。

127.0.0.1:6379> ping
如果现面 PONG 表示连接成功。

3.4.关闭Redis
第一步:查看redis进程
$ ps -aux | grep redis

第二步:杀死进程
$ kill -9 1693

4.Redis数据类型及操作
Redis的5种数据类型:
类型 说明
String 字符串
Hash 哈希(对象)
List 列表(List集合)
Set 集合
Sorted Set 有序集合

命令方式操作5种数据类型:
命令 说明 案例
KEYS * 查看所有键
4.1.String 字符串
一般用于存储字符串数据。最大存储512M的数据
命令 说明 案例
SET key value 设置指定 key 的值 SET uname “admin”
SET upwd “123”
GET key 获取指定 key 的值 GET uname
GETRANGE key start end 返回 key 中字符串值的子字符(截取),包后 GETRANGE uname 0 2
TYPE key 显示Key的类型 TYPE uname
INCR num 数字增,必须是数字类型的字符串,其他的字符串会报错的,相当于i++ SET n 10
INCR n
GET n
DECR mun 数字减,必须是数字类型的字符串,如果键不存在,帮你创建,初始值为0 SET n 10
DECR n
GET n

4.1.1.流量控制
这里我们将在java中使用redis-incr的特性来构建一个1分钟内只允许请求100次的控制代码,key代表在redis内存放的被控制的键值。
public static boolean flowControl(String key){
//最大允许100
int max = 100;
long total = 1L;
try {
if (jedisInstance.get(key) == null) {
//jedisInstance是Jedis连接实例,可以使单链接也可以使用链接池获取,实现方式请参考之前的blog内容
//如果redis目前没有这个key,创建并赋予0,有效时间为60s
jedisInstance.setex(key, 60, “0”);
} else {
//获取加1后的值
total = jedisInstance.incr(redisKey).longValue();
//Redis TTL命令以秒为单位返回key的剩余过期时间。当key不存在时,返回-2。当key存在但没有设置剩余生存时间时,返回-1。否则,以秒为单位,返回key的剩余生存时间。
if (jedisInstance.ttl(redisKey).longValue() == -1L){
//为给定key设置生存时间,当key过期时(生存时间为0),它会被自动删除。
jedisInstance.expire(redisKey, 60);
}
}
} catch (Exception e) {
logger.error(“流量控制组件:执行计数操作失败,无法执行计数”);
}
long keytotaltransations = max;
//判断是否已超过最大值,超过则返回false
if (total > keytotaltransations) {
return false;
}
return true;
}

4.2.Hash 哈希
一般用于存储对象。
命令 说明 案例
HMSET key field1 value1 field2 value2…… 添加对象(key为对象名,field字段,value字段值) HMSET user uname “admin” password “123” age 18
TYPE key 查看key(对象)类型 TYPE user
HGET key field 获取 key 中指定字段的值 HGET user uname
HGETALL key 获取指定 key 的所有字段和值 HGETALL user
HEXISTS key field 查看 key 中指定的字段是否存在 HEXISTS user age
HDEL key field1 [field2] 删除一个或多个哈希表字段 HDEL user uname age
HLEN key 获取 key 中字段的数量 HLEN user
4.3.List 链表
一般是简单的字符串列表,按照插入顺序排序。
链表是一种数据结构,我们学习过的LinkedList也是链表结构的一种。
链表分为很多种:单向链表、双向链表、循环链表、块状链表等等。
命令 说明 案例
LPUSH key value1 [value2] 将一个或多个值插入到列表头部(左侧) LPUSH zking “admin”
LPUSH zking “abc” “abb” “abc”
RPUSH key value1 [value2] 将一个或多个值插入到列表尾部(右侧) RPUSH zking “admin”
RPUSH zking “abc” “abb” “abc”
LPUSHX key value 将一个值插入到已存在列表的头部(左侧) LPUSHX zking “left”
RPUSHX key value 将一个值插入到已存在列表的尾部(右侧) RPUSHX zking “right”
LLEN key 获取列表长度 LLEN zking
LRANGE key start end 获取列表指定范围内的元素 LRANGE zking 0 1
LPOP key 移出并获取列表的第一个元素 LPOP zking
RPOP key 移除并获取列表最后一个元素 RPOP zking
4.4.Set 集合
集合是唯一字符串的无序集合。
唯一值表示集合中不允许键中有重复的数据。
命令 说明 案例
SADD key value1 [value2…] 向集合添加一个或多个成员。
重复数据不能插入 SADD course “java”
SADD course “sqlserver” “sql”
SSCAN key cursor [MATCH pattern] [COUNT count] 迭代集合中的元素 SSCAN course 0 match s*
SCARD key 获取集合的成员数 SCARD course
SREM key value1 [value2…] 向集合删除一个或多个成员 SREM course “java”
SISMEMBER key value 判断 member 元素是否存在,是返回1,不是返回0 SISMEMBER course “java”
SMEMBERS key 返回集合中的所有成员 SMEMBERS course
SDIFF key [key1, key2 …] 差集运算
属于key且不属于key1的元素构成的集合 SADD setA 1 2 3
SADD setB 2 3 4
SADD setC 1 2 5
SDIFF setA setB
SDIFF setA setB setC
SINTER key [key …] 交集运算 SINTER setA setB
SINTER setA setB setC
SUNION key [key …] 并集运算 SUNION setA setB
SUNION setA setB setC
4.5.Sorted Set 有序集合
实际上就是在集合类型上加了个有序而已。
有序集合比列表更耗内存。
命令 说明 案例
ZADD key score1 member1 [score2 member2] 向有序集合添加一个或多个成员,或者更新已存在成员的分数。
如果member存在,则score会覆盖原有的分数。 ZADD person 1 Tom
ZADD person 1 One 2 Two 3 Three
ZCARD key 获取有序集合的成员数 ZCARD person
ZCOUNT key min max 获得指定分数范围的元素个数 ZCARD person 1 3

5.Redis可视化工具

6.入门案例:Java实现对Redis数据的CRUD
6.1.用Maven搭建项目
6.2.引入Jedis依赖包
Redis在Java的实现是jedis,所以在项目中引入jedis的依赖:

redis.clients jedis 2.9.0 6.3.Jedis操作Redis基本数据类型 public class TestRedis { @Test public void test(){ //连接Redis(193.168.4.47为服务器IP地址,6379为redis的端口) Jedis jedis = new Jedis("193.168.4.47", 6379);

//验证密码,如果没有设置密码这段代码省略
//jedis.auth(“root”);
//jedis.connect(); //连接
//jedis.disconnect();//断开连接

    //获取所有的keySet<String> keys = jedis.keys("*");for (String key : keys) {System.out.println(key);}//1. 添加String类型数据jedis.set("name", "韩梅梅");// 获取string的值System.out.println(jedis.get("name"));//2. 添加哈希Hash类型数据Map<String, String> person = new HashMap<String, String>();person.put("pid","1");person.put("pname","菊花雷");person.put("page","39");//添加jedis.hmset("person", person);//查询Map<String, String> map = jedis.hgetAll("person");System.out.println(map.get("pid"));System.out.println(map.get("pname"));System.out.println(map.get("page"));//3. 存放链列Listjedis.lpush("students","纤纤");jedis.lpush("students","雷雷");jedis.lpush("students","蕾蕾");jedis.lpush("students","纤纤");//查询List<String> students = jedis.lrange("students", 0, -1);for (String s : students) {System.out.println(s);}//4. 存放集合Set类型jedis.sadd("hobbies", "eat");jedis.sadd("hobbies", "sleep");jedis.sadd("hobbies", "playDD");jedis.sadd("hobbies", "eat");Set<String> hobbies = jedis.smembers("hobbies");System.out.println(hobbies);

}
}
6.4.注意事项
查看端口:
$ netstat -tlunp

(1)远程访问redis时,先将远程服务器Redis的端口(6379)放开。
$ firewall-cmd --permanent --zone=public --add-port=6379/tcp
提示:success成功

运行Java代码:Jedis jedis = new Jedis(“193.168.4.47”, 6379);报错:
redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: connect timed out
连接超时

解决:关闭防火墙试试
$ service firewalld stop    #停止防火墙
$ systemctl disable firewalld.service     #禁止firewall开机启动
$ firewall-cmd --state #查看防火墙状态
再次运行Java代码测试,还是报错:Connection refused: connect 拒绝访问

redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out

解决:修改redis.conf文件内容:
注意:修改是redis-4.0.11目录下的redis.conf,而不是redis-4.0.11/src下的
$ vim redis.conf
注释 # bind 127.0.0.1,并将protected-mode设为no
……
#bind 127.0.0.1
……
protected-mode no
……
#bind 127.0.0.1注释掉该IP地址,表示允许网络访问。
注意:Redis默认只允许本机连接,网络访问不允许。因此注释掉该段代码,允许网络访问。
protected-mode no表示运行时报受保护异常。

重新加载redis.conf启动redis服务:
$ ./redis-server …/redis.conf
…/redis.conf是指上一级的redis.conf,是redis-4.0.11下的,否则是redis-4.0.11/src下的。

再次执行java测试,通过。

总结:关闭防火墙,修改redis.conf,开放6379端口。

Jedis其它操作参考:
//连接redis ,redis的默认端口是6379
Jedis jedis = new Jedis (“localhost”,6379);

//验证密码,如果没有设置密码这段代码省略
jedis.auth(“password”);
jedis.connect(); //连接
jedis.disconnect(); //断开连接
Set keys = jedis.keys("*"); //列出所有的key
Set keys = jedis.keys(“key”); //查找特定的key

//移除给定的一个或多个key,如果key不存在,则忽略该命令.
jedis.del(“key1”);
jedis.del(“key1”,“key2”,“key3”,“key4”,“key5”);

//移除给定key的生存时间(设置这个key永不过期)
jedis.persist(“key1”);

//检查给定key是否存在
jedis.exists(“key1”);

//将key改名为newkey,当key和newkey相同或者key不存在时,返回一个错误
jedis.rename(“key1”, “key2”);

//返回key所储存的值的类型
//none(key不存在),string(字符串),list(列表),set(集合),zset(有序集),hash(哈希表)
jedis.type(“key1”);

//设置key生存时间,当key过期时,它会被自动删除
jedis.expire(“key1”, 5); //5秒过期

//字符串值value关联到key。
jedis.set(“key1”, “value1”);

//将值value关联到key,并将key的生存时间设为seconds(秒)
jedis.setex(“foo”, 5, “haha”);

//清空所有的key
jedis.flushAll();

//返回key的个数
jedis.dbSize();

//哈希表key中的域field的值设为value
jedis.hset(“key1”, “field1”, “field1-value”);
jedis.hset(“key1”, “field2”, “field2-value”);
Map map = new HashMap();
map.put(“field1”, “field1-value”);
map.put(“field2”, “field2-value”);
jedis.hmset(“key1”, map);

//返回哈希表key中给定域field的值
jedis.hget(“key1”, “field1”);

//返回哈希表key中给定域field的值(多个)
List list = jedis.hmget(“key1”,“field1”,“field2”);
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}

//返回哈希表key中所有域和值
Map<String,String> map = jedis.hgetAll(“key1”);
for(Map.Entry entry: map.entrySet()) {
System.out.print(entry.getKey() + “:” + entry.getValue() + " ");
}

//删除哈希表key中的一个或多个指定域
jedis.hdel(“key1”, “field1”);
jedis.hdel(“key1”, “field1”,“field2”);

//查看哈希表key中,给定域field是否存在
jedis.hexists(“key1”, “field1”);

//返回哈希表key中的所有域
jedis.hkeys(“key1”);

//返回哈希表key中的所有值
jedis.hvals(“key1”);

//将值value插入到列表key的表头
jedis.lpush(“key1”, “value1-0”);
jedis.lpush(“key1”, “value1-1”);
jedis.lpush(“key1”, “value1-2”);

//返回列表key中指定区间内的元素,区间以偏移量start和stop指定.
//下标(index)参数start和stop从0开始;
//负数下标代表从后开始(-1表示列表的最后一个元素,-2表示列表的倒数第二个元素,以此类推)
List list = jedis.lrange(“key1”, 0, -1); //stop下标也在取值范围内(闭区间)
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}

//返回列表key的长度
jedis.llen(“key1”);

//将member元素加入到集合key当中
jedis.sadd(“key1”, “value0”);
jedis.sadd(“key1”, “value1”);

//移除集合中的member元素
jedis.srem(“key1”, “value1”);

//返回集合key中的所有成员
Set set = jedis.smembers(“key1”);

//判断元素是否是集合key的成员
jedis.sismember(“key1”, “value2”));

//返回集合key的元素的数量
jedis.scard(“key1”);

//返回一个集合的全部成员,该集合是所有给定集合的交集
jedis.sinter(“key1”,“key2”)

//返回一个集合的全部成员,该集合是所有给定集合的并集
jedis.sunion(“key1”,“key2”)

//返回一个集合的全部成员,该集合是所有给定集合的差集
jedis.sdiff(“key1”,“key2”);

7.Jedis的连接池使用
连接Redis用两种方式:
(1)Jedis直连Redis
(2)Jedis连接池
7.1.为什么要使用jedis连接池?
Redis作为缓存数据库理论上和MySQL一样需要客户端和服务端建立起来连接进行相关操作,使用MySQL的时候相信大家都会使用一款开源的连接池。例如C3P0,因为直接会消耗大量的数据库资源,每一次新建一个连接池,使用后再断开连接,对于频繁访问的场景,这显然不是高效。

7.2.Jedis直连Redis
生产环境一般使用连接池的方式对Redis连接进行管理,所有Jedis对象先放在池子中,每一次需要的时候连接Redis,只需要在池子中借,用完再归还给池子。

Jedis连接池使用方式

客户端连接Redis使用的是TCP协议,直接的方式每次需要建立TCP连接,而连接池的方式是可以预先初始化好Jedis连接,所以每次只需要从Jedis连接池借用即可,而借用和归还操作是在本地进行的,只有少量的并发同步开销,远远小于新建TCP连接的开销。另外直连的方式无法限制Jedis对象的个数,在极端情况下可能会造成连接泄露,而连接池的形式可以有效的保护和控制资源的使用。但是直连方式也并不是一无是处,两种方式各自的优劣:
直连
优点:简单方便,适用于少量长期连接的场景。
缺点: 1>存在每次新建/关闭TCP连接开销。
2>资源无法控制,极端情况会出现连接泄漏。
3>Jedis对象线程不安全。
连接池
优点: 1>无需每次连接都生成Jedis对象,降低开销。
2>使用连接池的形式保护和控制资源的使用。
缺点:相对于直连,使用相对麻烦,尤其在资源的管理上需要很多参数来保证,一旦不合理也会出现问题。

Jedis直连和连接池方式对比:
Jedis提供了JedisPool这个类作为对Jedis的连接池,同时使用了Apache的通用对象池工具common-pool作为资源的管理工具,下面是使用JedisPool操作Redis的代码示例:

(1)Jedis连接池(通常JedisPool是单例的)
//common-pool连接池配置,这里使用默认配置,后面小节会介绍具体配置说明
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
//初始化Jedis连接池
JedisPool jedisPool = new JedisPool(poolConfig, “192.168.43.119”, 6379);

(2)获取Jedis对象不再是直接生成一个Jedis对象,而是直接从连接池中获取,如下:
private final Static Logger logger = Logger.getLogger(Demo.class);
Jedis jedis = null;
try{
//1. 从连接池获取 jedis 对象
jedis = jedisPool.getResource();
//2. 执行操作
jedis.get(“hello”);
}catch(Exception e) {
logger.error(e.getMessage(), e);
}finally{
if(jedis != null){
//如果使用JedisPool,jedis.close() 操作不是关闭连接,代表归还连接池
jedis.close();
}
}

这里可以看到在finally中依然是jedis.close()操作,为什么会把连接关闭呢?这不和连接池的原则违背了吗?但实际上Jedis的close()实现方式如下:
public void close() {
//使用 Jedis 连接池
if(dataSource != null) {
if(client.isBroken()) {
this.dataSource.returnBrokenResource(this);
}else{
this.dataSource.returnResource(this);
}
//直连
}else{
client.close(); //还回连接池,不是真正的关闭了连接
}
}
}

参数说明
dataSource!=null代表使用的是连接池,所以jedis.close()代表归还连接给连接池,而且Jedis会判断当前连接是否已经断开。
dataSource=null代表直连,jedis.close()代表关闭连接。

前面GenericObjectPoolConfig使用的是默认配置,实际它提供有很多参数,例如池子中最大连接数、最大空闲连接数、最小空闲连接数、连接活性检测,等等,例如下面代码:
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
//设置最大连接数为默认值的 5 倍
poolConfig.setMaxTotal(GenericObjectPoolConfig.DEFAULT_MAX_TOTAL * 5);
//设置最大
poolConfig.setMaxIdle(GenericObjectPoolConfig.DEFAULT_MAX_IDLE * 3);
//设置最小空闲连接数为默认值的 2 倍
poolConfig.setMinIdle(GenericObjectPoolConfig.DEFAULT_MIN_IDLE * 2);
//设置开启 jmx 功能
poolConfig.setJmxEnabled(true);
//设置连接池没有连接后客户端的最大等待时间 ( 单位为毫秒 )
poolConfig.setMaxWaitMillis(3000);
上面几个是GenericObjectPoolConfig几个比较常用的属性。

7.3.创建Jedis连接池工具类
第一步:在resources下创建jedis.properties配置文件。
##################################

redis缓存配置

##################################
#配置Linux的IP地址
redis.host=192.168.43.119
#端口号
redis.port=6379
#设置连接超时时间(毫秒ms)
redis.timeout=3000
#授权密码
redis.password=
#访问数据库
redis.database=2
#是否使用连接池
redis.usePool=true

#redis连接池常用配置
#池中可借的最大数
redis.maxTotal=50
#允许池中空闲的最大连接数
redis.maxIdle=30
#允许池中空闲的最小连接数
redis.minIdle=10
#获取连接最大等待时间(毫秒)
redis.maxWaitMillis=12000
#当maxActive到达最大数,获取连接时的操作  0.抛异常 1.阻塞等待 2.创建新的(maxActive将失效) -->
redis.whenExhaustedAction=1
#在创建连接时,是否验证有效性
redis.testOnCreate=true
#在获取连接时,是否验证有效性
redis.testOnBorrow=true
#在归还连接时,是否验证有效性
redis.testOnReturn=true
#当连接空闲时,是否验证有效性
redis.testWhileIdle=false
#设定间隔没过多少毫秒进行一次后台连接清理的行动
redis.timeBetweenEvictionRunsMillis=3600000
#每次检查的连接数
redis.numTestsPerEvictionRun=5
#设定在进行后台对象清理时,视休眠时间超过了多少毫秒的对象为过期。过期的对象将被回收。如果这个值不是正数,那么对休眠时间没有特别的约束。
redis.minEvictableIdleTimeMillis=300000
redis.softMinEvictableIdleTimeMillis=300000

第二步:创建Jedis连接池工具类
redis.clients.jedis.JedisPoolConfig:存放配置信息
redis.clients.jedis.JedisPool:加载配置信息创建连接池

package com.xr.ssm.util;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Properties;

public class JedisUtil {

//创建jedis连接池
private static JedisPool jedisPool;static{try {//1.加载外部properties文件InputStream is = new BufferedInputStream(new FileInputStream("jedis.properties"));Properties properties = new Properties();properties.load(is);//2.创建jedis连接池配置对象JedisPoolConfig config = new JedisPoolConfig();//为jedis连接池配置对象的属性赋值config.setMaxTotal(Integer.parseInt(properties.getProperty("redis.maxActive")));config.setMaxIdle(Integer.parseInt(properties.getProperty("redis.maxIdle")));config.setMaxWaitMillis(Integer.parseInt(properties.getProperty("redis.maxWait")));config.setTestOnBorrow(Boolean.getBoolean(properties.getProperty("redis.testOnBorrow")));//3.创建jedis连接池jedisPool = new JedisPool(config, properties.getProperty("redis.host"), Integer.parseInt(properties.getProperty("redis.port")));}catch (Exception e){e.printStackTrace();}
}//获取Redis资源
public synchronized static Jedis getJedis(){Jedis jedis = null;try{if (jedisPool != null){jedis = jedisPool.getResource();  //从池子中获取一个jedis}}catch(Exception e){e.printStackTrace();}return jedis;
}//释放redis资源
@SuppressWarnings("deprecation")
public synchronized static void releaseConn(Jedis jedis){if (jedisPool != null){jedisPool.returnResource(jedis);}
}

}

测试使用:

8.SSM集成Redis(推荐)
在SSM整合基本上实现缓存,使用Maven搭建WebApp。
8.1.引入依赖
在SSM框架基础上添加:
redis数据库客户端连接包
Spring对redis的支持包

redis.clients jedis 2.9.0 org.springframework.data spring-data-redis 2.2.3.RELEASE 注:Jedis是Redis官方首选的Java客户端开发包。 Spring-data-redis包的版本要根据Redis的版本来,例如现在用的redis是4.0.11版本,spring-data-redis如果使用2.x.x RELEASE版本,就会报applicationContext.xml中jedisConnectionFactory对象创建错误。如图:

问题一:未使用Slf4j日志

解决办法:
为项目增加Slf4j日志功能。
(1)导包

org.slf4j jcl-over-slf4j 1.5.8 org.slf4j slf4j-api 1.5.8 org.slf4j slf4j-log4j12 1.5.8 org.apache.logging.log4j log4j-core 2.11.2 org.apache.logging.log4j log4j-api 2.11.2 spring内部默认使用的日志框架是: commons-logging(需排除该依赖) 引入“jcl-over-slf4j”依赖,使spring对common-logging的调用转为对slf4j的调用, 需要注意的是: 排除commons-logging依赖后,若不配置其他替代依赖(jcl-over-slf4j),容器初始化时会报错:java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory

(2)添加log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>

(3)在类中使用(测试)
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SimpleJob implements Job {
private Logger logger = LoggerFactory.getLogger(SimpleJob.class);
public void execute(JobExecutionContext context) throws JobExecutionException {
logger.info(new Date() + " : < " + jobMsg + " >, < " + triggerMsg + " >" );
}
}

可以改成Log4j2 + Slf4j

8.2.配置连接池参数
在resources下创建reids.properties配置文件,或在db.properties中添加Redis配置参数。主要作用:
设置redis的数据源参数
设置redis数据库连接池的参数
#redis缓存配置
#配置Linux的IP地址
redis.host=192.168.159.128
#端口号
redis.port=6379
#设置连接超时时间(毫秒)
redis.timeout=2000
redis.usePool=true

#redis连接池常用配置
#最大空闲数
redis.maxIdle=300
#最大活动数
redis.maxActive=600
#最大等待时间
redis.maxWait=1000
#调用borrowObject方法时,是否进行有效检查
redis.testOnBorrow=true
#调用returnObject方法时,是否进行有效检查
redis.testOnReturn=true
注意:.properties参数值后面不要留空格。

8.3.配置Jedis
在applicationContext.xml中,或创建个applicationContext-redis.xml中配置Jedis。

8.4.编写工具类
创建RedisTemplateUtil.java工具类,编写对Redis数据库String、Hash、List、Set四种类型数据的set|get方法。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Set;

@Service
public class RedisTemplateUtil {

@Autowired
private RedisTemplate<String, Object> redisTemplate;/*** 操作String类型set*/
public void setString(String key, Object value){ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();valueOperations.set(key, value);

//设置有效时间 .expire(), TimeUnit.SECONDS为时间单位
redisTemplate.expire(key, 1000, TimeUnit.SECONDS);

}/*** 操作String类型get*/
public Object getString(String key){return redisTemplate.opsForValue().get(key);
}/*** 操作List链表类型的set/get*/
public void setList(String key, List<?> value) {ListOperations<String, Object> listOperations = redisTemplate.opsForList();listOperations.leftPush(key, value);
}
public Object getList(String key) {return redisTemplate.opsForList().leftPop(key);
}/*** 操作set集合类型的set/get*/
public void setSet(String key, Set<?> value) {SetOperations<String, Object> setOperations = redisTemplate.opsForSet();setOperations.add(key, value);
}
public Object getSet(String key) {return redisTemplate.opsForSet().members(key);
}/*** 操作hash对象类型的set/get*/
public void setHash(String key, Map<String, ?> value) {HashOperations<String, Object, Object> hashOperations = redisTemplate.opsForHash();hashOperations.putAll(key, value);
}
public Object getHash(String key) {return redisTemplate.opsForHash().entries(key);
}/*** 根据Key键删除数据(针对String、Hash、List、Set等类型)*/
public void delete(String key) {redisTemplate.delete(key);
}

}

8.5.编写Controller类
@Controller
public class UserController {

@Autowired
private UserService userService;@Autowired
private RedisTemplateUtil redisTemplateUtil;@RequestMapping("/add")
public String add(User user){int n = userService.addUser(user);System.out.println(n);return "success.jsp";
}@RequestMapping("/getUser")
public String selectUsers(Map map){ObjectMapper om = new ObjectMapper();String key = "com.zking.controller.UserController.selectUsers";//1.先从缓存中获取Object value = redisTemplateUtil.getString(key);List<User> users = null;if(value == null){System.out.println("从数据库中读取...");try {//2.从数据库获取users = userService.selectUsers();String s = om.writeValueAsString(users);//3.将数据存入缓存redisTemplateUtil.setString(key, s);

//设置数据在redis中的有效期

        } catch (JsonProcessingException e) {e.printStackTrace();}}else{System.out.println("从缓存中读取...");

try {
users = om.readValue(value.toString(), new TypeReference<List>(){});
} catch (IOException e) {
e.printStackTrace();
}
}
map.put(“users”, users);
return “success.jsp”;
}
}

Jackson依赖:

com.fasterxml.jackson.core
jackson-databind
2.9.9

9.JSON注解
Jackson提供了一系列注解,方便对JSON序列化和反序列化进行控制,下面介绍一些常用的注解。
@JsonIgnore 此注解用于属性上,作用是进行JSON操作时忽略该属性。
@JsonFormat 此注解用于属性上,作用是把Date类型直接转化为想要的格式,如@JsonFormat(pattern = “yyyy-MM-dd HH-mm-ss”)。
@JsonProperty 此注解用于属性上,作用是把该属性的名称序列化为另外一个名称,如把trueName属性序列化为name,@JsonProperty(“name”)。
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Date;
/**

  • JSON序列化和反序列化使用的User类
    */
    public class User {

    private String name;

//不JSON序列化年龄属性
@JsonIgnore
private Integer age;

//格式化日期属性
@JsonFormat(pattern = "yyyy年MM月dd日")
private Date birthday;//序列化email属性为mail
@JsonProperty("my_email")
private String email;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;
}public Date getBirthday() {return birthday;
}public void setBirthday(Date birthday) {this.birthday = birthday;
}public String getEmail() {return email;
}public void setEmail(String email) {this.email = email;
}@Override
public String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +", birthday=" + birthday +", email='" + email + '\'' +'}';
}

}

import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;

public class JacksonDemo {

public static void main(String[] args) throws ParseException, IOException {User user = new User();user.setName("zhangsan");user.setEmail("zhangsan@163.com");user.setAge(20);SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd");user.setBirthday(dateformat.parse("1996-10-01"));ObjectMapper mapper = new ObjectMapper();String json = mapper.writeValueAsString(user);System.out.println(json);
}

}

{“name”:“zhangsan”,“birthday”:“1996年09月30日”,“my_email”:“zhangsan@163.com”}

10.Jedis连接池配置说明
10.1.资源数控制参数
参数名 含义 默认值 使用建议
maxTotal 资源池最大连接数 8
maxIdle 资源池允许最大空闲连接数 8 建议=maxTotal
minIdle 资源池确保最少空闲连接数 0 预热minIdle
jmxEnabled 是否开启jmx监控,可用于监控 true 建议开启

适合的maxTotal的例子:
假如命令平均执行时间0.001s,业务需要50000QPS,maxTotal理论值=0.001*50000=50个。实际值要偏大一点。
nodes(例如应用个数)*maxTotal不能超过redis的最大连接数(maxclients  redis服务端能接收的最大client客户端连接数)。

每秒查询率:
在internat上,经常用到每秒查询率来衡量域名系统服务器的性能,其即为QPS。
对fetches/sec,即每秒的响应请求数,也即是最大吞吐能力。
计算关系:QPS = 并发量 / 平均响应时间
并发量 = QPS * 平均响应时间

QPS:每秒查询率QPS是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准。
10.2.借还参数
参数名 含义 默认值 使用建议
blockWhenExhausted 当资源池用尽后,调用者是否要等待。只有当为true时,下面的maxWaitMillis才会生效 true 建议使用默认值
maxWaitMillis 当资源池连接用尽后,调用者的最大等待时间(单位毫秒) -1:表示永不超时 不建议使用默认值
testOnBorrow 向资源池借用连接时是否做连接有效性检查(ping),无效连接会被移除 false 建议false
testOnReturn 向资源池归还连接时是否做连接有效性测试(ping),无效连接会被移除 false 建议false

10.3.连接池常见报错
包的版本不一致会导致不兼容问题,出现NoSuchMethodError异常
redis.clients.jedis.exceptions.JedisConnectionException:Could not get a resource from the pool

Caused by: java.utils.NoSuchElementException:Timeout waiting for idle object
获取连接超时,资源池没有对应的资源。
redis.clients.jedis.exceptions.JedisConnectionException:Could not get a resource from the pool

Caused by: java.utils.NoSuchElementException:Pool exhausted

资源池中资源耗尽。
解决思路
慢查询阻塞:连接池的连接都被hang住了。
资源池参数不合理:QPS高、资源池太小。
连接泄露(没有close()):此类问题比较难定位。例如client list、netstat等、最重要是代码。
DNS异常。

参考 :
https://blog.csdn.net/pbrlovejava/article/details/82050033
https://blog.csdn.net/sunhongbing1024/article/details/82017614
https://www.toutiao.com/a6329614943227412737/
11.页面中设置缓存
<%@ taglib uri=“http://java.sun.com/jsp/jstl/core” prefix=“c” %>
<%@ page isELIgnored=“false” %>
……

编号 姓名 年龄
${p.pid} ${p.pname} ${p.page}

……

11.1.运行Tomcat测试查看该操作
第一次操作数据会去redis,后面再操作读取的就是redis缓存中的。
redis持久化需要课外自学:即将数据存到数据库

问题:添加一条记录,即要添加到数据库,又要添加到缓存
@RequestMapping("/add")
public String add(Person person){
//personDao.addPerson(person);
//声明一个key
String key=“com.zking.dao.PersonDao.getPersons”;
//根据key去缓存拿值
//String s=redisCache.getDataFromRedis(key);
//将s转换成对象集合
//List persons=JSON.parseArray(s,Person.class);
//调用dao方法获得对象
persons.add(person);
//将对象集合换成成json后存入缓存
redisCache.setDataToRedis(key,JSON.toJSONString(persons));
return “success”;
}

问题:
1.数据库表中数据发生改变,如何自动更新缓存数据
2.Key如何获取
12.Putty中文乱码问题
如果用的是Putty远程Linux,可能会出现乱码问题,以下是Putty乱码解决办法。Xshell无视(推荐使用)。

运行putty时显示的中文会乱码,解决办法很简单,看下图:

13.如何有效的防止Redis雪崩和穿透
14.Redis哨兵模式
15.Redis缓存(ProtoStuff序列化)
16.redis的一主二从三哨
17.Redis Sentinel主从高可用方案
18.Redis Cluster集群高可用方案
19.Redis做MySQL数据库的缓存时,redis如何做到和mysql数据库的同步?
【方案一】http://www.zhihu.com/question/23401553?sort=created
程序实现mysql的添加、更新、删除就删除redis数据。
程序查询redis,不存在就查询mysql并保存redis。
redis和mysql数据的同步,代码级别大致可以这样做:
读:读redis -> 没有,读mysql -> 把mysql数据写回redis。
写:写mysql -> 成功,写redis(捕捉所有mysql的修改、添加和删除事件,对redis进行操作)。

【方案二】http://www.linuxidc.com/Linux/2015-01/380.htm
实时获取mysql binlog进行解析,然后修改redis
MySQL到Redis数据方案:
无论MySQL还是Redis,自身都带有数据同步的机制,像比较常用的MySQL的Master/Slave模式,就是由Slave端分析Master的binlog来实现的,这样的数据其实还是一个异步过程,只不过当服务器都在同一内网时,异步的延迟几乎可以忽略。
那么理论上我们也可以用同样方式,分析MySQL的binlog文件并将数据插入Redis。但是这需要对binlog文件以及MySQL有非常深入的理解,同时由于binlog存在Statement/Row/Mixedlevel多种形式,分析binlog实现同步的工作量是非常大的。
因此这里选择了一种开发成本更加低廉的方式,借用已经比较成熟的MySQL UDF,将MySQL数据首先放入Gearman中,然后通过一个自己编写的PHP Gearman Worker,将数据同步到Redis。比分析binlog的方式增加了不少流程,但是实现成本更低,更容易操作。

【方案三】
使用mysql的udf,详情请看MySQL :: MySQL 5.1 Reference Manual :: 22.3 Adding New Functions to MySQL 然后通过trigger在表update和insert之后进行函数的调用,写入到redis中去。大致是这个样子。
【http://www.zhihu.com/question/27738066】
1.首先明确是不是一定要上缓存,当前架构的瓶颈在哪里,若瓶颈真是数据库操作上,再继续往下看。
2.明确memcached和redis的区别,到底要使用哪个。前者终究是个缓存,不可能永久保存数据(LRU机制),支持分布式,后者除了缓存的同时也支持把数据持久化到磁盘等,redis要自己去实现分布式缓存(貌似最新版本的已集成),自己去实现一致性hash。因为不知道你们的应用场景,不好说一定要用memcache还是redis,说不定用mongodb会更好,比如在存储日志方面。
3.缓存量大但又不常变化的数据,比如评论。
4.你的思路是对的,清晰明了,读DB前,先读缓存,如果有直接返回,如果没有再读DB,然后写入缓存层并返回。
5.考虑是否需要主从,读写分离,考虑是否分布式部署,考虑是否后续水平伸缩。
6.想要一劳永逸,后续维护和扩展方便,那就将现有的代码架构优化,按你说的替换数据库组件需要改动大量代码,说明当前架构存在问题。可以利用现有的一些框架,比如SpringMVC,将你的应用层和业务层和数据库层解耦。再上缓存之前把这些做好。
7.把读取缓存等操作做成服务组件,对业务层提供服务,业务层对应用层提供服务。
8.保留原始数据库组件,优化成服务组件,方便后续业务层灵活调用缓存或者是数据库。
9.不建议一次性全量上缓存,最开始不动核心业务,可以将边缘业务先换成缓存组件,一步步换至核心业务。
10.刷新内存,以Memcached为例,新增,修改和删除操作,一般采用lazy load的策略,即新增时只写入数据库,并不会马上更新Memcached,而是等到再次读取时才会加载到Memcached中,修改和删除操作也是更新数据库,然后将Memcached中的数据标记为失效,等待下次读取时再加载。

20.Redis的缓存作用

21.刷新缓存
1、通过java程序访问Redis数据库。

1)获取连接对象,Jedis jedis=new Jedis();通过构造函数设置主机地址和端口号。
如何需要连接远程的Redis,需要在防火墙中配置Redis的端口为6379。如何进行配置呢?
Redis存储与获取数据不涉及编解码问题,存的时候是什么样,取也是什么样。
不同版本的jar包和源码包也是可以进行绑定的。
把数据通过json包转化成json字符串进行存储。
2、Jedis连接池的使用:通过jedis的连接池pool获取连接对象。  JedisPoolConfig
1)创建连接池配置对象;数据库连接池常见配置项
2)创建redis连接池,连接池配置文件
最大闲置个数:超过30个闲置的连接,就关闭其余的连接。
最小闲置个数:至少要有10个闲置连接,如果闲置连接不够用,就会创建。
最大连接数(超过最大连接数,可能会出现连接超时)。
3)从连接池中获取连接资源。
4)关闭资源
3、把Redis常用操作封装成工具类:JedisPoolUtils
通过加载配置文件的形式 加载连接池参数信息
4、在Ecplise中如何加载配置文件?
5、Jedis的数据类型  value支持五种数据结构,关于key的定义要符合规范。

虚拟机redis连接windows本地相关推荐

  1. 虚拟机redis连接不上

    连接个redis图形界面工具给我整emo了,原本在学校还能连接,不知道为什么回来就不行了. 总结一下我这三个小时的redis连接挣扎: 1.配置上面 所有的bind 全部注释掉包括什么 bind 0. ...

  2. 配置idea 的浏览器框架、Windows本地安装git,以及如何远程连接gitlab

    配置idea 的浏览器框架.Windows本地安装gitl,以及如何远程连接gitlab 一.配置idea的浏览器框架 1.1.先定位到当前项目 1.2.左上角的File栏-------------- ...

  3. VMware虚拟机网络连接设置——仅主机模式(Windows版)

    VMware虚拟机网络连接设置--仅主机模式(Windows版) 前言 各位看官,小二已多次测试教程的实用性及准确性:请按目录顺序放心食用. 一.设置VMware的虚拟网络 1.1.打开虚拟网络编辑器 ...

  4. 四章: CentOS6.5 配置连接Windows远程桌面、创建新用户、禁用root在本地或远程使用ssh登录

    1,配置连接Windows远程桌面 yum -y install freerdp xfreerdp -g 800x600 -u administrator 192.168.31.13 2,rz.sz ...

  5. 通过xrdp实现远程桌面连接Windows Azure linux虚拟机

    本文以Oracle Linux 6.4虚拟机为示例(22及3389端口必须打开,分别用于SSH及RDP连接) 1.在安装xrdp之前,首先需要安装一些必要的包,如: # yum -y install ...

  6. 运维之阿里云和本地虚拟机的连接问题

    1.阿里云 使用公网ip进行连接       端口号为22 2.本地虚拟机进行连接 使用ip addr 命令查询 本地ip,然后使用ip号和22端口号,账号,密码进行连接

  7. windows本地安全策略实验-远程桌面连接锁定账户

    windows本地安全策略实验-远程桌面连接锁定账户 实验环境: 服务端:Win7-1:10.10.10.136,开启远程桌面服务 客户端:win7-2:10.10.10.153 确保客户端和服务端能 ...

  8. xp系统远程不上服务器,WindowsXP 连接Windows 2003远程桌面 本地打印机 映射不过去 解决办法...

    今天使用Windows XP连接Windows Server 2003的远程桌面,XP的本地打印机不能出现在Windows Server 2003的远程桌面.于是进行了下面的检查.还是没搞定,后来查看 ...

  9. 虚拟机怎么连云服务器,虚拟机怎么连接云服务器

    虚拟机怎么连接云服务器 内容精选 换一换 只有运行中的云服务器才允许用户登录.Windows操作系统用户名"Administrator".忘记密码,请先通过"重置密码&q ...

最新文章

  1. java ajax无刷分页_asp.net+ajax+json来实现无刷新分页功能
  2. (Oracle学习笔记) Oracle体系结构
  3. EOJ_1070_下落的小球
  4. Java 自定义异常(转载)
  5. conda安装tensorflow-gpu
  6. ln创建、删除软/硬链接
  7. SharePoint 2010多语言UI,以及开发人员需要注意的
  8. 论文中怎么引用yolo_论文中怎么加入脚注,并且对脚注的序号、位置、格式进行调整...
  9. 传递实体类对象_Java I/O 流之对象流中的序列化和反序列化
  10. spark视频-spark机器学习
  11. 2019牛客多校第四场B xor(线性基求交)题解
  12. linux进程与线程的通讯,实验进程与线程——Linux进程与线程通讯.ppt
  13. Android SDK下载
  14. JST日本压着端子XH系列线对板连接器PCB封装库(2.5mm间距)
  15. Linux下文件搜索、查找、查看命令
  16. 实现HTML的简单压缩
  17. 作为APIcaller识别发票信息
  18. Cisco Nexus 1000V, AVS , AVE的区别
  19. 刀片服务器在哪看cpu型号,了解认识刀片服务器
  20. 填写运算符判断等式是否成立

热门文章

  1. JAVA JDBC 增删改查简单例子
  2. 在阿里云备案网站域名可以使用腾讯云服务器吗?恐怕不
  3. VMware 16 安装包下载地址,安装指导
  4. 魔众题库系统 v6.4.0 题目导入优化 自动阅卷优化 后台菜单快捷搜索
  5. C语言—打字母单机游戏(简易)
  6. 没理解工作的本质,永远赚不了大钱
  7. 完整解释 Monad -- 程序员范畴论入门
  8. 分享一款自己制作的hexo主题
  9. C语言实现:扫雷小游戏(递归展开+标记/取消标记)详细版教程
  10. 二叉树的深度优先遍历 (前序 中序 后序)