public function test()
{
$model = new Customer();
$data = [
'phone' => '11012010086'
];
$model->replace(true)->save($data);
return $model->getLastSql();
}
问题描述:此处的replace(true)是不生效的,最终生成的sql依然是insert into 而不是预期的replace into
在源码中think/db/Connection类中 951行
/**
* 插入记录
* @access public
* @param Query $query 查询对象
* @param boolean $getLastInsID 返回自增主键
* @return mixed
*/
public function insert(Query $query, bool $getLastInsID = false)
{
// 分析查询表达式
$options = $query->parseOptions();
// 生成SQL语句
$sql = $this->builder->insert($query);
此处的代码根据builder走向不同的类, 测试代码中的模型操作在这里指向了think/db/Mysql类,源码如下:
/**
* 生成Insert SQL
* @access public
* @param Query $query 查询对象
* @param bool $replace 是否replace
* @return string
*/
public function insert(Query $query, bool $replace = false): string
{
$options = $query->getOptions();
// 分析并处理数据
$data = $this->parseData($query, $options['data']);
if (empty($data)) {
return '';
}
$set = [];
foreach ($data as $key => $val) {
$set[] = $key . ' = ' . $val;
}
return str_replace(
['%INSERT%', '%EXTRA%', '%TABLE%', '%PARTITION%', '%SET%', '%DUPLICATE%', '%COMMENT%'],
[
$replace ? 'REPLACE' : 'INSERT',
$this->parseExtra($query, $options['extra']),
$this->parseTable($query, $options['table']),
$this->parsePartition($query, $options['partition']),
implode(' , ', $set),
$this->parseDuplicate($query, $options['duplicate']),
$this->parseComment($query, $options['comment']),
],
$this->insertSql);
}
可以看到源码中此处的$replace是作为方法的参数单独存在的,而测试代码中replace()的设置在$options数组中,因此导致replace()未生效因其没有在Connection中显示传递,也没有获取$options中的replace来判断
此处可以修改
$replace ? 'REPLACE' : 'INSERT',
为与think/db/Builder中的一致!empty($options['replace']) ? 'REPLACE' : 'INSERT',
来修复该问题,但暂不清楚$replace作为单独参数存在的意义,希望@ThinkPHP 流年能解惑。 最佳答案
