mysql会话是客户端连接到断开期间的有状态交互过程,拥有独立内存和配置,会话变量仅在当前连接生效且随连接结束而清除。

MySQL 会话(session)就是你用客户端(比如 mysql -u root -p 或 Python 的 pymysql)连上 MySQL 后,从建立连接到断开连接之间那一段“有状态的交互过程”。它不是抽象概念,而是一个真实存在的、带独立内存和配置的运行实例。
会话变量只在当前连接里生效,关掉终端就清空
每个会话启动时,会从全局变量(@@GLOBAL.xxx)拷贝一份初始值作为自己的会话变量(@@SESSION.xxx)。之后你在该连接里改的任何 SET SESSION xxx = ...,都只影响自己,别人看不见,重启连接也不保留。
-
SET SESSION sort_buffer_size = 2M;—— 只让这个连接的排序更快,不影响其他应用或后台任务 -
SET SESSION time_zone = '+08:00';—— 避免NOW()返回 UTC 时间导致业务逻辑错乱 -
SET SESSION sql_mode = 'STRICT_TRANS_TABLES';—— 在测试环境临时开启严格模式,不改动生产全局配置
常见错误:在某个连接里执行了 SET sort_buffer_size = 2M;(漏写 SESSION),结果 MySQL 默认尝试改会话级变量,但因权限不足失败;或者误写成 SET GLOBAL,导致所有新连接都被影响,引发线上查询变慢。
会话生命周期 = 连接存在时间,不是 SQL 执行时间
一个会话始于 TCP 握手或 Unix socket 连接成功,终于你执行 EXIT、客户端崩溃、网络中断,或触发了 wait_timeout / interactive_timeout 超时。它和你执行多少条 SQL 无关——哪怕你连上去只敲了一条 SELECT 1; 就走人,这也是一个完整会话。
- 超时参数默认是 28800 秒(8 小时),长连接服务(如 Java 应用)务必确认是否设置了合理的
wait_timeout,否则连接池里大量“假活”连接会耗尽max_connections - MyBatis 的
SqlSession、JDBC 的Connection对象,底层都对应一个 MySQL 会话;close()不只是释放内存,更是向 MySQL 发送COM_QUIT包,真正结束会话 - 用
SHOW PROCESSLIST;看到的每一行,就是一个活跃会话;Command列为Sleep表示已连接但没在执行语句,仍在计时中
会话级配置常被忽略的三个硬坑
很多性能问题或字符乱码,根源不在表结构或 SQL 写法,而在会话初始化阶段没设对关键变量:
-
字符集错配:即使数据库/表是
utf8mb4,若会话的character_set_client、character_set_connection、character_set_results不一致,插入中文可能变成???,且SELECT返回的字段名也乱码 -
事务隔离级别未显式设置:默认是
REPEATABLE-READ,但某些微服务场景需要READ-COMMITTED来避免间隙锁阻塞;靠框架自动设?别信——检查连接池是否真传了sessionVariables=transaction_isolation=READ-COMMITTED -
SQL 模式被静默覆盖:Docker 启动的 MySQL 容器常带
--sql-mode=STRICT_TRANS_TABLES,但 JDBC URL 若没加sessionVariables=sql_mode='',老应用可能因严格模式报错中断
SET SESSION character_set_client = 'utf8mb4'; SET SESSION character_set_connection = 'utf8mb4'; SET SESSION character_set_results = 'utf8mb4';
这三个必须一起设,缺一不可;只设 character_set_client 是最常见的半吊子操作。
会话不是黑盒,它是你和 MySQL 之间最直接的“对话通道”。多数线上问题——慢查、乱码、锁等待、权限拒绝——追到底,八成要翻 SHOW VARIABLES LIKE '%xxx%'; 和 SHOW STATUS LIKE 'Threads_%'; 看当前会话状态。别总盯着 SQL 本身,先确认你坐的是哪张“聊天桌”。










