不仅有json这样字符串还有,List集合、哈希表....
NoSQL数据库
1.结构化(约束) / 非结构化
2. 关联的 (外键) / 非关联的(嵌套,重复)
3. SQL 查询 / 非SQL (每一个库要学不同的语法)
4.事务方面: ACID(原子性、一致性、隔离性,持久性) / BASE (无事务,基本满足)
如果对数据安全性要求较高,要满足ACID。此时应该选择SQL型数据库,而不是NoSQL。
Redis是基于C语言编写的,因此首先需要安装Redis所需要的gcc依赖:
yum install -y gcc tcl
然后将Redis安装包上传 我放到了/usr/local/src 目录: 这个目录一般情况下都是放我们的安装文件。
tar -xzf redis-6.2.6.tar.gz
解压后:进入redis目录
cd redis-6.2.6
运行编译 并 安装 命令
make && make install
如果没有出错,应该就安装成功了。
默认的安装路径是在 `/usr/local/bin`目录下:
cd /usr/local/bin
该目录以及默认配置到环境变量,因此可以在任意目录下运行这些命令。其中: - redis-cli:是redis提供的命令行客户端 - redis-server:是redis的服务端启动脚本 - redis-sentinel:是redis的哨兵启动脚本
redis的启动方式有很多种,例如: - 默认启动 - 指定配置启动 - 开机自启
安装完成后,在任意目录输入redis-server命令即可启动Redis:
这种启动属于`前台启动`,会阻塞整个会话窗口,窗口关闭或者按下`CTRL + C`则Redis停止。不推荐使用。
redis-server
redis启动成功。
如果要让Redis以`后台`方式启动,则必须修改Redis配置文件,就在我们之前解压的redis安装包下(`/usr/local/src/redis-6.2.6`),名字叫redis.conf:
我们先将这个配置文件备份一份:
进入目录
cd /usr/local/src/redis-6.2.6
备份
cp redis.conf redis.conf.bck
vi redis.conf
①允许访问的地址,默认是127.0.0.1,会导致只能在本地访问。修改为0.0.0.0则可以在任意IP访问,生产环境不要设置为0.0.0.0
bind 0.0.0.0
②守护进程,修改为yes后即可后台运行
daemonize yes
③密码,设置后访问Redis必须输入密码
requirepass qyy2001
监听的端口
port 6379
工作目录,默认是当前目录,也就是运行redis-server时的命令,日志、持久化等文件会保存在这个目录
dir .
数据库数量,设置为1,代表只使用1个库,默认有16个库,编号0~15
databases 1
设置redis能够使用的最大内存
maxmemory 512mb
日志文件,默认为空,不记录日志,可以指定日志文件名
logfile "redis.log"
进入redis安装目录
cd /usr/local/src/redis-6.2.6
启动
redis-server redis.conf
查看启动的进程
ps -ef | grep redis
可以直接杀死进程
ps -ef | grep redis
kill -9 402368
我们也可以通过配置来实现开机自启。
首先,新建一个系统服务文件:
vi /etc/systemd/system/redis.service
内容如下:
[Unit] Description=redis-server After=network.target [Service] Type=forking ExecStart=/usr/local/bin/redis-server /usr/local/src/redis-6.2.6/redis.conf PrivateTmp=true [Install] WantedBy=multi-user.target
然后重载系统服务:
systemctl daemon-reload
现在,我们可以用下面这组命令来操作redis了:
启动
systemctl start redis
停止
systemctl stop redis
重启
systemctl restart redis
查看状态
systemctl status redis
执行下面的命令,可以让redis开机自启:
systemctl enable redis
Redis安装完成后就自带了命令行客户端:redis-cli,使用方式如下:
redis-cli [options] [commonds]
-h 127.0.0.1:指定要连接的redis节点的IP地址,默认是127.0.0.1 这也可以省略不写,那么就是默认值。 外部连接 通过服务器的主机地址进行连接,这就和之前的配置文件有关系了,并且还和服务器的安全组、防火墙有关系。一定要开放6379这个端口号。否则连接不成功。 我的主机地址:113.44.83.92 -p 6379:指定要连接的redis节点的端口,默认是6379.这也可以省略不写,那么就是默认值。 -a qyy2001:指定redis的访问密码(不过我们一般不在这里指定。)
例如:
ping:与redis服务端做心跳测试,服务端正常会返回pong
不指定commond时,会
基本操作(重点)
1.先连接上redis。进入 redis-cli 的交互控制台:(默认是通过本机地址进行连接)
redis-cli
也可以指定服务器地址连接
redis-cli -h 113.44.83.92
2.通过auth命令指定用户名和密码,用户名可选。此时没有用户名
auth qyy2001
3.ping 输出 pong代表连接成功
ping
4. 增:
set name java 向redis里面存了一个键值对了。key是name,value是java
5.取:
get name
这是大神编写的。
如上图显示了 redis 默认的 16 个数据库
点击别的库,新建数据。就可以添加新的键值对。 然后保存。
在服务器上面查找到这个数据
select 1
get name
可以进行如下修改的测试。注意之前的配置文件也要修改
systemctl stop firewalld
sudo systemctl start firewalld
第一步:添加防火墙规则允许 6379 端口(TCP 协议)通过
sudo firewall-cmd --permanent --add-port=6379/tcp
第二步:
,使新添加的规则生效
sudo firewall-cmd --reload
protected-mode
:protected-mode no
sudo systemctl restart redis
yum install telnet - y
telnet进行测试
telnet 113.44.83.92 6379
安全组配置错误。 我有多个实例的安全组。但是关联实例的安全组只有一个。 而恰好这个安全组没有开放 6379 的端口号。随后我添加了之后就好了。
还有别的类型,如消息队列。后面会说到
命令忘了没关系,主要是要会查
比如看String
官方文档放在Keys这个目录里面
模糊匹配查询效率不高。
当成java中的Map操作。
阻塞式获取。 等100秒、如果拿不到就报错
在另一半插入数据。最终拿到数据。返回了数据和阻塞时间
类似rpop
将下列数据用Redis的Set集合来存储:
•张三的好友有:李四、王五、赵六
•李四的好友有:王五、麻子、二狗
利用Set的命令实现下列功能:
•计算张三的好友有几人
•计算张三和李四有哪些共同好友
•查询哪些人是张三的好友却不是李四的好友
•查询张三和李四的好友总共有哪些人
•判断李四是否是张三的好友
•判断张三是否是李四的好友
•将李四从张三的好友列表中移除
Jack 85, Lucy 89, Rose 82, Tom 95, Jerry 78, Amy 92, Miles 76
•并实现下列功能:
•删除Tom同学
•获取Amy同学的分数
zscore stus amy
•获取Rose同学的排名
•查询80分以下有几个学生
•给Amy同学加2分
•查出成绩前3名的同学
•查出成绩80分以下的所有同学
Jedis的官网地址: https://github.com/redis/jedis,我们先来个快速入门:
jedis依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>5.2.0</version>
</dependency>
单元测试
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
private Jedis jedis; @BeforeEach void setUp() { // 建立连接 jedis = new Jedis("192.168.150.101", 6379); // 设置密码 jedis.auth("123321"); // 选择库 jedis.select(0); }
@Test void testString() { // 插入数据,方法名称就是redis命令名称,非常简单 String result = jedis.set("name", "张三"); System.out.println("result = " + result); // 获取数据 String name = jedis.get("name"); System.out.println("name = " + name); }
@AfterEach void tearDown() { // 释放资源 if (jedis != null) { jedis.close(); } }
public class JedisConnectionFactory { private static final JedisPool jedisPool; static { JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); // 最大连接 jedisPoolConfig.setMaxTotal(8); // 最大空闲连接 jedisPoolConfig.setMaxIdle(8); // 最小空闲连接 jedisPoolConfig.setMinIdle(0); // 设置最长等待时间, ms jedisPoolConfig.setMaxWaitMillis(200); jedisPool = new JedisPool(jedisPoolConfig, "192.168.150.101", 6379, 1000, "123321"); } // 获取Jedis对象 public static Jedis getJedis(){ return jedisPool.getResource(); } }
SpringBoot已经提供了对SpringDataRedis的支持,使用非常简单:
<!--Redis依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!--连接池依赖--> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency>
spring: redis: host: 192.168.150.101 port: 6379 password: 123321 lettuce: pool: max-active: 8 # 最大连接 max-idle: 8 # 最大空闲连接 min-idle: 0 # 最小空闲连接 max-wait: 100 # 连接等待时间
现在的配置文件需要在redis后面加上data才行
@Autowired private RedisTemplate redisTemplate;
@SpringBootTest public class RedisTest { @Autowired private RedisTemplate redisTemplate; @Test void testString() { // 插入一条string类型数据 redisTemplate.opsForValue().set("name", "李四"); // 读取一条string类型数据 Object name = redisTemplate.opsForValue().get("name"); System.out.println("name = " + name); } }
在数据库中get。我们会发现找不到虎哥,因为它被"剁碎了” 这就和序列化相关了。会将字符串转成字节。 下一节会讲到
RedisTemplate可以接收任意Object作为值写入Redis,只不过写入前会把Object序列化为字节形式,默认是采用JDK序列化,得到的结果是这样的:
缺点: 1.可读性差 2.内存占用较大
我们可以
,代码如下:
@Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { // 创建Template RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); // 设置连接工厂 redisTemplate.setConnectionFactory(redisConnectionFactory); // 设置序列化工具 GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); // key和 hashKey采用 string序列化 redisTemplate.setKeySerializer(RedisSerializer.string()); redisTemplate.setHashKeySerializer(RedisSerializer.string()); // value和 hashValue采用 JSON序列化 redisTemplate.setValueSerializer(jsonRedisSerializer); redisTemplate.setHashValueSerializer(jsonRedisSerializer); return redisTemplate; }
此时RedisTemplate就符合我们的预期了。 再回到单元测试。 给RedisTemplate加个泛型。 此时就可以往里面存取数据了。这次就能把虎哥正确写入。替代、Rose了 对了因为我们没有引入SpringMVC。因此还要手动引入一个Jackson依赖 <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency>
此时虎哥写入进去了
尽管JSON的序列化方式可以满足我们的需求,但依然存在一些问题,如图:
为了在反序列化时知道对象的类型,JSON序列化器会将类的class类型写入json结果中,存入Redis,会带来额外的内存开销。
Spring默认提供了一个StringRedisTemplate类,它的key和value的序列化方式默认就是String方式。省去了我们自定义RedisTemplate的过程:
此时就可以这样写了。
@Autowired private StringRedisTemplate stringRedisTemplate; // JSON工具 private static final ObjectMapper mapper = new ObjectMapper(); @Test void testStringTemplate() throws JsonProcessingException { // 准备对象 User user = new User("虎哥", 18); // 手动序列化 String json = mapper.writeValueAsString(user); // 写入一条数据到redis stringRedisTemplate.opsForValue().set("user:200", json); // 读取数据 String val = stringRedisTemplate.opsForValue().get("user:200"); // 反序列化 User user1 = mapper.readValue(val, User.class); System.out.println("user1 = " + user1); }