首页 > 代码库 > Redis学习

Redis学习

打算认真地系统地学习一下redis,本文为鉴,笑。

 

先说认识

这货是一个数据库,特点是:NoSQL + 内存型

只是,其实多数人使用的都是“内存型”这个特性 -- 因为速度快,NoSQL 反而没那么显眼。

当然,如果只是“内存型”,其实还有很多选择,例如ehcache、memcache等,甚至web应用的session也算一个,或者,还可以自己构建一个Map用于存取数据。

之所以使用Redis,是因为它还提供了很多其他特性,例如多种数据格式、事务、集群、主从、持久化、订阅/发布等等。 -- 鉴于没有深入研究过ehcache、memcache,就不列出对比了。

 

开始

官方网站 redis.io 下载后,需要安装方可使用,详情请搜索之。--建议使用Linux运行,因为多数开源工具都优先支持Linux,总要接触的,不如直接开始。当然也有windows版本的,版本较旧就是。

Linux下安装后的内容:

[root@localhost redis-3.2.6]# cd /usr/local/bin/
[root@localhost bin]# ll
总用量 26344
-rw-r--r--. 1 root root     377 12月 24 14:55 dump.rdb
-rwxr-xr-x. 1 root root 5580287 12月 24 01:45 redis-benchmark
-rwxr-xr-x. 1 root root   22177 12月 24 01:45 redis-check-aof
-rwxr-xr-x. 1 root root 7826296 12月 24 01:45 redis-check-rdb
-rwxr-xr-x. 1 root root 5708996 12月 24 01:45 redis-cli
lrwxrwxrwx. 1 root root      12 12月 24 01:45 redis-sentinel -> redis-server
-rwxr-xr-x. 1 root root 7826296 12月 24 01:45 redis-server
[root@localhost bin]#

需要说明的是,redis-server可以直接启动,但是仅限于本机使用。正确的启动方式应该附加配置文件redis.conf -- 可以在redis解压后的目录中找到,如下:

[root@localhost bin]# ll ~/software/redis-3.2.6
总用量 200
-rw-rw-r--.  1 root root 80406 12月  6 16:38 00-RELEASENOTES
-rw-rw-r--.  1 root root    53 12月  6 16:38 BUGS
-rw-rw-r--.  1 root root  1805 12月  6 16:38 CONTRIBUTING
-rw-rw-r--.  1 root root  1487 12月  6 16:38 COPYING
drwxrwxr-x.  7 root root  4096 12月 24 01:42 deps
-rw-rw-r--.  1 root root    11 12月  6 16:38 INSTALL
-rw-rw-r--.  1 root root   151 12月  6 16:38 Makefile
-rw-rw-r--.  1 root root  4223 12月  6 16:38 MANIFESTO
-rw-rw-r--.  1 root root  6834 12月  6 16:38 README.md
-rw-rw-r--.  1 root root 46695 12月  6 16:38 redis.conf
-rwxrwxr-x.  1 root root   271 12月  6 16:38 runtest
-rwxrwxr-x.  1 root root   280 12月  6 16:38 runtest-cluster
-rwxrwxr-x.  1 root root   281 12月  6 16:38 runtest-sentinel
-rw-rw-r--.  1 root root  7606 12月  6 16:38 sentinel.conf
drwxrwxr-x.  2 root root  4096 12月 24 01:42 src
drwxrwxr-x. 10 root root  4096 12月  6 16:38 tests
drwxrwxr-x.  7 root root  4096 12月  6 16:38 utils
[root@localhost bin]#

但是,默认的配置仅限于回环访问,就是仅限于127.0.0.1访问,其他地址不行,所以需要修改一下(建议备份原有的)。

[root@localhost redis-3.2.6]# cat redis.conf 
# 许可IP
bind 127.0.0.1
# 监听端口
port 6379

tcp-backlog 511

# 客户端空闲N秒后关闭连接(0是禁用)
timeout 0

tcp-keepalive 300

# 是否改为守护进程
daemonize no

supervised no

pidfile /var/run/redis_6379.pid

loglevel notice

logfile ""

databases 16

################################ SNAPSHOTTING  ################################
# 持久化(保存到硬盘上)
# 900秒(15分钟)后,如果至少一个key发生改变
save 900 1
# 300秒(5分钟)后,如果至少十个key发生改变
save 300 10
# 50秒后,如果至少10000个key发生改变
save 60 10000


stop-writes-on-bgsave-error yes

rdbcompression yes

rdbchecksum yes
# 持久化的目标文件名
dbfilename dump.rdb

# 持久化的目标目录
dir ./



# 主从
slave-serve-stale-data yes

slave-read-only yes

repl-diskless-sync no

repl-diskless-sync-delay 5
 
repl-disable-tcp-nodelay no
 
slave-priority 100
 
 
################################## SECURITY ###################################
# 安全
# 要求客户端在处理命令之前先AUTH <PASSWD>
# 鉴于Redis非常快速,外部用户每秒可以尝试150K次密码,所以建议启用一个非常强壮的密码,否则很容易被破解。--本人建议配合bind使用或者仅使用bind。
# 默认注释,即不需要密码。这里我给放开了,所以需要密码foobared
requirepass foobared



# maxclients 10000

# maxmemory <bytes>
 
# maxmemory-policy noeviction
 
# maxmemory-samples 5
 
appendonly no

# The name of the append only file (default: "appendonly.aof")
appendfilename "appendonly.aof"

# appendfsync always
appendfsync everysec
# appendfsync no
 
no-appendfsync-on-rewrite no
 
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
 
aof-load-truncated yes
 
# Set it to 0 or a negative value for unlimited execution without warnings.
lua-time-limit 5000

################################ REDIS CLUSTER  ###############################
 
# cluster-enabled yes
 
# cluster-config-file nodes-6379.conf
 
# cluster-node-timeout 15000

# cluster-slave-validity-factor 10
 
# cluster-migration-barrier 1
 
# cluster-require-full-coverage yes
 

################################## SLOW LOG ###################################
 
slowlog-log-slower-than 10000
 
slowlog-max-len 128

################################ LATENCY MONITOR ##############################
 
latency-monitor-threshold 0

############################# EVENT NOTIFICATION ##############################
 
notify-keyspace-events ""

############################### ADVANCED CONFIG ###############################
 
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
 
list-max-ziplist-size -2
 
list-compress-depth 0
 
set-max-intset-entries 512
 
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
 
hll-sparse-max-bytes 3000
 
activerehashing yes
 
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
 
hz 10
 
aof-rewrite-incremental-fsync yes

以上是精简版,去掉了大段的英文注释。因为我使用了虚拟机+桥接方式,所以不能通过127.0.0.1:6379访问,所以放开了requirepass,这样就可以通过auth来验证了。

 

数据格式

Redis支持的数据格式有五种:string、list、hash、set、sortedset!

需要注意的是,这些数据格式的 -- 本质上都是字节数组(byte[])!

所以,Redis的任何一种格式都可以存储Java的所有的类型 -- 只要你将其转成字节数组 (byte[])!

Java中对象转成字节数组(byte[])的方式,最基本的是通过ByteArrayOutputStream和ObjectOutputStream将实现了Serializable接口的类对象转成字节数组。如下:

Person p = new Person();
p.setName("小雯");
p.setId("456321789");
p.setAge(13);
p.setWords("豆蔻年华二月初");

ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
    ObjectOutputStream objectOutputStream = new ObjectOutputStream(out);
    objectOutputStream.writeObject(p);
    byte[] byteArray = out.toByteArray();
} catch (IOException e) {
    e.printStackTrace();
}

或者,使用Jackson等序列化工具进行序列化 -- 更简洁明了,因为都是字符串。

需要提一句,不建议使用ByteArrayOutputStream和ObjectOutputStream这种原始方式进行序列化,因为会序列化很多不必要的信息。以上面的代码为例,实际上我们只需要name、id、age、words这四个properties的信息就足够了,但原始的序列化还会附加很多信息(如继承的类、接口等等),这样会浪费时间和空间。

所以,推荐使用Jackson、fastjson、gson等序列化工具。

 

客户端

Java的客户端推荐使用Jedis(其实我就知道这个),自带连接池、集群等配置,其方法与Redis完全一致。与Spring结合时可以使用RedisTemplate,类似RestTemplate。

新建maven项目,添加依赖即可:

<!-- jackson新版本 -->
<!-- jackson-databind依赖core和annation,所以不必重复导入 -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.8.5</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-joda</artifactId>
    <version>2.8.5</version>
</dependency>

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
</dependency>

现在就可以使用Jedis了,先放一个小例子,后面详细研究下每种数据格式对应的方法。

public class BasicDemo {
    private static final String PREFIX = "ABCDEF.";
    private static Jedis redis;

    // redis默认开启了保护,只允许本地回环连接请求(就是127.0.0.1),需要在redis.conf中修改。或设置密码、或bind许可ip。
    @Before
    public void setUp() {
        String host = "192.168.0.210";
        int port = 6379;
        redis = new Jedis(host, port);
        redis.auth("foobaredauth");
    }

    // STRING 操作 --TODO:实际上存储的是byte[],所以可以存储任意内容
    @Test
    public void string() {

        // SET key value: 将字符串值value关联到key。
        redis.set("name", "wangjun1");
        redis.set("id", "123456");
        redis.set("address", "guangzhou");

        // SETEX key seconds value :将值value关联到key,并将key的生存时间设为seconds(以秒为单位)。
        redis.setex("foo", 5, "haha");

        // MSET key value [key value ...] :同时设置一个或多个key-value对。
        redis.mset("haha", "111", "xixi", "222");

        // redis.flushAll();清空所有的key
        System.out.println(redis.dbSize());// dbSize是多少个key的个数

        // APPEND key value :如果key已经存在并且是一个字符串,APPEND命令将value追加到key原来的值之后。
        redis.append("foo", "*00");// 如果key已经存在并且是一个字符串,APPEND命令将value追加到key原来的值之后。

        // GET key 返回key所关联的字符串值
        String foo = redis.get("foo");
        System.out.println(foo);

        // MGET key [key ...] 返回所有(一个或多个)给定key的值
        List<String> list = redis.mget("haha", "xixi");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    }
}

 

 

 

 

 

未完待续

 

 

参考:

Redis 命令参考

为什么要选择使用 Redis ?

Redis学习