Redis-Java客户端Jedis

来源:互联网 发布:mac 命令行卸载软件 编辑:程序博客网 时间:2024/05/17 12:01

Redis-Java客户端Jedis

 

一.Jedis的下载方式

        Maven管理下,在pom文件中引入如下依赖即可:

<dependency>

            <groupId>redis.clients</groupId>

            <artifactId>jedis</artifactId>

             <version>2.9</version>

        </dependency>

二.Jedis的基本API

2.1 Jedis初始化

Jedis jedis = new jedis(String host, Stringport)

Jedis jedis = new jedis(String host,String port,intconnectionTimeout,final int soTimeout)

参数说明:

ip:redis服务器的ip地址

port:redis服务器的端口号

connectionTimeout:客户端连接超时

soTimeout:客户端读写超时

 

2.2 基本操作

三 Jedis对象序列化

3.1 jedis的序列化支持

Jedis本身没有提供序列化工具,但是他提供了操作字节数组的API

如下:

public String set(final String key, String value)

public String set(final byte[] key, byte[] value)

public byte[] get(final byte[] key)

public String set(final String key)

我们可以引入第三方序列化工具(如xml,json,protobuf,thrift等等,也可以自己实现,来完成对象类型数据的序列化和反序列化工作。

3.2 序列化步骤

我们可以引入第三方序列化工具(如xml,json,protobuf,thrift等等,也可以自己实现,来完成对象类型数据的序列化和反序列化工作。

下面以protostuff(ProtoBuf的java客户端)为例进行说明

1) protostuff的maven依赖

<protostuff.version>1.0.11</protostuff.version>

        <dependency>

            <groupId>com.dyuproject.protostuff</groupId>

            <artifactId>protostuff-runtime</artifactId>

            <version>${protostuff.version}</version>

        </dependency>

        <dependency>

            <groupId>com.dyuproject.protostuff</groupId>

            <artifactId>protostuff-core</artifactId>

            <version>${protostuff.version}</version>

    </dependency>  

(2)定义实体类

public classClub {

   privateintid;

   privateStringname;

   privateStringinfo;

   privateDatecreateDate;

   privateintrank;

    public int getId() {

        returnid;

    }

    public void setId(intid) {

        this.id =id;

    }

    public String getName() {

        returnname;

    }

    public void setName(String name) {

        this.name =name;

    }

    public String getInfo() {

        returninfo;

    }

    public void setInfo(String info) {

        this.info =info;

    }

    public Date getCreateDate() {

        returncreateDate;

    }

    public void setCreateDate(Date createDate) {

        this.createDate =createDate;

    }

    public int getRank() {

        returnrank;

    }

    public void setRank(intrank) {

        this.rank =rank;

    }

   

}

(3)提供序列化工具进行序列化和反序列化服务

/**

 *

 */

package com.example.serializationtools;

 

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.util.List;

 

import com.dyuproject.protostuff.LinkedBuffer;

import com.dyuproject.protostuff.ProtostuffIOUtil;

import com.dyuproject.protostuff.Schema;

import com.dyuproject.protostuff.runtime.RuntimeSchema;

 

/**

 * Protistuff序列化工具

 * @author shl

 *

 */

public class ProtostuffSerializer {

  public static <T> byte[]serialize(T obj) {

        if (obj == null) {

            throw newRuntimeException("序列化对象("+ obj + ")!");

        }

       @SuppressWarnings("unchecked")

        Schema<T> schema =(Schema<T>) RuntimeSchema.getSchema(obj.getClass());

        LinkedBuffer buffer =LinkedBuffer.allocate(1024 * 1024);

        byte[] protostuff = null;

        try {

            protostuff =ProtostuffIOUtil.toByteArray(obj, schema, buffer);

        } catch (Exception e) {

            throw newRuntimeException("序列化(" +obj.getClass() + ")对象(" + obj +")发生异常!", e);

        } finally {

            buffer.clear();

        }

        return protostuff;

    }

 

    public static <T> Tdeserialize(byte[] paramArrayOfByte, Class<T> targetClass) {

        if (paramArrayOfByte == null|| paramArrayOfByte.length == 0) {

            throw newRuntimeException("反序列化对象发生异常,byte序列为空!");

        }

        T instance = null;

        try {

            instance =targetClass.newInstance();

        } catch (InstantiationException |IllegalAccessException e) {

            throw newRuntimeException("反序列化过程中依据类型创建对象失败!",e);

        }

        Schema<T> schema =RuntimeSchema.getSchema(targetClass);

       ProtostuffIOUtil.mergeFrom(paramArrayOfByte, instance, schema);

        return instance;

    }

   

    public static <T> byte[]serializeList(List<T> objList) {

        if (objList == null ||objList.isEmpty()) {

            throw newRuntimeException("序列化对象列表("+ objList + ")参数异常!");

        }

       @SuppressWarnings("unchecked")

        Schema<T> schema =(Schema<T>) RuntimeSchema.getSchema(objList.get(0).getClass());

        LinkedBuffer buffer =LinkedBuffer.allocate(1024 * 1024);

        byte[] protostuff = null;

        ByteArrayOutputStream bos =null;

        try {

            bos = newByteArrayOutputStream();

           ProtostuffIOUtil.writeListTo(bos, objList, schema, buffer);

            protostuff =bos.toByteArray();

        } catch (Exception e) {

            throw new RuntimeException("序列化对象列表(" + objList + ")发生异常!",e);

        } finally {

            buffer.clear();

            try {

                if(bos!=null){

                    bos.close();

                }

            } catch (IOException e){

                e.printStackTrace();

            }

        }

       

        return protostuff;

    }

   

    public static <T>List<T> deserializeList(byte[] paramArrayOfByte, Class<T>targetClass) {

        if (paramArrayOfByte == null|| paramArrayOfByte.length == 0) {

            throw newRuntimeException("反序列化对象发生异常,byte序列为空!");

        }

       

        Schema<T> schema =RuntimeSchema.getSchema(targetClass);

        List<T> result = null;

        try {

            result =ProtostuffIOUtil.parseListFrom(new ByteArrayInputStream(paramArrayOfByte),schema);

        } catch (IOException e) {

            throw newRuntimeException("反序列化对象列表发生异常!",e);

        }

        return result;

    } 

}

 

(4)验证

    @Test

    public voidtestProtobufSerializer() {

        GenericObjectPoolConfig poolConfig =newGenericObjectPoolConfig();

        JedisPooljedisPool=newJedisPool(poolConfig,"10.3.34.101", 6378);

        Jedisjedis= null;

        jedis = jedisPool.getResource();

        jedis.set("hello1".getBytes(),"worldone".getBytes());

        System.out.println("-------");

        Clubclub= newClub();

        club.setId(1);

        club.setInfo("will win");

        club.setName("tian jin quan jian");

        club.setRank(1);

        club.setCreateDate(new Date());

        ProtostuffSerializerprotostuffSerializer =newProtostuffSerializer();

        byte[]clubbytes = protostuffSerializer.serialize(club);

        jedis.set("winner".getBytes(),clubbytes);

        byte[]winnerClubBytes = jedis.get("winner".getBytes());

        Club winnerClub = protostuffSerializer.deserialize(winnerClubBytes,Club.class);

        System.out.println(winnerClub.getId());

        System.out.println(winnerClub.getInfo());

        System.out.println(winnerClub.getName());

        System.out.println(winnerClub.getRank());

        System.out.println(winnerClub.getCreateDate());

       

        //jedis.dbSize()

  }

 

输出:

1

will win

tian jin quan jian

1

Thu Jul 13 14:51:53 CST 2017

2017-07-13 14:51:53.404  INFO16648 --- [       Thread-4]s.c.a.AnnotationConfigApplicationContext : Closingorg.springframework.context.annotation.AnnotationConfigApplicationContext@7c6908d7:startup date [Thu Jul 13 14:51:51 CST 2017]; root of context hierarchy

 

 

四. Jedis连接池

4.1 Jedis连接池的作用

Redis客户端与服务端的通讯会新建TCP连接,使用后再断开连接,对于频繁访问Redis的场景显然不是高效的使用方式。

Jedis可以使用连接池的方式对Jedis连接进行管理,预先初始化好一定数量的Jedis连接,并将Jedis连接预先放在池子(JedisPool)中,每次要连接Redis,都从JedisPool中获取连接,使用后在释放回连接池中,获取和释放连接的操作都是在客户端进行的,只有少量的并发同步开销,远远小于建立TCP连接的开销。另外,直连的方式还会造成创建大量的Jedis对象的风险,极端情况下会造成连接泄露,而连接池可以有效的保护和控制资源的使用。

4.2 Jedis连接池的初始化

//使用Apache的通用对象池工具common-pool做为资源管理工具

GenericObjectPoolConfig poolConfig = newGenericObjectPoolConfig();

//初始化jedis连接池

JedisPool jedisPool = new JedisPool(poolConfig,"10.3.34.101",6378);

Jedis jedis = null;

try {

   //从连接池获取jedis对象

jedis = jedisPool.getResource();

   jedis.get(“hello”);

} catch(Exception e) {

   log.error(e.getMessage,e);

} finally {

//如果使用JedisPool,close不是关闭连接,而是将连接归还到连接池中。

If(jedis != null) {

    Jedis.close();

}

}

       

4.3 Jedis连接池的参数说明

五. Jedis中Pipeline的支持

(1)使用jedis对象生产一个pipeline对象,直接调用jedis.pipelined();

(2)将命令封装到pipeline中,例如调用pipeline.del(key),写法和jedis.del(key)是一致的,只

不过此时并不真正执行命令

(3)执行pipeline.sync()完成此次批量命令的执行或者pipeline.syncAndReturnAll()批量执行命令并将命令的执行结果返回。

例如:

public classPipelineDemo {

    private static Jedis jedis = null;

    static {

        GenericObjectPoolConfig poolConfig =newGenericObjectPoolConfig();

        JedisPooljedisPool=newJedisPool(poolConfig,"10.3.34.101", 6378);      

        jedis = jedisPool.getResource();

    }

    public void batchSave() {

        //生成pipeline对象

        Pipelinepipelinejedis.pipelined();

        for (inti = 0; i < 10;i++) {

            //此时并未真正执行命令

            pipeline.set("key"+i,"value"+i);

        }

        //执行命令

        pipeline.sync();

        //或者List list =pipeline.syncAndReturnAll();

    }

}

六. Jedis的Lua脚本

Jedis中执行Lua脚本和redis-cli十分类似,Jedis提供了三个重要的函数实现Lua脚本的执行:

(1)      Object eval(String script, intkeyCount, String… params)

  eval函数有三个参数:

script:Lua脚本内容

keyCount:键的个数

params:相关参数keys和argv

 

以一个简单Lua脚本为例进行说明:

return redis.call(‘get’,KEYS[1])

 

在redis-cli中执行上面的Lua脚本方法如下:

eval "returnredis.call('get',KEYS[1])" 1 key1

 

在jedis中执行:

    Stringkey= "key1";

    Stringscript= "returnredis.call('GET',KEYS[1])";

    Objectobj= jedis.eval(script, 1,key);

    System.out.println(obj);

 

(2)      String scriptLoad(String script)

scriptload将脚本加载到redis中

在jedis中执行:    

String script= "returnredis.call('GET',KEYS[1])";

        sha = jedis.scriptLoad(script);

 

(3)      Object evalsha(String sha1, intkeyCount, String… params)

选项:

ScriptSha:脚本的SHA1

KeyCount:键的个数

params:相关参数KEYS和ARGV

 

       jedis实现:

        Stringkey= "key1";

        Stringscript= "returnredis.call('GET',KEYS[1])";    

        Stringsha= jedis.scriptLoad(script);

        Objectobj= jedis.evalsha(sha, 1,key);

 

七. jedis注意事项

(1)Jedis操作放在try catch finally中更加合理

(2)生产环境中使用jedis连接池

(3)如果key和value涉及了字节数组,需要选择合适的序列化方法

原创粉丝点击