php会话保存数据技术 php聊天记录怎么保存( 三 )


既然如此 , 在使用完 Session 后,立刻显示调用 session_write_close() 是不是就解决问题了哩php会话保存数据技术?比如上面例子中,在 sleep(5) 前面调用 session_write_close() 。
确实,这样 session2.php 就不会被 session1.php 所阻塞 。但是 , 显示调用了 session_write_close() 就意味着将数据写到文件中并结束当前会话 。那么,在后面代码中要使用 Session 时,必须重新调用 session_start() 。
例如:
?php
session_start();
$_SESSION['name'] = 'Jing';
var_dump($_SESSION);
session_write_close();
sleep(5);
session_start();
$_SESSION['name'] = 'Mr.Jing';
var_dump($_SESSION);
?
官方给出的方案:
对于大量使用 Ajax 或者并发请求的网站而言,这可能是一个严重的问题 。解决这个问题最简单的做法是如果修改了会话中的变量,那么应该尽快调用 session_write_close() 来保存会话数据并释放文件锁 。还有一种选择就是使用支持并发操作的会话保存管理器来替代文件会话保存管理器 。
我推荐的方式是使用 Redis 作为 Session 的处理器 。
拓展阅读:
为什么不能用 memcached 存储 Session
如何使用 Redis 作为 PHP Session handler
Session 数据是什么时候被删除的
这是一道经常被面试官问起的问题 。
先看看官方手册中的说明:
session.gc_maxlifetime 指定过了多少秒之后数据就会被视为"垃圾"并被清除 。垃圾搜集可能会在 session 启动的时候开始( 取决于 session.gc_probability 和 session.gc_divisor) 。session.gc_probability 与 session.gc_divisor 合起来用来管理 gc(garbage collection 垃圾回收)进程启动的概率 。此概率用 gc_probability/gc_divisor 计算得来 。例如 1/100 意味着在每个请求中有 1% 的概率启动 gc 进程 。session.gc_probability 默认为 1 , session.gc_divisor 默认为 100 。
继续用我上面那个不太恰当的比方吧:如果我们把物品放在超市的储物箱中而不取走,过了很久(比如一个月),那么保安就要清理这些储物箱中的物品了 。当然并不是超过期限了保安就一定会来清理 , 也许他懒,又或者他压根就没有想起来这件事情 。
再看看两段手册的引用:
如果使用默认的基于文件的会话处理器,则文件系统必须保持跟踪访问时间(atime) 。Windows FAT 文件系统不行 , 因此如果必须使用 FAT 文件系统或者其他不能跟踪 atime 的文件系统,那就不得不想别的办法来处理会话数据的垃圾回收 。自 PHP 4.2.3 起用 mtime(修改时间)来代替了 atime 。因此对于不能跟踪 atime 的文件系统也没问题了 。
GC 的运行时机并不是精准的,带有一定的或然性 , 所以这个设置项并不能确保旧的会话数据被删除 。某些会话存储处理模块不使用此设置项 。
对于这种删除机制,我是存疑的 。
比如 gc_probability/gc_divisor 设置得比较大,或者网站的请求量比较大,那么 GC 进程启动就会比较频繁 。
还有,GC 进程启动后都需要遍历 Session 文件列表,对比文件的修改时间和服务端的当前时间,判断文件是否过期而决定是否删除文件 。
这也是我觉得不应该使用 PHP 自带的 files 型 Session 处理器的原因 。而 Redis 或 Memcached 天生就支持 key/value 过期机制的,用于作为会话处理器很合适 。或者自己实现一个基于文件的处理器 , 当根据 session_id 获取对应的单个 Session 文件时判断文件是否过期 。
为什么重启浏览器后 Session 数据就取不到了
session.cookie_lifetime 以秒数指定了发送到浏览器的 cookie 的生命周期 。值为 0 表示"直到关闭浏览器" 。默认为 0 。

推荐阅读