前言

之前在项目中做一个发放第三方兑换券的功能。第三方券保存在数据库中,一张券是一条记录,用户在购买我们商品的时候,我们在数据库中抽取一张未发放的兑换券发放给用户。这个功能很简单,需要考虑分布式服务的并发场景,当时使用redis加分布式锁避免在并发场景下兑换券被重复发放问题,当时有两个业务服务都集成了这个功能并且由不同的开发人员完成,用的都是同一张表中兑换券,也都是用的redis锁做并发控制。测试在对这两个服务同时进行并发测试的时候发现了券被并发领取的问题,这分明就是redis锁没有锁住导致的。后来发现是测试环境两个服务redis配置的database不一样导致的。那redis中的database到底是啥,这里和大家一起学习下。

redis中的database由来

redis是一个字典结构的存储服务器,一个redis实例提供了多个用来存储数据的字典,客户端可以指定将数据存储在哪个字典中。这与在一个关系数据库实例中可以创建多个数据库类似,所以可以将其中的每个字典都理解成一个独立的数据库。独立数据库中存储的数据自然也是不相互关联的。redis默认支持16个数据库,可以通过调整redis的配置文件redis/redis.conf中的databases来修改这一个值,设置完毕后重启redis便完成配置。客户端与redis建立连接后会默认选择0号数据库,不过可以随时使用SELECT命令更换数据库。建立连接之后SELECT 1就切换到db1上了。springboot项目中可以指定具体的database

spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=123456
spring.redis.database=1
spring.redis.pool.max-idle=1000
spring.redis.pool.min-idle=0
spring.redis.pool.max-active=1000
spring.redis.pool.max-wait=-1

撸撸database的概念

由于redis不支持自定义数据库的名字,所以每个数据库都以编号命名。开发者则需要自己记录存储的数据与数据库的对应关系。另外redis也不支持为每个数据库设置不同的访问密码,所以一个客户端要么可以访问全部数据库,要么全部数据库都没有权限访问。但是,要正确地理解redis的database概念这里不得不提到一个命令,清空一个redis实例中所有数据库中的数据

redis 127.0.0.1:6379> FLUSHALL

该命令可以清空实例下的所有数据库数据,这与我们所熟知的关系型数据库所不同。关系型数据库多个库常用于存储不同应用程序的数据 ,且没有方式可以同时清空实例下的所有库数据。所以对于Redis来说这些db更像是一种命名空间,不适宜使用0号数据库存储A应用的数据而使用1号数据库B应用的数据,不同的应用应该使用不同的Redis实例存储数据。前言中说到给兑换券加锁,这种场景下两个服务必须使用同一个database。

总结

redis实例默认建立了16个db,由于不支持自主进行数据库命名所以以dbX的方式命名。默认数据库数量可以修改配置文件的database值来设定。对于db正确的理解应为“命名空间”,多个应用程序不应使用同一个redis不同库,而应一个应用程序对应一个Redis实例。我们项目中的redis是使用哨兵来保持高可用,并没有使用redis集群,redis集群下只有db0,不支持多db,这点需要注意。