一個redis實例能夠包含多個數據庫,客戶端能夠指定鏈接redis實例的哪一個數據庫。就比如咱們在mysql中能夠建立多個數據庫同樣,客戶端能夠指定鏈接哪一個數據庫。一個redis實例最多能夠提供16個數據庫,下標分別是從0-15,客戶端默認鏈接第0號數據庫。客戶端能夠經過select命令來選擇鏈接哪一個數據庫:java
select 1 #選擇鏈接1號數據庫
客戶端能夠經過move命令來將一個數據庫中的key移動到另外一個數據庫中mysql
select 0 move myset 1 #將0號數據庫中的myset移動到1號數據庫中
在redis中可使用multi exec discard 這三個命令來實現事務。在事務中,全部命令會被串行化順序執行,事務執行期間redis不會爲其餘客戶端提供任何服務,從而保證事務中的命令都被原子化執行redis
示例:sql
這裏用一個信用卡刷卡的例子來說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)時就會報錯, 程序中一般能夠捕獲這類錯誤再從新執行一次,直到成功。測試