SpringDataRedis事務處理

ZoiSkerst 8年前發布 | 34K 次閱讀 Redis NoSQL數據庫

來自: 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 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!