php的在页面载入时或调用session_start()时从数据源中读取session数据到$_SESSION变量。
当页面执行完毕或调用session_write_close()时把$_SESSION变量写入数据源。php默认的session.save_handler=files,可以通过文件锁来实现读写同步,保证session数据的一致性,不会产生问题。然而当使用sqlite作为session handler时,由于没有同步机制,会产生bug。如下代码:test1.phpsession_start();
$_SESSION['data1'] = 'data1';
sleep(10);
session_write_close();test2.phpsession_start();
$_SESSION['data2'] = 'data2';
session_write_close();
在同一浏览器进程里(保证使用相同的session_id),先访问test1.php,再访问test2.php,会发现data2根本没有写入sqlite数据库中。session.save_handler=memcache还没有测试,估计也有这个问题。如果采用默认的files handler会发现test2.php的请求会被挂起直至test1.php执行完毕,这就是文件锁同步机制造成的。我想到了两种解决方案:
1、实现互斥锁,保证同一session_id访问session数据是同步的,这样会产生一个阻塞的问题(php默认的session实现也会有这个问题)。
2、写入session数据时进行数据合并,不过这样仍然不能完全保证数据一致性。有没有人曾经碰到过这个问题?有什么解决方案吗?

解决方案 »

  1.   

    经测试,session.save_handler=memcache时也存在该bug。
      

  2.   

    重载session读写方法, 在关键位置自行处理
    用rename() 进行缓存替换
      

  3.   


    你说的现成委托是PHP的解决方案吗?
    能具体说说吗?
      

  4.   


    即使采用session_set_save_handler()重载也会有类似的问题,因为PHP没有内置的互斥锁的实现。linux可以使用sem_*系列函数来使用信号量,但是windows下没有类似函数,只能用文件读写锁代替,但是传说在高并发情况下文件锁会失效。
      

  5.   

    不是PHP,是做.NET项目时遇到,自己写个线程委托类就解决了啊!PHP你查下看,应该也可以的!
      

  6.   


    我想呢,一搜“线程委托”怎么都是说.net的,呵呵
      

  7.   

    请教一下,session.save_handle的配置参数有哪些?找不到文档啊!
      

  8.   


    运行php -i
    查看 Registered save handlers 一项的信息
    一般根据安装的扩展,有files(默认) user memcache sqlite
      

  9.   

    可以给PHP开发团队反映一下,应该会给你一些建议的
      

  10.   


    这个好, 直接上官网請求处理bug
      

  11.   

    用文件锁方案解决了,不过高并发下文件锁同步可能会有问题,linux下考虑采用信号量