SpringDataRedis事務處理
來自: http://segmentfault.com/a/1190000004393573
序
本文主要講述如何在java里頭使用redis進行cas操作。其實呢,redis不像memcached那樣顯示地支持cas操作,不過它有事務的概念。
準備
redis的樂觀鎖支持
Redis通過使用WATCH, MULTI, and EXEC組成的事務來實現樂觀鎖( 注意沒有用DISCARD ),Redis事務沒有回滾操作。在SpringDataRedis當中通過RedisTemplate的SessionCallback中來支持( 否則事務不生效 )。discard的話不需要自己代碼處理,callback返回null,成的話,返回非null,依據這個來判斷事務是否成功( 沒有拋異常 )。
實例
@Test public void cas() throws InterruptedException, ExecutionException { String key = "test-cas-1"; ValueOperations<String, String> strOps = redisTemplate.opsForValue(); strOps.set(key, "hello"); ExecutorService pool = Executors.newCachedThreadPool(); List<Callable<Object>> tasks = new ArrayList<>(); for(int i=0;i<5;i++){ final int idx = i; tasks.add(new Callable() { @Override public Object call() throws Exception { return redisTemplate.execute(new SessionCallback() { @Override public Object execute(RedisOperations operations) throws DataAccessException { operations.watch(key); String origin = (String) operations.opsForValue().get(key); operations.multi(); operations.opsForValue().set(key, origin + idx); Object rs = operations.exec(); System.out.println("set:"+origin+idx+" rs:"+rs); return rs; } }); } }); } List<Future<Object>> futures = pool.invokeAll(tasks); for(Future<Object> f:futures){ System.out.println(f.get()); } pool.shutdown(); pool.awaitTermination(1000, TimeUnit.MILLISECONDS); }
輸出
set:hello2 rs:null set:hello3 rs:[] set:hello1 rs:null set:hello4 rs:null set:hello0 rs:null
查看該值
127.0.0.1:6379> get test-cas-1 "\"hello3\""
坑
SessionCallback
沒有在SessionCallback里頭執行watch、multi、exec,而是自己單獨寫
與數據庫事務的混淆
template.setEnableTransactionSupport(true);
這個應該是支持數據庫的事務成功才執行的意思。
/*** Gets a Redis connection. Is aware of and will return any existing corresponding connections bound to the current * thread, for example when using a transaction manager. Will create a new Connection otherwise, if * {@code allowCreate} is <tt>true</tt>. * * @param factory connection factory for creating the connection * @param allowCreate whether a new (unbound) connection should be created when no connection can be found for the * current thread * @param bind binds the connection to the thread, in case one was created * @param enableTransactionSupport * @return an active Redis connection */ public static RedisConnection doGetConnection(RedisConnectionFactory factory, boolean allowCreate, boolean bind, boolean enableTransactionSupport) { Assert.notNull(factory, "No RedisConnectionFactory specified"); RedisConnectionHolder connHolder = (RedisConnectionHolder) TransactionSynchronizationManager.getResource(factory); if (connHolder != null) { if (enableTransactionSupport) { potentiallyRegisterTransactionSynchronisation(connHolder, factory); } return connHolder.getConnection(); } if (!allowCreate) { throw new IllegalArgumentException("No connection found and allowCreate = false"); } if (log.isDebugEnabled()) { log.debug("Opening RedisConnection"); } RedisConnection conn = factory.getConnection(); if (bind) { RedisConnection connectionToBind = conn; if (enableTransactionSupport && isActualNonReadonlyTransactionActive()) { connectionToBind = createConnectionProxy(conn, factory); } connHolder = new RedisConnectionHolder(connectionToBind); TransactionSynchronizationManager.bindResource(factory, connHolder); if (enableTransactionSupport) { potentiallyRegisterTransactionSynchronisation(connHolder, factory); } return connHolder.getConnection(); } return conn; }</pre>
不要跟本文的樂觀鎖說的事務混淆在一起。
參考
本文由用戶 ZoiSkerst 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!