redistemplate 乐观锁实践
来源:互联网 发布:淘宝c店转让 编辑:程序博客网 时间:2024/05/16 15:04
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的docker搭建
SpringBoot应用之分布式缓存
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:nullset:hello3 rs:[]set:hello1 rs:nullset:hello4 rs:nullset: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; }
不要跟本文的乐观锁说的事务混淆在一起。
- redistemplate 乐观锁实践
- redistemplate事务实践
- mysql乐观锁总结和实践
- mysql乐观锁总结和实践
- mysql乐观锁总结和实践
- mysql乐观锁总结和实践
- mysql乐观锁总结和实践
- mysql乐观锁总结和实践
- mysql乐观锁总结和实践
- mysql乐观锁总结和实践
- mysql乐观锁总结和实践
- mysql乐观锁总结和实践
- mysql乐观锁总结和实践
- mysql乐观锁总结和实践
- mysql乐观锁总结和实践
- mysql乐观锁总结和实践
- mysql乐观锁总结和实践
- mysql乐观锁总结和实践
- Chrome被hao123.com劫持了,消灭它
- AI的道德挑战
- u-boot中的date命令
- dlib+VS2015配置与dlib特征点检测
- Hopfield神经网络详解
- redistemplate 乐观锁实践
- 初级自定义cell
- 查看预定义宏 以及查看预定义的路径
- IOException
- Ubuntu16.04 安装opencv3.3.1
- Flask-应用(程序)上下文和请求上下文
- 杨大腔调近期作息时间一览
- docker资料
- Spring Boot学习笔记----POI(Excel导入导出)