expire相关知识
-
微服务-分布式锁(二)-Redis方案1 LUA+SETNX+EXPIRE先用setnx来抢锁,如果抢到之后,再用expire给锁设置一个过期时间,防止锁忘记了释放。setnx(key, value)setnx 的含义就是 SET if Not Exists,该方法是原子的。如果 key 不存在,则设置当前 key 为 value 成功,返回 1;如果当前 key 已经存在,则设置当前 key 失败,返回 0。expire(key, seconds)expire 设置过期时间,要注意的是 setnx 命令不能设置 key 的超时时间,只能通过 expire() 来对 key 设置。1.1 使用Lua脚本(SETNX+EXPIRE)可以使用Lua脚本来保证原子性(包含setnx和expire两条指令),加解锁代码如下:/** * 使用Lua脚本,脚本中使用setnex+expire命令进行加锁操作 */public boolean lock(Jedis jedis, String key, String uniqueId, int seconds
-
js操作cookie写在前面在app中嵌入的h5应用,有时需要获取cookie的中的参数,但是通过请求服务端然后返回,确实太麻烦,所以就想通过js直接操作cookie的做法。JS操作cookie<script> /* 设置cookie name:键 value:值 expire:过期时间 */ function setCookie(name, value, expire) { var exp = new Date(); exp.setTime(exp.getTime() + expire * 24 * 60 * 60 * 1000 * 1); document.cookie =
-
redis如何设置键过期和键过期对内存的影响如何设置键过期Redis所有的键都可以设置过期属性,内部保存在过期字典中。expire key seconds --键在seconds秒后过期expireat key timestamp --键在秒级时间戳timestamp后过期注意:expireat和expire类似,不同在于 EXPIREAT 命令接受的时间参数是 UNIX 时间戳(unix timestamp)。//key 不存在测试 127.0.0.1:6379> exists test:key:expire (integer) 0 127.0.0.1:6379> expire test:key:expire 15 (integer) 0 127.0.0.1:6379> ttl test:key:expire (integer) -2 //key存在 127.0.0.1:6379> 
-
vue 封装cookie,请求,登录拦截,接口拦截作者:陈88原文链接:https://segmentfault.com/a/1190000015278958一:封装Cookie方法在util文件夹下,我们创建util.js文件,然后上代码//设置cookieexport function setCookie (c_name, value, expire) { var date = new Date() date.setSeconds(date.getSeconds() + expire) document.cookie = c_name + "=" + escape(value) + ";&n
expire相关课程
expire相关教程
- 2.缓存配置文件 打开 config\cache.php,设置如下内容:<?php// +----------------------------------------------------------------------// | 缓存设置// +----------------------------------------------------------------------return [ // 默认缓存驱动 'default' => env('cache.driver', 'file'), // 缓存连接方式配置 'stores' => [ 'file' => [ // 驱动方式 'type' => 'File', // 缓存保存目录 'path' => '../runtime/study/', // 缓存前缀 'prefix' => '', // 缓存有效期 0表示永久缓存 'expire' => 0, // 缓存标签前缀 'tag_prefix' => 'tag:', // 序列化机制 例如 ['serialize', 'unserialize'] 'serialize' => [], ], // redis缓存 'redis' => [ // 驱动方式 'type' => 'redis', // 服务器地址 'host' => env('REDIS.HOST', '127.0.0.1'), ], ],];如下图所示:Tips: 其中默认缓存驱动中的 env('cache.driver', 'file') 表示从 .env 文件中出 [CACHE] 模块下的 DRIVER 变量的值,默认是 file,redis 配置中的 env('REDIS.HOST', '127.0.0.1') 也是同理。
- 2.2 Redis 分布式锁 面试官提问: 既然谈到了分布式锁的应用场景,在实战环境是如何实现分布式锁的呢?题目解析:目前分布式锁最主要有三种实现方式:(1)基于 Redis 集群的模式;(2)基于 Zookeeper 集群的模式;(3)基于 DB 数据库的模式本章节只关注 Redis 的部分,核心思路是通过 setnx 指令,实例: public static void wrongWayLock(Jedis jedis, String prefix_key, String id, int expire_time) { // 加锁 Long result = jedis.setnx(prefix_key, id); if (result==1){ // 如果加锁成功,设置过期时间 jedis.expire(prefix_key,expire_time); } }加锁步骤主要分为两步:(1)通过 setnx 指令加锁,setnx 的含义是 set if not exist,即如果 redis 不存在已有的 prefix_key ,则写入 prefix_key ,设置对应 value=id,并且调用返回为 1,如果已有 prefix_key ,则不写入并且返回非 1.(2)通过 expire 指令,设置过期时间,如果 prefix_key 代表的锁一直没有删除,则在定时后自动失效,防止产生死锁的情况。上述代码并不完美,其中 setnx() 和 expire() 函数并不是原子操作,如果执行 setnx() 指令之后,redis 集群出现网络抖动或者在线服务本身异常,导致后续 expire() 指令并没有执行,prefix_key 代表的锁并没有被加上过期时间,还是有产生死锁的可能性,我们对上述代码进行改造,实例: public static boolean setLock(Jedis jedis, String prefix_key, String id, int expire_time) { if(jedis.set(prefix_key, id, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expire_time) == 1) { return true; //加锁成功 } return false; //加锁失败 }这种方案是将加锁和设置过期时间合并为一个步骤,一次 set,是原子操作。另外还有诸多开源代码解决这个问题,例如通过开源 lua 脚本,基于 redis 集群进行改造。既然有加锁的过程,就有操作执行结束之后释放锁的过程,实例: public static void unLock(Jedis jedis, String prefix_key, String id){ //如果在集群中存在prefix_key的值,并且和之前配置的id相同 if(id.equals(jedis.get(prefix_key))){ //删除prefix_key键值对 jedis.del(prefix_key); } }使用分布式锁都是为了应对高并发的场景,高并发场景下,上述代码存在严重的并发执行问题。例如第一行 if 判断完成之后,其他线程已经提前进入条件判断并且执行了 del 操作,当前线程再执行 del 操作就不合理。还是出现了没有保证操作原子性的问题,通用的解决方案是通过 lua 脚本的 eval() 函数,首先获取锁对应的 value(即我们的 id ),如果相等才删除锁,lua 脚本能保证原子性,实例: public boolean unlock(String prefix_key,String request){ //lua脚本 String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; Long result = jedis.eval(script, Collections.singletonList(prefix_key), Collections.singletonList(id)); if (result == 1){ return true ; } return false; }
- 8.内置验证规则表 下面列出 ThinkPHP 提供的内置验证规则:验证规则名含义require验证字段为必须number验证字段是否为数字类型integer验证字段是否为整数float验证字段是否为浮点型boolean 或 bool验证字段是否为布尔值email验证字段是否符合邮箱格式array验证字段是否为数组date验证字段是否为有效的日期alpha验证字段是否为纯字母alphaNum验证字段是否为字母+数字混合alphaDash验证字段是否为字母+数字+_+-混合chs验证字段是否为 汉字chsAlpha验证字段是否为 汉字+字母混合chsAlphaNum验证字段是否为 汉字+字母+数字混合chsDash验证字段是否为 汉字+字母+数字+_+-混合cntrl验证字段是否控制字符(换行、缩进、空格)graph验证字段是否为可打印字符(空格除外)print验证字段是否为可打印字符(包括空格)lower验证字段是否为小写字母upper验证字段是否为大写字母space验证字段是否为空白字符(包括缩进,垂直制表符,换行符,回车和换页字符)xdigit验证字段是否为十六进制字符串url验证字段是否为有效的URL地址ip验证字段是否为有效的IP地址,支持验证ipv4和ipv6格式的IP地址dateFormat:format验证字段是否为指定格式的日期,如 dateFormat:y-m-d 表示年月日mobile验证字段是否为有效的手机格式idCard验证字段是否为有效的身份证格式macAddr验证字段是否为有效的MAC地址zip验证字段是否为有效的邮政编码in验证字段是否为是否在某个范围,如 in:1,2,3 表示取值在 1,2,3中notIn验证字段是否为不在某个范围between验证字段是否为在某个区间,如 between:1,10 表示 1-10 之间notBetween验证字段是否为不在某个范围length:num1,num2验证字段是否为长度是否在某个范围,如 length:4,25 长度在 4-25,length:4 表示指定长度,如果验证的数据是数组,则判断数组的长度。如果验证的数据是File对象,则判断文件的大小。max:number验证字段的 最大长度,如 max:10 表示最大长度 10,注意不包含字段不存在的情况,如果验证的数据是数组,则判断数组的长度。如果验证的数据是File对象,则判断文件的大小。min:number验证字段的 最小长度,如min:5 表示最小长度 5,注意不包含字段不存在的情况,如果验证的数据是数组,则判断数组的长度。如果验证的数据是File对象,则判断文件的大小。after:日期验证字段是否为在某个日期之后,如 after:2020-11-18 表示 2020-11-18 之后before:日期验证字段是否为在某个日期之前,如 after:2020-11-18 表示 2020-11-18 之前expire:开始时间,结束时间验证当前操作(注意不是某个值)是否在某个有效日期之内,如expire:2020-1-21,2020-5-1表示 2020-01-21 至 2020-05-01 之间allowIp:allow1,allow2,…验证当前请求的IP是否允许访问,如 'allowIp:114.45.4.55' 表示ip为 114.45.4.55denyIp:allow1,allow2,…验证当前请求的IP是否禁止访问,如 denyIp:114.45.4.55confirm验证字段是否为和另外一个字段值一致,如 confirm:new_value 表示当前判断字段值是否和 new_value 字段值一致eq 或者 = 或者 same验证字段是否为等于某个值,如eq:100 表示等于 100,=:10 表示等于 10,same:20 表示等于 20egt 或者 >=验证字段是否为大于等于某个值,如 egt:30表示大于等于30,>=50 表示大于等于50gt 或者 >验证字段是否为大于某个值,同上elt 或者 <=验证字段是否为小于等于某个值,同上lt 或者 <验证字段是否为小于某个值file验证字段是否为一个上传文件image:width,height,type验证字段是否为一个图像文件,其中 width,height和type都是可选,width和height必须同时定义fileExt:允许的文件后缀验证字段是否为上传文件后缀fileMime:允许的文件类型验证字段是否为上传文件类型fileSize:允许的文件字节大小验证字段是否为上传文件大小token:表单令牌名称表单令牌验证unique:table,field,except,pk验证当前请求的字段值是否为唯一的requireIf:field,value验证某个字段的值等于某个值的时候必须requireWith:field验证某个字段有值的时候必须requireWithout:field验证某个字段没有值的时候必须requireCallback:callable验证当某个callable为真的时候字段必须
- 3.2 Django 中 Session 操作相关源码 Django 中和 Session 相关的代码较多,我们不去深入追究源码细节,主要是程序的执行过程。比如在哪里设置的 request.session 值以及 session 相关信息如何保存到数据库中的等等。我们先整体看下 Session 相关的代码位置:这里有几个比较重要的地方,一个是 backends 目录,下面是不同保存 Session 数据方式的代码,如使用数据库存储、缓存存储或者文件系统存储等,每种存储方式对应着一个代码文件,里面定义的类和方法都是一致的,这样就可以无缝切换存储引擎。第二个是 middleware.py 文件,我们先要了解下 Django 中 MIDDLEWARE 的工作流程,可以如下图所示:由于在 settings.py 中间设置了 Session 的中间件,所以 request 和 response 也会经历 Session 中间件的这个流程,看 session 目录下的 middleware.py 文件的代码:class SessionMiddleware(MiddlewareMixin): def __init__(self, get_response=None): self.get_response = get_response engine = import_module(settings.SESSION_ENGINE) self.SessionStore = engine.SessionStore def process_request(self, request): session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME) request.session = self.SessionStore(session_key) def process_response(self, request, response): """ If request.session was modified, or if the configuration is to save the session every time, save the changes and set a session cookie or delete the session cookie if the session has been emptied. """ try: accessed = request.session.accessed modified = request.session.modified empty = request.session.is_empty() except AttributeError: pass else: # First check if we need to delete this cookie. # The session should be deleted only if the session is entirely empty if settings.SESSION_COOKIE_NAME in request.COOKIES and empty: response.delete_cookie( settings.SESSION_COOKIE_NAME, path=settings.SESSION_COOKIE_PATH, domain=settings.SESSION_COOKIE_DOMAIN, ) else: if accessed: patch_vary_headers(response, ('Cookie',)) if (modified or settings.SESSION_SAVE_EVERY_REQUEST) and not empty: if request.session.get_expire_at_browser_close(): max_age = None expires = None else: max_age = request.session.get_expiry_age() expires_time = time.time() + max_age expires = http_date(expires_time) # Save the session data and refresh the client cookie. # Skip session save for 500 responses, refs #3881. if response.status_code != 500: try: request.session.save() except UpdateError: raise SuspiciousOperation( "The request's session was deleted before the " "request completed. The user may have logged " "out in a concurrent request, for example." ) response.set_cookie( # 默认值便是session_id settings.SESSION_COOKIE_NAME, request.session.session_key, max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN, path=settings.SESSION_COOKIE_PATH, secure=settings.SESSION_COOKIE_SECURE or None, httponly=settings.SESSION_COOKIE_HTTPONLY or None, samesite=settings.SESSION_COOKIE_SAMESITE, ) return response首先看 __init__() 方法中的设置了对应 Session 的存储引擎,接下来的 process_request() 方法中我们可以看到 request.session = self.SessionStore(session_key) 这行语句正是给 request 的 session 属性赋值,而这个值正是存储引擎模块下的 SessionStore 类的实例。而对于 process_response() 方法,从代码中可以看到,它完成了 Session 数据的保存以及将 session_id 值写到 cookie 中去并返回给客户端,调用的方法正是我们前面介绍到的 set_cookie() 方法。接下来,我们看看其他几个 python 文件中的代码。例如下面的 models.py 定义了 Session 的 model 模型,包括字段以及管理器:# 源码位置:django/contrib/sessions/models.pyfrom django.contrib.sessions.base_session import ( AbstractBaseSession, BaseSessionManager,)class SessionManager(BaseSessionManager): use_in_migrations = Trueclass Session(AbstractBaseSession): objects = SessionManager() @classmethod def get_session_store_class(cls): from django.contrib.sessions.backends.db import SessionStore return SessionStore class Meta(AbstractBaseSession.Meta): db_table = 'django_session'从这段代码可以看到 Session 如果使用数据库保存数据的话,其建立的表名为:django_session,其字段类型并不在这里定义,而是继承的父类 BaseSessionManager,这个类定义就在 base_session.py 文件中:class BaseSessionManager(models.Manager): def encode(self, session_dict): """ Return the given session dictionary serialized and encoded as a string. """ session_store_class = self.model.get_session_store_class() return session_store_class().encode(session_dict) def save(self, session_key, session_dict, expire_date): s = self.model(session_key, self.encode(session_dict), expire_date) if session_dict: s.save() else: s.delete() # Clear sessions with no data. return sclass AbstractBaseSession(models.Model): session_key = models.CharField(_('session key'), max_length=40, primary_key=True) session_data = models.TextField(_('session data')) expire_date = models.DateTimeField(_('expire date'), db_index=True) objects = BaseSessionManager() class Meta: abstract = True verbose_name = _('session') verbose_name_plural = _('sessions') def __str__(self): return self.session_key @classmethod def get_session_store_class(cls): raise NotImplementedError def get_decoded(self): session_store_class = self.get_session_store_class() return session_store_class().decode(self.session_data)从这里就可以看到 django_session 表有3个字段,分别是session_key、session_data 和 expire_date。继承这个基类必须要实现 get_session_store_class() 这个方法。另外 app.py 用于指明 session 应用名称,exceptions.py 定义了两个简单的异常,serializers.py 的内容也比较简单,仅仅使用 pickle 模块封装了一个用于序列化的类:import picklefrom django.core.signing import JSONSerializer as BaseJSONSerializerclass PickleSerializer: """ Simple wrapper around pickle to be used in signing.dumps and signing.loads. """ protocol = pickle.HIGHEST_PROTOCOL def dumps(self, obj): return pickle.dumps(obj, self.protocol) def loads(self, data): return pickle.loads(data)JSONSerializer = BaseJSONSerializer我们也可以简单使用下这个类,其实就是熟悉 pickle 模块的 dumps() 和 loads() 方法。(django-manual) [root@server first_django_app]# python manage.py shellPython 3.8.1 (default, Dec 24 2019, 17:04:00) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linuxType "help", "copyright", "credits" or "license" for more information.(InteractiveConsole)>>> from django.contrib.sessions.serializers import PickleSerializer>>> from hello_app.views import Member>>> Member.objects.all().get(name='spyinx-1')<Member: <spyinx-1, 18017715080>>>>> m = Member.objects.all().get(name='spyinx-1')>>> PickleSerializer().dumps(m)b'\x80\x05\x95o\x01\x00\x00\x00\x00\x00\x00\x8c\x15django.db.models.base\x94\x8c\x0emodel_unpickle\x94\x93\x94\x8c\thello_app\x94\x8c\x06Member\x94\x86\x94\x85\x94R\x94}\x94(\x8c\x06_state\x94h\x00\x8c\nModelState\x94\x93\x94)\x81\x94}\x94(\x8c\x06adding\x94\x89\x8c\x02db\x94\x8c\x07default\x94ub\x8c\x02id\x94K\x05\x8c\x04name\x94\x8c\x08spyinx-1\x94\x8c\x03age\x94\x8c\x0225\x94\x8c\x03sex\x94K\x00\x8c\noccupation\x94\x8c\x07teacher\x94\x8c\tphone_num\x94\x8c\x0b18017715080\x94\x8c\x05email\x94\x8c\n221@qq.com\x94\x8c\x04city\x94\x8c\x08shenzhen\x94\x8c\rregister_date\x94\x8c\x08datetime\x94\x8c\x08datetime\x94\x93\x94C\n\x07\xe4\x04\t\x10\x18\n\x00\x00\x00\x94\x85\x94R\x94\x8c\x0cvip_level_id\x94N\x8c\x0f_django_version\x94\x8c\x062.2.11\x94ub.'>>> m1 = PickleSerializer().loads(s)>>> type(m1)<class 'hello_app.models.Member'>>>> m1.name'spyinx-1'最后,关于 Session 的引擎不用过多细究,里面默认用到的是 backends/db.py。如果使用的是缓存引擎,代码内容也是大同小异的。主要认真研究两个类:backends/base.py 中的 SessionBase 类。这个是所有 SessionStore 的基类,它具有的方法正是我们操作 session 的方法;backends/db.py 中的 SessionStore 类。前面的 request.session 便是该类的一个实例,它的代码内容也是不复杂的,主要针对该种存储方式需要完成特定的保存(save())、删除(delete()) 以及导入(load())等方法。到此为止,Django 中关于 Session 的代码就这么多了。剩下的代码细节还需要各位去慢慢专研,也希望大家能认真钻研 Django 的源码,多多思考,然后多多实践。
- 07 SQL Insert SQL 程序员的必学技能
- 21 Python 中的命名空间 来这里学习 Python 的进阶应用。
expire相关搜索
-
e preventdefault
e4a
each
each的用法
easter
easter day
easyui
easyui 官网
echarts
eclipse
eclipse 64位下载
eclipse android
eclipse tomcat
eclipse 教程
eclipse 快捷键
eclipseadt
eclipse安装教程
eclipse插件
eclipse插件下载
eclipse教程