天天看點

tp5 session mysql_[Tp5.1] 為什麼TP5.1 預設配置開啟session_start() 使用完session處理後之後,不立即session_write_close()...

感谢大佬热心回复,这样说tp5.1的默认的文件session存储等待进程处理结束后才close是有意而为之?

但是我看代码并不像呀,配置项中use_lock=true不这么操作,不是应该使用use_lock=true才这样吗?怎么相反了。如下关键代码段:

/thinkphp/library/think/Session.php:123:

public function init(array $config = [])

{

$config = $config ?: $this->config;

$isDoStart = false;

if (isset($config['use_trans_sid'])) {

ini_set('session.use_trans_sid', $config['use_trans_sid'] ? 1 : 0);

}

// 启动session

if (!empty($config['auto_start']) && PHP_SESSION_ACTIVE != session_status()) {

ini_set('session.auto_start', 0);

$isDoStart = true;

}

if (isset($config['prefix'])) {

$this->prefix = $config['prefix'];

}

if (isset($config['use_lock'])) {

$this->lock = $config['use_lock']; //这里初始化

}

/thinkphp/library/think/Session.php:348:

protected function unlock()

{

if (empty($this->lock)) {

return;

}

$this->pause(); //这里面才执行 session_write_close();

if ($this->lockDriver && method_exists($this->lockDriver, 'unlock')) {

$sessID = isset($_COOKIE[$this->sessKey]) ? $_COOKIE[$this->sessKey] : '';

$this->lockDriver->unlock($sessID);

}

}

另外,请教下。对于同一用户,不用session文件锁方式,限制串行访问或并行访问,由于读数据不同步造成的乱数据。如下业务情况:

测试SQL:

-- ----------------------------

-- Table structure for order

-- ----------------------------

DROP TABLE IF EXISTS `order`;

CREATE TABLE `order` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`user_id` int(11) NOT NULL,

`payment_status` tinyint(2) NOT NULL COMMENT '0未支付1已支付',

PRIMARY KEY (`id`),

KEY `idx_user_id` (`user_id`)

) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- ----------------------------

-- Records of order

-- ----------------------------

BEGIN;

INSERT INTO `order` VALUES (1, 1, 0);

COMMIT;

-- ----------------------------

-- Table structure for order_payment

-- ----------------------------

DROP TABLE IF EXISTS `order_payment`;

CREATE TABLE `order_payment` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`order_id` int(11) NOT NULL,

PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

SET FOREIGN_KEY_CHECKS = 1;

A事务

B事务

begin

begin

查找用户是否支付 select id,payment_status from order where user_id = 1,得到payment_status=0未支付

订单未支付 支付todo 添加条支付记录,并更改状态 insert into order_payment(order_id) VALUES(1);update order set payment_status = 1 where id = 1;

查找用户是否支付 select id,payment_status from order where user_id = 1,得到payment_status=0未支付

commit

订单未支付 支付todo 添加条支付记录,并更改状态 insert into order_payment(order_id) VALUES(1);update order set payment_status = 1 where id = 1;

commit

结论:在默认的RR事务级别下,由于串行或并行读引起的订单支付记录多了一条。

为了解决上面的业务,我想的有两种解决方案 :

1、可以用innodb默认隔离级别RR加互斥锁for update处理(这个好像会产生死锁)

2、用redis的set原子特性加锁。进行单用户全局锁

不知道还有没有其他更好的解决方案