Redis的優勢:
1、性能極高 – Redis能讀的速度是110000次/s,寫的速度是81000次/s 。
2、豐富的數據類型 – Redis支持二進制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 數據類型操作。
3、原子 – Redis的所有操作都是原子性的,意思就是要麼成功執行要麼失敗完全不執行。單個操作是原子性的。多個操作也支持事務,即原子性,通過MULTI和EXEC指令包起來。
4、豐富的特性 – Redis還支持 publish/subscribe, 通知, key 過期等等特性。
Redis可作爲數據庫,可降低數據IO的讀操作,減輕IO的壓力。可以減少CPU和內存的壓力。並且可以修改表結構,特殊對待某一條數據。並且Redis是NoSQL,讀取速度快,對於較大數據處理快。
Redis做緩存,可用於高頻次訪問的數據;也可用於分佈式架構中session共享。
搭建步驟:
一、採用IDEA搭建Springboot項目,並引入redis所需的依賴。如下
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
</dependency>
二、配置Redis數據源信息
server.port=1104
server.tomcat.uri-encoding=UTF-8
#################redis基礎配置###################
# 數據庫設置
spring.redis.database=5
#宿主機IP
spring.redis.host=localhost
#端口號
spring.redis.port=6379
#密碼
spring.redis.password=jane@2018
# 連接超時時間 單位 ms(毫秒)
spring.redis.timeout=3000
#################redis線程池設置#################
# 連接池中的最大空閒連接,默認值也是8。
spring.redis.jedis.pool.max-idle=500
#連接池中的最小空閒連接,默認值也是0。
spring.redis.jedis.pool.min-idle=50
# 如果賦值爲-1,則表示不限制;如果pool已經分配了maxActive個jedis實例,則此時pool的狀態爲exhausted(耗盡)。
spring.redis.jedis.pool.max-wait=2000
# 等待可用連接的最大時間,單位毫秒,默認值爲-1,表示永不超時。如果超過等待時間,則直接拋出JedisConnectionException
spring.redis.jedis.pool.max-active=1000
三、編寫Redis配置類
添加一個conf包,放置redis的一些配置類
1、首先添加RedisConf類,實例化Redis的一系列操作對象,例如HashOperations、SetOperations等,本demo中只使用了HashOperations。但是其他操作對象同樣實例,以便後續的擴展
package com.jane.demo.conf.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.core.*; /** * @author jane * @version 2018/03/08 */ @Configuration public class RedisConf { @Autowired private StringRedisTemplate redisTemplate; /** * 實例化 HashOperations 對象,可以使用 Hash 類型操作 */ /*@Bean public HashOperations<String, String, String> hashOperations() { return redisTemplate.opsForHash(); }*/ /** * 實例化 ValueOperations 對象,可以使用 String 操作 */ @Bean public ValueOperations<String, String> valueOperations() { return redisTemplate.opsForValue(); } /** * 實例化 ListOperations 對象,可以使用 List 操作 * @return */ @Bean public ListOperations<String, String> listOperations() { return redisTemplate.opsForList(); } /** * 實例化 SetOperations 對象,可以使用 Set 操作 */ @Bean public SetOperations<String, String> setOperations() { return redisTemplate.opsForSet(); } /** * 實例化 ZSetOperations 對象,可以使用 ZSet 操作 */ @Bean public ZSetOperations<String, String> zSetOperations() { return redisTemplate.opsForZSet(); } }
2、分別定義了讀和取的Redis庫接口
2.1 Redis寫操作庫接口IWriteRedisRepository<T>,可用於不同的類型的數據的寫入
package com.jane.demo.conf; /** * 緩存寫操作 * @param <T> */ public interface IWriteRedisRepository<T> extends IRedisRepository<T> { /** * 插入緩存,並不過期 * @param key 鍵 * @param t 值 */ void put(String key, T t); /** *插入緩存 * @param key 鍵 * @param t 值 * @param expire 過期時間,如果爲-1,則不設置過期時間 */ void put(String key, T t, long expire); /** * 移除緩存 * @param key */ void remove(String key); /** * 清空緩存 */ void empty(); }
2.2 Redis讀操作庫接口 IReadRedisRepository<T>
package com.jane.demo.conf; import java.util.List; import java.util.Set; /** * 緩存讀操作 * * @author jane * @version 2018/03/08 */ public interface IReadRedisRepository<T> extends IRedisRepository<T> { /** * 獲取鍵值key的Value * @param key 鍵 * @return */ T get(String key); /** * 獲取所有緩存Value信息 * @return */ List<T> getAll(); /** * 獲取所有鍵值key * @return */ Set<String> getKeys(); /** * 鍵值key是否存在 * @param key 鍵 * @return */ boolean isKeyExists(String key); /** * Redis緩存計數器 * @return */ long count(); }
3、創建一個抽象類AbstractRedisRepository<T>,實現上面的兩個Redis的讀寫操作接口
package com.jane.demo.conf.impl; import com.alibaba.fastjson.JSON; import com.jane.demo.conf.IReadRedisRepository; import com.jane.demo.conf.IWriteRedisRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.HashOperations; import org.springframework.data.redis.core.StringRedisTemplate; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; /** * Redis緩存操作 * * @author jane * @version 2018/03/08 */ public abstract class AbstractRedisRepository<T> implements IReadRedisRepository<T>, IWriteRedisRepository<T> { @Autowired private StringRedisTemplate stringRedisTemplate; @Autowired private HashOperations<String, String, String> hashOperations; /** * 插入緩存,並不過期 * @param key 鍵 * @param t 值 */ @Override public void put(String key, T t) { put(key, t, -1); } /** * 插入緩存 * @param key 鍵 * @param t 值 * @param expire 過期時間,如果爲-1,則不設置過期時間 */ @Override public void put(String key, T t, long expire) { hashOperations.put(getRedisKey(), key, JSON.toJSONString(t)); if (expire != -1) { stringRedisTemplate.expire(getRedisKey(), expire, TimeUnit.SECONDS); } } /** * 移除緩存 * @param key */ @Override public void remove(String key) { hashOperations.delete(getRedisKey(), key); } /** * 清空緩存 */ @Override public void empty() { Set<String> set = hashOperations.keys(getRedisKey()); set.forEach(key -> hashOperations.delete(getRedisKey(), key)); } /** * 獲取緩存Value * @param key * @return */ @Override public T get(String key) { return JSON.parseObject(hashOperations.get(getRedisKey(), key), getSerializeClass()); } /** * 序列化對象 * @return */ protected abstract Class<T> getSerializeClass(); /** * 獲取所有緩存Value * @return */ @Override public List<T> getAll() { return JSON.parseArray(JSON.toJSONString(hashOperations.values(getRedisKey())), getSerializeClass()); } /** * 獲取所有緩存的key * @return */ @Override public Set<String> getKeys() { return hashOperations.keys(getRedisKey()); } /** * 鍵值key是否存在 * @param key 鍵 * @return */ @Override public boolean isKeyExists(String key) { return hashOperations.hasKey(getRedisKey(), key); } /** * 緩存計數器 * @return */ @Override public long count() { return hashOperations.size(getRedisKey()); } }
4、創建一個RedisKey的類,這個類的作用類似於數據庫中表名,比如我添加的是USER_KEY。即用戶表
package com.jane.demo.conf; /** * 系統模塊名稱,類似與表名 * @author jane * @version 2018/03/09 */ public class RedisKey { public final static String USER_KEY = "JANE.DEMO.USER"; //用戶(表) }
四、添加簡單的業務邏輯和實體類
1、添加實體類User
package com.jane.demo.entity; import lombok.Data; /** * 用戶類 * 登錄名唯一作爲鍵值 * @author jane * @version 2018/03/09 */ @Data public class User { private String name; //用戶姓名 private String phoneNumber; //電話 private String loginName; //登錄名(唯一) }
2、添加繼承AbstractRedisRepository的UserRedis類,並設置起redisKey和序列化。
package com.jane.demo.redis; import com.jane.demo.conf.RedisKey; import com.jane.demo.conf.impl.AbstractRedisRepository; import com.jane.demo.entity.User; import org.springframework.stereotype.Component; /** * 用戶模塊 * @author jane * @version 2018/03/09 */ @Component public class UserRedis extends AbstractRedisRepository<User> { @Override public String getRedisKey() { return RedisKey.USER_KEY; } @Override protected Class<User> getSerializeClass() { return User.class; } }
3、添加UserService,簡單定義user的CRUD。
package com.jane.demo.service; import com.jane.demo.entity.User; import com.jane.demo.redis.UserRedis; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; /** * @author jane * @version 2018/03/09 */ @Service public class UserService { @Autowired private UserRedis userRedis; /** * 保存用戶(登錄名唯一,作爲鍵值) * @param user 用戶信息 */ public void saveUser(User user){ userRedis.put(user.getLoginName(), user); } /** * 根據登錄名獲取用戶信息 * @param loginName 登錄名 * @return 用戶信息 */ public User getUser(String loginName){ return userRedis.get(loginName); } /** * 判斷當前登錄名稱是否存在 * @param loginName 登錄名 * @return 存在返回true,否則false */ public boolean isExsist(String loginName){ return userRedis.isKeyExists(loginName); } /** * 獲取所有用戶信息 * @return 用戶集 */ public List<User> findAll(){ return userRedis.getAll(); } }
4、添加UserController控制層,用於用戶的簡單交互。
package com.jane.demo.controller; import com.jane.demo.entity.User; import com.jane.demo.model.JsonModel; import com.jane.demo.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; /** * 用戶控制層 * @author jane * @version 2018/03/09 */ @RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @RequestMapping(value = "/test", method = RequestMethod.GET) public JsonModel test(){ return new JsonModel(200, "測試成功"); } @RequestMapping(value = "/create", method = RequestMethod.POST) public JsonModel create(User user){ if (!userService.isExsist(user.getLoginName())){ userService.saveUser(user); return new JsonModel(200,"成功添加!"); }else { return new JsonModel(304,"已存在,無法添加!"); } } @RequestMapping(value = "/getOne", method = RequestMethod.GET) public JsonModel get(String loginName){ return new JsonModel(200, userService.getUser(loginName),"成功"); } }
五、採用junit中的MockMvc測試控制層
package com.jane.demo.controller; import com.alibaba.fastjson.JSONObject; import com.jane.demo.entity.User; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; /** * 用戶控制層測試 * * @author jane * @version 2018/03/11 */ @RunWith(SpringRunner.class) @SpringBootTest public class UserControllerTest { /** 模擬MVC對象*/ private MockMvc mockMvc; /**注入Web應用上下文*/ @Autowired private WebApplicationContext webApplicationContext; @Before public void setup(){ this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build(); } /** * 測試用戶的添加 * @throws Exception */ @Test @Ignore public void testCreate()throws Exception{ User user = new User(); user.setName("JunitTest"); user.setPhoneNumber("1234531"); user.setLoginName("junit"); MvcResult result = mockMvc.perform(post("/user/create?name=JunitTest&phoneNumber=1234531&loginName=junit").contentType(MediaType.APPLICATION_JSON) .content(JSONObject.toJSONString(user))) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)) .andReturn(); System.out.println(result.getResponse().getContentAsString()); } /** * 測試web項目是否部署成功 * @throws Exception */ @Test @Ignore public void testWeb()throws Exception { String result = mockMvc.perform(get("/user/test").contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); System.out.println("-------返回的JSON:" + result); } /** * 測試getOne * @throws Exception */ @Test public void testGetOne()throws Exception { MvcResult result = mockMvc.perform(get("/user/getOne").contentType(MediaType.APPLICATION_JSON) .param("loginName","jane")) .andExpect(status().isOk()) .andReturn(); System.out.println(result.getResponse().getContentAsString()); } }
項目源代碼地址:redis_springboot