Home | 简体中文 | 繁体中文 | 杂文 | Github | 知乎专栏 | 51CTO学院 | CSDN程序员研修院 | OSChina 博客 | 腾讯云社区 | 阿里云栖社区 | Facebook | Linkedin | Youtube | 打赏(Donations) | About
知乎专栏多维度架构

第 5 章 Spring Data

目录

5.1. Spring Data with Redis
5.1.1. 集成 Redis XML 方式
5.1.2. RedisTemplate
5.1.3. Spring Data Redis - Repository Examples
5.2. Spring Data with MongoDB
5.2.1. Example Spring Data MongoDB
5.2.2. MongoDB 多数据源
5.2.3. @Document
5.2.4. MongoRepository
5.2.5. mongoTemplate
5.2.6. GeoJson 反序列化
5.2.7. FAQ
5.3. Spring Data with MySQL
5.3.1. 选择数据库表引擎
5.3.2. 声明实体
5.3.3. 实体继承
5.3.4. Repository
5.3.5. 事务 @Transactional
5.3.6. TransactionTemplate
5.3.7. 锁 @Lock
5.4. EntityManager
5.5. Spring Data with JdbcTemplate
5.5.1. execute
5.5.2. queryForInt
5.5.3. queryForLong
5.5.4. queryForObject
5.5.5. queryForList
5.5.6. queryForMap
5.5.7. query
5.5.8. queryForRowSet
5.5.9. update
5.5.10.
5.5.11. 实例参考
5.6. Spring Data with Elasticsearch
5.6.1. 内嵌 Elasticsearch
5.6.2. 集群模式
5.6.3. Document
5.6.4. Elasticsearch 删除操作
5.6.5. FAQ
5.7. Spring boot with Data restful
5.7.1. Maven
5.8. Apache ShardingSphere
5.8.1. 微服务集群环境,雪花算法出现重复ID
5.9. Spring Data FAQ
5.9.1. No identifier specified for entity
5.9.2. Oracle Date 类型显示日期和时间
5.9.3. java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.Integer
5.9.4. Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query

5.1. Spring Data with Redis

5.1.1. 集成 Redis XML 方式

5.1.1.1. pom.xml

		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-redis</artifactId>
		</dependency>			
		
			

5.1.1.2. springframework-servlet.xml

		
	<!-- Redis Connection Factory -->
	<bean id="jedisConnFactory"
		class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
		p:host-name="192.168.2.1" p:port="6379" p:use-pool="true" />

	<!-- redis redisTemplate definition -->
	<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
		p:connection-factory-ref="jedisConnFactory" />
		
			

例 5.1. Spring Data Redis Example

			
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">

	<mvc:resources location="/images/" mapping="/images/**" />
	<mvc:resources location="/css/" mapping="/css/**" />

	<context:component-scan base-package="cn.netkiller.controller" />

	<mvc:annotation-driven />

	<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="viewClass"
			value="org.springframework.web.servlet.view.JstlView" />
		<property name="prefix" value="/WEB-INF/jsp/" />
		<property name="suffix" value=".jsp" />
		<!-- <property name="viewNames" value="*.jsp" /> -->
	</bean>

	<bean id="configuracion"
		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="location" value="classpath:resources/development.properties" />
	</bean>

	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="${jdbc.driverClassName}" />
		<property name="url" value="${jdbc.url}" />
		<property name="username" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />
	</bean>

	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
	</bean>
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="cn.netkiller.mapper" />
	</bean>

	<bean id="userService" class="cn.netkiller.service.UserService">
	</bean>

	<!-- Redis Connection Factory -->
	<bean id="jedisConnFactory"
		class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
		p:host-name="192.168.2.1" p:port="6379" p:use-pool="true" />

	<!-- redis redisTemplate definition -->
	<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
		p:connection-factory-ref="jedisConnFactory" />
</beans>				
			
				

5.1.1.3. Controller

		
package cn.netkiller.controller;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import cn.netkiller.model.User;

@Controller
public class CacheController {

	// inject the actual redisTemplate
	@Autowired
	private RedisTemplate<String, String> redisTemplate;

	// inject the redisTemplate as ListOperations
	@Resource(name = "redisTemplate")
	private ListOperations<String, String> listOps;

	@RequestMapping("/cache")
	public ModelAndView cache() {

		String message = "";

		User user = new User();
		user.setId("1");
		user.setName("Neo");
		user.setAge(30);

		String key = "user";
		listOps.leftPush(key, user.toString());
		message = listOps.leftPop(key);

		redisTemplate.setKeySerializer(new StringRedisSerializer());
		redisTemplate.setValueSerializer(new StringRedisSerializer());
		redisTemplate.opsForValue().set("key", user.toString());

		return new ModelAndView("index/index", "variable", message);
	}
}
		
			

5.1.1.4. index.jsp

		
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<br>
	<div style="text-align:center">
		<h2>
			${variable}
		</h2>
	</div>
</body>
</html>			
		
			

5.1.1.5. 测试

请求URL http://your.domain.com/your.html

		
[root@master ~]# redis-cli 
redis 127.0.0.1:6379> keys *
1) "\xac\xed\x00\x05t\x00\x04user"
2) "key"

redis 127.0.0.1:6379> get key
"\xac\xed\x00\x05t\x00\x1dUser [id=1, name=Neo, age=30]"
		
			
[提示]提示

Spring Redis 默认使用 Byte数据类型存储Key,在redis-cli中会看到 "\xac\xed\x00\x05t\x00\x04" 前缀不方便get操作,所以我们会设置使用字符串,通过 redisTemplate.setKeySerializer(new StringRedisSerializer()); 实现

5.1.2. RedisTemplate

5.1.2.1. stringRedisTemplate 基本用法

			
stringRedisTemplate.opsForValue().set("test", "100",60*10,TimeUnit.SECONDS);	//向redis里存入数据和设置缓存时间
stringRedisTemplate.opsForValue().get("test")									//根据key获取缓存中的val
stringRedisTemplate.getExpire("test")											//根据key获取过期时间
stringRedisTemplate.getExpire("test",TimeUnit.SECONDS)							//根据key获取过期时间并换算成指定单位
stringRedisTemplate.delete("test");												//根据key删除缓存
stringRedisTemplate.hasKey("546545");											//检查key是否存在,返回boolean值
stringRedisTemplate.expire("test",1000 , TimeUnit.MILLISECONDS);				//设置过期时间	
			
			

5.1.2.2. 设置缓存时间

			
例子:设置 name 缓存 10 秒

redisTemplate.opsForValue().set("name","neo",10, TimeUnit.SECONDS);
redisTemplate.opsForValue().get("name")

结果:由于设置的是10秒失效,十秒之内查询有结果,十秒之后返回为null			
			
			

5.1.2.3. 字符串截取

			
设置:redisTemplate.opsForValue().set("hello","Helloworld");
代码:System.out.println(redisTemplate.opsForValue().get("hello",0,5));
结果:Hellow
代码:System.out.println(redisTemplate.opsForValue().get("hello",0,-1));
结果:Helloworld
代码:System.out.println(redisTemplate.opsForValue().get("hello",-3,-1));
结果:rld			
			
			

5.1.2.4. 追加字符串

			
redisTemplate.opsForValue().append("hello","Hello");
System.out.println(redisTemplate.opsForValue().get("hello"));

redisTemplate.opsForValue().append("hello","world");
System.out.println(redisTemplate.opsForValue().get("hello")); // 结果:Helloworld        			
			
			

5.1.2.5. 设置键的字符串值并返回其旧值

			
	redisTemplate.opsForValue().set("name","neo");
    System.out.println(redisTemplate.opsForValue().getAndSet("name","Jerry"));
	// 结果 neo			
			
			

5.1.2.6. increment

			
stringRedisTemplate.opsForValue().set("test", "100");							//向redis里存入数据			
stringRedisTemplate.boundValueOps("test").increment(-50);						//val做-60操作
stringRedisTemplate.boundValueOps("test").increment(100);						//val +100
stringRedisTemplate.opsForValue().get("test")									//根据key获取缓存中的val		
			
			

5.1.2.7. 删除 key

		
	private void cleanNewToday() {
		long begin = System.currentTimeMillis();
        
		redisTemplate.delete("news:today");
    
        long end = System.currentTimeMillis();
		logger.info("Schedule clean redis {} 耗时 {} 秒", "cleanNewFlash()", (end-begin) / 1000 );
	}
		
			

5.1.2.8. 返回字符串长度

			
redisTemplate.opsForValue().set("key","hello world");
System.out.println(redisTemplate.opsForValue().size("key"));			
			
			

5.1.2.9. 如果key不存便缓存。

			
System.out.println(redisTemplate.opsForValue().setIfAbsent("name","neo"));	// name 之前已经存在 false
System.out.println(redisTemplate.opsForValue().setIfAbsent("age","11"));		// age 之前不存在	true
			
			

setIfAbsent 实现分布式锁

			
boolean static = Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent("lock:order", 1, 1, TimeUnit.DAYS));			
			
			

5.1.2.10. 缓存多个值 /获取多个值 multiSet / multiGet

			
Map<String,String> maps = new HashMap<String, String>();
	maps.put("multi1","multi1");
	maps.put("multi2","multi2");
	maps.put("multi3","multi3");

redisTemplate.opsForValue().multiSet(maps);

List<String> keys = new ArrayList<String>();
	keys.add("multi1");
	keys.add("multi2");
	keys.add("multi3");

System.out.println(redisTemplate.opsForValue().multiGet(keys));			
			
			

输出结果

			
[multi1, multi2, multi3]			
			
			

为多个键分别设置它们的值,如果存在则返回false,不存在返回true

			
Map<String,String> maps = new HashMap<String, String>();
        maps.put("multi11","multi11");
        maps.put("multi22","multi22");
        maps.put("multi33","multi33");
Map<String,String> maps2 = new HashMap<String, String>();
        maps2.put("multi1","multi1");
        maps2.put("multi2","multi2");
        maps2.put("multi3","multi3");

System.out.println(redisTemplate.opsForValue().multiSetIfAbsent(maps)); 	// 返回 true
System.out.println(redisTemplate.opsForValue().multiSetIfAbsent(maps2));	// 返回 false
			
			

5.1.2.11. List

rightPush
			
ListOperations<String, Object> list = redisTemplate.opsForList();
list.rightPush("books", "Linux");
list.rightPush("books", "Java");
System.out.println(list.range("books", 0, 1));

System.out.println(redisTemplate.opsForList().size("list"));
			
				
rightPushAll
				
		String[] stringarrays = new String[]{"1","2","3"};
        redisTemplate.opsForList().rightPushAll("listarrayright",stringarrays);
        System.out.println(redisTemplate.opsForList().range("listarrayright",0,-1));				
				
				
				
		List<Object> strings = new ArrayList<Object>();
        strings.add("1");
        strings.add("2");
        strings.add("3");
        redisTemplate.opsForList().rightPushAll("listcollectionright", strings);
        System.out.println(redisTemplate.opsForList().range("listcollectionright",0,-1));				
				
				
rightPushIfPresent
				
		System.out.println("========== KEY 不存在===========");
		System.out.println(redisTemplate.opsForList().rightPushIfPresent("rightPushIfPresent","aa"));
        System.out.println(redisTemplate.opsForList().rightPushIfPresent("rightPushIfPresent","bb"));
        System.out.println("========== KEY 已经存在===========");
        System.out.println(redisTemplate.opsForList().rightPushIfPresent("rightPushIfPresent","aa"));
        System.out.println(redisTemplate.opsForList().rightPushIfPresent("rightPushIfPresent","bb"));				
				
				
leftPush
			
redisTemplate.opsForList().leftPush("list","java");
redisTemplate.opsForList().leftPush("list","python");
redisTemplate.opsForList().leftPush("list","c++");			
			
				
leftPushAll

批量把一个数组插入到列表中

				
	String[] stringarrays = new String[]{"1","2","3"};
    redisTemplate.opsForList().leftPushAll("listarray",stringarrays);	
				
				

批量把一个集合插入到列表中

			
使用:List<Object> strings = new ArrayList<Object>();
        strings.add("1");
        strings.add("2");
        strings.add("3");
        redisTemplate.opsForList().leftPushAll("listcollection", strings);
        System.out.println(redisTemplate.opsForList().range("listcollection",0,-1));
结果:[3, 2, 1]			
			
				
range
			
    System.out.println(redisTemplate.opsForList().range("listarray",0,-1));
	// 结果:[3, 2, 1]				
			
				

5.1.2.12. SET 数据类型

Redis的Set是无序集合并且集合成员是唯一的,这就意味着集合中不能出现重复的数据。

			
stringRedisTemplate.opsForSet().add("test", "1","2","3");						//向指定key中存放set集合
stringRedisTemplate.opsForSet().isMember("test", "1")							//根据key查看集合中是否存在指定数据
stringRedisTemplate.opsForSet().members("test");								//根据key获取set集合				
			
			
		
//添加 一个 set 集合
SetOperations<String, Object> set = redisTemplate.opsForSet();
set.add("Member", "neo");
set.add("Member", "36");
set.add("Member", "178cm");
//输出 set 集合
System.out.println(set.members("Member"));	
		
			
		
package cn.netkiller.api.restful;

import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import common.pojo.ResponseRestful;

@RestController
@RequestMapping("/news")
public class NewsRestController {

	@Autowired
	private RedisTemplate<String, String> redisTemplate;

	@RequestMapping(value = "/flash/{count}")
	public ResponseRestful flash(@PathVariable("count") long count) {
		if(count == 0L) {
			count=10L;
		}
		Set<String> news = this.redisTemplate.opsForZSet().reverseRange("news:flash", 0, count);
		if (news == null) {
			return new ResponseRestful(false, 10, "没有查询到结果", news);
		}
		return new ResponseRestful(true, 0, "返回数据: " + news.size() + " 条", news);
	}
	
	public void addRecentUser(long userId, String name) {  
	    String key = RedisKeyGenerator.genRecentBrowsingPositionsKey(String.valueOf(userId));  
	    // 获取已缓存的最近浏览的职位  
	    ZSetOperations<String, String> zSetOperations = redisTempalte.opsForZSet();  
        //zset内部是按分数来排序的,这里用当前时间做分数  
	    zSetOperations.add(key, name, System.currentTimeMillis());  
	    zSetOperations.removeRange(key, 0, -6);  
	}  
	
}
		
			
返回集合中的所有成员
				
System.out.println(redisTemplate.opsForSet().members("setTest"));				
				
				
取出一个成员
				
System.out.println(redisTemplate.opsForSet().pop("setTest"));				
				
				
随机获取无序集合中的一个元素
				
System.out.println("Random member: " + redisTemplate.opsForSet().randomMember("setTest"));				
				
				
随机获取 n 个成员(存在重复数据)
				
System.out.println("Random member: " + redisTemplate.opsForSet().randomMembers("setTest",5));
// 结果 Random member: [ccc, ddd, ddd, ddd, aaa]				
				
				
随机获取 n 个不重复成员
				
System.out.println("Random members: " + redisTemplate.opsForSet().distinctRandomMembers("setTest",5));
//结果 Random members: [aaa, bbb, ddd, ccc]				
				
				
在两个 SET 间移动数据
				
	redisTemplate.opsForSet().move("key1","aaa","key2");
	System.out.println(redisTemplate.opsForSet().members("key1"));
    System.out.println(redisTemplate.opsForSet().members("key2"));				
				
				
成员删除
				
String[] arrays = new String[]{"Java","PHP"};
System.out.println(redisTemplate.opsForSet().remove("setTest",arrays));				
				
				
返回集合数量
				
System.out.println(redisTemplate.opsForSet().size("setTest"));				
				
				
判断元素是否在集合成员中
				
ystem.out.println(redisTemplate.opsForSet().isMember("setTest","Linux"));				
				
				
对比两个集合求交集
				
	System.out.println(redisTemplate.opsForSet().members("key"));
    System.out.println(redisTemplate.opsForSet().members("otherKey"));
    System.out.println(redisTemplate.opsForSet().intersect("key","otherKey"));				
				
				
				
        List<String> library2 = new ArrayList<String>();
        library2.add("Linux");
        library2.add("FreeBSD");
        System.out.println(redisTemplate.opsForSet().intersect("library1",library2));				
				
				
对比两个集合求交集,然后存储到新的 key 中
				
System.out.println(redisTemplate.opsForSet().intersectAndStore("key","otherKey","destKey"));				
				
				
				
		List<String> otherKey = new ArrayList<String>();
        otherKey.add("《Netkiller Java 手札》");
        otherKey.add("《Netkiller Spring Cloud 手札》");
        System.out.println(redisTemplate.opsForSet().intersectAndStore("key",otherKey,"destKey"));				
				
				
合并两个集合,并去处重复数据
				
	System.out.println(redisTemplate.opsForSet().union("setTest1","setTest2"));
	
	List<String> otherKey = new ArrayList<String>();
    otherKey.add("《Netkiller Java 手札》");
    otherKey.add("《Netkiller Spring Cloud 手札》");
    System.out.println(redisTemplate.opsForSet().union("setTest",otherKey));		
				
				
合并两个集合去重复后保存到新的 key 中
				
	System.out.println(redisTemplate.opsForSet().unionAndStore("key","otherKey","destKey"));
	System.out.println(redisTemplate.opsForSet().unionAndStore("key",otherKey,"destKey"));					
				
				
计算两个合集的差集
				
	System.out.println(redisTemplate.opsForSet().difference("key","otherKey"));		
	
	List<String> otherKey = new ArrayList<String>();
    otherKey.add("setTest2");
    otherKey.add("setTest3");
    System.out.println(redisTemplate.opsForSet().difference("key",otherKey));		
				
				
计算两个合集的差集,然后保存到新的 key 中
				
	System.out.println(redisTemplate.opsForSet().differenceAndStore("key","otherKey","destKey"));
				
				
遍历 SET 集合
				
	Cursor<Object> curosr = redisTemplate.opsForSet().scan("setTest", ScanOptions.NONE);
    while(curosr.hasNext()){
        System.out.println(curosr.next());
    }				
				
				

5.1.2.13. 有序的 set 集合

			
//添加有序的 set 集合
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
zset.add("zMember", "neo", 0);
zset.add("zMember", "36", 1);
zset.add("zMember", "178cm", 2);
//输出有序 set 集合
System.out.println(zset.rangeByScore("zMember", 0, 2));				
			
			

5.1.2.14. Hash

put
				
	redisTemplate.opsForHash().put("redisHash","name","neo");
    redisTemplate.opsForHash().put("redisHash","age",30);
    redisTemplate.opsForHash().put("redisHash","nickname","netkiller");				
				
				
putAll
				
HashOperations<String, Object, Object>  hash = redisTemplate.opsForHash();
Map<String,Object> map = new HashMap<String,Object>();
map.put("name", "neo");
map.put("age", "36");
hash.putAll("member", map);

System.out.println(hash.entries("member"));		
				
				
从键中的哈希获取给定hashKey的值
				
	System.out.println(redisTemplate.opsForHash().get("redisHash","age"));				
				
				
delete

删除指定的哈希 hashKeys

				
	System.out.println(redisTemplate.opsForHash().delete("redisHash","name"));
				
				
确定哈希hashKey是否存在

确定哈希hashKey是否存在

				
System.out.println(redisTemplate.opsForHash().hasKey("redisHash","age"));				
				
				
从哈希中获取指定的多个 hashKey 的值
				
	List<Object> keys = new ArrayList<Object>();
    keys.add("name");
    keys.add("age");
    System.out.println(redisTemplate.opsForHash().multiGet("redisHash",keys))				
				
				
只有hashKey不存在时才能添加值
				
	System.out.println(redisTemplate.opsForHash().putIfAbsent("redisHash","age",30));				
				
				
获取整个Hash
				
System.out.println(redisTemplate.opsForHash().entries("redisHash"));					
				
				
获取所有key
				

System.out.println(redisTemplate.opsForHash().keys("redisHash1"));				
				
				
通过 hashKey 获取所有值
				
System.out.println(redisTemplate.opsForHash().values("redisHash"));				
				
				
值加法操作
				
System.out.println(redisTemplate.opsForHash().increment("redisHash","age",1)				
				
				
遍历 Hash 表
				
	Cursor<Map.Entry<Object, Object>> curosr = redisTemplate.opsForHash().scan("redisHash", ScanOptions.ScanOptions.NONE);
	while(curosr.hasNext()){
	    Map.Entry<Object, Object> entry = curosr.next();
	    System.out.println(entry.getKey()+":"+entry.getValue());
	}				
				
				

5.1.2.15. 过期时间未执行

Spring Redis 中设置过期时间方法如下

		
设置 key
redisTemplate.opsForValue().setIfAbsent("key", "value");
设置过期时间
redisTemplate.expire("key", 30000, TimeUnit.MILLISECONDS);
释放 key
redisTemplate.delete("key");		
		
			

这样存在一个问题,当程序运行一半被强行终止,可能导致setIfAbsent运行完成,但是expire未被执行,这样 key 便永远不会释放。解决方案如下,使用RedisCallback执行原生 Redis 命令。

		
String result = redisTemplate.execute(new RedisCallback<String>() {
	@Override
	public String doInRedis(RedisConnection connection) throws DataAccessException {
		JedisCommands commands = (JedisCommands) connection.getNativeConnection();
		return commands.set(key, value, "NX", "PX", expire);
	}
});		
		
			

5.1.2.16. setBit / getBit 二进制位操作

			
setBit Boolean setBit(K key, long offset, boolean value);

offset 二进制位置(从左向右数)
value 位 ture 表示 0,false 表示 1			
			
			
			
    // 'a' 的ASCII码是 97 转换为二进制是:01100001
    // 'b' 的ASCII码是 98 转换为二进制是:01100010
    // 'c' 的ASCII码是 99 转换为二进制是:01100011
    			
	redisTemplate.opsForValue().set("bitTest","a");    
    
    redisTemplate.opsForValue().setBit("bitTest",7, false); 	// 01100011
    redisTemplate.opsForValue().setBit("bitTest",8, true);	// 01100010
    System.out.println(redisTemplate.opsForValue().get("bitTest"));
    redisTemplate.opsForValue().setBit("bitTest",8, false);	// 01100011
    System.out.println(redisTemplate.opsForValue().get("bitTest"));			
			
			

getBit Boolean getBit(K key, long offset); 获取键对应值的ascii码的在offset处位值

			
System.out.println(redisTemplate.opsForValue().getBit("bitTest",7));			
			
			

5.1.2.17. 存储 Json 对象

集成 RedisTemplate 定义新类 JsonRedisTemplate
			
package cn.netkiller.wallet.redis;

import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.fasterxml.jackson.databind.ObjectMapper;

public class JsonRedisTemplate extends RedisTemplate<String, Object> {

	public JsonRedisTemplate(RedisConnectionFactory connectionFactory, ObjectMapper objectMapper, Class<?> valueType) {
		RedisSerializer<String> stringSerializer = new StringRedisSerializer();
		super.setKeySerializer(stringSerializer);
		super.setHashKeySerializer(stringSerializer);
		super.setHashValueSerializer(stringSerializer);
		Jackson2JsonRedisSerializer<?> jsonRedisSerializer = new Jackson2JsonRedisSerializer<>(valueType);
		jsonRedisSerializer.setObjectMapper(objectMapper);
		super.setValueSerializer(jsonRedisSerializer);
		super.setConnectionFactory(connectionFactory);
		super.afterPropertiesSet();
	}
}
			
			
				
配置 Redis
			
package cn.netkiller.wallet.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;

import com.fasterxml.jackson.databind.ObjectMapper;

import cn.netkiller.wallet.redis.JsonRedisTemplate;
import cn.netkiller.wallet.redis.RedisMessageSubscriber;

@Configuration
public class RedisConfig {

	public RedisConfig() {
	}

	@Bean
	public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory connectionFactory) {
		StringRedisTemplate redisTemplate = new StringRedisTemplate();
		redisTemplate.setConnectionFactory(connectionFactory);
		return redisTemplate;
	}

	@Bean
	public MessageListenerAdapter messageListener() {
		return new MessageListenerAdapter(new RedisMessageSubscriber());
	}

	@Bean
	public ChannelTopic topic() {
		return new ChannelTopic("demo");
	}

	@Bean
	public RedisMessageListenerContainer redisContainer(RedisConnectionFactory connectionFactory, MessageListenerAdapter messageListener) {
		RedisMessageListenerContainer container = new RedisMessageListenerContainer();

		container.setConnectionFactory(connectionFactory);
		container.addMessageListener(messageListener(), topic());
		container.addMessageListener(messageListener(), new ChannelTopic("test"));
		return container;
	}

	@Bean
	public ObjectMapper objectMapper() {
		return new ObjectMapper();
	}

	@Bean
	public JsonRedisTemplate jsonRedisTemplate(RedisConnectionFactory connectionFactory, ObjectMapper objectMapper) {
		return new JsonRedisTemplate(connectionFactory, objectMapper, Object.class);
	}

}
			
			
				
测试
			
package cn.netkiller.wallet.restful;

import java.io.IOException;
import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import cn.netkiller.wallet.pojo.RestfulResponse;
import cn.netkiller.wallet.redis.JsonRedisTemplate;
import cn.netkiller.wallet.redis.RedisMessagePublisher;

@RestController
public class TestRestController {
	private static final Logger logger = LoggerFactory.getLogger(TestRestController.class);

	@Autowired
	private StringRedisTemplate stringRedisTemplate;

	@Autowired
	private JsonRedisTemplate jsonRedisTemplate;

	public TestRestController() {

	}

	@GetMapping("/version")
	public String version() throws IOException {
		Web3ClientVersion web3ClientVersion = web3j.web3ClientVersion().send();
		String clientVersion = web3ClientVersion.getWeb3ClientVersion();
		logger.info(clientVersion);
		return clientVersion;
	}

	@GetMapping("/pub/demo")
	public String pub() {

		RedisMessagePublisher publisher = new RedisMessagePublisher(stringRedisTemplate, new ChannelTopic("demo"));
		String message = "Message " + UUID.randomUUID();
		publisher.publish(message);
		return message;
	}

	@GetMapping("/pub/test")
	public String pub(@RequestParam String message) {

		RedisMessagePublisher publisher = new RedisMessagePublisher(stringRedisTemplate, new ChannelTopic("test"));
		publisher.publish(message);
		return message;
	}

	@GetMapping("/pub/json")
	public RestfulResponse pubJson() {
		RestfulResponse restfulResponse = new RestfulResponse(true, 0, null, null);
		jsonRedisTemplate.opsForValue().set("test", restfulResponse);
		jsonRedisTemplate.convertAndSend("test", restfulResponse);
		return restfulResponse;
	}
}
			
				

5.1.3. Spring Data Redis - Repository Examples

5.1.3.1. @EnableRedisRepositories 启动 Redis 仓库

			
package api.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;

@Configuration
@EnableRedisRepositories
public class CachingConfigurer {

}			
			
			

5.1.3.2. 定义 Domain 类

			
package api.domain;

import java.util.List;

import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Reference;
import org.springframework.data.redis.core.RedisHash;
import org.springframework.data.redis.core.index.Indexed;

@RedisHash("persons")
public class Person {

	public enum Gender {
		FEMALE, MALE
	}

	@Id
	private String id;

	@Indexed
	private String firstname;
	@Indexed
	private String lastname;

	private Gender gender;
	private Address address;

	@Reference
	private List<Person> children;

	public Person() {
		// TODO Auto-generated constructor stub
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getFirstname() {
		return firstname;
	}

	public void setFirstname(String firstname) {
		this.firstname = firstname;
	}

	public String getLastname() {
		return lastname;
	}

	public void setLastname(String lastname) {
		this.lastname = lastname;
	}

	public Gender getGender() {
		return gender;
	}

	public void setGender(Gender gender) {
		this.gender = gender;
	}

	public Address getAddress() {
		return address;
	}

	public void setAddress(Address address) {
		this.address = address;
	}

	public List<Person> getChildren() {
		return children;
	}

	public void setChildren(List<Person> children) {
		this.children = children;
	}

	@Override
	public String toString() {
		return "Person [id=" + id + ", firstname=" + firstname + ", lastname=" + lastname + ", gender=" + gender + ", address=" + address + ", children=" + children + "]";
	}

}
			
			
			

			
package api.domain;

import org.springframework.data.geo.Point;
import org.springframework.data.redis.core.index.GeoIndexed;
import org.springframework.data.redis.core.index.Indexed;

public class Address {

	private @Indexed String city;
	private String country;
	private @GeoIndexed Point location;

	public Address(String city, String country, Point location) {
		this.city = city;
		this.country = country;
		this.location = location;
	}

	public String getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}

	public String getCountry() {
		return country;
	}

	public void setCountry(String country) {
		this.country = country;
	}

	public Point getLocation() {
		return location;
	}

	public void setLocation(Point location) {
		this.location = location;
	}

}			
			
			

5.1.3.3. Repository 接口

			
package api.repository;

import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.geo.Circle;
import org.springframework.data.repository.CrudRepository;

import api.domain.Person;

public interface PersonRepository extends CrudRepository<Person, String> {
	List<Person> findByLastname(String lastname);

	Page<Person> findPersonByLastname(String lastname, Pageable page);

	List<Person> findByFirstnameAndLastname(String firstname, String lastname);

	List<Person> findByFirstnameOrLastname(String firstname, String lastname);

	List<Person> findByAddress_City(String city);

	List<Person> findByAddress_LocationWithin(Circle circle);
}
			
			
			

5.1.3.4. 测试代码

			
package api.restful;

import java.util.Arrays;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Point;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import api.domain.Person;
import api.domain.Address;

import api.repository.PersonRepository;

@RestController
@RequestMapping("/test")
public class TestRestController {
	private static final Logger logger = LoggerFactory.getLogger(TestRestController.class);

	@Autowired
	private PersonRepository personRepository;

	public TestRestController() {

	}

	@GetMapping("/redis")
	public Person redis() {

		Person children = new Person();
		children.setFirstname("Lisa");
		children.setLastname("Chen");
		children.setGender(Person.Gender.FEMALE);

		Person person = new Person();
		person.setFirstname("Neo");
		person.setLastname("Chen");
		person.setGender(Person.Gender.MALE);

		// List<Person> childrens = new ArrayList<Person>();

		person.setChildren(Arrays.asList(children));

		Point point = new Point(Double.valueOf("28.352734"), Double.valueOf("32.807382"));
		Address address = new Address("Shenzhen", "China", point);
		person.setAddress(address);
		personRepository.save(person);
		return person;
	}

}