事務(wù)
Redis事務(wù)可以一次執(zhí)行多個(gè)命令表谊。三個(gè)特點(diǎn):
- Redis單條命令保證原子性钞护,但Redis事務(wù)不保證原子性!
- 事務(wù)的所有命令都會(huì)被序列化爆办,在執(zhí)行過(guò)程中难咕,會(huì)按照順序執(zhí)行。
- 所有命令在事務(wù)中距辆,沒(méi)有直接執(zhí)行余佃,只有在發(fā)起執(zhí)行命令的時(shí)候才會(huì)執(zhí)行。
Redis事務(wù)順序:開(kāi)啟事務(wù)(multi) ==> 命令入隊(duì) ==> 執(zhí)行事務(wù)(exec)
- 開(kāi)啟跨算、執(zhí)行事務(wù)(multi爆土、exec)
127.0.0.1:6379> multi #mutli開(kāi)啟事務(wù)
OK
127.0.0.1:6379> set k1 v1 #命令入隊(duì)
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec #執(zhí)行事務(wù)
1) OK
2) OK
3) "v2"
4) OK
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
3) "k1"
- 放棄事務(wù)(discard)
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> discard #中途放棄事務(wù),事務(wù)不執(zhí)行
OK
127.0.0.1:6379> get k1
(nil)
- 編譯型異常
語(yǔ)法錯(cuò)誤诸蚕,事務(wù)中所有命令都不會(huì)執(zhí)行步势。
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> getset k3 #命令錯(cuò)誤氧猬,不存在該命令,所有命令都不會(huì)執(zhí)行
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> set k5 v5
QUEUED
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> keys *
(empty list or set)
- 運(yùn)行時(shí)異常
邏輯錯(cuò)誤立润,其他命令可以正常執(zhí)行狂窑,錯(cuò)誤命令拋出異常。
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> incr k1 # 此時(shí)執(zhí)行命令失敗桑腮,但不影響其他命令執(zhí)行
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> get k4
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) (error) ERR value is not an integer or out of range
4) OK
5) OK
6) "v4"
127.0.0.1:6379> keys *
1) "k4"
2) "k2"
3) "k3"
4) "k1"
- 事務(wù)的悲觀鎖和樂(lè)觀鎖(watch)
- 悲觀鎖:假定任何時(shí)候都會(huì)出問(wèn)題泉哈,無(wú)論做什么都會(huì)加鎖。
- 樂(lè)觀鎖:假定任何時(shí)候都不會(huì)出問(wèn)題破讨,只在要出錯(cuò)時(shí)加鎖丛晦。樂(lè)觀鎖一般通過(guò)添加字段version實(shí)現(xiàn),更新數(shù)據(jù)時(shí)比較version提陶,以此表明在此期間是否有人修改過(guò)數(shù)據(jù)烫沙。大部分軟件包括Redis都采用的是樂(lè)觀鎖機(jī)制,因?yàn)楸^鎖效率太低隙笆。
不加樂(lè)觀鎖時(shí):
###進(jìn)程1
127.0.0.1:6379> unwatch #不監(jiān)視任何資源
OK
127.0.0.1:6379> get money
"100"
127.0.0.1:6379> get out
"0"
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 20
QUEUED
127.0.0.1:6379> incrby out 20 #此時(shí)在執(zhí)行exec命令前執(zhí)行進(jìn)程2锌蓄,再執(zhí)行事務(wù)
QUEUED
127.0.0.1:6379> exec
1) (integer) 180
2) (integer) 20
###進(jìn)程2
127.0.0.1:6379> get money
"100"
127.0.0.1:6379> get out
"0"
127.0.0.1:6379> set money 200
OK
加樂(lè)觀鎖時(shí):
###進(jìn)程1
127.0.0.1:6379> get money
"200"
127.0.0.1:6379> get out
"0"
127.0.0.1:6379> watch money #樂(lè)觀鎖監(jiān)視money,即獲取money的version
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 20
QUEUED
127.0.0.1:6379> incrby out 20 #此時(shí)在執(zhí)行exec命令前執(zhí)行進(jìn)程2撑柔,再事務(wù)
QUEUED
127.0.0.1:6379> exec
(nil)
###進(jìn)程2
127.0.0.1:6379> get money
"200"
127.0.0.1:6379> get out
"0"
127.0.0.1:6379> set money 100
OK
Jedis:使用Java操作Redis
使用Java操作Redis的中間件瘸爽。
- 導(dǎo)入依賴(lài)
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.2.0</version>
</dependency>
- Jedis中所有命令郭蕉,都和Redis中一樣捻悯。
Jedis jedis = new Jedis("localhost",6379);
System.out.println(jedis.ping());
System.out.println(jedis.set("k1","k2")); //OK
System.out.println(jedis.get("k1")); //k2
- Jedis中事務(wù)操作
Jedis jedis = new Jedis("localhost",6379);
jedis.flushDB();
Transaction multi = jedis.multi();
try {
multi.set("k1","v1");
multi.set("k2","v2");
multi.exec(); //執(zhí)行事務(wù)
} catch (Exception e) {
multi.discard(); //放棄事務(wù)
e.printStackTrace();
} finally {
System.out.println(jedis.get("k1"));
System.out.println(jedis.get("k2"));
jedis.close(); //關(guān)閉連接
}
Spring Boot整合Redis
- Spring Boot 2.X之后夸赫,將原來(lái)使用的Jedis替換成lettuce车海。
- lettuce采用netty,實(shí)例可以在多個(gè)線程中共享刻蚯,不存在線程不安全的情況淑蔚,更像NIO模式锈遥。而Jedis采用的是直連峻凫,多個(gè)線程操作的話渗鬼,是不安全的。
步驟:
- 導(dǎo)入依賴(lài)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 連接配置
//yml連接Redis
spring:
redis:
host: 127.0.0.1
port: 6379
//使用Redis
@Autowired
private RedisTemplate redisTemplate;
- 操作數(shù)據(jù)
//對(duì)各個(gè)數(shù)據(jù)類(lèi)型進(jìn)行操作
ValueOperations valueOperations = redisTemplate.opsForValue();
ListOperations listOperations = redisTemplate.opsForList();
SetOperations setOperations = redisTemplate.opsForSet();
HashOperations hashOperations = redisTemplate.opsForHash();
ZSetOperations zSetOperations = redisTemplate.opsForZSet();
GeoOperations geoOperations = redisTemplate.opsForGeo();
HyperLogLogOperations hyperLogLogOperations = redisTemplate.opsForHyperLogLog();
//獲取連接對(duì)象
RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
connection.flushAll();
connection.flushDb();
redis.conf配置文件
- 配置文件 unit單位對(duì)大小寫(xiě)不敏感
- 綁定網(wǎng)絡(luò)
bind 127.0.0.1 #綁定ip
protected-mode yew #保護(hù)模式
port 6379 #端口
- Redis默認(rèn)不是以守護(hù)進(jìn)程的方式運(yùn)行荧琼,可以通過(guò)配置參數(shù)乍钻,啟用守護(hù)進(jìn)程
daemonize yes #默認(rèn)為no,yes啟用守護(hù)進(jìn)程
- 日志配置
loglevel notice #日志等級(jí)
logfile "" #日志文件的位置
- 持久化及rdb配置:在規(guī)定時(shí)間內(nèi)铭腕,執(zhí)行固定次操作,就會(huì)持久化到文件 .rdb和.aof
save 900 1 #900秒內(nèi)多糠,至少有1個(gè)key進(jìn)行了修改累舷,就會(huì)進(jìn)行持久化操作。
save 300 10 #300秒內(nèi)夹孔,至少有10個(gè)key進(jìn)行了修改被盈,就會(huì)進(jìn)行持久化操作析孽。
save 60 10000 #60秒內(nèi),至少有10000個(gè)key進(jìn)行了修改只怎,就回進(jìn)行持久化操作袜瞬。
stop-writes-on-bgsave-error yes #持久化操作如果出錯(cuò),是否繼續(xù)工作身堡。yes表示繼續(xù)邓尤。
rdbcompression yes #是否壓縮.rdb文件,壓縮需要消耗CPU資源
rdbchecksum yes #保存.rdb文件時(shí)是否進(jìn)行校驗(yàn)贴谎。
dir ./ #.rdb文件保存的目錄
- 安全
requirepass foobared #登錄redis默認(rèn)沒(méi)有密碼汞扎,可設(shè)置登錄密碼
- 限制
maxClients 10000 #設(shè)置連接客戶端最大數(shù)量
maxmemory <bytes> #設(shè)置redis最大內(nèi)存容量
maxmemory-policy noeviction #內(nèi)存達(dá)到上限后的處理策略
#volatile-lru:只對(duì)設(shè)置了過(guò)期時(shí)間的key進(jìn)行LRU算法,redis默認(rèn)采用此策略
#allkeyds-lru:刪除LRU算法的key
#volatile-random:隨機(jī)刪除即將過(guò)期的key
#allkeys-random:隨機(jī)刪除
#volatile-ttl:刪除即將過(guò)期的
#noeviction:永不過(guò)期擅这,返回錯(cuò)誤
- aof配置
appendonly no #aof默認(rèn)不開(kāi)啟澈魄,使用rdb方式持久化。在大部分情況下仲翎,rdb完全夠用痹扇。
appendfilename "appendonly.aof" #aof文件名
appendfsync everysec #每秒執(zhí)行一次同步,但可能會(huì)丟失1s的數(shù)據(jù)
#always #每次修改都同步溯香,會(huì)消耗性能
#no #不同步