前兩天寫過 springMVC+memcached 的整合,我從這個基礎上改造一下,把redis和springmvc整合到一塊兒。javascript
和memcached同樣,redis也有java專用的客戶端,官網推薦使用的是:jedis。css
看了一部分資料,你們推薦使用 spring-data-redis (spring在jedis的基礎上又包裝了一層),可是實際中感受寫起來有點麻煩,不如原生態的jedis好用。html
因此我利用spring的構造注入作了一個springmvc整合jedis的例子。java
先了解下redis吧,這些資料袋都是從網上看到的:jquery
Redis使用c語言編寫,面向「鍵/值」對類型數據的分佈式NoSql數據庫系統。
目前提供五中數據類型
string(字符串)
list(鏈表)
Hash(哈希)
set(集合)
zset(sorted set 有序集合),有2中編碼類型:ziplist,skiplist,當zset中數據較多時,將會被重構爲skiplist。
默認端口6379
redis-server.exe:服務端
redis-check-dump.exe:本地數據庫檢查
redis-check-aof.exe:更新日誌檢查
redis-benchmark.exe:性能測試,用以模擬同時由N個客戶端發送M個 SETs/GETs 查詢.
redis-cli.exe: 這個是客戶端,服務端開啓後,客戶端就能夠輸入各類命令測試了web
先寫一個Test類,測一下redis的基本數據類型和jedis的一些經常使用方法。如下的測試方法也都是從網上看到的,只不過爲了驗證是否準確以及jar包版本的問題,我本身親自敲了一遍。redis
注意jedis是redis的一個客戶端,是個jar包,不要搞混了……spring
public class Test { public static void main(String[] args) { // Jedis js = new Jedis("127.0.0.1", 6379); // js.set("key001", "redis001"); // String val = js.get("key001"); // System.out.println(val); // js.del("key001"); /**************************測試Redis的數據類型**************************/ /** * list */ // js.rpush("list1", "aaaaaaaaaaaaaaaaaaaaaa"); // js.rpush("list1", "bbbbbbbbbbbbbbbbbbbbbb"); // js.rpush("list1", "ccccccccccccccccccccc"); // js.rpush("list1", "dddddddddddddd"); // List<String> vals = js.lrange("list1", 0, -1); // for (int i = 0; i < vals.size(); i++) { // System.out.println(vals.get(i)); // } /** * set 無須惟一 */ // js.sadd("s1", "順序3"); // js.sadd("s1", "a"); // js.sadd("s1", "b"); // js.sadd("s1", "1"); // js.sadd("s1", "蛤蛤蛤"); // js.sadd("s1", "2"); // js.sadd("s1", "so waht?"); // js.sadd("s1", "%^"); // js.sadd("s1", "順序1"); // js.sadd("s1", "亂碼嗎?"); // js.sadd("s1", "順序2"); // Set<String> s = js.smembers("s1"); // for (String string : s) { // System.out.println(s); // } // js.srem("s1", "蛤蛤蛤"); /** * zset(sorted set 有序集合) * 有2中編碼類型:ziplist,skiplist,當zset中數據較多時,將會被重構爲skiplist */ // js.zadd("zs", 92, "張三1"); // js.zadd("zs", 93, "張三7"); // js.zadd("zs", 94, "張三5"); // js.zadd("zs", 87, "張三9"); // js.zadd("zs", 66, "張三"); // js.zadd("zs", 19, "張三0"); // Set<String> sets = js.zrange("zs", 0, -1); // for (String string : sets) { // System.out.println(sets); // } /** * Hash */ // Map m = new HashMap(); // m.put("1", "t"); // m.put("2", "ttt"); // m.put("username", "老王"); // m.put("password", "123456"); // m.put("age", "79"); // m.put("sex", "man"); // js.hmset("m", m); // List<String> v = js.hmget("m", new String[]{"username","age"}); // List<String> v1 = js.hmget("m", "sex"); // System.out.println(v); // System.out.println(v1); // js.hdel("m", "username");//刪除map中的某一個鍵的鍵值對 /**************************事務控制**************************/ /** * 事務方式(Transactions) * 他主要目的是保障,一個client發起的事務中的命令能夠連續的執行,而中間不會插入其餘client的命令。 * * 咱們調用jedis.watch(…)方法來監控key,若是調用後key值發生變化,則整個事務會執行失敗。 * 另外,事務中某個操做失敗,並不會回滾其餘操做。這一點須要注意。 * 還有,咱們能夠使用discard()方法來取消事務。 */ // Jedis js1 = new Jedis("127.0.0.1", 6379); // long s = System.currentTimeMillis(); // Transaction tx = js1.multi(); // for (int i = 0; i < 99999; i++) { // tx.set("keyttt"+i, "valttt"+i); // } // List<Object> res= tx.exec(); // long e = System.currentTimeMillis(); // System.out.println((e-s)/1000.0+"秒"); //System.out.println(res); // js1.disconnect(); /**************************管道**************************/ /** * 管道(Pipelining) * 有時,咱們須要採用異步方式,一次發送多個指令,不一樣步等待其返回結果。 * 這樣能夠取得很是好的執行效率。這就是管道 */ // Jedis js2 = new Jedis("127.0.0.1", 6379); // long s = System.currentTimeMillis(); // Pipeline pe = js2.pipelined(); // for (int i = 0; i < 9999; i++) { // pe.set("keya"+i, "valuea"+i); // } // List<Object> l = pe.syncAndReturnAll(); // long e = System.currentTimeMillis(); // System.out.println((e-s)/1000.0+"秒"); // js2.disconnect(); /**************************管道中調用事務**************************/ /** * 管道中調用事務 * 在用法上看,管道中包含了事務 */ // Jedis js3 = new Jedis("127.0.0.1", 6379); // long s = System.currentTimeMillis(); // Pipeline pe = js3.pipelined(); // pe.multi(); // for (int i = 0; i < 9999; i++) { // pe.set("keybb"+i, "valuebb"+i); // } // pe.exec(); // List<Object> l = pe.syncAndReturnAll(); // long e = System.currentTimeMillis(); // System.out.println((e-s)/1000.0+"秒"); // js3.disconnect(); /**************************分佈式直連同步調用**************************/ /** * 分佈式直連同步調用 * 線程不安全的,不建議在線程池中使用直連 */ // List<JedisShardInfo> shards = Arrays.asList( // new JedisShardInfo("localhost",6379), // new JedisShardInfo("localhost",6380)); // ShardedJedis sharding = new ShardedJedis(shards); // long start = System.currentTimeMillis(); // for (int i = 0; i < 100000; i++) { // String result = sharding.set("sn" + i, "n" + i); // } // long end = System.currentTimeMillis(); // System.out.println("Simple@Sharing SET: " + ((end - start)/1000.0) + " seconds"); // sharding.disconnect(); /**************************分佈式直連同步調用**************************/ /** * 分佈式直連異步調用 * 線程不安全的,不建議在線程池中使用直連 */ // List<JedisShardInfo> shards = Arrays.asList( // new JedisShardInfo("localhost",6379), // new JedisShardInfo("localhost",6380)); // ShardedJedis sharding = new ShardedJedis(shards); // ShardedJedisPipeline pipeline = sharding.pipelined(); // long start = System.currentTimeMillis(); // for (int i = 0; i < 100000; i++) { // pipeline.set("sp" + i, "p" + i); // } // List<Object> results = pipeline.syncAndReturnAll(); // long end = System.currentTimeMillis(); // System.out.println("Pipelined@Sharing SET: " + ((end - start)/1000.0) + " seconds"); // sharding.disconnect(); /**************************分佈式鏈接池同步調用**************************/ /** * 同步方式 */ // List<JedisShardInfo> shards = Arrays.asList( // new JedisShardInfo("localhost",6379), // new JedisShardInfo("localhost",6380)); // // ShardedJedisPool pool = new ShardedJedisPool(new JedisPoolConfig(), shards); // // ShardedJedis one = pool.getResource(); // // long start = System.currentTimeMillis(); // for (int i = 0; i < 100000; i++) { // String result = one.set("spn" + i, "n" + i); // } // long end = System.currentTimeMillis(); // pool.returnResource(one); // System.out.println("Simple@Pool SET: " + ((end - start)/1000.0) + " seconds"); // // pool.destroy(); // /**************************分佈式鏈接池異步調用**************************/ /** * 異步方式 */ // List<JedisShardInfo> shards = Arrays.asList( // new JedisShardInfo("localhost",6379), // new JedisShardInfo("localhost",6380)); // // ShardedJedisPool pool = new ShardedJedisPool(new JedisPoolConfig(), shards); // // ShardedJedis one = pool.getResource(); // // ShardedJedisPipeline pipeline = one.pipelined(); // // long start = System.currentTimeMillis(); // for (int i = 0; i < 100000; i++) { // pipeline.set("sppn" + i, "n" + i); // } // List<Object> results = pipeline.syncAndReturnAll(); // long end = System.currentTimeMillis(); // pool.returnResource(one); // System.out.println("Pipelined@Pool SET: " + ((end - start)/1000.0) + " seconds"); // pool.destroy(); /**************************其餘**************************/ /** * 清空全部 */ // js.flushAll(); /** * 銷燬連接 */ // js.disconnect(); }
開始貼代碼了,springMVC整合jedis數據庫
web.xmlexpress
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>SpringMVC-Redis</display-name> <!-- 引入 spring --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:/applicationContext*.xml</param-value> </context-param> <!-- 引入 springMVC --> <servlet> <servlet-name>springMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:/spring-servlet-config.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>springMVC</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- 編碼 UTF-8 --> <filter> <filter-name>SpringMVC-Redis-Encoding</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>SpringMVC-Redis-Encoding</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
index.jsp
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery/jquery-1.8.0.min.js"></script> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>index 2</title> </head> <body> <div><font color="red" size="10px">${returnMsg}</font></div> <form action="${pageContext.request.contextPath }/TestRequest/test" method="post" name="loginForm" id="loginForm"> <div> 用戶名:<input class="username" type="text" id="username" name="username" value=''/> </div> <div > 密碼:<input class="password" type="password" id="password" name="password" value=""/> </div> <div><input type="button" value="submit" onclick="login()" /></div> </form> <script type="text/javascript"> function login(){ var username = $("#username").val(); var password = $("#password").val(); $("#loginForm").submit(); } document.onkeydown=function(event){ e = event ? event :(window.event ? window.event : null); if(e.keyCode==13){ login(); } } </script> </body> </html>
spring-servlet-config.xml
<?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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd"> <!-- 使用@Controllers前配置 --> <mvc:annotation-driven /> <!-- 容器加載時 自動掃描全部註解 --> <context:component-scan base-package="com.test" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> <context:include-filter type="annotation" expression="org.springframework.stereotype.Service" /> <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository" /> <context:include-filter type="annotation" expression="org.springframework.stereotype.Component" /> </context:component-scan> <!-- 配置靜態資源 --> <mvc:resources mapping="/js/**" location="/js/" /> <mvc:resources mapping="/image/**" location="/image/" /> <mvc:resources mapping="/css/**" location="/css/" /> <!-- 使用jsp做爲視圖 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass"> <value>org.springframework.web.servlet.view.JstlView</value> </property> <!-- 目標路徑返回到pages下 使用jsp做爲視圖 --> <property name="prefix" value="/pages/"></property> <property name="suffix" value=".jsp"></property> </bean> <!-- 異常處理 --> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="org.apache.shiro.authz.UnauthorizedException">error/403</prop> </props> </property> </bean> </beans>
先把這些貼上來是由於這些文件內容都和上篇博文」springMVC+memcached 「的如出一轍
applicationContext.xml
利用spring的構造注入,把集羣參數傳入RedisInitBean中,而且在項目啓動的時候加載RedisInitBean的有參構造方法
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"> <bean id="RedisInitBean" class="com.test.test.RedisInitBean" > <!-- IP:Port --> <constructor-arg index="0" type="List"> <list> <value>127.0.0.1:6379</value> <value>192.168.3.27:6380</value> </list> </constructor-arg> <!-- maxWaitMillis --> <constructor-arg index="1" type="long"> <value>1000</value> </constructor-arg> <!-- MaxIdle --> <constructor-arg index="2" type="int"> <value>200</value> </constructor-arg> <!-- testOnBorrow --> <constructor-arg index="3" type="Boolean"> <value>true</value> </constructor-arg> </bean> </beans>
RedisInitBean.java
這裏面要說一下,使用的是 分佈式鏈接池 異步調用!
package com.test.test; import java.util.Arrays; import java.util.List; import redis.clients.jedis.JedisPoolConfig; import redis.clients.jedis.JedisShardInfo; import redis.clients.jedis.ShardedJedis; import redis.clients.jedis.ShardedJedisPool; public class RedisInitBean { private List Host; private long maxWaitMillis; private int MaxIdle; private Boolean testOnBorrow; private static List<JedisShardInfo> shards ; private static ShardedJedisPool pool; private static ShardedJedis jedis; public RedisInitBean(List host, long maxWaitMillis, int maxIdle, Boolean testOnBorrow) { super(); Host = host; this.maxWaitMillis = maxWaitMillis; MaxIdle = maxIdle; this.testOnBorrow = testOnBorrow; if(host.size()!=0){ for (int i = 0; i < host.size(); i++) { String h[] = ((String) host.get(i)).split(":"); shards = Arrays.asList(new JedisShardInfo(h[0].trim(),Integer.parseInt(h[1].trim()))); System.out.println(shards); } }else{ System.out.println("請檢查Redis配置,host項爲必填項!格式[IP:PORT]"); } pool = new ShardedJedisPool(new JedisPoolConfig(), shards); jedis = pool.getResource(); } public synchronized ShardedJedis getSingletonInstance(){ return jedis; } public synchronized static void returnResource(){ pool.returnResource(jedis); } public synchronized static void destroy(){ pool.destroy(); } }
TestRequest.java
剛纔咱們寫的index.jsp中,提交了表單後瀏覽器會發起請求,spring攔截請求後會找到註解匹配的類中的方法,TestRequest就是了。
package com.test.web; import java.util.List; import javax.servlet.http.HttpSession; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; import redis.clients.jedis.ShardedJedis; import redis.clients.jedis.ShardedJedisPipeline; import com.test.test.RedisInitBean; @Controller @RequestMapping("/TestRequest") public class TestRequest { @Autowired private RedisInitBean rib; @RequestMapping("/test") public ModelAndView test(@RequestParam(value = "username") final String userid, @RequestParam(value = "password") final String passwd, HttpSession session){ ModelAndView m = new ModelAndView(); m.setViewName("../index"); ShardedJedis jedis = rib.getSingletonInstance(); ShardedJedisPipeline pipeline = jedis.pipelined(); long start = System.currentTimeMillis(); for (int i = 0; i < 99999; i++) { pipeline.set("zhenbn" + i, "n" + i); } List<Object> results = pipeline.syncAndReturnAll(); long end = System.currentTimeMillis(); rib.returnResource(); rib.destroy(); System.out.println("分佈式鏈接池異步調用耗時: " + ((end - start)/1000.0) + " 秒"); try { Thread.sleep(5000);//睡5秒,而後打印jedis返回的結果 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("返回結果:"+results); m.addObject("returnMsg","麼麼噠!"); return m; } }
存完以後,咱們能夠取一下試試,看看到底有沒有存進去。
看,取到了吧~
使用jedis的時候要注意配合commons-pool2.jar使用,不然會報錯的。
緣由是 JedisPoolConfig extends GenericObjectPoolConfig,
而GenericObjectPoolConfig則是:
BaseObjectPoolConfig則是: