精华内容
下载资源
问答
  • Java连接redis种方式

    2020-08-31 20:28:40
    一、原生方法连接redis 第一步:加依赖 <dependency> <groupId>redis.clients</groupId> <artifactId>...启动redis的服务。...获得连接对象,连接对象分装操作redis的方法: Jedis jedi

    一、原生方法连接redis

    第一步:加依赖

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

    第二步:

    启动redis的服务。
    在这里插入图片描述

    第三步:

    获得连接对象,连接对象分装操作redis的方法:

    Jedis jedis=new Jedis("127.0.0.1");
    jedis.set("JEDSI JAVA","hello jedis");
    String value=jedis.get("JEDSI JAVA");

    弊端:每次连接都会创建jedis对象,严重降低效率。在互联网的背景下》使用springboot添加第二种工厂模式创建连接对象,会大大提高redis的性能

    二、通过springboot的jar包

    第一步:添加依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
        <version>2.3.1.RELEASE</version>
    </dependency>

    第二步:

    1、在application.properties里添加配置:

    #端口
    spring.redis.port=6379
    #redis服务地址
    spring.redis.host=127.0.0.1
    #redis密码,默认为空
    spring.redis.password=

    2、在工具包里面写配置类

    package com.util;
    
    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.RedisTemplate;
    import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
    import org.springframework.data.redis.serializer.StringRedisSerializer;
    
    import java.io.Serializable;
    /**
     * @Auth朱定欢
     * 作用:创建连接对象
     * */
    @Configuration
    public class redisconfig {
        @Bean
        //通过配置类对连接对象配置
        public RedisTemplate<String , Serializable> getRedis(RedisConnectionFactory factory){
            //获得连接对象
            RedisTemplate<String, Serializable> redisTemplate=new RedisTemplate<String, Serializable>();
          //设置连接工厂
           redisTemplate.setConnectionFactory(factory);
           //key进行序列化
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            //规定value的序列化格式
            Jackson2JsonRedisSerializer jackson2JsonRedisSerializer=new Jackson2JsonRedisSerializer(Object.class);
            //value进行序列化
            redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
            //返回连接对象
            return redisTemplate;
        }
    }
    
    

    3、通过控制器进行调用

    package com.Controller;
    
    import com.pojo.User;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.*;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class Rediscontroller {
        @Autowired
        RedisTemplate redisTemplate;
    
        @RequestMapping("/redis")
        public Object helloRedis(){
    
            User he=new User();
            he.setAge(11);
            he.setId("yihao");
            he.setName("nihao");
            //字符类型的数据
            ValueOperations  valueOperations=redisTemplate.opsForValue();
            //通过对象在redis对象进行存储
            valueOperations.set("USER_INFO",he);
            //获取刚刚存储的对象
            Object value=valueOperations.get("USER_INFO");
            System.out.println(value);
            //操作hash类型的数据
            HashOperations hashOperations=redisTemplate.opsForHash();
            //操作列表的数据
            ListOperations listOperations=redisTemplate.opsForList();
            //操作有序集合类型的数据
            ZSetOperations zSetOperations=redisTemplate.opsForZSet();
            //操作无序集合类型的数据
            SetOperations setOperations=redisTemplate.opsForSet();
            return value;
        }
    }
    

    4、简单类对象:

    package com.pojo;
    
    import java.io.Serializable;
    
    public class User implements Serializable {
        private String name;
        private int age;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        private String id;
    }
    

    注意:
    简单类对象需要进行序列化,否则会报错如下的错。

    java.lang.IllegalArgumentException: DefaultSerializer requires a Serializable payload but received an object of type [com.pojo.User]
     at org.springframework.core.serializer.DefaultSerializer.serialize(DefaultSerializer.java:43) ~[spring-core-5.2.7.RELEASE.jar:5.2.7.RELEASE]
     at org.springframework.core.serializer.Serializer.serializeToByteArray(Serializer.java:56) ~[spring-core-5.2.7.RELEASE.jar:5.2.7.RELEASE]
     at org.springframework.core.serializer.support.SerializingConverter.convert(SerializingConverter.java:60) ~[spring-core-5.2.7.RELEASE.jar:5.2.7.RELEASE]
     at org.springframework.core.serializer.support.SerializingConverter.convert(SerializingConverter.java:33) ~[spring-core-5.2.7.RELEASE.jar:5.2.7.RELEASE]
     at org.springframework.da

    启动服务就可以调用了。
    在redis就可以看到以字符串形式存储的序列化数据
    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • 小白今天刚接触redis,发现用java操作redis时有两方法,第一是 Jedis jedis=new Jedis("192.168.228.55",6379); 通过这个对象jedis.set可以往redis里设置key 另一种方式是通过一个什么RedisTemplate.opsForValue...
  • Java操作Redis

    千次阅读 2016-03-19 11:20:43
    Java操作Redis还是十分好上手的,Jedis的方法和数据库的命令几乎一模一样,连名字都懒得改的,基本上都是set、get、lpush、lpop、sadd之类的


           前几篇博客我们介绍了Redis的概念、数据类型和不同数据类型下的数据操作。在进行数据操作的时候,我们是直接使用命令的,那如何在项目中操作Redis的数据呢?今天小编就带大家看一下在java下如何操作Redis的数据。



    准备工作:

           新建项目,需要引入jar包 jedis-2.1.0.jar    commons-pool-1.5.5.jar

           Jedis是Redis的java客户端,后面的操作都会用到。



    小试牛刀:

         查询所有key,相当于数据库命令“keys *”。

                //连接Redis,6379端口
              Jedis jedis=new Jedis("192.168.22.226",6379); 
    		//查询所有key值
    		Set keys=jedis.keys("*");
    		Iterator iterator=keys.iterator();
                  //遍历
    		while(iterator.hasNext()){
    			Object obj=iterator.next();
    			System.out.println("=======[key值]:"+obj);
    		}


    执行输出结果:




    进阶:

           Redis的数据类型分为五种:String,hashes,list,set和Sortedsets。这里只以其中的几个为例,简要说明。

    1、list  

                  //list操作--先进后出
    		jedis.lpush("list001", "001");
    		jedis.lpush("list001", "002");
    		jedis.lpush("list001", "003");
    		System.out.println("key为list001中的元素有:"+jedis.lrange("list001", 0, -1));
    		System.out.println(jedis.lpop("list001"));
    		System.out.println(jedis.lpop("list001"));
    		System.out.println(jedis.lpop("list001"));


    显示结果:




          在前一篇博客中,我们演示了list操作中模拟队列、栈的进出,这里就不再赘述了。大家可以下面自己测试,很简单的。


    2、hash

    在hash操作中,仍旧是hset命令进行添加。

                    jedis.hset("user001", "book", "Redis");
    		jedis.hset("user001", "page", "500");

    3、set

    //添加元素
    		jedis.sadd("set02", "one");
    		jedis.sadd("set02", "two");
    		jedis.sadd("set02", "three");
    		jedis.sadd("set02", "four");
    		//读取
    		Set set = jedis.smembers("set02");
    		//遍历打印输出
    		Iterator iterator = set.iterator();
    		while (iterator.hasNext()) {
    			Object obj = iterator.next();
    			System.out.println("key为set02中的元素有:"+obj);
    		}



    项目实战:

          在ITOO中,redis用来实现不同系统间的Session共享,Redis所存储的数据类型也只有String一种类型,因此项目中也只对这种类型进行了再一次的封装。


    初始化方法

    // ip地址
        private String host = "192.168.22.246";
        private int port = 6379;
    
        // 0 - never expire
        private int expire = 0;
    
     
        private int timeout = 0;
    
        private String password = "";
    
    	//Redis池
        private static JedisPool jedisPool = null;
    
        /**
         * 初始化方法
         */
        public void init()
        {
        	//配置信息
            JedisPoolConfig jedisConfig = new JedisPoolConfig();
    
            jedisConfig.setMaxIdle(100);
            jedisConfig.setMaxTotal(1000);
            jedisConfig.setMaxWaitMillis(2000);
    
            jedisConfig.setTestWhileIdle(true);
            jedisConfig.setMinEvictableIdleTimeMillis(60000);
            jedisConfig.setTimeBetweenEvictionRunsMillis(30000);
            jedisConfig.setNumTestsPerEvictionRun(-1);
    
            if (jedisPool == null)
            {
                if (password != null && !"".equals(password))
                {
    
                    jedisPool = new JedisPool(jedisConfig, host, port, timeout,
                            password);
                }
                else if (timeout != 0)
                {
                    jedisPool = new JedisPool(jedisConfig, host, port, timeout);
                }
                else
                {
                    jedisPool = new JedisPool(jedisConfig, host, port);
                }
    
            }
        }

    添加方法

    /**
         * set
         * 
         * @param key
         * @param value
         * @return
         */
        public byte[] set(byte[] key, byte[] value)
        {
            //实例化jedis
            Jedis jedis = jedisPool.getResource();
           
            try
            {
              //使用set命令添加
                jedis.set(key, value);
                if (this.expire != 0)
                {
                   //有效时间
                    jedis.expire(key, this.expire);
                }
            }
            finally
            {
                jedisPool.returnResource(jedis);
            }
            return value;
        }
    

          如果是获取元素,就使用get命令,其他的代码都很类似,就不再重复了。


          Java操作Redis还是十分好上手的,Jedis的方法和数据库的命令几乎一模一样,连名字都懒得改的,基本上都是set、get、lpush、lpop、sadd之类的,如果这些命令还不熟悉,就翻翻小编前几篇博客吧。不过性能这块还没怎么考虑过,期待下回分享吧……


    展开全文
  • Redis是一个著名的key-value存储系统,也是nosql中的最常见的一种,这篇文章主要给大家总结了关于在java中jedis操作redis几种常见方式,文中给出了详细的示例代码供大家参考学习,需要的朋友们下面来一起看看吧。
  • redis 工具集 使用 jedis 操作 redis几种方式的集成和测试
  • Java操作Redis,使用Redis实现分布式锁

    千次阅读 2020-05-27 17:03:03
    目录jedis方式依赖使用jedis从jedis连接池获取连接连接redis集群spring data ...操作redis有3常见方式 jedis:提供的方法和redis指令相同,方法使用简单、方便,但需要自己创建连接。 spring data redis:在jedis


     

    java中操作redis常见的2个客户端

    • jedis:采用直连redis server的方式;提供了redis的基础操作。在多线程环境下,用于与redis服务器交互的Jedis对象非线程安全,线程需要从jedis连接池中获取jedis连接。
    • Lettuce:网络通信基于netty,性能高;连接实例(StatefulRedisConnection)线程安全,可以被多个线程共同使用。

     

    java中操作redis常用的3个类库

    • jedis:基于jedis客户端,常用于编写基础|公共类库
    • spring data redis:基于Lettuce客户端,搭配spring使用十分方便
    • redisson:以上2个都是关注redis的基础操作,redisson则关注redis的分布式操作,封装好了分布式的Lock、Semaphore、CountDownLatch、集合、队列等工具,对于分布式协调、开发十分方便。

     

    jedis方式

    依赖

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

     

    使用jedis

    // 重载方法很多,可指定超时时间、是否使用ssl等
    Jedis jedis=new Jedis("192.168.1.9", 6379);
    
    // jedis.auth("xxxx");  //如果需要密码
    // jedis.select(0);  //选择要使用的数据库
    
    if (jedis.ping().equals("PONG")){  //连接成功
        jedis.zadd("users", 1223, "zhangsan");
        jedis.zadd("users", 2568, "lisi");
        jedis.zadd("users", 1379, "wangwu");
    
        //迭代
        Set<Tuple> users = jedis.zrangeWithScores("users", 0, -1);  //[0,-1]
        for (Tuple user:users){
            String name = user.getElement(); //获取元素值
            double score = user.getScore(); //获取分数
            System.out.println(name+"的积分是:"+score);
        }
    }
    else{
        System.out.println("无法连接redis服务器");
    }
    
    jedis.close();
    

     

    从jedis连接池获取连接

    // jedis连接池配置
    JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
    jedisPoolConfig.setMaxTotal(15);
    jedisPoolConfig.setMaxIdle(10);
    jedisPoolConfig.setMinIdle(5);
    jedisPoolConfig.setMaxWaitMillis(180);//若一个Jedis对象闲置多少秒,就销毁
    
    // 重载方法很多,可指定超时时间、是否使用ssl、密码等
    JedisPool jedisPool= new JedisPool(jedisPoolConfig, "192.168.1.9", 6379);
    Jedis jedis = jedisPool.getResource();
    

     

    连接redis集群

    // 集群节点
    Set<HostAndPort> nodes = new HashSet();
    nodes.add(new HostAndPort("192.168.1.1", 6379));
    nodes.add(new HostAndPort("192.168.1.2", 6379));
    nodes.add(new HostAndPort("192.168.1.3", 6379));
    nodes.add(new HostAndPort("192.168.1.4", 6379));
    nodes.add(new HostAndPort("192.168.1.5", 6379));
    nodes.add(new HostAndPort("192.168.1.6", 6379));
    
    // 获取JedisCluster对象,通过JedisCluster对象来操作
    JedisCluster jedisCluster = new JedisCluster(nodes);
    
    String user = jedisCluster.get("user");
    
    jedisCluster.close();
    

     

    spring data redis方式

    依赖

    创建springboot项目时勾选 NoSQL -> Spring Data Redis(Access+Driver),或者手动添加依赖

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

     

    yml

    spring:
      redis:
        #单机版redis配置,默认localhost、6379、0
        host: 192.168.1.1
        port: 6379
        database: 0
        #连接到redis服务器的超时时间,ms
        timeout: 3000
    
        #如果是redis集群,则使用以下配置
    #    cluster:
    #      nodes: 192.168.1.1:6379,192.168.1.2:6379,192.168.1.3:6379
    
        #jedis连接池配置
        jedis:
          pool:
            #默认8,-1表示不限制
            max-active: 200
            #默认0
            min-idle: 50
            #默认8
            max-idle: 100
            #如果jedis连接池没有闲置连接可用,最多等待多少ms
            max-wait: 3000
    

     

    工具类

    直接使用RedisTemplate提供的方法,一句代码要写很长,可以自己封装一下,使用时注入RedisUtil;也可以不封装,直接使用RedisTemplate

    @Component
    public class RedisUtil {
    
        @Autowired
        private static StringRedisTemplate redisTemplate;
    
        public static void set(String key,String value){
            redisTemplate.opsForValue().set(key,value);
        }
    
        public static String get(String key){
            return redisTemplate.opsForValue().get(key);
        }
    
        public static void hset(String key,String field,Object value {
            redisTemplate.opsForHash().put(key,field,value);
        }
    
        public static Object hget(String key,String field){
            return redisTemplate.opsForHash().get(key,field);
        }
    
        //......
    
    }
    

     

    使用Redis实现分布式锁

    分布式锁需要解决的问题

    • 互斥性:同一时间段,只能有一个redis客户端获取到锁(持有锁)
    • 防止死锁:应该给key设置有效期,防止获取到锁的线程出现问题一直持有锁
    • 高性能:锁的粒度要小,比如读、写锁分开,尽可能减小锁住的范围
    • 可重入:同一个线程在获取到锁后,可以重复拿到同一个资源的锁

     

    jedis方式

    setnx() 设置key

    • 若返回1,说明设置成功,获取到锁;获取到锁后用expire() 给key设置有效期,预防发生故障锁不能及时释放
    • 若返回0,说明设置失败,这个key已经存在,锁已被其它线程持有,重试。重试可以用for循环来写,设置重试次数,失败时线程沉睡一小段时间,醒来继续循环、重试,如果达到指定次数还未获取到锁就退出循环、放弃

    在任务执行过程中,如果发生异常,不能继续往下执行,也应该马上释放锁。任务完成后用del()删除key或者用expire()将有效期置为0,释放锁。
     

    上面的方式分为setnx()、expire()2步,不满足原子性,可能出现2个问题

    • 多线程下的并发操作问题
    • 执行完setnx后,由于宕机、网络故障等原因导致expire执行失败
       

    更好的方式:使用redis命令的原子性

    #ex指定过期时间(s),px也是指定过期时间(ms),nx是key不存在时才执行set(即新建),xx表示key已存在时才执行set(即更新)
    set lock "xxxxxxx" ex 60 nx
    
    
    // jedis
    jedis.set("lock", "xxxxxx", SetParams.setParams().ex(120).nx());
    

    值一般设置为线程号

     

    spring data redis方式

    对应的方法如下

    // 设置key,absent,缺席、不存在,返回布尔值
    Boolean redisTemplate.opsForValue().setIfAbsent(key,value)     
    // 设置有效期,key、数值、单位
    redisTemplate.expire(key,2TimeUnit.MINUTES)
    
    // 更好的写法,原子性
    Boolean redisTemplate.opsForValue().setIfAbsent(key,value,2TimeUnit.MINUTES)    
    
    // 删除key
    redisTemplate.delete(key)
    

     

    redisson

    基础方式

    依赖

    <dependency>
        <groupId>org.redisson</groupId>
        <artifactId>redisson</artifactId>
        <version>3.16.1</version>
    </dependency>
    

     

    获取RedissonClient

    /**
     * 获取本地单机版redis的 RedissonClient
     */
    public static RedissonClient getRedissonClientForLocalServer() {
        //不指定config,默认为 127.0.0.1:6379
        return Redisson.create();
    }
    
    /**
     * 获取单机版redis的 RedissonClient
     */
    public static RedissonClient getRedissonClientForSingleServer() {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");
        return Redisson.create(config);
    }
    
    /**
     * 获取redis集群的 RedissonClient
     */
    public static RedissonClient getRedissonClient() {
        Config config = new Config();
        config.useReplicatedServers().addNodeAddress("redis://127.0.0.1:6377", "redis://127.0.0.1:6378", "redis://127.0.0.1:6379");
        return Redisson.create(config);
    }
    
    • config都可以使用set指定密码、使用的库,默认不需要密码、使用db0
    • redis://127.0.0.1:6379,地址可以以redis开头,也可以rediss开头,第二个s表示使用ssl安全通信,服务器通常都部署在内网中,使用redis即可。

    配置项可参考:https://github.com/redisson/redisson/wiki/2.-%E9%85%8D%E7%BD%AE%E6%96%B9%E6%B3%95

     

    redisson-spring-boot-starter方式

    依赖

    <dependency>
        <groupId>org.redisson</groupId>
        <artifactId>redisson-spring-boot-starter</artifactId>
        <version>3.16.1</version>
    </dependency>
    

    这个依赖中已经包含了redisson的基础依赖、spring data redis的依赖,所以基础方式、spring data redis也是可以直接用的。
     

    yml

    spring:
      redis:
        #单机版redis配置,默认localhost、6379、0
        host: 182.61.45.66
        port: 6379
        database: 0
        #连接到redis服务器的超时时间,ms
        timeout: 3000
    
        #如果是redis集群,则使用以下配置
        #    cluster:
        #      nodes: 192.168.1.1:6379,192.168.1.2:6379,192.168.1.3:6379
    
        #jedis连接池配置
        jedis:
          pool:
            #默认8,-1表示不限制
            max-active: 200
            #默认0
            min-idle: 50
            #默认8
            max-idle: 100
            #如果jedis连接池没有闲置连接可用,最多等待多少ms
            max-wait: 3000
    

    使用spring data redis的配置即可。

    可以直接注入使用 RedisTemplate、RedissonClient 这2个bean。

    更多配置可参考:https://github.com/redisson/redisson/blob/master/redisson-spring-boot-starter/README.md

     

    实现分布式锁

    //参数指定key的名称,这个key会作为锁,在释放锁时会被删除,所以不要指定为有其它作用的key,应该用专门的key作为锁
    RLock rLock = redissonClient.getLock("xxx");
    //尝试获取锁,对应的key创建成功意味着获取到锁,会一直阻塞在这里直到获取到锁
    rLock.lock();
    try {
        //使用共享资源
    } finally {
        //释放锁,释放时会自动删除作为锁的key
        rLock.unlock();
    }
    

     

    可以指定锁的类型

    //可重入锁(Reentrant Lock)
    RLock reentrantLock = redissonClient.getLock("xxx");
    
    //公平锁
    RLock fairLock = redissonClient.getFairLock("xxx");
    
    //读写锁
    RReadWriteLock rwLock = redissonClient.getReadWriteLock("xxx");
    //获取读锁
    rwlock.readLock().lock();
    //获取写锁
    rwlock.writeLock().lock();
    

     

    获取锁的几种方法

    //获取不到锁时会一直阻塞线程;获取到锁后如果出现问题不会释放锁,可能导致死锁
    rLock.lock();
    
    //2个参数指定释放锁的超时时间,如果获取到锁后在指定时间内未释放锁,会自动释放
    rLock.lock(3, TimeUnit.MINUTES);
    
    //第1个参数指定获取锁的超时时间,第2个参数指定释放锁的超时时间,返回值表示是否获取到锁
    //如果在指定的时间内未获取到锁,直接返回false,不再阻塞线程
    boolean result = rLock.tryLock(5, 3, TimeUnit.MINUTES);
    

    一般使用后2种,不使用无参的lock()。

     

    redisson实现分布式锁的原理

    加锁:尝试获取锁,创建key成功说明获取到锁;如果key已存在获取锁失败,则订阅锁释放的消息,并阻塞线程,接收到锁释放的通知后再次尝试获取锁。key是hash类型。

    释放锁:使用完共享资源后删除key,删除key即释放锁。

     

    redisson实现分布式锁存在的问题

    在redis集群模式下,如果创建key成功、获取到锁,但在尚未同步到任何一个slave时master宕机,选举一个slave作为master,此时新master上不存在对应的key,其它线程依然可以创建key成功、获取到锁,可能存在多个线程获取到同一把锁的情况。

     

    redisson的更多分布式操作可参考

    https://github.com/redisson/redisson/wiki/8.-%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81%E5%92%8C%E5%90%8C%E6%AD%A5%E5%99%A8

    https://blog.csdn.net/qq_25582465/article/details/109309624

    展开全文
  • java调用redis的八种方式

    千次阅读 2017-11-13 10:58:52
    Redis是一个著名的key-value存储系统,而作为其官方推荐的Java版客户端jedis也非常强大和稳定,支持事务、管道及有jedis自身实现的分布式。在这里对jedis关于事务、管道和分布式的调用方式做一个简单的介绍和对比:...

    Redis是一个著名的key-value存储系统,而作为其官方推荐的Java版客户端jedis也非常强大和稳定,支持事务、管道及有jedis自身实现的分布式。

    在这里对jedis关于事务、管道和分布式的调用方式做一个简单的介绍和对比:

    一、普通同步方式

    最简单和基础的调用方式,

    @Test
    public void test1Normal() {
        Jedis jedis = new Jedis("localhost");
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            String result = jedis.set("n" + i, "n" + i);
        }
        long end = System.currentTimeMillis();
        System.out.println("Simple SET: " + ((end - start)/1000.0) + " seconds");
        jedis.disconnect();
    }

    很简单吧,每次set之后都可以返回结果,标记是否成功。

    二、事务方式(Transactions)

    redis的事务很简单,他主要目的是保障,一个client发起的事务中的命令可以连续的执行,而中间不会插入其他client的命令。

    看下面例子:

    @Test
    public void test2Trans() {
        Jedis jedis = new Jedis("localhost");
        long start = System.currentTimeMillis();
        Transaction tx = jedis.multi();
        for (int i = 0; i < 100000; i++) {
            tx.set("t" + i, "t" + i);
        }
        List<Object> results = tx.exec();
        long end = System.currentTimeMillis();
        System.out.println("Transaction SET: " + ((end - start)/1000.0) + " seconds");
        jedis.disconnect();
    }

    我们调用jedis.watch(…)方法来监控key,如果调用后key值发生变化,则整个事务会执行失败。另外,事务中某个操作失败,并不会回滚其他操作。这一点需要注意。还有,我们可以使用discard()方法来取消事务。

    三、管道(Pipelining)

    有时,我们需要采用异步方式,一次发送多个指令,不同步等待其返回结果。这样可以取得非常好的执行效率。这就是管道,调用方法如下:

    @Test
    public void test3Pipelined() {
        Jedis jedis = new Jedis("localhost");
        Pipeline pipeline = jedis.pipelined();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            pipeline.set("p" + i, "p" + i);
        }
        List<Object> results = pipeline.syncAndReturnAll();
        long end = System.currentTimeMillis();
        System.out.println("Pipelined SET: " + ((end - start)/1000.0) + " seconds");
        jedis.disconnect();
    }

    四、管道中调用事务

    就Jedis提供的方法而言,是可以做到在管道中使用事务,其代码如下:

    @Test
    public void test4combPipelineTrans() {
        jedis = new Jedis("localhost"); 
        long start = System.currentTimeMillis();
        Pipeline pipeline = jedis.pipelined();
        pipeline.multi();
        for (int i = 0; i < 100000; i++) {
            pipeline.set("" + i, "" + i);
        }
        pipeline.exec();
        List<Object> results = pipeline.syncAndReturnAll();
        long end = System.currentTimeMillis();
        System.out.println("Pipelined transaction: " + ((end - start)/1000.0) + " seconds");
        jedis.disconnect();
    }

    但是经测试(见本文后续部分),发现其效率和单独使用事务差不多,甚至还略微差点。

    五、分布式直连同步调用

    @Test
    public void test5shardNormal() {
        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();
    }

    这个是分布式直接连接,并且是同步调用,每步执行都返回执行结果。类似地,还有异步管道调用。

    六、分布式直连异步调用

    @Test
    public void test6shardpipelined() {
        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();
    }

    七、分布式连接池同步调用

    如果,你的分布式调用代码是运行在线程中,那么上面两个直连调用方式就不合适了,因为直连方式是非线程安全的,这个时候,你就必须选择连接池调用。

    @Test
    public void test7shardSimplePool() {
        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();
    }

    上面是同步方式,当然还有异步方式。

    八、分布式连接池异步调用

    @Test
    public void test8shardPipelinedPool() {
        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();
    }

    九、需要注意的地方

    事务和管道都是异步模式。在事务和管道中不能同步查询结果。比如下面两个调用,都是不允许的:

     Transaction tx = jedis.multi();
     for (int i = 0; i < 100000; i++) {
         tx.set("t" + i, "t" + i);
     }
     System.out.println(tx.get("t1000").get());  //不允许
    
     List<Object> results = tx.exec();
    
     …
     …
    
     Pipeline pipeline = jedis.pipelined();
     long start = System.currentTimeMillis();
     for (int i = 0; i < 100000; i++) {
         pipeline.set("p" + i, "p" + i);
     }
     System.out.println(pipeline.get("p1000").get()); //不允许
    
     List<Object> results = pipeline.syncAndReturnAll();

    事务和管道都是异步的,个人感觉,在管道中再进行事务调用,没有必要,不如直接进行事务模式。

    分布式中,连接池的性能比直连的性能略好(见后续测试部分)。

    分布式调用中不支持事务。

    因为事务是在服务器端实现,而在分布式中,每批次的调用对象都可能访问不同的机器,所以,没法进行事务。

    十、测试

    运行上面的代码,进行测试,其结果如下:

    Simple SET: 5.227 seconds
    
    Transaction SET: 0.5 seconds
    Pipelined SET: 0.353 seconds
    Pipelined transaction: 0.509 seconds
    
    Simple@Sharing SET: 5.289 seconds
    Pipelined@Sharing SET: 0.348 seconds
    
    Simple@Pool SET: 5.039 seconds
    Pipelined@Pool SET: 0.401 seconds

    另外,经测试分布式中用到的机器越多,调用会越慢。上面是2片,下面是5片:

    Simple@Sharing SET: 5.494 seconds
    Pipelined@Sharing SET: 0.51 seconds
    Simple@Pool SET: 5.223 seconds
    Pipelined@Pool SET: 0.518 seconds

    下面是10片:

    Simple@Sharing SET: 5.9 seconds
    Pipelined@Sharing SET: 0.794 seconds
    Simple@Pool SET: 5.624 seconds
    Pipelined@Pool SET: 0.762 seconds

    下面是100片:

    Simple@Sharing SET: 14.055 seconds
    Pipelined@Sharing SET: 8.185 seconds
    Simple@Pool SET: 13.29 seconds
    Pipelined@Pool SET: 7.767 seconds

    分布式中,连接池方式调用不但线程安全外,根据上面的测试数据,也可以看出连接池比直连的效率更好。

    十一、完整的测试代码

    package com.example.nosqlclient;
    
    import java.util.Arrays;
    import java.util.List;
    
    import org.junit.AfterClass;
    import org.junit.BeforeClass;
    import org.junit.Test;
    
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPoolConfig;
    import redis.clients.jedis.JedisShardInfo;
    import redis.clients.jedis.Pipeline;
    import redis.clients.jedis.ShardedJedis;
    import redis.clients.jedis.ShardedJedisPipeline;
    import redis.clients.jedis.ShardedJedisPool;
    import redis.clients.jedis.Transaction;
    
    import org.junit.FixMethodOrder;
    import org.junit.runners.MethodSorters;
    
    @FixMethodOrder(MethodSorters.NAME_ASCENDING)
    public class TestJedis {
    
        private static Jedis jedis;
        private static ShardedJedis sharding;
        private static ShardedJedisPool pool;
    
        @BeforeClass
        public static void setUpBeforeClass() throws Exception {
            List<JedisShardInfo> shards = Arrays.asList(
                    new JedisShardInfo("localhost",6379),
                    new JedisShardInfo("localhost",6379)); //使用相同的ip:port,仅作测试
    
    
            jedis = new Jedis("localhost"); 
            sharding = new ShardedJedis(shards);
    
            pool = new ShardedJedisPool(new JedisPoolConfig(), shards);
        }
    
        @AfterClass
        public static void tearDownAfterClass() throws Exception {
            jedis.disconnect();
            sharding.disconnect();
            pool.destroy();
        }
    
        @Test
        public void test1Normal() {
            long start = System.currentTimeMillis();
            for (int i = 0; i < 100000; i++) {
                String result = jedis.set("n" + i, "n" + i);
            }
            long end = System.currentTimeMillis();
            System.out.println("Simple SET: " + ((end - start)/1000.0) + " seconds");
        }
    
        @Test
        public void test2Trans() {
            long start = System.currentTimeMillis();
            Transaction tx = jedis.multi();
            for (int i = 0; i < 100000; i++) {
                tx.set("t" + i, "t" + i);
            }
            //System.out.println(tx.get("t1000").get());
    
            List<Object> results = tx.exec();
            long end = System.currentTimeMillis();
            System.out.println("Transaction SET: " + ((end - start)/1000.0) + " seconds");
        }
    
        @Test
        public void test3Pipelined() {
            Pipeline pipeline = jedis.pipelined();
            long start = System.currentTimeMillis();
            for (int i = 0; i < 100000; i++) {
                pipeline.set("p" + i, "p" + i);
            }
            //System.out.println(pipeline.get("p1000").get());
            List<Object> results = pipeline.syncAndReturnAll();
            long end = System.currentTimeMillis();
            System.out.println("Pipelined SET: " + ((end - start)/1000.0) + " seconds");
        }
    
        @Test
        public void test4combPipelineTrans() {
            long start = System.currentTimeMillis();
            Pipeline pipeline = jedis.pipelined();
            pipeline.multi();
            for (int i = 0; i < 100000; i++) {
                pipeline.set("" + i, "" + i);
            }
            pipeline.exec();
            List<Object> results = pipeline.syncAndReturnAll();
            long end = System.currentTimeMillis();
            System.out.println("Pipelined transaction: " + ((end - start)/1000.0) + " seconds");
        }
    
        @Test
        public void test5shardNormal() {
            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");
        }
    
        @Test
        public void test6shardpipelined() {
            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");
        }
    
        @Test
        public void test7shardSimplePool() {
            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");
        }
    
        @Test
        public void test8shardPipelinedPool() {
            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");
        }
    }
    展开全文
  • jedis常用api(java操作redis

    千次阅读 2019-03-08 00:15:40
    jedis常用api(java操作redis) https://www.cnblogs.com/holdouts/articles/5808361.html 使用Java操作Redis需要jedis-2.1.0.jar,下载地址:http://files.cnblogs.com/liuling/jedis-2.1.0.jar.zip 如果需要...
  • jedis操作redis几种方式

    千次阅读 2016-12-06 10:03:38
    redis是一个著名的key-value存储系统,也是nosql中的最常见的一。其实,个人认为,redis最强大的地方不在于其存储,而在于其强大的缓存作用。 我们可以把它想象成一个巨大的(多借点集群,聚合多借点的内存)的Map...
  • redis 存储自定义java对象有几种方式

    千次阅读 2016-04-22 01:23:45
    最近去面试,碰到面试官提问,如果要把一个自定义的java对象存储到redis中,除了一般使用json和序列化之外,还有一,可以配置redis的配置文件,操作hash类型,直接使用HGETALL (或者其他操作hash的命令),取出来...
  • java操作Jedis和虚拟机操作redis

    千次阅读 2018-12-12 11:05:26
    Java操作redis (企业里面用的多) string(字符串 存储对象集合 Json串) hash(哈希 存储单个对象) list(列表 存储String集合) (企业里面用的少) set(集合) zset(sorted set:有序集合) zadd/zrevrange ...
  • Redis几种序列化方式分析

    千次阅读 2019-12-15 20:29:19
    一般redis的序列化方式主要有:字符串序列化、json序列化、xml序列化、jdk序列化,具体可查阅org.springframework.data.redis.serializer.RedisSerializer 的实现类,其中对于json序列化,官方实现的是jackson的序列...
  • Java客户端访问redis方式: jedis springboot集成的StringRedisTemplate与RedisTemplate (StringRedisTemplate继承了RedisTemplate,两者方法一模一样,不同之处是RedisTemplate使用的是...
  • redis:非关系型数据库,...首先是单个redisjava中的使用。 //redis连接池配置对象 JedisPoolConfig config = new JedisPoolConfig(); //在指定时刻通过pool能够获取到的最大的连接的jedis个数,默认8 config...
  • Java中使用Redis的两种方式

    千次阅读 2018-03-08 18:48:49
    Java中使用Redis的2种方式: 1.使用标准Jedis来操作Redis实例 2.使用spring-data-redis操作Redis实例Redis的分布式和集群 1.Redis使用 ShardedJedisPool 来实现客户端分片的分布式(多主零备) 2.Redis集群分为 ...
  • Java使用Jedis操作Redis的5数据类型

    千次阅读 2020-06-19 19:08:28
    Jedis集成了Redis的相关命令操作,它是Java语言操作Redis数据库的桥梁。Jedis客户端封装了Redis数据库的大量命令,因此具有许多Redis操作API。可以阅读 《Jedis API 文档》。 1.1Jedis的获取 在使用Jedis之前,...
  • 主要介绍redis数据类型在Java中的详细使用 , 注释特别详细, 里面有我邮箱, 不懂的地方随时问我. 非常值得学习. 更多redis资料, 请与我邮箱联系!
  • java代码操作Redis数据库

    千次阅读 2017-07-26 19:41:14
    先学习用命令操作Redis数据,再来写java代码操作,先用命令的方式做下,然后使用该Redis 提供api方式操作一下会更能容易理解。 学习地址: 【1】http://www.yiibai.com/redis/redis_quick_guide.html 【2】...
  • DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients. In this mode connections are...
  • Java连接Redis

    2016-02-25 23:51:16
    首先电脑上需要有Java开发环境和安装Redis服务,其次下载Java Redis驱动,地址为http://mvnrepository.com/artifact/redis.clients/jedis  在工程中添加下载的redis驱动包,然后开始写程序,代码如下: package ...
  • jedis、redisson、lettuce ... Redisson实现了分布式和可扩展的Java数据结构,提供很多分布式相关操作服务,例如,分布式锁,分布式集合,可通过Redis支持延迟队列。和Jedis相比,功能较为简单,.
  • Redis几种集群模式

    万次阅读 2018-11-28 14:22:16
    现在越来越多的项目都会利用到redis,多实例redis服务比单实例要复杂的多...我们常用sharding技术来对此进行管理,其集群模式主要有以下几种方式: 主从复制 哨兵模式 Redis官方 Cluster集群模式(服务端sharding)...
  • package com.jjf.redis; import org.junit.Assert; import org.junit.Test; import redis.clients.jedis.BinaryClient; import redis.clients.jedis.Jedis;...import java.util.List; /** * Created by jjf_lenovo
  • Java中使用Redis几种数据类型总结

    千次阅读 2018-05-16 17:35:01
    Java中使用Redis有五基本数据类型String、hash、list、Set、zset。1.String,最基本的类型方法 set、get2.hashredis 127.0.0.1:6379&gt; HMSET user:1 username redis.net....

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 102,795
精华内容 41,118
关键字:

java操作redis的几种方式

java 订阅
redis 订阅