mysql中操作事务时要注意的事项

操作事务是个很普遍的过程,凡时对数据库的修改有相互依赖都应该使用事务解决。操作事务时要注意以下几点:

1、尽量使用Exception捕获MYSQL的异常

所以第一步:要设置PDO的异常模式为PDO::ERRMODE_EXCEPTION,PDO::ATTR_ERRMODE,有以下三个值:

  • PDO::ERRMODE_SILENT: 默认模式,不主动报错,需要主动以 $pdo->errorInfo()的形式获取错误信息。
  • PDO::ERRMODE_WARNING: 引发 E_WARNING 错误,主动报错
  • PDO::ERRMODE_EXCEPTION: 主动抛出 exceptions 异常,需要以try{}cath(){}输出错误信息。

我们在连接MYSQL时使用以下:

$pdo=new pdo("mysql:host=localhost;dbname=dbname","user","****", array(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION));

将上面这句代码写在try catch中,捕获异常,注意PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION必须写在new pdo中。不然mysql连接错误的信息是捕获不到的。catch中的类限制为PDOException,如果有命名空间注意在前面加上顶级命名空间,不然也捕获不了异常的。

2、MYSQL的事务开始前先关闭AUTOCOMMIT

$pdo->setAttribute(PDO::ATTR_AUTOCOMMIT, 0);
$rs = $pdo->beginTransaction();

注意beginTransaction是有返回值的,在调用事务beginTransaction时最好判断其返回值,如果本身返回为false,则后面就不用再回滚。

3、操作事务及回滚

切记在所有的return之前或者其它结束事务之前都记得调用rollBack方法,rollBack方法中也是有返回值的,最好判断返回值,并重试2次回滚,以防止一次回滚发生异常,导致事务锁住。

4、执行开启自动提交

$pdo->setAttribute(PDO::ATTR_AUTOCOMMIT, 1);

此步非常关键,不管是执行commit还是执行rollBack都务必执行此步,自动提交的意义是你执行的每一句SQL是否直接执行MYSQL.默认的MYSQL就是自动提交的,即你执行一条SQL语句,它就更改到数据库,如果MYSQL不是自动提交,则你执行的MYSQL语句就全部卡在那里等待执行。

事务出现异常时最常出现的现象就是前端浏览器涉及到被锁表或行的请求都处在等待中,最后可能报错mysql innodb Lock wait timeout exceeded; try restarting transaction问题,此时:

第一:可通过SHOW ENGINE INNODB STATUSG;查询报错信息,这个信息量太大了,不好排查。

第二:使用select * from information_schema.innodb_trx G; 查询运行的任务列表。

mysql> select * from information_schema.innodb_trx G;                  
*************************** 1. row ***************************
                    trx_id: 1429E713A
                 trx_state: RUNNING
               trx_started: 2018-04-02 16:25:31
     trx_requested_lock_id: NULL
          trx_wait_started: NULL
                trx_weight: 0
       trx_mysql_thread_id: 23698460
                 trx_query: NULL
       trx_operation_state: NULL
         trx_tables_in_use: 0
         trx_tables_locked: 0
          trx_lock_structs: 0
     trx_lock_memory_bytes: 376
           trx_rows_locked: 0
         trx_rows_modified: 0
   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
mysql> select trx_id,trx_started,trx_state,trx_mysql_thread_id,trx_rows_locked from information_schema.innodb_trx;     
+-----------+---------------------+-----------+---------------------+-----------------+
| trx_id    | trx_started         | trx_state | trx_mysql_thread_id | trx_rows_locked |
+-----------+---------------------+-----------+---------------------+-----------------+
| 1429E713A | 2018-04-02 16:25:31 | RUNNING   |            23698460 |               0 |
| 1429E7138 | 2018-04-02 16:25:31 | RUNNING   |            23698458 |               0 |
| 1429E7136 | 2018-04-02 16:25:31 | RUNNING   |            23697458 |               0 |
| 1429E6734 | 2018-04-02 16:14:39 | RUNNING   |            23698477 |               1 |
+-----------+---------------------+-----------+---------------------+-----------------+
4 rows in set (0.00 sec)
#可以通过trx_mysql_thread_id值查询processlist查看导致异常的mysql连接
select * from information_schema.processlist where and id =23698477;

第三,可以排查mysql的bin日志:MYSQL日志文件: show variables like general_log_file;

mysql>  show variables like 'general_log_file';
+------------------+-------------------------------+
| Variable_name    | Value                         |
+------------------+-------------------------------+
| general_log_file | /opt/data/mysql/localhost.log |
+------------------+-------------------------------+
1 row in set (0.00 sec)

找到日志文件,直接查看binlog文件可能有乱码。

/opt/modules/mysql/bin/mysqlbinlog --base64-output=DECODE-ROWS  mysql-bin.000098

但上面的这个命令只能将已有的日志文件解码展示,不区分里面的数据库,如果日志文件很大,就歇菜了。下面的命令可以指定数据库开始时间:

/opt/modules/mysql/bin/mysqlbinlog --start-datetime='2018-04-02 10:25:00' -d baotoutiao mysql-bin.000098

但上面的命令都不够好,下面这个最佳。可以实现模拟tail -f的功能。并且可指定数据库,非常好用。

export D=$(date +"%Y-%m-%d %H:%M:%S" --date="1 minutes ago"); watch "/opt/modules/mysql/bin/mysqlbinlog --start-datetime="$D" -d dbname --base64-output=decode-rows -v mysql-bin.000098|tail -n 50"
标签:MySQL 发布于:2019-10-25 15:48:48