我们使用maven构建项目,所以需要添加以下pom依赖,如果不需要打包,则可以省略 build
中的内容
<dependencies>
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<!-- <verbal>true</verbal>-->
</configuration>
</plugin>
</plugins>
</build>
public static void main(String[] args) {
// 配置redis连接池
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
// 设置连接池的最大连接数
jedisPoolConfig.setMaxTotal(50);
// 设置连接池最大空闲的数量
jedisPoolConfig.setMaxIdle(10);
// 设置连接池最小空闲的数量
jedisPoolConfig.setMinIdle(5);
// 连接最大超时时间
jedisPoolConfig.setMaxWaitMillis(30000);
// 创建redis连接池
JedisPool jedisPool = new JedisPool(jedisPoolConfig, "192.168.100.111", 6379);
// 获取redis对象
Jedis jedis = jedisPool.getResource();
// 预先删除
jedis.flushDB();
// 1、创建两个list 名字分别为ltest1 ltest2.
// 2、Ltest1 从左到右为1 2 3 4 5 6 7 8 9,ltest2 从左到右为 f e d c b a
jedis.lpush("ltest1", "9", "8", "7", "6", "5", "4", "3", "2", "1");
jedis.lpush("ltest2", "a", "b", "c", "d", "e", "f");
// 3、在Ltest1的3 左边插入3333
jedis.linsert("ltest1", BinaryClient.LIST_POSITION.BEFORE, "3", "3333");
// 4、在6右边插入6666
jedis.linsert("ltest1", BinaryClient.LIST_POSITION.AFTER, "6", "6666");
// 5、通过索引查询Ltest2 索引为3的数据
String index_3 = jedis.lindex("ltest2", 3);
System.out.println(index_3);
// 6、将ltest2的e 修改为EEE
jedis.lset("ltest2", 1, "EEE");
// 7、只保留ltest2的EEE d c b
jedis.ltrim("ltest2", 1, 4);
// 8、移除ltest1右边一个数据并插入ltest2的左边
jedis.rpoplpush("ltest1", "ltest2");
System.out.println("ltest1 ---> " + jedis.lrange("ltest1", 0, -1));
System.out.println("ltest2 ---> " + jedis.lrange("ltest2", 0, -1));
// 将redis连接放回连接池
jedis.close();
// 关闭redis连接池
jedisPool.close();
}
public static void main(String[] args) {
// 配置redis连接池
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
// 设置连接池的最大连接数
jedisPoolConfig.setMaxTotal(50);
// 设置连接池最大空闲的数量
jedisPoolConfig.setMaxIdle(10);
// 设置连接池最小空闲的数量
jedisPoolConfig.setMinIdle(5);
// 连接最大超时时间
jedisPoolConfig.setMaxWaitMillis(30000);
// 创建redis连接池
JedisPool jedisPool = new JedisPool(jedisPoolConfig, "192.168.100.111", 6379);
// 获取redis对象
Jedis jedis = jedisPool.getResource();
// 清空数据
jedis.flushDB();
// 1.添加set 集合 setdemo1(aa,bb,cc,dd,ee,ff) setdemo2(11,22,33,dd,ee,ff)
jedis.sadd("setdemo1", "aa", "bb", "cc", "dd", "ee", "ff");
jedis.sadd("setdemo2", "11", "22", "33", "dd", "ee", "ff");
// 2.将两个集合的交集写入setdemo3
jedis.sinterstore("setdemo3", "setdemo1", "setdemo2");
// 3.将两个集合的并集写入setdemo4
jedis.sunionstore("setdemo4", "setdemo1", "setdemo2");
// 4.将setdemo2集合与setdemo1集合的差集写入setdemo5
jedis.sdiffstore("setdemo5", "setdemo2", "setdemo1");
// 5.将setdemo2内的11 移动到setdemo1内
jedis.smove("setdemo2", "setdemo1", "11");
// 6.删除setdemo1内的bb
jedis.srem("setdemo1", "bb");
System.out.println("setdemo1 ---> " + jedis.smembers("setdemo1"));
System.out.println("setdemo2 ---> " + jedis.smembers("setdemo2"));
System.out.println("setdemo3 ---> " + jedis.smembers("setdemo3"));
System.out.println("setdemo4 ---> " + jedis.smembers("setdemo4"));
System.out.println("setdemo5 ---> " + jedis.smembers("setdemo5"));
// 将redis连接放回连接池
jedis.close();
// 关闭redis连接池
jedisPool.close();
}
组队中
某个命令出现了报告错误,执行时整个的所有队列都会被取消执行阶段
某个命令报出了错误,则只有报错的命令不会被执行,而其他命令都会执行,不会回滚传统的关系型数据库里就用到了很多这种机制
,比如行锁,表锁,读锁,写锁,都是在做操作之前先上锁版本号
等机制实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量
,Redis就是利用这种check-and-set机制实现事务的在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里
Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失
在Linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,Linux中引入了“写时复制技术
”,一般情况父进程和子进程会共用同一段物理内存,只有进程空间的各段的内容要发生变化时,才会将父进程的内容复制一份给子进程
在redis.conf
中配置文件名称,默认为dump.rdb
SAVE
或者BGSAVE
命令手动触发RDB快照保存
SAVE
和 BGSAVE
两个命令都会调用 rdbSave
函数,但它们调用的方式各有不同:
SAVE
直接调用 rdbSave
,阻塞 Redis 主进程,直到保存完成为止。在主进程阻塞期间,服务器不能处理客户端的任何请求BGSAVE
则 fork 出一个子进程
,子进程
负责调用 rdbSave
,并在保存完成之后向主进程发送信号,通知保存已完成; Redis 服务器在BGSAVE 执行期间仍然可以继续处理客户端的请求1.先通过 config get dir
查询 rdb
文件的目录
2.将dump.rdb
的文件备份即可
1.关闭Redis
2.把备份的dump.rdb
的文件拷贝到工作目录下
3.启动Redis, 备份数据会直接加载dump.rdb
优点:
缺点:
以日志的形式来记录每个写操作
,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,Redis启动时会把AOF文件中记录的所有写操作顺序执行一遍,确保数据恢复到最新
如果AOF和RDB同时开启,那么Redis默认会使用AOF进行恢复数据,因为RDB触发保存机制是有条件的,如果没有达到触发条件,那么在这段没有触发条件的时间内,一旦宕机,那么数据就会丢失,而AOF默认是每秒都会保存写操作
,相较于RDB,丢失数据的风险相较小一点,所以通过AOF恢复数据更保险
AOF的备份机制和性能虽然和RDB不同, 但是备份和恢复的操作同RDB一样,都是备份appendonly.aof
即可,需要恢复时拷贝文件到Redis工作目录下,启动系统即加载
如遇到AOF文件损坏,可通过 redis-check-aof --fix appendonly.aof
进行恢复
AOF采用文件追加方式,文件会越来越大为避免出现此种情况,新增了重写机制,当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集.可以使用命令bgrewriteaof
AOF文件持续增长而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后再rename),遍历新进程的内存中数据,每条记录有一条的Set语句。重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似
重写虽然可以节约大量磁盘空间,减少恢复时间。但是每次重写还是有一定的负担的,因此设定Redis要满足一定条件才会进行重写
系统载入时或者上次重写完毕时,Redis会记录此时AOF大小,设为base_size
,如果Redis的AOF当前大小 >= base_size + base_size*100%
(默认) 且当前大小 >= 64mb
(默认)的情况下,Redis会对AOF进行重写(rewrite)
redis-check-aof
工具轻松修复