昆明网站建设方案策划,wordpress开启多站点后台没显示,wordpress修改文章页面模板,千图网免费海报素材图库前言
最近博主感觉捅了Redis窝#xff0c;从Redis主从#xff0c;哨兵#xff0c;集群#xff0c;集群原理纷纷讲了一遍#xff0c;不知道大家都学会了多少#xff0c;想着送佛送到西#xff0c;不如再添一把火#xff0c;所以今天带给大家的博客是Redis事务#xff…前言
最近博主感觉捅了Redis窝从Redis主从哨兵集群集群原理纷纷讲了一遍不知道大家都学会了多少想着送佛送到西不如再添一把火所以今天带给大家的博客是Redis事务有人要问什么Redis也有事务没错Redis也有类似于MySQL的事务不要惊奇这也不是刚刚有只是很多人平时不常用罢了。
事务
事务我们知道是存在于关系型数据库中的一种数据处理手段主要责任是数据的CRUD还包括了事务提交和回滚。那么在Redis里有没有一种机制也能处理数据的提交和回滚呢答案是肯定的那就是Redis事务它是一个类原子的隔离操作将一系列指令按需排队并顺序执行期间不会被其他指令插队。但Redis事务在运行时无法预测所以也无法回滚。
指令
在Redis事务中共有三大指令
multi开启事务exec执行事务discard取消事务
在multi之后开启事务此时可以set多个key这些key将按照顺序存入先进先出的队列exec执行事务这些事务将按照入队的顺序执行在这些事务执行过程中不受其他的插入指令影响。在组队阶段使用discard指令由于未使用exec指令开启事务所以前面队列中的操作将全部取消。
我们来做个演示首先开启一个Redis服务
redis-server redis1.conf
连接redis
redis-cli -h localhost -p 6379
正常执行 取消执行 因为没有执行exec所以discard后前面的c和d都不会执行。
组队错误 可以看到在组队时抱了错事务是不会执行的。
执行错误 我们在set c之后对c进行1操作由于c不是integer类型所以报错了但是我们发现最终c和d被存储进了redis从这一点来看运行过程中的异常不会导致队列中的任务取消。
Redis和锁
为了保证数据的安全性我们有时候在做key的存储的时候会给key加锁防止多个线程的情况下key被篡改去情况发生一般发生在抢购/秒杀时对库存的操作上。
被关锁就不再多提了使用被关锁可以完全防止key被篡改但相应的线程也将被阻塞降低效率这里说说乐观锁在redis里的使用我们看如下操作。
首先我们需要再开一个命令行模拟两个线程的场景:
在开始前我们先通过flushdb指令清空redis中的数据 监听key并开启事务
线程1: 线程2: 操作并提交key
线程1: 线程2: 可以看到线程2在对a1的时候出问题了返回nil。像不像CAS没错乐观锁的本质就是CAS比较并交换比较的值被改变了自然不会存入新值。
回滚与原子性
Redis回滚
那有人要问了 redis到底能不能回滚其实在上面我们已经得到了答案就是在组队阶段是可以回滚的看“组队错误”在执行阶段是不支持回滚的看“执行错误”。
所以最终我们得出结论在使用中redis可支持回滚但是情况比较复杂是一种可预知的错误而那些不可预知的错误则是无法回滚。
原子性
基于以上redis事务执行时出现的组队和执行问题所以利用redis做库存的扣减似乎是一件不太稳妥的事所以为了弥补这个缺陷我们需要使用redis的原子性。原子性的特点就是要么一起执行要么不执行。这里我们应该都听说一个东西叫lua脚本其特点我就不多说了总之就是执行快且保证原子性不被打断但是lua脚本也不支持回滚所以关于redis的回滚大家就不要纠结了。
Spring Boot接入Redis事务
关于Spring Boot接入Redis事务怎么说呢感觉没太大必要哈哈不过也不能说一无是处用还是有人在用的这里博主就简单讲讲怎么用。
启动Redis服务 上面Redis已经启动了直接用。
redisTemplate使用事务
添加依赖
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId
/dependency
添加配置
spring.redis.host127.0.0.1
spring.redis.port6379 准备测试代码 Testvoid testTransaction() {//开启事务支持redisTemplate.setEnableTransactionSupport(true);//开启事务redisTemplate.multi();redisTemplate.opsForValue().set(name1, codingfire1);redisTemplate.opsForValue().set(name2, codingfire2);//执行事务redisTemplate.exec();System.out.println(redisTemplate.opsForValue().get(name1));System.out.println(redisTemplate.opsForValue().get(name2));}
以上代码在运行的时候发现报错了 但是当我打开redis可视化工具查看时发现数据已经存进去了 官方是通过Jedis来实现事务的所以这个问题出现了还让人有点懵很多人说是因为没开启事务支持但是博主明显开启了所以有些无从解答了有知道原因的可以告诉博主。
但是活人不能让尿憋死啊有一种SessionCallback的方式是很多人都推荐使用的我们来看看 Testpublic void testTransaction2(){redisTemplate.execute(new SessionCallbackListObject(){Overridepublic ListObject execute(RedisOperations operations) throws DataAccessException {operations.multi();operations.opsForValue().set(name3,codingfire3);operations.opsForValue().set(name4,codingfire4);operations.opsForValue().set(name5,codingfire5);return redisTemplate.exec();}});} 执行后没报错我们看下redis可视化工具 测试成功。
Jedis引入
我们刚刚提到了一种Jedis实现的方式下面我们来说说Jedis怎么实现。
添加依赖
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId
/dependencydependencygroupIdredis.clients/groupIdartifactIdjedis/artifactIdversion3.3.0/version
/dependency
添加配置
spring.redis.host127.0.0.1
spring.redis.port6379 准备测试代码 Testpublic void testTransaction3(){Jedis jedis new Jedis(127.0.0.1,6379);;//开启事务Transaction transaction jedis.multi();try {transaction.set(key1, v1);//制造异常,测试取消事务//int i1/0;transaction.set(key2, v2);//执行事务transaction.exec();}catch (Exception e){//取消事务transaction.discard();e.printStackTrace();}}
查看redis可视化工具 测试成功。
结语
以上是对redis事务的一个实操过程建议大家在做key的存入的时候不要对多个key进行关联主要是避免出现数据不一致的情况。整体上就是这样推荐使用SessionCallback和Jedis的方式虽然你可能不一定会用到这东西但是万一用到了呢