Redis多数据库、事务、加锁

论坛 期权论坛 脚本     
匿名技术用户   2021-1-2 02:29   11   0

一.多数据库

一个redis实例可以包含多个数据库,客户端可以指定连接redis实例的哪个数据库。就好比我们在mysql中可以创建多个数据库一样,客户端可以指定连接哪个数据库。一个redis实例最多可以提供16个数据库,下标分别是从0-15,客户端默认连接第0号数据库。客户端可以通过select命令来选择连接哪个数据库:

select 1
#选择连接1号数据库

客户端可以通过move命令来将一个数据库中的key移动到另一个数据库中

select 0
move myset 1
#将0号数据库中的myset移动到1号数据库中

二.redis事务

在redis中可以使用multi exec discard 这三个命令来实现事务。在事务中,所有命令会被串行化顺序执行,事务执行期间redis不会为其他客户端提供任何服务,从而保证事务中的命令都被原子化执行

  • multi 开启事务,这后边执行的命令都会被存到命令的队列当中
  • exec 相当于关系型数据库事务中的commit,提交事务
  • discard 相当于关系型数据库事务中的rollback,回滚操作

示例:

155601_gmbM_3381212.png

160449_0Bgq_3381212.png

三.加锁

这里用一个信用卡刷卡的例子来讲redis加锁的问题:

假设balance为可用余额,debt为欠款,amtToSubtract为实刷额度,刷卡操作涉及到balance(可用余额)的减少和debt的增加,因此这里用事务进行管理,

package jedis;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

public class TestTransaction {
  
   public boolean transMethod() throws InterruptedException {
      Jedis jedis = new Jedis("10.2.1.121", 6379);
      jedis.auth("123456");
      int balance;// 可用余额
      int debt;// 欠额
      int amtToSubtract = 10;// 实刷额度
  
      jedis.watch("balance");//标记balabce余额
      
      balance = Integer.parseInt(jedis.get("balance"));
      if (balance < amtToSubtract) {
        jedis.unwatch();
        System.out.println("modify");
        return false;
      } else {
        System.out.println("***********transaction");
        Transaction transaction = jedis.multi();//开启事务

        System.out.println("线程进入休眠......");
        Thread.sleep(7000);
               //jedis.set("balance","5");//此处不该出现,这是模拟多线程下其他程序已经修改了该条目,
                                          //测试时我是在线程休眠时,手动在redis客户端中更改了balance的值

        transaction.decrBy("balance", amtToSubtract);
        transaction.incrBy("debt", amtToSubtract);
        transaction.exec();//提交事务
        balance = Integer.parseInt(jedis.get("balance"));
        debt = Integer.parseInt(jedis.get("debt"));
  
        System.out.println("*******" + balance);
        System.out.println("*******" + debt);
        return true;
      }
   }
  
   
   public static void main(String[] args) throws InterruptedException {
      TestTransaction test = new TestTransaction();
      boolean retValue = test.transMethod();
      System.out.println("main retValue-------: " + retValue);
   }
 }
  

通俗点讲,watch命令就是标记一个键,如果标记了一个键, 在提交事务前如果该键被别人修改过,那事务就会失败,这种情况通常可以在程序中重新再尝试一次。
在本例中,就首先标记了键balance,然后检查余额是否足够,不足就取消标记,并不做扣减; 足够的话,就启动事务进行更新操作,如果在此期间键balance被其它人修改, 那在提交事务(执行exec)时就会报错, 程序中通常可以捕获这类错误再重新执行一次,直到成功。

转载于:https://my.oschina.net/u/3381212/blog/1570544

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP