Redis系列学习(三)之java api接入及事务

Redis系列学习(三)之java api接入及事务

一、 引言

想把redis数据库接入java,首先官方推荐的jedis框架,里面包含了redis的基本操作以及命令行操作。极大的方便了我们的工作。
git地址

maven的pom.xml引用:

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

二、 先上个简单例子

例子里包括了上篇文章学习到的所以的命令行操作对应的APi方法,由于我们已经学习了命令行操作redis数据库的方法,这里时候再研究API,我们相信就没那么难了。

例子

package com.sea;

import java.util.HashMap;
import java.util.Map;

import redis.clients.jedis.BinaryClient;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class RedisClient {
    // 客户端连接
    private Jedis jedis;

    // 客户端连接池
    private JedisPool jedisPool;

    public RedisClient() {
        initialPool();
        jedis = jedisPool.getResource();
    }

    /**
     * 初始化
     */
    private void initialPool() {
        // 池基本配置
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(20);
        config.setMaxIdle(5);
        config.setMaxWaitMillis(1000l);
        config.setTestOnBorrow(false);
        jedisPool = new JedisPool(config, "127.0.0.1", 6379);
    }

    public void show() {
        testOperate();
        //释放资源
        jedisPool.close();
    }

    private void testOperate() {
        System.out.println("======================通用命令操作==========================");
        jedis.keys("*");//查找所以的key
        jedis.keys("test*");//查找以test开头的key
        jedis.del("tt");//删除
        jedis.exists("tt");//查询key是否存在
        jedis.expire("name", 60);//设置过期时间,单位秒
        jedis.ttl("name");//查看key离超时还剩的时间
        jedis.type("name");//查看key的数据类型
        jedis.flushDB();// 清空数据
        jedis.auth("123456");//设置连接密码

        System.out.println("======================String命令操作==========================");
        //增加
        jedis.set("name", "chenyuan");
        jedis.set("age", "100");
        System.out.println("测试字符串添加:" + jedis.get("name"));

        //修改
        jedis.set("name", "chenyuan");
        jedis.append("name", "33");//追加
        jedis.incr("age");//加1
        jedis.decr("age");//减1
        jedis.incrBy("age", 6);//加指定值
        jedis.decrBy("age", 6);//减指定值
        System.out.println("测试字符串修改:" + jedis.get("name"));

        //删除
        jedis.del("name");//单条删除
        jedis.del("name","age");//多条删除
        System.out.println("测试字符串删除:" + jedis.get("name"));



        System.out.println("======================hash命令操作==========================");
        //增加
        jedis.hset("testHash", "counrty", "china");//向testHash表里添加一条记录
        Map<String,String> data = new HashMap<String, String>();
        data.put("sex", "man");
        data.put("add", "nibo");
        jedis.hmset("testHash", data);//向testHash表里添加多条记录


        //修改
        jedis.hset("testHash", "counrty", "china1");//直接覆盖值
        jedis.hset("testHash", "age", "999");//直接覆盖值
        jedis.hincrBy("testHash", "age", 1);//增加指定值

        //查找
        jedis.hget("testHash", "counrty");//查找

        //扩展命令
        jedis.hexists("testHash", "counrty");//判断testHash表里是否存在key是counrty的元素
        jedis.hlen("testHash");//表长度
        jedis.hkeys("testHash");//获得所以keys
        jedis.hvals("testHash");//获得所以values


        //删除
        jedis.hdel("testHash", "counrty");//删除单条记录
        jedis.hdel("testHash", "counrty","age");//删除多条记录,没有就忽略


        System.out.println("======================list命令操作==========================");
        //增加
        jedis.lpushx("testList", "1,2,3,4,5,6,a,b,c,d,e,f");//向表插入数据,表不存在则忽略
        jedis.lpush("testList", "1,2,3,4,5,6,a,b,c,d,e,f");//向表插入数据,表不存在就创建
        jedis.linsert("testList", BinaryClient.LIST_POSITION.BEFORE, "e", "99");//在元素值是f的前面插入99
        jedis.linsert("testList", BinaryClient.LIST_POSITION.AFTER, "f", "100");//在元素值是f的后面插入100


        //删除
        jedis.rpop("testList");//弹出
        jedis.lrem("testList", 2, "d");//指令会删除count个值为value的元素; 如果count大于0则从头遍历;如果count小于0则从尾遍历;如果count等于0,删除链表中所有等于某个值的元素

        //修改
        jedis.lset("testList", 0, "aa");//修改指定索引号位置的值
        //查询
        jedis.lrange("testList", 0, 3);//查找某范围值
    }
}

单一Jedis实例不是线程安全的。为了避免这些问题,可以使用JedisPool,JedisPool是一个线程安全的网络连接池。可以用JedisPool创建一些可靠Jedis实例,可以从池中拿到Jedis的实例。

三、 事务

事务即一个连续的,不会被其它进程打断的状态,要么一起成功,要么一起失败。保证数据的一致和完整性。
redis的事务确保命令会有序的,连续的执行,中间不会被其它client的命令串插。
redis事务中的所有命令都会序列化、按顺序地执行,在事务执行的过程中,redis不会在为其他的数据库客户端提供任何的服务,从而保证事务中所有的命令都被原子化,而且事务中的命令要么全部被执行,要么全部都不执行。

开启事务:multi
提交事务:exec
回滚命令:discard(清除所有先前在一个事务中放入队列的命令,然后恢复正常的连接状态)
添加监视:watch(key),监视某个key的变化,如果在事务执行之前这个(或这些) key被其他命令所改动,那么会取消事务里全部命令。
取消监视:unwatch(key)

与java api对应的方法如下:

        //开户事务,返回事务对象 
        Transaction transaction = jedis.multi();

        //提交事务
        transaction.exec();

        //回滚
        transaction.discard();

        //监视key值的变化
        transaction.watch("name");

当输入MULTI命令后,服务器返回OK表示事务开始成功,然后依次输入需要在本次事务中执行的所有命令,每次输入一个命令服务器并不会马上执行,而是返回”QUEUED”,这表示命令已经被服务器接受并且暂时保存起来,最后输入EXEC命令后,本次事务中的所有命令才会被依次执行,可以看到最后服务器一次性返回了三个OK,这里返回的结果与发送的命令是按顺序一一对应的,这说明这次事务中的命令全都执行成功了。

总结:开户事务后,后面的命令会加入队列中直接调用exec提交事务才开始执行。redis保证事务2点重要性:1、事务里的命令要么全部执行,要么全部不执行。2、事务执行命令添加的按顺序执行,中间不会乱序,也不会穿插其它客户端命令。

事务的错误处理机制
1、语法错误。命令不存在或参数错误的话,这在执行exec命令之前就知道了,因为如果正确加入到命令队列里会返回“QUEUED”,否则Redis将返回一个错误,如果Redis 2.6.5之前的版本会忽略错误的命令,执行其他正确的命令,2.6.5之后的版本会忽略这个事务中的所有命令,都不执行。
2、运行错误。运行时发生的错误,即使错误发生(redis接收并执行,并没有把它当作错误来处理),后面的命令也会继续执行。

注意:redis的回滚并非关系型数据库里“回滚”的意思,redis追求更快速,更高效的算法,它主动忽略了回滚错误的处理,它要程序员自己确保命令执行不会出错

总结下来。意思就是,redis支持事务处理,语法错误的情况下会确保命令全部执行或全部不执行,而且按添加顺序执行。在运行错误的情况下,redis会忽略错误命令,继续执行下面的命令。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值