連接到Redis
使用Redis和Spring時的首要任務之一是通過IoC容器連接到Redis。為此,需要java連接器(或綁定)。無論選擇哪種庫,你都只需要使用一組Spring Data Redis API(在所有連接器中行為一致):org.springframework.data.redis.connection軟件包及其RedisConnection與RedisConnectionFactory接口,用于處理和檢索與Redis的活動連接。
RedisConnection和RedisConnectionFactory
RedisConnection提供了Redis通信和核心構建塊,因為它處理與Redis后端的通信。它還會自動將基礎鏈接庫異常轉換為Spring一致的DAO異常層次結構,以便您可以在不更改任何代碼的情況下切換連接器,因為操作語義保持不變。
當按照上篇文檔配置好Redis后,IOC會加載ConnectionFactory,我們可以直接注入,然后創建連接操作Redis。
RedisConnection提供了Redis 各大數據類型的操作API:
public interface RedisConnection extends RedisCommands, AutoCloseable {default RedisGeoCommands geoCommands() {return this;}default RedisHashCommands hashCommands() {return this;}default RedisHyperLogLogCommands hyperLogLogCommands() {return this;}default RedisKeyCommands keyCommands() {return this;}default RedisListCommands listCommands() {return this;}default RedisSetCommands setCommands() {return this;}default RedisScriptingCommands scriptingCommands() {return this;}default RedisServerCommands serverCommands() {return this;}default RedisStreamCommands streamCommands() {return this;}default RedisStringCommands stringCommands() {return this;}default RedisZSetCommands zSetCommands() {return this;}
}
@AutowiredLettuceConnectionFactory lettuceConnectionFactory;@Testvoid lettuceConnectionFactoryTest() {RedisConnection connection = lettuceConnectionFactory.getConnection();Boolean result = connection.set("k".getBytes(), "1".getBytes());System.err.println(result);byte[] bytes = connection.get("k".getBytes());assert bytes != null;System.err.println("k:" + new String(bytes));}
RedisTemplate簡介
大多數用戶可能會使用RedisTemplate及其相應的軟件包org.springframework.data.redis.core。實際上,由于模版具有豐富的功能集,因此它是Redis模塊的中心類。該模板為Redis交互提供了高級抽象,雖然RedisConnection提供了接受和返回二進制值(byte數組)的低級方法,但是模板負責序列化和連接管理,使用戶無需處理此類細節。
此外,該模板提供了操作視圖(根據Redis命令參考進行分組),提供了豐富的,通用的接口,用于針對某種類型或某些鍵(通過keyBound接口),如下表所述:
界面? | 描述 |
按鍵類型操作 | |
GeoOperations | Redis的地理空間操作的,比如GEOADD,GEORADIUS... |
HashOperations | Redis哈希操作 |
HyperLogLogOperations | Redis的HyperLogLog操作,例如PFADD,PFCONT,... |
ListOperations | Redis列表操作 |
SetOperations | Redis設置操作 |
ValueOperations | Redis字符串(或值)操作 |
ZSetOperations | Redis zset(或排序集)操作 |
關鍵綁定操作 | |
BoundGeoOperations | Redis鍵綁定地理空間操作 |
BoundHashOperations | Redis哈希鍵綁定操作 |
BoundKeyOperations | Redis按鍵綁定操作 |
BoundListOperations | Redis列表鍵綁定操作 |
BoundSetOperations | Redis設置鍵綁定操作 |
BoundValueOperations | Redis字符串(或值)鍵綁定操作 |
BoundZSetOperations | Redis zset(或排序集)鍵綁定操作 |
序列化器
自帶序列化器
RedisTemplate大多數操作都使用基于Java的序列化器。這意味著模板編寫或讀取的任何對象都將通過Java進行序列化和反序列化。你可以在模板上更改序列化機制,Redis模塊提供了幾種實現,可在org.springframework.data.redis.serializer軟件包中找到,您還可以將任何序列化器設置為null,并通過將enableDefaultSerializer屬性設置為來將RedisTemplate與原始字節數組一起使用False。請注意,模板要求所有鍵都不為空。但是,只要基礎串行器接受這些值,它們就可以為空。
從框架的角度來看,Redis中存儲的數據僅為字節。盡管Redis本身支持各種類型,但在大多數情況下,它們是指數據的存儲方式而不是數據的表示方式。由用戶決定是否將信息轉換為字符串或任何其他對象。
在Spring Data中,用戶(自定義)類型和原始數據之間的轉換(反之亦然)在org.springframework.data.redis.serializer包中的Redis中進行處理。
該軟件包包含兩種類型的序列化器,它們負責序列化過程:
- 基于的兩路串行器RedisSerializer。
- 使用RedisElementReader和的元素讀取器和寫入器RedisElementWriter。
框架自帶各種序列化器:
名稱 | 說明 |
OxmSerializer | 通過Spring OXM支持將其用于對象/XML映射 |
ByteArrayRedisSerializer | Byte數組序列化 |
GenericJackson2JsonRedisSerializer | 以JSON格式去存儲數據,會保存序列化的對象的包名和類名,反序列化時以這個作為標示就可以反序列化成指定的對象。效率低,占用內存高 |
GenericToStringSerializer | 可以將任何對象泛化為字符串并序列化 |
StringRedisSerializer | 簡單的字符串序列化 |
JdkSerializationRedisSerializer | JDK序列化,默認用于RedisCache和RedisTemplate |
Jackson2JsonRedisSerializer | 以JSON格式去存儲數據,需要指明序列化的類Class,可以使用Object.class |
自定義序列化器
RedisTemplate默認使用JDK序列化,可以使用自帶其他的序列化,或者自己實現第三方序列化方式,比如:
- google:Protobuf
- faceBook:Thrift
- kryo
- hessian
- fst
- Jackson
- Gson
- FastJson
Protobuf序列化
ProtoBuf(Google Protocol Buffer)是由Google公司用于數據交換的序列結構化數據格式,具有跨平臺、跨語言、可擴展特性,類型于常用的XML及JSON,但具有更小的傳輸體積、更高的編碼、編碼能力,特別適合于數據存儲、網絡數據傳輸等對存儲體積、實時性要求高的領域。
優點:性能好,效率高。支持向后兼容和向前兼容。支持多種編程語言(Java,C++,python);
缺點:二進制格式導致可讀性差(二進制格式)
RedisTemplate使用Protobuf
1、添加POM;
<dependency><groupId>io.protostuff</groupId><artifactId>protostuff-runtime</artifactId><version>1.7.4</version></dependency><dependency><groupId>io.protostuff</groupId><artifactId>protostuff-core</artifactId><version>1.7.4</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency>
1、?實現RedisSerializer接口;
@Slf4j
public class ProtoStuffRedisSerializer<T> implements RedisSerializer<T> {// RuntimeSchema是一個包含業務對象所有信息的類,包括類信息、字段信息private static final Schema<ProtoStuffWrapper> schema = RuntimeSchema.getSchema(ProtoStuffWrapper.class);/*** 序列化:對象=》字節數組** @param t 需要序列化的對象t* @return 二進制* @throws SerializationException 序列化異常*/@Overridepublic byte[] serialize(T t) throws SerializationException {if (t == null) {return null;}// 開辟了512字節緩存,用來存放業務對象序列化之后存放的地方,如果空間不足,會自動擴展擴展LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);byte[] bytes;try {// 序列化bytes = ProtostuffIOUtil.toByteArray(new ProtoStuffWrapper<>(t), schema, buffer);} finally {buffer.clear();}return bytes;}/*** 反序列化 字節數組=》對象** @param bytes 字節數組* @return 對象* @throws SerializationException 序列化異常*/@Overridepublic T deserialize(byte[] bytes) throws SerializationException {if (bytes == null || bytes.length == 0) {return null;}try {ProtoStuffWrapper<T> protoStuffWrapper = new ProtoStuffWrapper<>();// 反序列ProtostuffIOUtil.mergeFrom(bytes, protoStuffWrapper, schema);return protoStuffWrapper.getT();} catch (Exception e) {throw new RuntimeException(e);}}/*** 序列化包裝類,深度克隆,避免無法獲取schema** @param <T> 業務對象*/public static class ProtoStuffWrapper<T> implements Cloneable {private T t;ProtoStuffWrapper() {}ProtoStuffWrapper(T t) {this.t = t;}public T getT() {return t;}public void setT(T t) {this.t = t;}@Override@SuppressWarnings("unchecked")public ProtoStuffWrapper<T> clone() {try {return (ProtoStuffWrapper<T>) super.clone();} catch (CloneNotSupportedException e) {return new ProtoStuffWrapper<T>();}}}
}
1、?創建RedisTemplate,設置序列化;
/*** 創建RedisTemplate** @param redisConnectionFactory 連接工廠* @param <T> 值類型* @return RedisTemplate*/@Bean(name = "redisTemplate")public <T> RedisTemplate<String, T> redisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate<String, T> redisTemplate = new RedisTemplate<>();// 設置連接工廠redisTemplate.setConnectionFactory(redisConnectionFactory);// String序列化對象RedisSerializer<String> stringRedisSerializer = RedisSerializer.string();// ProtoStuff序列化ProtoStuffRedisSerializer<T> protoStuffRedisSerializer = new ProtoStuffRedisSerializer<>();// 序列化配置=>KeyredisTemplate.setKeySerializer(stringRedisSerializer); // 所有Key都設置為字符串,方便閱讀redisTemplate.setHashKeySerializer(protoStuffRedisSerializer); // 設置Hash數據結構中的Key// 序列化配置=>ValueredisTemplate.setValueSerializer(protoStuffRedisSerializer); // 所有ValueredisTemplate.setHashValueSerializer(protoStuffRedisSerializer); // Hash數據結構中的ValueredisTemplate.afterPropertiesSet();return redisTemplate;}
1、?添加測試實體類;
@ToString
@Data
public class User {String userName;String password;int age;
}
1、?添加測試類測試;
@Testvoid protoStuffTest() {User user = new User();user.setAge(20);user.setUserName("韓梅梅");user.setPassword("123456");redisTemplate.boundValueOps("k").set(user);User user1 = redisTemplate.boundValueOps("k").get();redisTemplate.boundHashOps("hash").putIfAbsent("kkk","vvv");System.err.println(user1.toString());}