定时任务运行时大约有20%的概率会出现问题一与问题二
pymysql.err.InternalError: Packet sequence number wrong - got 45 e
大致意思是当前数据库连接发了一个序号的45的包,但收到的包序号不是45,错乱了。网上查找了各种资料,大致都说是多线程引起,即多个线程共用了同一个数据库连接解决方案有如下:
使用了多线程,多线程共享了同一个数据库连接,但每个execute前没有加上互斥锁
方法一:每个execute前加上互斥锁
lock.acquire()
cursor.execute(command,data)
lock.release()
每个线程拥有自己的数据库连接,即在线程调用函数中加上数据库连接代码
所有线程共用一个连接池,需要考虑线程总数和连接池连接数上限的问题
尝试了各种方法,还把每个线程db.session中数据库连接对象的内存地址打印出来了,确定每个线程都是唯一的,没有共用。
db.session是个全局对象,所有线程引用的都是同一个对象,不是每个线程一个。但是数据库连接只是db.session对象中的一个属性,这个属性存储在db.session.registry.registry中,registry是werkzeug.local.Local()类型的对象为key-value存储结构,key为当前线程ID,value为每个线程独立的值。每个线程一个连接,互不影响互不干扰。可以通过如下语句获取当前线程的数据库连接对象:db.session.registry.registry.get(threading.get_ident()))
(sqlalchemy.exc.InvalidRequestError) Can’t reconnect until invalid transaction is rolled back
大致的意思是在同一个数据库连接中,在发起新的数据库请求前,必须先关闭掉之前报错的事务,不要认为自己没有开启事务,采用Flask-SQLAlchemy时,即使是最简单的select语句,也会自动开启事务,查询完成时会自动回滚。如下日志:
2019-08-10 12:42:18,312 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2019-08-10 12:42:18,312 - Thread-1 - 123145310482432 - log.py - info - 110 -【INFO】- BEGIN (implicit)
2019-08-10 12:42:18,319 INFO sqlalchemy.engine.base.Engine SELECT user.status AS user_status, user.id AS user_id, user.username AS user_username, user.name AS user_name, user.phone AS user_phone, user.email AS user_email, user.address AS user_address, user.remark AS user_remark, user.create_time AS user_create_time
FROM user
WHERE user.status = %(status_1)s
2019-08-10 12:42:18,319 - Thread-1 - 123145310482432 - log.py - info - 110 -【INFO】- SELECT user.status AS user_status, user.id AS user_id, user.username AS user_username, user.name AS user_name, user.phone AS user_phone, user.email AS user_email, user.address AS user_address, user.remark AS user_remark, user.create_time AS user_create_time
FROM user
WHERE user.status = %(status_1)s
2019-08-10 12:42:18,319 INFO sqlalchemy.engine.base.Engine {‘status_1’: 1}
2019-08-10 12:42:18,319 - Thread-1 - 123145310482432 - log.py - info - 110 -【INFO】- {‘status_1’: 1}
2019-08-10 12:42:18,329 INFO sqlalchemy.engine.base.Engine ROLLBACK
2019-08-10 12:42:18,329 - Thread-1 - 123145310482432 - log.py - info - 110 -【INFO】- ROLLBACK
sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (1040, ‘Too many connections’)
默认情况下mysql服务器端最大允许154个连接,此错误即是客户端发起的连接数太多,已经超过了数据库服务端的最大限制,从而导致的报错。但是ThreadPoolExecutor只开了20个线程,加上个别的访问请求,肯定不多超过154的限制,但定时任务运行时查看Mysql的连接(show processlist)时却一直在涨,直到超过限制报错。