TP ORM使用问题

由于swoole 是在常驻内存+协程环境下运行的,使用TP ORM 时,TP ORM自带了很多静态变量,将会出现问题,具体分析如下:

非协程常驻内存模式

在同步,非协程模式下,一个worker在一个时间内只处理一个请求,到max_request时也将重启进程,可以勉强操作sql,但是以下静态变量会出现问题:

think\Db 静态变量:

  1. protected static $config = [];
  2. //数据库配置,几乎没有影响
  3. protected static $query;
  4. //查询类名,没有影响
  5. protected static $queryMap = [
  6. 'mongo' => '\\think\\db\Mongo',
  7. ];
  8. //查询类自动映射,没有影响
  9. public static $queryTimes = 0;
  10. //数据库查询次数
  11. //常驻内存下是全局查询次数
  12. public static $executeTimes = 0;
  13. //执行次数
  14. //常驻内存下其实是全局执行执行次数
  15. protected static $cacheHandler;
  16. //缓存对象,没有影响

think\Model 静态变量:

  1. protected static $initialized = [];
  2. //初始化过的模型.
  3. //原本作用:确保一个模型类中的init方法在一次请求中只被执行一次
  4. //常驻内存下:一个模型只在第一次请求时执行该方法,后续请求不再执行,极有可能会造成bug
  5. protected static $readMaster;
  6. //是否从主库读取数据
  7. //几乎没有影响

think\db\Connection 静态变量:

  1. protected static $instance = [];
  2. //PDO操作实例
  3. //建立的连接管理实例
  4. //协程模式,高并发下可能会导致数据库操作bug
  5. protected static $event = [];
  6. //监听回调
  7. //原本作用:给模型设置的事件回调
  8. //常驻内存下:随着运行时间不断增加将不断增加运行内存,一次请求增加的事件将影响到另外一次请求
  9. protected static $info = [];
  10. // 数据表信息
  11. // 几乎没有影响
  12. protected static $log = [];
  13. // 数据库日志
  14. // 原本作用: 记录一个请求的所有日志操作
  15. // 常驻内存: 随着数据库的不断操作,会使该变量不断增加,会造成内存溢出

think\db\Query 静态变量:

  1. protected static $connections = [];
  2. // 数据库Connection对象
  3. // 暂时没发现使用的地方
  4. private static $event = [];
  5. //回调事件
  6. //原本作用:一次请求下,设置自身的回调事件
  7. //常驻内存下:一次请求增加的事件将影响到另外一次请求
  8. private static $extend = [];
  9. //扩展查询方法
  10. //几乎没有影响
  11. private static $readMaster = [];
  12. //需要读取主库的表
  13. //原本作用:设置某一个或者全部模型是否从主库读取数据
  14. //常驻内存下:如果在一个请求执行了Query::readMaster()方法,Query::$readMaster不会释放,将会影响到其他请求

think\Db\ModelEvent 静态变量:

  1. private static $event = [];
  2. // 回调事件
  3. //原本作用:给模型设置的事件回调
  4. //常驻内存下:随着运行时间不断增加将不断增加运行内存,一次请求增加的事件将影响到另外一次请求
  5. protected static $observe = ['before_write', 'after_write', 'before_insert', 'after_insert', 'before_update', 'after_update', 'before_delete', 'after_delete', 'before_restore', 'after_restore'];
  6. //模型事件观察
  7. //没有影响

协程常驻内存模式

在协程模式下,多个客户端共用一个数据库连接,将会出现数据库操作异常问题, 例如:

  • 用户A访问业务A,数据库开启事务->支付逻辑->完成事务
  • 用户B同时访问业务B,插入n条数据
  • 用户C同时访问业务A,数据库开启事务->支付逻辑->逻辑出错,回滚

在这个逻辑中,由于都是共享一个数据库操作,并且受协程切换影响,数据库执行步骤可能会变为: 用户A数据库开启事务->用户B插入n条数据->用户C开启事务->用户A支付逻辑->用户C支付逻辑->用户C逻辑错误,回滚事务->用户A完成事务
当数据库这样执行时,用户A,B,C的所有数据库操作都将回滚,但是前端可能却会返回成功.

同样,由于静态变量共用,其他回调事件等问题同样存在