详解java之redis篇(spring-data-redis整合)

1,利用spring-data-redis整合

项目使用的pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>

 <groupId>com.x.redis</groupId>
 <artifactId>Spring_redis</artifactId>
 <version>1.0-SNAPSHOT</version>
 <packaging>jar</packaging>

 <name>Spring_redis</name>
 <url>http://maven.apache.org</url>

 <properties>
 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 </properties>

 <dependencies>
  <dependency>
  <groupId>org.springframework.data</groupId>
  <artifactId>spring-data-redis</artifactId>
  <version>1.0.2.RELEASE</version>
 </dependency>
 <dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>3.1.2.RELEASE</version>
 </dependency> 

 <dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
  <version>2.1.0</version>
 </dependency> 

  <dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.8.2</version>
  <scope>test</scope>
 </dependency>
    <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.6.1</version>
   </dependency>
   <!-- 将现有的jakarta commons logging的调用转换成lsf4j的调用。 -->
   <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>1.6.1</version>
   </dependency>
   <!-- Hack:确保commons-logging的jar包不被引入,否则将和jcl-over-slf4j冲突 -->
   <dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.1.1</version>
    <scope>provided</scope>
   </dependency>
   <!-- slf4j的实现:logback,用来取代log4j。更快、更强! -->
   <dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>0.9.24</version>
    <scope>runtime</scope>
   </dependency>
 </dependencies>
</project>

除了log部分,只有一个spring core 和 spring-data-redis了

项目文件目录结构:

applicationContext.xml:

1,context:property-placeholder 标签用来导入properties文件。从而替换${redis.maxIdle}这样的变量。

2,context:component-scan 是为了在com.x.redis.dao报下的类能够实用spring的注解注入的方式。

3,事实上我们只需要把JedisPoolConfig配数来就好了,接下来就是spring的封装了。所以直接看UserDAOImpl的实现就明白了。

<?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:p="http://www.springframework.org/schema/p"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xsi:schemaLocation="
   http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> 

 <context:property-placeholder location="classpath:redis.properties" />
 <context:component-scan base-package="com.x.redis.dao">
 </context:component-scan>
 <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
  <property name="maxIdle" value="${redis.maxIdle}" />
  <property name="maxActive" value="${redis.maxActive}" />
  <property name="maxWait" value="${redis.maxWait}" />
  <property name="testOnBorrow" value="${redis.testOnBorrow}" />
 </bean> 

 <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
  p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.pass}" p:pool-config-ref="poolConfig"/> 

 <bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
  <property name="connectionFactory" ref="connectionFactory" />
 </bean>   

 <bean id="userDAO" class="com.x.redis.dao.impl.UserDAOImpl" />
</beans>

redis.properties:

# Redis settings
#redis.host=192.168.20.101
#redis.port=6380
#redis.pass=foobared
redis.host=127.0.0.1
redis.port=6379
redis.pass=

redis.maxIdle=300
redis.maxActive=600
redis.maxWait=1000
redis.testOnBorrow=true

UserDAOImpl:

1,spring对dao层的封装很多用了类似于下面代码的模板方式。

2,RedisTemplate就是spring对redis的一个封装而已。

public class UserDAOImpl implements UserDAO {

 @Autowired
 protected RedisTemplate<Serializable, Serializable> redisTemplate;

 public void saveUser(final User user) {
  redisTemplate.execute(new RedisCallback<Object>() {

   @Override
   public Object doInRedis(RedisConnection connection) throws DataAccessException {
    connection.set(redisTemplate.getStringSerializer().serialize("user.uid." + user.getId()),
        redisTemplate.getStringSerializer().serialize(user.getName()));
    return null;
   }
  });
 }

 @Override
 public User getUser(final long id) {
  return redisTemplate.execute(new RedisCallback<User>() {
   @Override
   public User doInRedis(RedisConnection connection) throws DataAccessException {
    byte[] key = redisTemplate.getStringSerializer().serialize("user.uid." + id);
    if (connection.exists(key)) {
     byte[] value = connection.get(key);
     String name = redisTemplate.getStringSerializer().deserialize(value);
     User user = new User();
     user.setName(name);
     user.setId(id);
     return user;
    }
    return null;
   }
  });
 }

}

其他:

User:

public class User {

 private long id;
 private String name;

 public long getId() {
  return id;
 }

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

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }
}

测试代码:

public static void main(String[] args) {
  ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:/applicationContext.xml");
  UserDAO userDAO = (UserDAO)ac.getBean("userDAO");
  User user1 = new User();
  user1.setId(1);
  user1.setName("obama");
  userDAO.saveUser(user1);
  User user2 = userDAO.getUser(1);
  System.out.println(user2.getName());
 }

2,不利用spring-data-redis整合

个人觉得这样整合灵活度更大,能够更加明了的完成任务。

pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>

 <groupId>com.d.work</groupId>
 <artifactId>Redis_Templete</artifactId>
 <version>1.0-SNAPSHOT</version>
 <packaging>jar</packaging>

 <name>Redis_Templete</name>
 <url>http://maven.apache.org</url>

 <properties>
 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 </properties>

 <dependencies>
 <dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>3.8.1</version>
  <scope>test</scope>
 </dependency>
 <dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
  <version>2.1.0</version>
 </dependency>
  <dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>3.1.2.RELEASE</version>
 </dependency>
  <dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-beans</artifactId>
  <version>3.1.2.RELEASE</version>
 </dependency>
  <dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>3.1.2.RELEASE</version>
 </dependency>
 <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.6.1</version>
   </dependency>
   <!-- 将现有的jakarta commons logging的调用转换成lsf4j的调用。 -->
   <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>1.6.1</version>
   </dependency>
   <!-- Hack:确保commons-logging的jar包不被引入,否则将和jcl-over-slf4j冲突 -->
   <dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.1.1</version>
    <scope>provided</scope>
   </dependency>
   <!-- slf4j的实现:logback,用来取代log4j。更快、更强! -->
   <dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>0.9.24</version>
    <scope>runtime</scope>
   </dependency>
 </dependencies>
</project>

目录结构:

data-source.xml

1,context:property-placeholder 和 context:component-scan 前面解释过啦。

2,配置了一个ShardedJedisPool,在jdeis里 还有个JedisPool。这两个的区别:

一个是分片形式,可以连接有主备的redis服务端,一个是单个的。详细后续学习

3,因为不使用spring-data-redis的封装,所以自己要自己封装一个

<?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:p="http://www.springframework.org/schema/p"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xsi:schemaLocation="
   http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> 

 <context:property-placeholder location="classpath:redis.properties" />
 <context:component-scan base-package="com.d.work.main">
 </context:component-scan>
  <context:component-scan base-package="com.d.work.redis">
 </context:component-scan>
 <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
  <property name="maxActive" value="50" />
  <property name="maxIdle" value="8" />
  <property name="maxWait" value="1000" />
  <property name="testOnBorrow" value="true"/>
  <property name="testOnReturn" value="true"/>
  <!-- <property name="testWhileIdle" value="true"/> -->
 </bean>

 <bean id="shardedJedisPool" class="redis.clients.jedis.ShardedJedisPool" scope="singleton">
  <constructor-arg index="0" ref="jedisPoolConfig" />
  <constructor-arg index="1">
   <list>
    <bean class="redis.clients.jedis.JedisShardInfo">
     <constructor-arg name="host" value="${redis.host}" />
     <constructor-arg name="port" value="${redis.port}" />
     <constructor-arg name="timeout" value="${redis.timeout}" />
     <constructor-arg name="weight" value="1" />
    </bean>
   </list>
  </constructor-arg>
 </bean>
</beans>

RedisDataSource:定义三个方法

public interface RedisDataSource {
 public abstract ShardedJedis getRedisClient();
 public void returnResource(ShardedJedis shardedJedis);
 public void returnResource(ShardedJedis shardedJedis,boolean broken);
}

实现redisDataSource:

1, 注入配置好的ShardedJedisPool,这三个方法的作用:

  • getRedisClient() : 取得redis的客户端,可以执行命令了。
  • returnResource(ShardedJedis shardedJedis) : 将资源返还给pool
  • returnResource(ShardedJedis shardedJedis, boolean broken) : 出现异常后,将资源返还给pool (其实不需要第二个方法)
@Repository("redisDataSource")
public class RedisDataSourceImpl implements RedisDataSource {

 private static final Logger log = LoggerFactory.getLogger(RedisDataSourceImpl.class);

 @Autowired
 private ShardedJedisPool shardedJedisPool;

 public ShardedJedis getRedisClient() {
  try {
   ShardedJedis shardJedis = shardedJedisPool.getResource();
   return shardJedis;
  } catch (Exception e) {
   log.error("getRedisClent error", e);
  }
  return null;
 }

 public void returnResource(ShardedJedis shardedJedis) {
  shardedJedisPool.returnResource(shardedJedis);
 }

 public void returnResource(ShardedJedis shardedJedis, boolean broken) {
  if (broken) {
   shardedJedisPool.returnBrokenResource(shardedJedis);
  } else {
   shardedJedisPool.returnResource(shardedJedis);
  }
 }
}

第二层的封装:RedisClientTemplate,例子实现了放值和取值。最后代码提供了全部命令的实现。

代码就是映射性质的又一次调用jedis的方法而已,用了个broken来做标示符,决定返还资源的方式。

这一层的目的主要也是让再上层的调用不需要关心pool中链接的取得和返还问题了。

@Repository("redisClientTemplate")
public class RedisClientTemplate {

 private static final Logger log = LoggerFactory.getLogger(RedisClientTemplate.class);

 @Autowired
 private RedisDataSource  redisDataSource;

 public void disconnect() {
  ShardedJedis shardedJedis = redisDataSource.getRedisClient();
  shardedJedis.disconnect();
 }

 /**
  * 设置单个值
  *
  * @param key
  * @param value
  * @return
  */
 public String set(String key, String value) {
  String result = null;

  ShardedJedis shardedJedis = redisDataSource.getRedisClient();
  if (shardedJedis == null) {
   return result;
  }
  boolean broken = false;
  try {
   result = shardedJedis.set(key, value);
  } catch (Exception e) {
   log.error(e.getMessage(), e);
   broken = true;
  } finally {
   redisDataSource.returnResource(shardedJedis, broken);
  }
  return result;
 }

 /**
  * 获取单个值
  *
  * @param key
  * @return
  */
 public String get(String key) {
  String result = null;
  ShardedJedis shardedJedis = redisDataSource.getRedisClient();
  if (shardedJedis == null) {
   return result;
  }

  boolean broken = false;
  try {
   result = shardedJedis.get(key);

  } catch (Exception e) {
   log.error(e.getMessage(), e);
   broken = true;
  } finally {
   redisDataSource.returnResource(shardedJedis, broken);
  }
  return result;
 }
}

测试代码:

 public static void main(String[] args) {
  ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:/data-source.xml");
  RedisClientTemplate redisClient = (RedisClientTemplate)ac.getBean("redisClientTemplate");
  redisClient.set("a", "abc");
  System.out.println(redisClient.get("a"));
 }

附上RedisClientTemplate全部实现:

RedisClientTemplate代码太多,附上下载地址:http://xiazai.jb51.net/201701/yuanma/RedisClientTemplate_jb51.rar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • java日期相关类实例详解

    一.Date类 类 Date 表示特定的瞬间,精确到毫秒.用距离1970年1月1日00:00:00的毫秒数(long)类型来表示一个特定的时间点,该值可正可负. Date类中很多方法已经过时,使用Calendar来替代. 常用方法有 long getTime() void setTime(long time) public class T01Date { public static void main(String[] args) { //getTime():返回的时间是距离1970年的毫秒数.

  • java 查询oracle数据库所有表DatabaseMetaData的用法(详解)

    一 . 得到这个对象的实例 Connection con ; con = DriverManager.getConnection(url,userName,password); DatabaseMetaData dbmd = con.getMetaData(); 二. 方法getTables的用法 原型: ResultSet DatabaseMetaData.getTables(String catalog,String schema,String tableName,String []type

  • 浅析Java.IO输入输出流 过滤流 buffer流和data流

    java.io使用了适配器模式装饰模式等设计模式来解决字符流的套接和输入输出问题. 字节流只能一次处理一个字节,为了更方便的操作数据,便加入了套接流. 问题引入: 缓冲流为什么比普通的文件字节流效率高? 不带缓冲的操作,每读一个字节就要写入一个字节. 由于涉及磁盘的IO操作相比内存的操作要慢很多,所以不带缓冲的流效率很低. 带缓冲的流,可以一次读很多字节,但不向磁盘中写入,只是先放到内存里. 等凑够了缓冲区大小的时候一次性写入磁盘,这种方式可以减少磁盘操作次数,速度就会提高很多! 这就是两者的区

  • 从最基本的Java工程搭建SpringMVC+SpringDataJPA+Hibernate

    本文会介绍从一个最基本的java工程,到Web工程,到集成Spring.SpringMVC.SpringDataJPA+Hibernate. 平时我们可能是通过一个模板搭建一个工程,或者是直接导入一个项目,而本文选择从最基本的java工程开始,目的是为了展示更多原理. 当然,我们还是从一个最基本的Maven工程开始,其实普通的非Maven工程,搭建过程几乎是一模一样的,只是Jar包需要我们手动的添加到工程中,而Maven工程就只是修改配置文件即可. 下面就正式开始. 1.基于Maven(如果不使

  • java DataInputStream和DataOutputStream详解及实例代码

    java DataInputStream和DataOutputStream详解 操作基本数据类型的流 DataInputStream DataOutputStream import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public c

  • 详解java 中Spring jsonp 跨域请求的实例

    详解java 中Spring jsonp 跨域请求的实例 jsonp介绍 JSONP(JSON with Padding)是JSON的一种"使用模式",可用于解决主流浏览器的跨域数据访问的问题.由于同源策略,一般来说位于 server1.example.com 的网页无法与不是 server1.example.com的服务器沟通,而 HTML 的<script> 元素是一个例外.利用 <script> 元素的这个开放策略,网页可以得到从其他来源动态产生的 JSO

  • 详解Java 包扫描实现和应用(Jar篇)

    如果你曾经使用过 Spring, 那你已经配过 包扫描路径吧,那包扫描是怎么实现的呢?让我们自己写个包扫描 上篇文章中介绍了使用 File 遍历的方式去进行包扫描,这篇主要补充一下jar包的扫描方式,在我们的项目中一般都会去依赖一些其他jar 包, 比如添加 guava 依赖 <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <ve

  • 详解JAVA Spring 中的事件机制

    说到事件机制,可能脑海中最先浮现的就是日常使用的各种 listener,listener去监听事件源,如果被监听的事件有变化就会通知listener,从而针对变化做相应的动作.这些listener是怎么实现的呢?说listener之前,我们先从设计模式开始讲起. 观察者模式 观察者模式一般包含以下几个对象: Subject:被观察的对象.它提供一系列方法来增加和删除观察者对象,同时它定义了通知方法notify().目标类可以是接口,也可以是抽象类或具体类. ConcreteSubject:具体的

  • 详解Java redis中缓存穿透 缓存击穿 雪崩三种现象以及解决方法

    目录 前言 一.缓存穿透 二.缓存击穿 三.雪崩现象 总结 前言 本文主要阐述redis中的三种现象 1.缓存穿透 2.缓存击穿 3.雪崩现象 本文主要说明本人对三种情况的理解,如果需要知道redis基础请查看其他博客,加油! 一.缓存穿透 理解:何为缓存穿透,先要了解穿透,这样有助于区分穿透和击穿,穿透就类似于伤害一点一点的累计,最终打到穿透的目的,类似于射手,一下一下普通攻击,最终杀死对方,先上图 先来描述一下缓存穿透的过程: 1.由于我们取数据的原则是先查询redis上,如果redis上有

  • 详解java调用python的几种用法(看这篇就够了)

    java调用python的几种用法如下: 在java类中直接执行python语句 在java类中直接调用本地python脚本 使用Runtime.getRuntime()执行python脚本文件(推荐) 调用python脚本中的函数 准备工作: 创建maven工程,结构如下: 到官网https://www.jython.org/download.html下载Jython的jar包或者在maven的pom.xml文件中加入如下代码: <dependency> <groupId>org

  • 详解Java如何使用注解来配置Spring容器

    目录 介绍 @Bean and @Configuration AnnotationConfigApplicationContext实例化容器 通过使用 register(Class...) 以编程方式构建容器 @ComponentScan启用组件扫描 Bean的依赖 生命周期回调 Bean指定作用域 自定义bean名称 Bean别名 Bean注入之间的依赖 @Import @ImportResource @PropertySource 支持多个properties文件 ApplicationCo

  • 详解Java集合类之HashSet篇

    目录 1.Set接口方法 2.HashSet 3.HashSet的扩容机制 - 初次添加数据 4.HashSet的扩容机制 - 继续添加数据 5.HashSet的扩容机制 - 添加重复元素 1.Set接口方法 Set接口对象存放的数据是没有重复,且数据是无序存放的(添加顺序和存放顺序不一致,但是这个存放的顺序是固定的,不会随机变化) 代码示例: import java.util.HashSet; import java.util.Iterator; import java.util.Set; /

  • 详解Java集合类之List篇

    目录 1.集合框架体系 2.Collection接口 3.迭代器 4.List接口 5.ArrayList ArrayList扩容机制 ArrayList使用实例 6.Vector 7.LinkedList 增加元素源码分析 删除元素源码分析 LinkedList使用Demo 8.ArrayList和LinkedList的选择 1.集合框架体系 集合框架被设计成要满足以下几个目标. 该框架必须是高性能的.基本集合(动态数组,链表,树,哈希表)的实现也必须是高效的. 该框架允许不同类型的集合,以类

  • 详解Java集合类之Map篇

    目录 1.Map接口介绍 2.Map接口分析 3.Map接口方法 4.Map遍历方式 1.Map接口介绍 Map用于保存具有映射关系的数据:Key - Value 对于Set,底层其实依然是一个Map,但是Set选择不使用Value,也就是Set的Value值始终是一个常量 Map中的Key和Value可以是任何类型的数据,会封装到HashMap$Node对象中 Map中的Key不能重复,但是Value可以重复,当有相同的Key时,等价与替换操作 2.Map接口分析 存放Map键值对是在Hash

  • 详解Java集合类之HashTable,Properties篇

    目录 1.基本介绍 2.HashTable底层 3.HashTable扩容机制 4.HashMap和HashTable的对比 5.Properties 6.集合选型规则 1.基本介绍 HashTable的键和值都不能为空,否则会抛出一个异常 使用方法基本与HashMap一致 HashTable是线程安全的,HashMap是线程不安全的 2.HashTable底层 先上代码: Hashtable hashtable = new Hashtable(); hashtable.put("john&qu

随机推荐