Redis事務本質是一組命令的集合。執行時,一個事務中全部的命令都會被序列化,在事務執行,會按照順序執行、一次性、排他性執行全部的命令。java
Redis事務沒有隔離級別的概念。全部的事務中,並無直接被執行,只有發起執行命令時纔會被執行。執行命令Exec。mysql
Redis執行單挑命令是保證原子性的,可是事務不保證原子性。git
Redis執行事務的流程:github
①開啓事務(multi);redis
②命令進入Queued隊列;spring
③執行事務(exec)sql
①正常流程執行事務具體操做以下:數據庫
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> set k3 v3 QUEUED
#執行事務 127.0.0.1:6379> exec 1) OK 2) OK 3) "v2" 4) OK
②在執行事務的過程當中,放棄事務執行:json
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 k4 v4 QUEUED 127.0.0.1:6379> discard #取消事務,取消事務以後,能夠看到,取消以前的隊列中的操做全部都沒有被執行 OK 127.0.0.1:6379> get k1 (nil) 127.0.0.1:6379> get k2 (nil) 127.0.0.1:6379> get k4 (nil)
③編譯型異常(代碼有問題,命令有錯誤),此時執行事務中全部的命令都不會被執行:緩存
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 #沒有這個命令,編譯環境都沒有經過 (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> get k1 (nil) 127.0.0.1:6379> get k5 (nil)
④運行時異常(1/0),此時執行事務中只會影響有異常的那個命令而不會影響其餘命令執行,錯誤命令拋出異常:
127.0.0.1:6379> set k1 "v1" OK 127.0.0.1:6379> multi OK 127.0.0.1:6379> incr k1 #執行時會失敗,最終不影響其它命令正常執行 QUEUED 127.0.0.1:6379> set k2 v2 QUEUED 127.0.0.1:6379> set k3 v3 QUEUED 127.0.0.1:6379> get k3 QUEUED 127.0.0.1:6379> get k2 QUEUED 127.0.0.1:6379> exec 1) (error) ERR value is not an integer or out of range #雖然第一條命令報錯了,可是依舊正常執行成功了,運行時錯誤 2) OK 3) OK 4) "v3" 5) "v2" 127.0.0.1:6379> get k2 "v2" 127.0.0.1:6379> get k3 "v3"
這裏先講述一個悲觀鎖與樂觀鎖的概念:
Redis測試監視:
正常場景狀況:
127.0.0.1:6379> set money 100 OK 127.0.0.1:6379> set out 0 OK 127.0.0.1:6379> watch money #監視money對象 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 QUEUED 127.0.0.1:6379> exec #事務一旦執行成功以後,監控就會取消 1) (integer) 80 2) (integer) 20
測試多線程修改值後,修改失敗,使用watch,至關於樂觀鎖:
127.0.0.1:6379> watch money #監視money OK 127.0.0.1:6379> multi #線程1操做money OK 127.0.0.1:6379> DECRBY money 10 QUEUED 127.0.0.1:6379> INCRBY out 10 QUEUED 127.0.0.1:6379> exec (nil)
127.0.0.1:6379> get money #線程2修改money
"80"
127.0.0.1:6379> set money 1000
OK
執行樂觀鎖失敗後,須要進行解鎖操做,unwatch,再從新進行監視,執行事務操做:
127.0.0.1:6379> unwatch OK 127.0.0.1:6379> watch money OK 127.0.0.1:6379> multi OK 127.0.0.1:6379> DECRBY money 10 QUEUED 127.0.0.1:6379> incrby money 10 QUEUED 127.0.0.1:6379> exec 1) (integer) 990 2) (integer) 1000 127.0.0.1:6379> watch money OK 127.0.0.1:6379> multi OK 127.0.0.1:6379> DECRBY money 10 QUEUED 127.0.0.1:6379> INCRBY out 10 QUEUED 127.0.0.1:6379> exec 1) (integer) 990 2) (integer) 30
Jedis是Redis官方推薦的java鏈接開發工具,是java操做redis的中間件。
①建立java maven項目,導入jedis依賴包:
<!--導入jedis的包--> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>3.3.0</version> </dependency> <!--fastjson--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.62</version> </dependency>
②鏈接測試,斷開鏈接操做:
public class JedisDemo { public static void main(String[] args) { //1.建立Jedis對象 Jedis jedis = new Jedis("127.0.0.1", 6379); //驗證密碼,若是沒有設置密碼則無需該操做 //jedis.auth(""); jedis.connect(); //2.執行命令操做 System.out.println(jedis.ping()); //輸出PONG表示成功 //3.執行redis相關命令操做 jedis.flushAll(); //清空全部的key操做 //4.關閉斷開鏈接 jedis.disconnect(); } }
這裏爲了簡化操做使用了本機地址進行鏈接測試,若是須要鏈接遠端雲服務redis地址,須要進行雲服務器相關的端口設置,具體設置以下見博客:
https://blog.csdn.net/weixin_43878332/article/details/108741367
①鍵值對操做
public class JedisKeyDemo { public static void main(String[] args) { Jedis jedis = new Jedis("127.0.0.1", 6379); System.out.println("清空數據:" + jedis.flushDB()); System.out.println("判斷某個鍵是否存在:" + jedis.exists("username")); System.out.println("新增<'username','kuangshen'>的鍵值對:"+jedis.set(" username", " kuangshen")); System.out.println("新增<'password','password'>的鍵值對:"+jedis.set(" password", " password")); System.out.print("系統中全部的鍵以下:"); Set<String> keys = jedis.keys("*"); System.out.println(keys); System.out.println("刪除鍵password:" + jedis.del("password")); System.out.println("判斷鍵password是否存在:"+jedis.exists(" password")); System.out.println("查看鍵username所存儲的值的類型:"+jedis.type(" username")); System.out.println("隨機返回key空間的一個:" + jedis.randomKey()); System.out.println("重命名key:" + jedis.rename("username", "name")); System.out.println("取出改後的name:" + jedis.get("name")); System.out.println("按索引查詢:" + jedis.select(0)); System.out.println("刪除當前選擇數據庫中的全部key:" + jedis.flushDB()); System.out.println("返回當前數據庫中key的數目:" + jedis.dbSize()); System.out.println("刪除全部數據庫中的全部key:" + jedis.flushAll()); } }
②對String操做命令:
public class JedisStringDemo { public static void main(String[] args) { Jedis jedis = new Jedis("127.0.0.1", 6379); jedis.flushDB(); System.out.println("===========增長數據==========="); System.out.println(jedis.set("key1", "value1")); System.out.println(jedis.set("key2", "value2")); System.out.println(jedis.set("key3", "value3")); System.out.println("刪除鍵key2:" + jedis.del("key2")); System.out.println("獲取鍵key2:" + jedis.get("key2")); System.out.println("修改key1:" + jedis.set("key1", "value1Changed")); System.out.println("獲取key1的值:" + jedis.get("key1")); System.out.println("在key3後面加入值:" + jedis.append("key3", "End")); System.out.println("key3的值:" + jedis.get("key3")); System.out.println("增長多個鍵值對:" + jedis.mset("key01", "value01", "key02", "value02", "key03", "value03")); System.out.println("獲取多個鍵值對:" + jedis.mget("key01", "key02", "key03")); System.out.println("獲取多個鍵值對:" + jedis.mget("key01", "key02", "key03", "key04")); System.out.println("刪除多個鍵值對:" + jedis.del("key01", "key02")); System.out.println("獲取多個鍵值對:" + jedis.mget("key01", "key02", "key03")); jedis.flushDB(); System.out.println("===========新增鍵值對防止覆蓋原先值=============="); System.out.println(jedis.setnx("key1", "value1")); System.out.println(jedis.setnx("key2", "value2")); System.out.println(jedis.setnx("key2", "value2-new")); System.out.println(jedis.get("key1")); System.out.println(jedis.get("key2")); System.out.println("===========新增鍵值對並設置有效時間============="); System.out.println(jedis.setex("key3", 2, "value3")); System.out.println(jedis.get("key3")); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(jedis.get("key3")); System.out.println("===========獲取原值,更新爲新值=========="); System.out.println(jedis.getSet("key2", "key2GetSet")); System.out.println(jedis.get("key2")); System.out.println("得到key2的值的字串:" + jedis.getrange("key2", 2, 4)); } }
③對List的操做:
public class JedisListDemo { public static void main(String[] args) { Jedis jedis = new Jedis("127.0.0.1", 6379); jedis.flushDB(); System.out.println("===========添加一個list==========="); jedis.lpush("collections", "ArrayList", "Vector", "Stack", "HashMap", "WeakHashMap", "LinkedHashMap"); jedis.lpush("collections", "HashSet"); jedis.lpush("collections", "TreeSet"); jedis.lpush("collections", "TreeMap"); //-1表明倒數第一個元素,-2表明倒數第二個元素,end爲-1表示查詢所有 System.out.println("collections的內容:" + jedis.lrange("collections", 0, -1)); System.out.println("collections區間0-3的元素:" + jedis.lrange("collections", 0, 3)); System.out.println("==============================="); // 刪除列表指定的值 ,第二個參數爲刪除的個數(有重複時),後add進去的值先被刪,相似於出棧 System.out.println("刪除指定元素個數:" + jedis.lrem("collections", 2, "HashMap")); System.out.println("collections的內容:" + jedis.lrange("collections", 0, -1)); System.out.println("刪除下表0-3區間以外的元素:" + jedis.ltrim("collections", 0, 3)); System.out.println("collections的內容:" + jedis.lrange("collections", 0, -1)); System.out.println("collections列表出棧(左端):" + jedis.lpop("collections")); System.out.println("collections的內容:" + jedis.lrange("collections", 0, -1)); System.out.println("collections添加元素,從列表右端,與lpush相對應:" + jedis.rpush("collections", "EnumMap")); System.out.println("collections的內容:" + jedis.lrange("collections", 0, -1)); System.out.println("collections列表出棧(右端):" + jedis.rpop("collections")); System.out.println("collections的內容:" + jedis.lrange("collections", 0, -1)); System.out.println("修改collections指定下標1的內容:" + jedis.lset("collections", 1, "LinkedArrayList")); System.out.println("collections的內容:" + jedis.lrange("collections", 0, -1)); System.out.println("==============================="); System.out.println("collections的長度:" + jedis.llen("collections")); System.out.println("獲取collections下標爲2的元素:" + jedis.lindex("collections", 2)); System.out.println("==============================="); jedis.lpush("sortedList", "3", "6", "2", "0", "7", "4"); System.out.println("sortedList排序前:" + jedis.lrange("sortedList", 0, -1)); System.out.println(jedis.sort("sortedList")); System.out.println("sortedList排序後:" + jedis.lrange("sortedList", 0, -1)); } }
④對Set的操做:
public class JedisSetDemo { public static void main(String[] args) { Jedis jedis = new Jedis("127.0.0.1", 6379); jedis.flushDB(); System.out.println("============向集合中添加元素(不重複)============"); System.out.println(jedis.sadd("eleSet","e1","e2","e4","e3","e0","e8","e7","e5")); System.out.println(jedis.sadd("eleSet", "e6")); System.out.println(jedis.sadd("eleSet", "e6")); System.out.println("eleSet的全部元素爲:"+jedis.smembers("eleSet")); System.out.println("刪除一個元素e0:"+jedis.srem("eleSet", "e0")); System.out.println("eleSet的全部元素爲:"+jedis.smembers("eleSet")); System.out.println("刪除兩個元素e7和e6:"+jedis.srem("eleSet","e7","e6")); System.out.println("eleSet的全部元素爲:"+jedis.smembers("eleSet")); System.out.println("隨機的移除集合中的一個元素:"+jedis.spop("eleSet")); System.out.println("隨機的移除集合中的一個元素:"+jedis.spop("eleSet")); System.out.println("eleSet的全部元素爲:"+jedis.smembers("eleSet")); System.out.println("eleSet中包含元素的個數:"+jedis.scard("eleSet")); System.out.println("e3是否在eleSet中:"+jedis.sismember("eleSet","e3")); System.out.println("e1是否在eleSet中:"+jedis.sismember("eleSet","e1")); System.out.println("e1是否在eleSet中:"+jedis.sismember("eleSet","e5")); System.out.println("================================="); System.out.println(jedis.sadd("eleSet1","e1","e2","e4","e3","e0","e8","e7","e5")); System.out.println(jedis.sadd("eleSet2", "e1","e2","e4","e3","e0","e8")); System.out.println("將eleSet1中刪除e1並存入eleSet3中:"+jedis.smove("eleSet1", "eleSet3", "e1"));//移到集合元素 System.out.println("將eleSet1中刪除e2並存入eleSet3中:"+jedis.smove("eleSet1", "eleSet3", "e2")); System.out.println("eleSet1中的元素:"+jedis.smembers("eleSet1")); System.out.println("eleSet3中的元素:"+jedis.smembers("eleSet3")); System.out.println("============集合運算================="); System.out.println("eleSet1中的元素:"+jedis.smembers("eleSet1")); System.out.println("eleSet2中的元素:"+jedis.smembers("eleSet2")); System.out.println("eleSet1和eleSet2的交集:"+jedis.sinter("eleSet1","eleSet2")); System.out.println("eleSet1和eleSet2的並集:"+jedis.sunion("eleSet1","eleSet2")); System.out.println("eleSet1和eleSet2的差集:"+jedis.sdiff("eleSet1","eleSet2"));//eleSet1中有,eleSet2中沒有 jedis.sinterstore("eleSet4","eleSet1","eleSet2");//求交集並將交集保存到dstkey的集合 System.out.println("eleSet4中的元素:"+jedis.smembers("eleSet4")); } }
⑤對Hash的操做:
public class JedisHashDemo { public static void main(String[] args) { Jedis jedis = new Jedis("127.0.0.1", 6379); jedis.flushDB(); Map<String, String> map = new HashMap(); map.put("key1", "value1"); map.put("key2", "value2"); map.put("key3", "value3"); map.put("key4", "value4"); //添加名稱爲hash(key)的hash元素 jedis.hmset("hash", map); //向名稱爲hash的hash中添加key爲key5,value爲value5元素 jedis.hset("hash", "key5", "value5"); System.out.println("散列hash的全部鍵值對爲:" + jedis.hgetAll("hash"));//return Map<String,String> System.out.println("散列hash的全部鍵爲:"+jedis.hkeys("hash"));//return Set<String> System.out.println("散列hash的全部值爲:"+jedis.hvals("hash"));//return List<String> System.out.println("將key6保存的值加上一個整數,若是key6不存在則添加key6:"+jedis.hincrBy("hash", "key6", 6)); System.out.println("散列hash的全部鍵值對爲:"+jedis.hgetAll("hash")); System.out.println("將key6保存的值加上一個整數,若是key6不存在則添加key6:"+jedis.hincrBy("hash", "key6", 3)); System.out.println("散列hash的全部鍵值對爲:"+jedis.hgetAll("hash")); System.out.println("刪除一個或者多個鍵值對:"+jedis.hdel("hash", "key2")); System.out.println("散列hash的全部鍵值對爲:"+jedis.hgetAll("hash")); System.out.println("散列hash中鍵值對的個數:"+jedis.hlen("hash")); System.out.println("判斷hash中是否存在key2:"+jedis.hexists("hash","key2")); System.out.println("判斷hash中是否存在key3:"+jedis.hexists("hash","key3")); System.out.println("獲取hash中的值:"+jedis.hmget("hash","key3")); System.out.println("獲取hash中的值:"+jedis.hmget("hash","key3","key4")); } }
public class MultiDemo { public static void main(String[] args) { //建立客戶端鏈接服務端,redis服務端須要被開啓 Jedis jedis = new Jedis("127.0.0.1", 6379); jedis.flushDB(); JSONObject jsonObject = new JSONObject(); jsonObject.put("hello", "world"); jsonObject.put("name", "java"); //開啓事務 Transaction multi = jedis.multi(); String result = jsonObject.toJSONString(); try { //向redis存入一條數據 multi.set("json", result); //再存入一條數據 multi.set("json2", result); //這裏引起了異常,用0做爲被除數 int i = 100 / 0; //若是沒有引起異常,執行進入隊列的命令 multi.exec(); } catch (Exception e) { e.printStackTrace(); //若是出現異常,回滾 multi.discard(); } finally { System.out.println(jedis.get("json")); System.out.println(jedis.get("json2")); //最終關閉客戶端 jedis.close(); } } }
在SpringBoot2.x以後,原來使用的jedis被替換成了lettuce。
lettuce底層採用的是netty,實例中能夠再多個線程中進行共享,不存在線程不安全的狀況,能夠減小線程的數量(NIO模式);
jedis底層採用的是直聯,多個線程操做的話,是不安全的,若是要避免不安全的狀況,則須要使用jedis pool鏈接池,耗費資源開銷比較大(BIO模式)。
源碼分析:
@Bean @ConditionalOnMissingBean(name = {"redisTemplate"}) //咱們能夠自定義一個redisTemplate來替換這個默認的bean public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
//默認的RedisTemplate沒有過多的設置,redis對象都是須要序列化的
//這裏的template對象的泛型都是Object的,咱們後續使用須要進行替換成String類型的 RedisTemplate<Object, Object> template = new RedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; } @Bean @ConditionalOnMissingBean //因爲String類型是redis中經常使用的類型,因此單獨提取了一個StringRedisTempalte出來 public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { StringRedisTemplate template = new StringRedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; }
因此,包括鏈接池的配置,在SpringBoot2.x中須要使用lettuce的pool。
①導入依賴:
<!--操做redis--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
②配置鏈接:
spring: datasource: # 驅動配置信息 url: jdbc:mysql://localhost:3306/spring_boot?useUnicode=true&characterEncoding=utf8 username: root password: root type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver # 鏈接池的配置信息 filters: stat maxActive: 20 initialSize: 1 maxWait: 60000 minIdle: 1 timeBetweenEvictionRunsMillis: 60000 minEvictableIdleTimeMillis: 300000 validationQuery: select 'x' testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true maxOpenPreparedStatements: 20 redis: host: 127.0.0.1 port: 6379 password: pass1234 pool: max-active: 100 max-idle: 10 max-wait: 100000 timeout: 0
①默認的redisTemplate操做API:
@Autowired
private RedisTemplate redisTemplate;
@Test
void contextLoads() {
/***
* redisTemplate使用:
* opsForValue:操做字符串,相似於String
* opsForList:操做List
* opsForSet
* opsForHash
* opsForZset
* opsForGeo
*opsForHyperLogLog
*/
//獲取redis的鏈接對象
/*RedisConnection redisConnection = redisTemplate.getConnectionFactory().getConnection();
redisConnection.flushAll();
redisConnection.flushDb();*/
redisTemplate.opsForValue().set("mykey", "這個是中文");
System.out.println(redisTemplate.opsForValue().get("mykey"));
}
②自定義重寫序列化redieTemplate:
重寫的RedisTemplate實現了String key的操做,並對json序列化進行了封裝,只要對象實現Serializable接口,就能夠進行存取封裝操做:
@Configuration
public class RedisConfig {
@Bean
@SuppressWarnings("all")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key採用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也採用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式採用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式採用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
寫一個Redis工具類:
相比於直接用RedisTemplate操做Redis,須要不少行代碼,所以直接封裝好一個 RedisUtils,這樣寫代碼更方便點。這個RedisUtils交給Spring容器實例化,使用時直接註解注入。
@Component public class RedisUtil { @Autowired private RedisTemplate<String, Object> redisTemplate; // =============================common============================ /** * 指定緩存失效時間 * * @param key 鍵 * @param time 時間(秒) */ public boolean expire(String key, long time) { try { if (time > 0) { redisTemplate.expire(key, time, TimeUnit.SECONDS); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 根據key 獲取過時時間 * * @param key 鍵 不能爲null * @return 時間(秒) 返回0表明爲永久有效 */ public long getExpire(String key) { return redisTemplate.getExpire(key, TimeUnit.SECONDS); } /** * 判斷key是否存在 * * @param key 鍵 * @return true 存在 false不存在 */ public boolean hasKey(String key) { try { return redisTemplate.hasKey(key); } catch (Exception e) { e.printStackTrace(); return false; } } /** * 刪除緩存 * * @param key 能夠傳一個值 或多個 */ @SuppressWarnings("unchecked") public void del(String... key) { if (key != null && key.length > 0) { if (key.length == 1) { redisTemplate.delete(key[0]); } else { redisTemplate.delete(CollectionUtils.arrayToList(key)); } } } // ============================String============================= /** * 普通緩存獲取 * * @param key 鍵 * @return 值 */ public Object get(String key) { return key == null ? null : redisTemplate.opsForValue().get(key); } /** * 普通緩存放入 * * @param key 鍵 * @param value 值 * @return true成功 false失敗 */ public boolean set(String key, Object value) { try { redisTemplate.opsForValue().set(key, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 普通緩存放入並設置時間 * * @param key 鍵 * @param value 值 * @param time 時間(秒) time要大於0 若是time小於等於0 將設置無限期 * @return true成功 false 失敗 */ public boolean set(String key, Object value, long time) { try { if (time > 0) { redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); } else { set(key, value); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 遞增 * * @param key 鍵 * @param delta 要增長几(大於0) */ public long incr(String key, long delta) { if (delta < 0) { throw new RuntimeException("遞增因子必須大於0"); } return redisTemplate.opsForValue().increment(key, delta); } /** * 遞減 * * @param key 鍵 * @param delta 要減小几(小於0) */ public long decr(String key, long delta) { if (delta < 0) { throw new RuntimeException("遞減因子必須大於0"); } return redisTemplate.opsForValue().increment(key, -delta); } // ================================Map================================= /** * HashGet * * @param key 鍵 不能爲null * @param item 項 不能爲null */ public Object hget(String key, String item) { return redisTemplate.opsForHash().get(key, item); } /** * 獲取hashKey對應的全部鍵值 * * @param key 鍵 * @return 對應的多個鍵值 */ public Map<Object, Object> hmget(String key) { return redisTemplate.opsForHash().entries(key); } /** * HashSet * * @param key 鍵 * @param map 對應多個鍵值 */ public boolean hmset(String key, Map<String, Object> map) { try { redisTemplate.opsForHash().putAll(key, map); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * HashSet 並設置時間 * * @param key 鍵 * @param map 對應多個鍵值 * @param time 時間(秒) * @return true成功 false失敗 */ public boolean hmset(String key, Map<String, Object> map, long time) { try { redisTemplate.opsForHash().putAll(key, map); if (time > 0) { expire(key, time); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 向一張hash表中放入數據,若是不存在將建立 * * @param key 鍵 * @param item 項 * @param value 值 * @return true 成功 false失敗 */ public boolean hset(String key, String item, Object value) { try { redisTemplate.opsForHash().put(key, item, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 向一張hash表中放入數據,若是不存在將建立 * * @param key 鍵 * @param item 項 * @param value 值 * @param time 時間(秒) 注意:若是已存在的hash表有時間,這裏將會替換原有的時間 * @return true 成功 false失敗 */ public boolean hset(String key, String item, Object value, long time) { try { redisTemplate.opsForHash().put(key, item, value); if (time > 0) { expire(key, time); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 刪除hash表中的值 * * @param key 鍵 不能爲null * @param item 項 可使多個 不能爲null */ public void hdel(String key, Object... item) { redisTemplate.opsForHash().delete(key, item); } /** * 判斷hash表中是否有該項的值 * * @param key 鍵 不能爲null * @param item 項 不能爲null * @return true 存在 false不存在 */ public boolean hHasKey(String key, String item) { return redisTemplate.opsForHash().hasKey(key, item); } /** * hash遞增 若是不存在,就會建立一個 並把新增後的值返回 * * @param key 鍵 * @param item 項 * @param by 要增長几(大於0) */ public double hincr(String key, String item, double by) { return redisTemplate.opsForHash().increment(key, item, by); } /** * hash遞減 * * @param key 鍵 * @param item 項 * @param by 要減小記(小於0) */ public double hdecr(String key, String item, double by) { return redisTemplate.opsForHash().increment(key, item, -by); } // ============================set============================= /** * 根據key獲取Set中的全部值 * * @param key 鍵 */ public Set<Object> sGet(String key) { try { return redisTemplate.opsForSet().members(key); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 根據value從一個set中查詢,是否存在 * * @param key 鍵 * @param value 值 * @return true 存在 false不存在 */ public boolean sHasKey(String key, Object value) { try { return redisTemplate.opsForSet().isMember(key, value); } catch (Exception e) { e.printStackTrace(); return false; } } /** * 將數據放入set緩存 * * @param key 鍵 * @param values 值 能夠是多個 * @return 成功個數 */ public long sSet(String key, Object... values) { try { return redisTemplate.opsForSet().add(key, values); } catch (Exception e) { e.printStackTrace(); return 0; } } /** * 將set數據放入緩存 * * @param key 鍵 * @param time 時間(秒) * @param values 值 能夠是多個 * @return 成功個數 */ public long sSetAndTime(String key, long time, Object... values) { try { Long count = redisTemplate.opsForSet().add(key, values); if (time > 0) expire(key, time); return count; } catch (Exception e) { e.printStackTrace(); return 0; } } /** * 獲取set緩存的長度 * * @param key 鍵 */ public long sGetSetSize(String key) { try { return redisTemplate.opsForSet().size(key); } catch (Exception e) { e.printStackTrace(); return 0; } } /** * 移除值爲value的 * * @param key 鍵 * @param values 值 能夠是多個 * @return 移除的個數 */ public long setRemove(String key, Object... values) { try { Long count = redisTemplate.opsForSet().remove(key, values); return count; } catch (Exception e) { e.printStackTrace(); return 0; } } // ===============================list================================= /** * 獲取list緩存的內容 * * @param key 鍵 * @param start 開始 * @param end 結束 0 到 -1表明全部值 */ public List<Object> lGet(String key, long start, long end) { try { return redisTemplate.opsForList().range(key, start, end); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 獲取list緩存的長度 * * @param key 鍵 */ public long lGetListSize(String key) { try { return redisTemplate.opsForList().size(key); } catch (Exception e) { e.printStackTrace(); return 0; } } /** * 經過索引 獲取list中的值 * * @param key 鍵 * @param index 索引 index>=0時, 0 表頭,1 第二個元素,依次類推;index<0 * 時,-1,表尾,-2倒數第二個元素,依次類推 */ public Object lGetIndex(String key, long index) { try { return redisTemplate.opsForList().index(key, index); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 將list放入緩存 * * @param key 鍵 * @param value 值 */ public boolean lSet(String key, Object value) { try { redisTemplate.opsForList().rightPush(key, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 將list放入緩存 * * @param key 鍵 * @param value 值 * @param time 時間(秒) */ public boolean lSet(String key, Object value, long time) { try { redisTemplate.opsForList().rightPush(key, value); if (time > 0) expire(key, time); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 將list放入緩存 * * @param key 鍵 * @param value 值 * @return */ public boolean lSet(String key, List<Object> value) { try { redisTemplate.opsForList().rightPushAll(key, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 將list放入緩存 * * @param key 鍵 * @param value 值 * @param time 時間(秒) * @return */ public boolean lSet(String key, List<Object> value, long time) { try { redisTemplate.opsForList().rightPushAll(key, value); if (time > 0) expire(key, time); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 根據索引修改list中的某條數據 * * @param key 鍵 * @param index 索引 * @param value 值 * @return */ public boolean lUpdateIndex(String key, long index, Object value) { try { redisTemplate.opsForList().set(key, index, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 移除N個值爲value * * @param key 鍵 * @param count 移除多少個 * @param value 值 * @return 移除的個數 */ public long lRemove(String key, long count, Object value) { try { Long remove = redisTemplate.opsForList().remove(key, count, value); return remove; } catch (Exception e) { e.printStackTrace(); return 0; } } }
示例代碼已上傳至Github地址:
https://github.com/devyf/SpringBoot_Study/tree/master/Springboot_redis