记一次关于MySQL与PHP的蠢事

时间:2022-07-22
本文章向大家介绍记一次关于MySQL与PHP的蠢事,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

事情是这样的

缘由:

一个稍微有些小复杂的事务。首先需要初始化一些记录的值,然后选取一些新的记录,对新的记录进行排序,然后再将排序等信息写入。

出现的问题:

SQL是按照 id in (xxx, xxx) 来写的。

# 这就是问题所在, 按这个查找 会出现一些意料不到的问题。
SELECT * FROM infos WHERE id IN(55001170412000002)

数据库id 存储是使用的 varchar(50), id形如 55001170412000002, 已经超过了默认的int11。

之前的失误

由于内部系统,使用的CI没有考虑注入之类的安全问题。 直接使用客户端传递的字段 拼接SQL。前端使用Ajax传递的数字型列表。后台处理方式是简单的增加了 ''。

这个其实是没问题的。问题是 在SQL中,使用了未添加 '' 的列表。

/* $ids_ 为处理过的字符串型列表、$ids 为原始数字型的列表 */
SELECT * FROM '.self::$infos.' WHERE id IN('.$ids.') ORDER BY FIELD(id, '.$ids_.');

第一次错误的处理

在前端 将数字型列表 修改为 字符串型列表。

然后发现后端有处理过的$ids_,然后把SQL修改 全部使用处理过的。

并将前端的修改force push,回滚到未修改的版本。第一次失误:(此处JS存在缓存问题...但当时还没有发现)。

修改之后发现更严重的问题。前端修改排序之后,提交一直等待,然后

Query error: Lock wait timeout exceeded; try restarting transaction

数据库死锁....

第二次修改

第二次失误:使用Postman模拟数据提交,但是却没有再次确认浏览器提交的数据格式。

这也导致了,使用Postman偶尔可以正常提交,多数也是死锁的情况。

第三次修改

第三次失误:粗心的忽略了后台数据库SQL本身报错。也就是 给列表字段加了两次 '''' 单引号。

Query error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'xxxx'

第四个失误:而不是第四次。发现 跟着CI官网的 数据库事务。并没有 try...catch...

这时应该真相就出来了。

开启事务-->执行出错-->异常退出 (并没有回滚或者提交导致)

总结

数据库事务 一定要回滚或者提交

try {
	trans()
	commit()
} catch(Exception e) {
	rollback()
} finally {
	close()?
}

MySQL 死锁相关

mysql> SELECT * FROM information_schema.INNODB_TRXG
*************************** 1. row ***************************
                    trx_id: 8483802
                 trx_state: RUNNING
               trx_started: 2017-04-24 20:53:54
     trx_requested_lock_id: NULL
          trx_wait_started: NULL
                trx_weight: 12
       trx_mysql_thread_id: 111844
                 trx_query: NULL
       trx_operation_state: NULL
         trx_tables_in_use: 0
         trx_tables_locked: 0
          trx_lock_structs: 5
     trx_lock_memory_bytes: 1248
           trx_rows_locked: 15
         trx_rows_modified: 7
   trx_concurrency_tickets: 0
       trx_isolation_level: REPEATABLE READ
         trx_unique_checks: 1
    trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
 trx_adaptive_hash_latched: 0
 trx_adaptive_hash_timeout: 10000
          trx_is_read_only: 0
trx_autocommit_non_locking: 0
1 row in set (0.04 sec)

# 确认无效后,直接kill掉即可
mysql> kill 111844;
Query OK, 0 rows affected (0.04 sec)