zoukankan      html  css  js  c++  java
  • redistemplate 乐观锁实践

        public Object testRedisWatch() {
    
            try {
                stringRedisTemplate.execute(new SessionCallback() {
                    @Override
                    public Object execute(RedisOperations operations) throws DataAccessException {
    
                        operations.watch("testRedisWatch");
                        operations.multi();
                        operations.opsForValue().set("testRedisWatch", "0");
                        try {
                            Thread.sleep(5000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        Object rs = operations.exec();
                        System.out.println(rs);
                        return rs;
    
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            return null;
        }



    
    

    初始值:

    127.0.0.1:6389> get testRedisWatch

    "initial"

    考虑两种情况:

    A

    代码执行:

    operations.watch("testRedisWatch");
                        operations.multi();
                        operations.opsForValue().set("testRedisWatch", "0");
                        try {
                            Thread.sleep(5000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }

    代码执行:

    Object rs = operations.exec();

    输出:

    []


    此时的值为:

    127.0.0.1:6389> get testRedisWatch

    "0"

    表明watch与exec之间没有其它客户端改变值的情况下,rs输出非空对象

    B

    代码执行:

    operations.watch("testRedisWatch");
                        operations.multi();
                        operations.opsForValue().set("testRedisWatch", "0");
                        try {
                            Thread.sleep(5000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }



    客户端执行:

    127.0.0.1:6389> set testRedisWatch another

    OK

    代码执行:

    Object rs = operations.exec();

    输出:

    null


    此时的最终值为:

    127.0.0.1:6389> get testRedisWatch

    "another"

    代码中的

    operations.opsForValue().set("testRedisWatch", "0");

    失效了

    表明watch与exec之间有其它客户端改变值的情况下,rs输出空对象,改值失败

    参考:

    SpringDataRedis事务处理

    本文主要讲述如何在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

    我:其中1个拿到了锁,其余4个挂了

    查看该值

    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;
        }

    不要跟本文的乐观锁说的事务混淆在一起。

     
  • 相关阅读:
    JDBC_PreparedStatement
    JDBC_Statement
    JDBC连接数据库
    Oracle语句
    MySQL用户和权限
    MySQL执行计划
    MySQL创建索引
    MySQL正则表达式
    MySQLshow查询
    MySQL多表连接和分页查询
  • 原文地址:https://www.cnblogs.com/silyvin/p/9106721.html
Copyright © 2011-2022 走看看