Laravel 中出现异常报错 Wrong COM_STMT_PREPARE response size. Received 7

本文介绍了一种解决PHP项目中出现的WrongCOM_STMT_PREPAREresponsesize错误的方法,通过调整PDO配置参数PDO::ATTR_EMULATE_PREPARES及PDO::ATTR_STRINGIFY_FETCHES来解决因数据库迁移引发的问题,并提供了四种不同配置组合的实验结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天项目出现Wrong COM_STMT_PREPARE response size. Received 7
输入图片说明

原本以为近期迁移数据库导致的 后来发现pdo连接配置有问题

需要在配置里加上这一项 PDO::ATTR_EMULATE_PREPARES => true

'mysql' => [
  'driver' => 'mysql',
  'host' => env('DB_HOST', 'localhost'),
  //.......
  'options'   => [PDO::ATTR_EMULATE_PREPARES => true,]
],

PDO::ATTR_STRINGIFY_FETCHES(提取的时候将数值转换为字符串)
PDO::ATTR_EMULATE_PREPARES(启用或禁用预处理语句的模拟)

做如下配置后mysql返回数据测试


$pdo = new PDO($dsn, $user, $pass, $options);


/* 实验1,结果 int 不转为 string */  

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);

/* 实验2,结果 int 转为 string */  

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);

/* 实验3,结果 int 转为 string */  

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
$pdo->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);

/* 实验4,结果 int 转为 string */  

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
$pdo->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);

转载于:https://my.oschina.net/ives/blog/1813166

<think>我们分析这段代码,它主要完成SQLite语句的预处理(prepare)操作,并封装成一个std::shared_ptr管理的对象,同时记录了一些性能和错误日志。代码分析如下:1.声明一个原始语句指针`sqlite3_stmt*raw_stmt=nullptr;`,用于接收预处理后的语句句柄。2.创建一个`CostHelper`对象,用于计算准备语句所花费的时间(性能统计)。3.调用`sqlite3_prepare_v3`函数准备SQL语句。如果返回不是`SQLITE_OK`,则打印错误并返回-1。4.准备完成后,记录当前SQLite内存使用情况(日志级别为ERROR,可能是为了调试或监控)。5.获取准备语句所花费的时间(`cost_helper.GetCost()`)。6.即使没有超过阈值,这里也注释掉了条件判断,直接打印了一条INFO级别的日志,记录了准备语句所花费的系统时间和线程CPU时间,以及数据库句柄和SQL语句。7.将原始语句指针`raw_stmt`封装到一个`std::shared_ptr`中,并指定了自定义删除器。在删除器中,当需要释放这个语句句柄时,会调用`sqlite3_finalize`,并在失败且数据库句柄存在时打印错误。注意:代码中有一段被注释的条件判断,原本可能是想当时间消耗超过某个阈值时才打印日志,但现在是无论消耗多少时间都打印INFO日志。下面我们针对这段代码提出一些相关问题。§§相关问题§§:1.`sqlite3_prepare_v3`函数的作用是什么?它的各个参数分别代表什么?2.为什么要使用`std::shared_ptr`来管理`sqlite3_stmt*`?自定义删除器的作用是什么?3.代码中`CostHelper`的作用是什么?它是如何实现计时功能的?4.在自定义删除器中,为什么要先获取`db_pointer`(通过`sqlite3_db_handle(stmt)`)?这样做的目的是什么?5.这段代码中日志记录的设计有什么优缺点?在生产环境中,你认为应如何改进日志记录?</think>### 代码分析 这段代码主要实现 SQLite 语句预处理 (`sqlite3_prepare_v3`) 的封装,包含错误处理、性能监控和资源管理。核心流程如下: 1. **预处理 SQL 语句** 调用 `sqlite3_prepare_v3` 编译 SQL 语句,生成底层语句句柄 `raw_stmt`。 2. **错误处理** 若预处理失败,打印错误信息并返回 `-1`。 3. **性能监控** - 记录当前 SQLite 内存使用量 (`sqlite3_memory_used`) - 通过 `CostHelper` 计算预处理耗时 - 打印耗时日志(无条件记录,注释显示原本计划超过阈值才记录) 4. **资源管理** 用 `std::shared_ptr` 托管 `raw_stmt`,自定义删除器确保语句句柄安全释放(调用 `sqlite3_finalize`)。 --- ### 关键代码解释 #### 1. 语句预处理与错误处理 ```cpp if (sqlite3_prepare_v3(db_handle.get(), sql.data(), -1, flag, &raw_stmt, nullptr) != SQLITE_OK) { PrintSQLiteError(GetSQLiteError(db_handle), __FILE__, __LINE__); // 打印错误 return -1; // 返回错误码 } ``` - **参数说明**: - `db_handle`:数据库连接句柄 - `sql.data()`:待编译的 SQL 语句 - `-1`:自动计算 SQL 字符串长度 - `flag`:预处理标志(如 `SQLITE_PREPARE_PERSISTENT`) - **错误处理**:获取错误信息并记录文件名、行号。 #### 2. 性能监控日志 ```cpp SQLITE_LOG_ERROR("current sqlite memory used: %lld bytes...", sqlite3_memory_used(), ...); const auto cost = cost_helper.GetCost(); // 获取耗时 SQLITE_LOG_INFO("Prepare cost:%lu:%lu ...", cost.sys_time_cost_ns, ...); ``` - `sqlite3_memory_used()`:获取 SQLite 当前内存使用量 - `cost_helper.GetCost()`:返回包含系统时间和 CPU 时间的结构体 #### 3. 智能指针资源管理 ```cpp stmt_ = std::shared_ptr<sqlite3_stmt>(raw_stmt, [](sqlite3_stmt* stmt) { if (stmt) { auto db_pointer = sqlite3_db_handle(stmt); // 获取关联的数据库连接 SQLITE_LOG_ERROR("sqlite3_finalize stmt:%p \n", stmt); if (sqlite3_finalize(stmt) != SQLITE_OK && db_pointer) { PrintSQLiteError(GetSQLiteErrorRaw(db_pointer), __FILE__, __LINE__); } } }); ``` - **自定义删除器**:释放时调用 `sqlite3_finalize` 销毁语句 - **错误兜底**:若释放失败,通过 `sqlite3_db_handle` 获取关联数据库连接打印错误 - **空指针检查**:避免对空指针调用 `sqlite3_finalize` --- ### 潜在改进点 1. **条件日志优化** 取消注释阈值检查,避免高频小语句污染日志: ```cpp if (cost.sys_time_cost_ns > cost_threshold_for_print_) { SQLITE_LOG_INFO(...); // 仅耗时超阈值时记录 } ``` 2. **内存泄漏风险** 若 `sqlite3_prepare_v3` 部分成功(返回非 `OK` 但 `raw_stmt` 非空),需额外清理: ```cpp if (raw_stmt != nullptr) { sqlite3_finalize(raw_stmt); // 确保资源释放 } ``` 3. **耗时统计范围** `CostHelper` 应在 `sqlite3_prepare_v3` **之前**初始化,否则统计不完整。 --- ### 日志输出示例 ```log [ERROR] current sqlite memory used: 1024000 bytes, handle:123 raw_stmt:0x7f8a... [INFO] Prepare cost:150000:120000 handle:123 sql:SELECT * FROM users [ERROR] sqlite3_finalize stmt:0x7f8a... // 语句释放日志 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值