Redis—java客户端及事务

Redis—java客户端

​ Redis不仅使用命令客户端来操作,而且可以使用程序客户端操作。现在基本上主流的语言都有客户端支持,比如Java、C、C#、C++、php、Node.js、Go等。

​ 在官方网站里列一些Java的客户端,有Jedis、Redisson、Jredis、JDBC-Redis等,其中官方推荐使用Jedis和Redisson。在企业中用的最多的就是Jedis

​ 在这里对Jedis和Redisson进行对比介绍:

Jedis

  • 轻量,简洁,便于集成和改造
  • 支持连接池
  • 支持pipelining、事务、LUA Scripting、Redis Sentinel、Redis Cluster
  • 不支持读写分离,需要自己实现
  • 文档差(真的很差,几乎没有……)

Redisson

  • 基于Netty实现,采用非阻塞IO,性能高
  • 支持异步请求
  • 支持连接池
  • 支持pipelining、LUA Scripting、Redis Sentinel、Redis Cluster
  • 不支持事务,官方建议以LUA Scripting代替事务
  • 支持在Redis Cluster架构下使用pipelining
  • 支持读写分离,支持读负载均衡,在主从复制和Redis Cluster架构下都可以使用
  • 内建Tomcat Session Manager,为Tomcat 6/7/8提供了会话共享功能
  • 可以与Spring Session集成,实现基于Redis的会话共享
  • 文档较丰富,有中文文档

​ 对于Jedis和Redisson的选择,同样应遵循前述的原理,尽管Jedis比起Redisson有各种各样的不足,但也应该在需要使用Redisson的高级特性时再选用Redisson,避免造成不必要的程序复杂度提升。

linux 关闭防火墙

连接时需要关闭防火墙,否则会被拒绝连接redis

查看防火状态
systemctl status firewalld

service  iptables status
暂时关闭防火墙
systemctl stop firewalld

service  iptables stop
永久关闭防火墙
systemctl disable firewalld

chkconfig iptables off
重启防火墙
systemctl enable firewalld

service iptables restart 

使用教程

pom.xml
		<dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.2.0</version>
        </dependency>
直接连接
public class jedisTest {
    @Test
    public void testjedis1(){
        Jedis jedis = new Jedis("192.168.74.134",65500);
        String name = jedis.get("name");
        System.out.println(name);
        jedis.close();
    }
}

注意:如果出现下面错误:
在这里插入图片描述
这是由于lunix防火墙阻止连接,关闭防火墙就可以了,具体上面有。

连接池连接
public class jedisTest {
    @Test
    public void testJedisByPool(){
        GenericObjectPoolConfig config = new GenericObjectPoolConfig();
        config.setMaxTotal(10);//设置连接数量
        config.setMaxIdle(5);//设置最大闲置
        JedisPool pool = new JedisPool(config,"192.168.74.134",65500);
        Jedis jedis = pool.getResource();
        String name = jedis.get("name");
        System.out.println(name);
        jedis.close();
        pool.close();
    }
}

注意:如果出现下面错误:

在这里插入图片描述

根据官方就是缺少slf4j的jar包,在pom.xml加入下面下面依赖:

	 <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-simple</artifactId>
          <version>1.7.25</version>
          <scope>compile</scope>
      </dependency>
连接哨兵集群
  1. 将哨兵集群服务启动

  2. 连接

    public class jedisTest {
        //连接哨兵集群
        @Test
        public void testRedisSentine(){
            //哨兵的地址信息放在set里面
            Set<String> address = new HashSet<>();
            address.add("192.168.74.134:26379");
            address.add("192.168.74.134:26380");
            address.add("192.168.74.134:26381");
    
            //连接池配置,可以配置也可以使用默认 默认则不写
            GenericObjectPoolConfig config = new GenericObjectPoolConfig();
            //设置连接数量
            config.setMaxTotal(10);
            //设置最大闲置
            config.setMaxIdle(5);
            //连接哨兵
            //使用默认配置
            //JedisSentinelPool pool = new JedisSentinelPool("mymaster",address);
            //自定义配置连接池
            JedisSentinelPool pool = new JedisSentinelPool("mymaster",address,config);
    
            Jedis jedis = pool.getResource();
            //添加
            jedis.set("name","lb");
            //取值
            String name = jedis.get("name");
            System.out.println(name);
            jedis.close();
            pool.close();
        }
    }
    

连接集群

  1. 首先启动集群

  2. 连接集群

    public class jedisTest {
        //连接集群
        @Test
        public void testRedisCluster(){
            //节点信息 操作时客户端不区分主从节点,所以只配主节点,这样可以避免数据写到从节点里面成为临时数据
            Set<HostAndPort> hostInfo = new HashSet<>();
            hostInfo.add(new HostAndPort("192.168.74.134",7001));
            hostInfo.add(new HostAndPort("192.168.74.134",7002));
            hostInfo.add(new HostAndPort("192.168.74.134",7003));
            //连接池配置信息
            GenericObjectPoolConfig config = new GenericObjectPoolConfig();
            //设置连接数量
            config.setMaxTotal(10);
            //设置最大闲置
            config.setMaxIdle(5);
            //连接集群
            //不使用连接池
            //JedisCluster cluster = new JedisCluster(hostInfo);
    
            //使用连接池
            JedisCluster cluster = new JedisCluster(hostInfo, config);
            //存值
            cluster.set("first","你好,集群");
            //取值
            String first = cluster.get("first");
            System.out.println(first);
            cluster.close();
        }
    }
    

Redis事务

概念

​ redis是单线程的,所以在redis中所有命令都是原子操作。而当要多条redis命令同时执行而不被打断时,则需要使用redis的事务了。

​ Redis 事务的本质是一组命令的集合。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。

总结说:redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。

特性

Redis 事务带有以下两个重要的保证:

  • 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
  • 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。

过程

一个事务从开始到执行会经历以下三个阶段:

  • 开始事务。
  • 命令入队。
  • 执行事务。

Redis事务指令

redis中的事务是用以下4个命令来实现的:

  • MULTI
  • EXEC
  • DISCARD
  • WATCH

1.MULTI

HLTI指令用于开启事,返回 ok 表示打开了一个事务命令队列,客户端在此之后发送的命令不会立即被执行,而是储存到一个从列中,且总是返回QUEUED

2.EXEC

EXEC指令用于执行自MULTI后的所有指令,该方法返回一个数组,元素为事务指令的返回值,其顺序与执行指令的顺序相同;

3.DISCARD

DISCARD可以清空事务队列,井放弃执行事务:

4.WATCH

在事务中watch用于监视某个key,当key被修改时该事务将整体取消,对应的unwatch用于取消对某个key的监视。

异常行为

  • 若事务提交前入队的指令包含错误的语法则大多数客户端会停止并取消事务

  • 若事务执行时(exec)某条指令执行失败,如操作类型不匹配时,该条指令失败然而其他后续的指令依然会被执

不支持回滚

如果你有使用关系式数据库的经验,那么"Redis在事务失败时不进行回滚。而是继续执行余下的命令”这种做法可能会让你觉得有点奇怪。

以下是这种做法的优点:

  • Redis 命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上面,这也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。
  • 因为不需要对回滚进行支持,所以Redis的内部可以保持简单且快速。

在通常情况下,回滚并不能解决编程错误带来的问题。

java客户端使用事务案例

public class jedisTest {
    //事务
    @Test
    public void testRedisTransaction(){
        //连接redis
        Jedis jedis = new Jedis("192.168.74.134", 65500);
        //开启事务
        Transaction multi = jedis.multi();
        try{
            multi.set("a","A1");
            multi.set("b","B1");
            //模拟异常
            //int i = 1 / 0;
            multi.set("c","C1");
            //提交事务
            multi.exec();
        }catch (Exception e){
            //取消事务
            multi.discard();
        }
    }
}

spring+Jedis

整合的方式有很多.例如Spring提供的RedisTemplate,Spring缓存注解等,迷有自定义AOR,逑里介绍最简单的一种方式即直接将使用到的Bean配置到容器中;

添加依赖

		<dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.2.0</version>
        </dependency>
        <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-simple</artifactId>
          <version>1.7.25</version>
          <scope>compile</scope>
      </dependency>

配置xml

连接单机Redis
 	<!--  连接单机版redis  销毁时自动关闭 多例-->
    <bean class="redis.clients.jedis.Jedis" destroy-method="close" scope="prototype">
        <constructor-arg name="host" value="192.168.74.134"/>
        <constructor-arg name="port" value="65500"/>
    </bean>

测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:redis-config.xml")
public class testRedis {
    @Autowired
    private Jedis jedis;
    @Test
    public void test1(){
        //存值
        jedis.set("name","lbb");
        //取值
        String name = jedis.get("name");
        
        System.out.println(name);
    }
}
连接哨兵
<!--  连接池配置对象  -->
    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxTotal" value="10"/>
        <property name="maxIdle" value="5"/>
    </bean>
    <!--  连接哨兵 获取连接池 -->
    <bean id="sentinelPool" class="redis.clients.jedis.JedisSentinelPool">
        <constructor-arg name="masterName" value="mymaster"/>
        <constructor-arg name="sentinels">
            <set>
                <value>192.168.74.134:26379</value>
                <value>192.168.74.134:26380</value>
                <value>192.168.74.134:26381</value>
            </set>
        </constructor-arg>
        <constructor-arg name="poolConfig" ref="poolConfig"/>
    </bean>
    <!--  通过bean工厂来 获取jedis对象 多例 销毁时关闭连接 -->
    <bean factory-bean="sentinelPool" factory-method="getResource" destroy-method="close" scope="prototype"/>

测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:redis-config.xml")
public class testRedis {
    @Autowired
    private Jedis jedis;
    @Test
    public void test2(){
        jedis.set("name", "lbb");
        String name = jedis.get("name");
        System.out.println(name);
    }
}
连接集群
	<!--  连接池配置对象  -->
    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxTotal" value="10"/>
        <property name="maxIdle" value="5"/>
    </bean>
     <!--  连接集群  -->
    <bean class="redis.clients.jedis.JedisCluster" destroy-method="close" scope="prototype">
        <constructor-arg name="poolConfig" ref="poolConfig"/>
        <constructor-arg name="nodes">
            <set>
                <bean class="redis.clients.jedis.HostAndPort" c:host="192.168.74.134" c:port="7001"/>
                <bean class="redis.clients.jedis.HostAndPort" c:host="192.168.74.134" c:port="7002"/>
                <bean class="redis.clients.jedis.HostAndPort" c:host="192.168.74.134" c:port="7003"/>
            </set>
        </constructor-arg>
    </bean>

测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:redis-config.xml")
public class testRedis {
    @Autowired
    private JedisCluster cluster;
    @Test
    public void test1(){
        cluster.set("test","集群测试");
        String test = cluster.get("test");
        System.out.println(test);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值