reids事务

概念

可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞

作用

一个队列中,一次性、顺序性、排他性的执行一系列命令

常用命令

正常操作事务:

放弃事务:

其实redis对于事务是部分支持:

例如incr k1虽然是错误的(类似于java的运行时异常),但是其他几个结果依然可以成功操作。

watch监控

悲观锁/乐观锁/CAS(Check And Set)

1、悲观锁

悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁

2、乐观锁

乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。

乐观锁策略:提交版本必须大于记录当前版本才能执行更新

3、CAS

CAS机制当中使用了3个基本操作数:内存地址V,旧的预期值A,要修改的新值B。

更新一个变量的时候,只有当变量的预期值A和内存地址V当中的实际值相同时,才会将内存地址V对应的值修改为B。

4、watch小结

a、Watch指令,类似乐观锁,事务提交时,如果Key的值已被别的客户端改变,比如某个list已被别的客户端push/pop过了,整个事务队列都不会被执行

b、通过WATCH命令在事务执行之前监控了多个Keys,倘若在WATCH之后有任何Key的值发生了变化,EXEC命令执行的事务都将被放弃,同时返回Nullmulti-bulk应答以通知调用者事务执行失败

3阶段

开启:以MULTI开始一个事务

入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面

执行:由EXEC命令触发事务

3特性

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

没有隔离级别的概念:队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行,也就不存在”事务内的查询要看到事务里的更新,在事务外查询不能看到”这个让人万分头痛的问题

不保证原子性:redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚

Redis的发布订阅

概念

进程间的一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。

命令

主从复制 -----Redis的复制(Master/Slave)

概念

行话:也就是我们所说的主从复制,主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主

1、一主二仆-----将军死了,士兵等待上级派新将军

2、薪火相传

上一个Slave可以是下一个slave的Master,Slave同样可以接收其他slaves的连接和同步请求,那么该slave作为了链条中下一个的master,可以有效减轻master的写压力。

中途变更转向:会清除之前的数据,重新建立拷贝最新的。

slaveof 新主库IP 新主库端口

3、反客为主

使当前数据库停止与其他数据库的同步,转成主数据库。-----将军死了,士兵替代他

SLAVEOF no one

作用

1、读写分离

2、容灾恢复

配置

1、配从(库)不配主(库)

2、从库配置:slaveof 主库IP 主库端口

每次与master断开之后,都需要重新连接,除非你配置进redis.conf文件。info replication可以查看当前redis服务信息,master or slave

代表master为192.168.101.3,端口为6379

复制原理

1、slave启动成功连接到master后会发送一个sync命令

2、Master接到命令启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,以完成一次完全同步

3、全量复制:而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。

4、增量复制:Master继续将新的所有收集到的修改命令依次传给slave,完成同步

5、但是只要是重新连接master,一次完全同步(全量复制)将被自动执行

哨兵模式

概念

反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库。一组sentinel能同时监控多个Master

配置

在redis目录下新建sentinel.conf文件,名字绝不能错

 sentinel monitor 被监控数据库名字(自己起名字) 127.0.0.1 6379 1

上面最后一个数字1,表示主机挂掉后salve投票看让谁接替成为主机,得票数多少后成为主机

启动

总结:将军死了,士兵进行投票,票数合格的当选将军;此时将军又活了,回来变成小弟了。

缺点

由于所有的写操作都是先在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。

jedis

所需jar包

commons-pool-1.6.jar、jedis-2.1.0.jar

测试连通性

public class Demo01 {
public static void main(String[] args) {
     //连接本地的 Redis 服务
     Jedis jedis = new Jedis("127.0.0.1",6379);
     //查看服务是否运行,打出pong表示OK
     System.out.println("connection is OK==========>: "+jedis.ping());
   }
}

常用api

package com.atguigu.redis.test;
import java.util.*;
import redis.clients.jedis.Jedis; public class Test02 {
public static void main(String[] args) {
Jedis jedis = new Jedis("127.0.0.1",6379);       //key
      Set<String> keys = jedis.keys("*");
      for(Iterator iterator = keys.iterator(); iterator.hasNext();) {
        String key = (String) iterator.next();
        System.out.println(key);
      }
      System.out.println("jedis.exists====>"+jedis.exists("k2"));
      System.out.println(jedis.ttl("k1"));       //String
      //jedis.append("k1","myreids");
      System.out.println(jedis.get("k1"));
      jedis.set("k4","k4_redis");
      System.out.println("----------------------------------------");
      jedis.mset("str1","v1","str2","v2","str3","v3");
      System.out.println(jedis.mget("str1","str2","str3"));
     
//list
      System.out.println("----------------------------------------");
      //jedis.lpush("mylist","v1","v2","v3","v4","v5");
      List<String> list = jedis.lrange("mylist",0,-1);
      for(String element : list) {
        System.out.println(element);
      }
     
//set
      jedis.sadd("orders","jd001");
      jedis.sadd("orders","jd002");
      jedis.sadd("orders","jd003");
      Set<String> set1 = jedis.smembers("orders");
      for(Iterator iterator = set1.iterator(); iterator.hasNext();) {
        String string = (String) iterator.next();
        System.out.println(string);
      }
      jedis.srem("orders","jd002");
      System.out.println(jedis.smembers("orders").size());
     
//hash
      jedis.hset("hash1","userName","lisi");
      System.out.println(jedis.hget("hash1","userName"));
      Map<String,String> map = new HashMap<String,String>();
      map.put("telphone","13811814763");
      map.put("address","atguigu");
      map.put("email","abc@163.com");
      jedis.hmset("hash2",map);
      List<String> result = jedis.hmget("hash2", "telphone","email");
      for(String element : result) {
        System.out.println(element);
      }
     
//zset
      jedis.zadd("zset01",60d,"v1");
      jedis.zadd("zset01",70d,"v2");
      jedis.zadd("zset01",80d,"v3");
      jedis.zadd("zset01",90d,"v4");
     
      Set<String> s1 = jedis.zrange("zset01",0,-1);
      for(Iterator iterator = s1.iterator(); iterator.hasNext();) {
        String string = (String) iterator.next();
        System.out.println(string);
      }     
   }
}

事务提交

主从复制

public static void main(String[] args) throws InterruptedException 
  {
     Jedis jedis_M = new Jedis("127.0.0.1",6379);
     Jedis jedis_S = new Jedis("127.0.0.1",6380);
     
     jedis_S.slaveof("127.0.0.1",6379);
     
     jedis_M.set("k6","v6");
     Thread.sleep(500);
     System.out.println(jedis_S.get("k6"));
  }

jedispool

package com.atguigu.redis.test;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig; public class JedisPoolUtil {
  
 private static volatile JedisPool jedisPool = null;//被volatile修饰的变量不会被本地线程缓存,对该变量的读写都是直接操作共享内存。
  
  private JedisPoolUtil() {}
  
  public static JedisPool getJedisPoolInstance()
 {
     if(null == jedisPool)
    {
       synchronized (JedisPoolUtil.class)
      {
          if(null == jedisPool)
         {
           JedisPoolConfig poolConfig = new JedisPoolConfig();
           poolConfig.setMaxActive(1000);
           poolConfig.setMaxIdle(32);
           poolConfig.setMaxWait(100*1000);
           poolConfig.setTestOnBorrow(true);
            
            jedisPool = new JedisPool(poolConfig,"127.0.0.1");
         }
      }
    }
     return jedisPool;
 }
  
  public static void release(JedisPool jedisPool,Jedis jedis)
 {
     if(null != jedis)
    {
      jedisPool.returnResourceObject(jedis);
    }
 }
}
 
package com.atguigu.redis.test;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool; public class Test01 {
  public static void main(String[] args) {
     JedisPool jedisPool = JedisPoolUtil.getJedisPoolInstance();
     Jedis jedis = null;
     
     try 
     {
       jedis = jedisPool.getResource();
       jedis.set("k18","v183");
       
     } catch (Exception e) {
       e.printStackTrace();
     }finally{
       JedisPoolUtil.release(jedisPool, jedis);
     }
  }
}
 

配置总结:

JedisPool的配置参数大部分是由JedisPoolConfig的对应项来赋值的。

maxActive:控制一个pool可分配多少个jedis实例,通过pool.getResource()来获取;如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted。
maxIdle:控制一个pool最多有多少个状态为idle(空闲)的jedis实例;
whenExhaustedAction:表示当pool中的jedis实例都被allocated完时,pool要采取的操作;默认有三种。
   WHEN_EXHAUSTED_FAIL --> 表示无jedis实例时,直接抛出NoSuchElementException;
   WHEN_EXHAUSTED_BLOCK --> 则表示阻塞住,或者达到maxWait时抛出JedisConnectionException;
   WHEN_EXHAUSTED_GROW --> 则表示新建一个jedis实例,也就说设置的maxActive无用;
maxWait:表示当borrow一个jedis实例时,最大的等待时间,如果超过等待时间,则直接抛JedisConnectionException;
testOnBorrow:获得一个jedis实例的时候是否检查连接可用性(ping());如果为true,则得到的jedis实例均是可用的;

testOnReturn:return 一个jedis实例给pool时,是否检查连接可用性(ping());

testWhileIdle:如果为true,表示有一个idle object evitor线程对idle object进行扫描,如果validate失败,此object会被从pool中drop掉;这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义;

timeBetweenEvictionRunsMillis:表示idle object evitor两次扫描之间要sleep的毫秒数;

numTestsPerEvictionRun:表示idle object evitor每次扫描的最多的对象数;

minEvictableIdleTimeMillis:表示一个对象至少停留在idle状态的最短时间,然后才能被idle object evitor扫描并驱逐;这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义;

softMinEvictableIdleTimeMillis:在minEvictableIdleTimeMillis基础上,加入了至少minIdle个对象已经在pool里面了。如果为-1,evicted不会根据idle time驱逐任何对象。如果minEvictableIdleTimeMillis>0,则此项设置无意义,且只有在timeBetweenEvictionRunsMillis大于0时才有意义;

lifo:borrowObject返回对象时,是采用DEFAULT_LIFO(last in first out,即类似cache的最频繁使用队列),如果为False,则表示FIFO队列;

==================================================================================================================
其中JedisPoolConfig对一些参数的默认设置如下:
testWhileIdle=true
minEvictableIdleTimeMills=60000
timeBetweenEvictionRunsMillis=30000
numTestsPerEvictionRun=-1

最新文章

  1. Bugtags 测试平台(支持ios、android)
  2. Win10 IoT C#开发 2 - 创建基于XAML的UI程序 及 应用的三种部署方法
  3. Windows系统小知识
  4. [SVN] SVN在Eclipse里的各个状态解释
  5. cxf 消息寻址
  6. LeetCode Combination Sum III
  7. 【转】Asp.net中时间格式化的6种方法详细总结
  8. 最近对python颇有兴趣
  9. Ruby require 路径问题
  10. 使用开源word操作组件DocX的记录
  11. Android源代码分析-资源载入机制
  12. Tomcat、JBOSS、WebSphere、WebLogic、Apache等技术概述
  13. fdisk 命令详解
  14. 下拉框、下拉控件之Select2。自动补全的使用
  15. Alienware R8外星人台式机安装双系统(WIN10+Ubuntu)的总结
  16. (链表 双指针) leetcode 19. Remove Nth Node From End of List
  17. java并发编程系列一、多线程
  18. Idea项目如何迁移到Eclipse
  19. 『TensotFlow』RNN/LSTM古诗生成
  20. Tilera--100核cpu

热门文章

  1. CSS3新属性之---flex box布局实例
  2. ## jvm知识点零碎整理
  3. spring boot thymeleaf简单示例
  4. iptables failed: iptables --wait -t nat -A DOCKER -p tcp -d 0/0 --dport 5000 -j DNAT --to-destination
  5. finalize的作用
  6. PHP算法之宝石与石头
  7. 如何使用webpack 打包图片
  8. 校园商铺-2Logback配置与使用-3验证配置
  9. 阿里云图数据库GraphDB上线,助力图数据处理
  10. BZOJ 1398: Vijos1382寻找主人 Necklace(最小表示法)