- TP ORM使用问题
- 非协程常驻内存模式
- think\Db 静态变量:
- think\Model 静态变量:
- think\db\Connection 静态变量:
- think\db\Query 静态变量:
- think\Db\ModelEvent 静态变量:
- 协程常驻内存模式
- 非协程常驻内存模式
TP ORM使用问题
由于swoole 是在常驻内存+协程环境下运行的,使用TP ORM 时,TP ORM自带了很多静态变量,将会出现问题,具体分析如下:
非协程常驻内存模式
在同步,非协程模式下,一个worker在一个时间内只处理一个请求,到max_request时也将重启进程,可以勉强操作sql,但是以下静态变量会出现问题:
think\Db 静态变量:
protected static $config = [];//数据库配置,几乎没有影响protected static $query;//查询类名,没有影响protected static $queryMap = ['mongo' => '\\think\\db\Mongo',];//查询类自动映射,没有影响public static $queryTimes = 0;//数据库查询次数//常驻内存下是全局查询次数public static $executeTimes = 0;//执行次数//常驻内存下其实是全局执行执行次数protected static $cacheHandler;//缓存对象,没有影响
think\Model 静态变量:
protected static $initialized = [];//初始化过的模型.//原本作用:确保一个模型类中的init方法在一次请求中只被执行一次//常驻内存下:一个模型只在第一次请求时执行该方法,后续请求不再执行,极有可能会造成bugprotected static $readMaster;//是否从主库读取数据//几乎没有影响
think\db\Connection 静态变量:
protected static $instance = [];//PDO操作实例//建立的连接管理实例//协程模式,高并发下可能会导致数据库操作bugprotected static $event = [];//监听回调//原本作用:给模型设置的事件回调//常驻内存下:随着运行时间不断增加将不断增加运行内存,一次请求增加的事件将影响到另外一次请求protected static $info = [];// 数据表信息// 几乎没有影响protected static $log = [];// 数据库日志// 原本作用: 记录一个请求的所有日志操作// 常驻内存: 随着数据库的不断操作,会使该变量不断增加,会造成内存溢出
think\db\Query 静态变量:
protected static $connections = [];// 数据库Connection对象// 暂时没发现使用的地方private static $event = [];//回调事件//原本作用:一次请求下,设置自身的回调事件//常驻内存下:一次请求增加的事件将影响到另外一次请求private static $extend = [];//扩展查询方法//几乎没有影响private static $readMaster = [];//需要读取主库的表//原本作用:设置某一个或者全部模型是否从主库读取数据//常驻内存下:如果在一个请求执行了Query::readMaster()方法,Query::$readMaster不会释放,将会影响到其他请求
think\Db\ModelEvent 静态变量:
private static $event = [];// 回调事件//原本作用:给模型设置的事件回调//常驻内存下:随着运行时间不断增加将不断增加运行内存,一次请求增加的事件将影响到另外一次请求protected static $observe = ['before_write', 'after_write', 'before_insert', 'after_insert', 'before_update', 'after_update', 'before_delete', 'after_delete', 'before_restore', 'after_restore'];//模型事件观察//没有影响
协程常驻内存模式
在协程模式下,多个客户端共用一个数据库连接,将会出现数据库操作异常问题,
例如:
- 用户A访问业务A,数据库开启事务->支付逻辑->完成事务
- 用户B同时访问业务B,插入n条数据
- 用户C同时访问业务A,数据库开启事务->支付逻辑->逻辑出错,回滚
在这个逻辑中,由于都是共享一个数据库操作,并且受协程切换影响,数据库执行步骤可能会变为:
用户A数据库开启事务->用户B插入n条数据->用户C开启事务->用户A支付逻辑->用户C支付逻辑->用户C逻辑错误,回滚事务->用户A完成事务
当数据库这样执行时,用户A,B,C的所有数据库操作都将回滚,但是前端可能却会返回成功.
同样,由于静态变量共用,其他回调事件等问题同样存在
