Java开发Redis的事务与Watch原理分析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java开发Redis的事务与Watch原理分析相关的知识,希望对你有一定的参考价值。

Redis中的业务(transaction)是一组指令的调集。业务同指令一样都是Redis最小的履行单位,一个业务中的指令要么都履行,要么都不履行。Redis业务的完结需求用到 MULTI  EXEC两个指令,业务开端的时分先向Redis服务器发送 MULTI 指令,然后顺次发送需求在本次业务中处理的指令,最终再发送 EXEC 指令表明业务指令完毕。严厉意义来讲,redis的业务和我们了解的传统数据库(如mysql)的业务是不一样的。

一丶redis中的业务界说

Redis中的业务(transaction)是一组指令的调集。

业务同指令一样都是Redis的最小履行单位,一个业务中的指令要么都履行,要么都不履行。

业务的原理是先将归于一个业务的指令发送给Redis,然后再让Redis顺次履行这些指令。

Redis确保一个业务中的一切指令要么都履行,要么都不履行。如果在发送EXEC指令前客户端断线了,则Redis会清空业务行列,业务中的一切指令都不会履行。而一旦客户端发送了EXEC指令,一切的指令就都会被履行,即便尔后客户端断线也没关系,因为Redis中现已记录了一切要履行的指令。

除此之外,Redis的业务还能确保一个业务内的指令顺次履行而不被其他指令刺进。试想客户端A需求履行几条指令,同时客户端B发送了一条指令,如果不运用业务,则客户端B的指令可能会刺进到客户端A的几条指令中履行。如果不期望发作这种情况,也能够运用业务。

二丶业务的应用

业务的应用非常遍及,如银行转账过程中A给B汇款,首要体系从A的账户中将钱划走,然后向B的账户添加相应的金额。这两个过程有必要归于同一个业务,要么全履行,要么全不履行。否则只履行第一步,钱就凭空消失了,这明显让人无法承受。

三丶和传统的业务不同

和传统的mysql业务不同的事,即便我们的加钱操作失利,我们也无法在这一组指令中让整个状况回滚到操作之前

四丶业务的过错处理

如果一个业务中的某个指令履行犯错,Redis会怎样处理呢?要回答这个问题,首要需求知道什么原因会导致指令履行犯错。

语法过错

语法过错指指令不存在或许指令参数的个数不对。比如:

redis>MULTIOKredis>SET key valueQUEUEDredis>SET key(error)ERR wrongnumber of arguments for ‘set‘ commandredis> errorCOMMAND key(error) ERR unknown command ‘errorCOMMAND‘redis> EXEC(error) EXECABORTTransaction discarded because of previous errors.

跟在MULTI指令后履行了3个指令:一个是正确的指令,成功地加入业务行列;其余两个指令都有语法过错。而只需有一个指令有语法过错,履行EXEC指令后Redis就会直接回来过错,连语法正确的指令也不会履行。

这儿需求留意一点:

Redis 2.6.5之前的版本会疏忽有语法过错的指令,然后履行业务中其他语法正确的指令。就此例而言,SET key value会被履行,EXEC指令会回来一个结果:1) OK。

运转过错

运转过错指在指令履行时呈现的过错,比如运用散列类型的指令操作调集类型的键,这种过错在实践履行之前Redis是无法发现的,所以在业务里这样的指令是会被Redis承受并履行的。如果业务里的一条指令呈现了运转过错,业务里其他的指令仍然会继续履行(包含犯错指令之后的指令),示例如下:

redis>MULTIOKredis>SET key 1QUEUEDredis>SADD key 2QUEUEDredis>SETkey 3QUEUEDredis>EXEC1) OK2) (error) ERR Operation against a keyholding the wrong kind of value3) OKredis>GET key"3"

可见尽管SADD key 2呈现了过错,可是SET key 3仍然履行了。

Redis的业务没有关系数据库业务供给的回滚(rollback)功用。为此开发者有必要在业务履行犯错后自己收拾剩余的摊子(将数据库恢复回业务履行前的状况等,这儿我们一般采取日志记录然后业务补偿的方式来处理,可是一般情况下,在redis做的操作不应该有这种强共同性要求的需求,我们以为这种需求为不合理的规划)。

五丶Watch指令

我们可能知道redis供给了根据incr指令来操作一个整数型数值的原子递加,那么我们假定如果redis没有这个incr指令,我们该怎样完结这个incr的操作呢?

那么我们下面的正主watch就要上场了。

怎么运用watch指令

正常情况下我们想要对一个整形数值做修正是这么做的(伪代码完结):

val = GET mykey val = val + 1 SET mykey $val

可是上述的代码会呈现一个问题,因为上面吧正常的一个incr(原子递加操作)分为了两部分,那么在多线程(分布式)环境中,这个操作就有可能不再具有原子性了。

研讨过java的juc包的人应该都知道cas,那么redis也供给了这样的一个机制,就是运用watch指令来完结的。

watch指令描绘

WATCH指令能够监控一个或多个键,一旦其中有一个键被修正(或删除),之后的业务就不会履行。监控一向继续到EXEC指令(业务中的指令是在EXEC之后才履行的,所以在MULTI指令后能够修正WATCH监控的键值)

运用watch完结incr

具体做法如下:

WATCH mykey val = GET mykey val = val + 1 MULTI SET mykey $val EXEC

和此前代码不同的是,新代码在获取mykey的值之前先通过WATCH指令监控了该键,尔后又将set指令包围在业务中,这样就能够有用的确保每个衔接在履行EXEC之前,如果当时衔接获取的mykey的值被其它衔接的客户端修正,那么当时衔接的EXEC指令将履行失利。这样调用者在判别回来值后就能够得悉val是否被从头设置成功。

留意点

因为WATCH指令的效果只是当被监控的键值被修正后阻止之后一个业务的履行,而不能确保其他客户端不修正这一键值,所以在一般的情况下我们需求在EXEC履行失利后从头履行整个函数。

履行EXEC指令后会撤销对一切键的监控,如果不想履行业务中的指令也能够运用UNWATCH指令来撤销监控。

完结一个hsetNX函数

我们完结的hsetNX这个功用是:仅当字段存在时才赋值。

为了防止竞态条件我们运用watch和业务来完结这一功用(伪代码):

WATCH key isFieldExists = HEXISTS key, field if isFieldExists is 1MULTI HSET key, field, value EXEC else UNWATCH return isFieldExists

在代码中会判别要赋值的字段是否存在,如果字段不存在的话就不履行业务中的指令,但需求运用UNWATCH指令来确保下一个业务的履行不会受到影响。

总结

以 上就是我对Java开发Redis的业务与Watch原理剖析问题及其优化总结,共享给我们,期望我们能够了解什么是Java开发Redis的业务与Watch原理剖析问题及其优化。觉得收成的话能够点个重视收藏转发一波喔,谢谢大佬们支撑!

1、多写多敲代码,好的代码与厚实的基础知识一定是实践出来的

2、能够去百度查找腾讯讲堂图灵学院的视频来学习一下java架构实战事例,还挺不错的。

最终,每一位读到这儿的网友,感谢你们本领心地看完。期望在成为一名更优异的Java程序员的道路上,我们能够一起学习、一起前进。


以上是关于Java开发Redis的事务与Watch原理分析的主要内容,如果未能解决你的问题,请参考以下文章

Redis发布订阅和事务实现原理

Redis发布订阅和事务实现原理

Redis源码剖析 - Redis之事务的实现原理

Redis的事务和watch

Redis的事务和watch

Redis事务的实现原理