• redis和mysql数据一致问题
    Redis 作为缓存层,MySQL 作为存储层,两者数据一致性问题是分布式系统中的常见挑战。以下从不一致原因、解决方案、适用场景三方面详细分析,并提供实践建议。一、数据不一致的核心原因缓存更新策略问题先更新数据库,再更新缓存并发场景下可能导致缓存与数据库数据不一致。示例:线程 A 更新数据库字段 count=10。线程 B 读取缓存(旧值 count=5)并完成业务逻辑。线程 A 更新缓存为 count=10。最终缓存与数据库一致,但线程 B 读取到了旧值。先更新缓存,再更新数据库数据库更新失败时,缓存与数据库数据不一致。示例:线程 A 更新缓存为 count=10。数据库更新操作因网络问题失败,缓存为新值,数据库为旧值。缓存穿透、击穿、雪崩缓存穿透:大量请求访问不存在的数据,直接击穿缓存到数据库,导致数据库压力陡增,可能因脏数据更新缓存引发不一致。缓存击穿:热点数据过期瞬间,大量请求同时访问数据库,可能因更新顺序问题导致缓存与数据库不一致。缓存雪崩:大量缓存集中过期,请求涌入数据库,若数据库更新不及时,缓存重建后可能携带旧数据。异步更新与延迟问题异步队列(如 Kafka)处理缓存更新时,若队列积压或消费失败,会导致缓存更新延迟,引发数据不一致。二、解决方案:保证数据最终一致性缓存更新策略优化策略 实现逻辑 适用场景 优缺点Cache-Aside(旁路缓存) 读操作:先查缓存,命中则返回未命中则查数据库,更新缓存写操作:先更新数据库,再删除缓存 读多写少场景(如商品详情页) - 优点:逻辑简单,避免脏数据缺点:删除缓存后首次读会穿透到数据库Write-Through(写穿) 写操作时同时更新数据库和缓存,两者都成功才算操作完成 对一致性要求极高的场景 - 优点:强一致性缺点:性能较低(两次写操作)Write-Behind(写回) 写操作时先更新缓存,再通过异步任务批量更新数据库(类似 Linux 磁盘缓存机制) 写多读少场景(如日志系统) - 优点:高性能缺点:异步任务失败会导致数据丢失Delete Cache(删除缓存) 写操作时先更新数据库,再删除缓存(主流方案,需结合重试或消息队列) 大多数读写混合场景 - 优点:避免缓存与数据库双写不一致缺点:需处理缓存击穿问题推荐方案:读多写少场景:采用 Cache-Aside + 删除缓存,写操作后删除缓存,读操作时自动重建缓存。写多读少场景:采用 Write-Behind + 异步重试,通过队列保证数据库最终更新。解决缓存穿透、击穿、雪崩缓存穿透:对不存在的数据,缓存一个特殊值(如 null)并设置短过期时间(如 5 分钟),避免重复查询数据库。使用布隆过滤器(Bloom Filter)提前过滤无效请求。缓存击穿:对热点数据设置互斥锁(如 Redis 的 setnx),确保同一时间只有一个线程重建缓存。延长热点数据过期时间,或采用逻辑过期(在缓存值中存储过期时间,业务层判断是否需要异步更新)。缓存雪崩:给缓存过期时间添加随机抖动(如 TTL=300s±30s),避免集中过期。启用 Redis 集群的主从复制和哨兵机制,保障缓存层高可用。对核心业务添加熔断机制(如 Hystrix),防止数据库被压垮。异步更新与补偿机制消息队列异步更新缓存:写操作时,先更新数据库,再向消息队列(如 Kafka、RabbitMQ)发送一条更新缓存的消息,消费者监听队列并执行缓存删除或更新操作。示例流程:是否更新 MySQL成功?发送消息到队列返回失败消费者消费消息,删除 Redis 缓存重试与死信队列:若缓存更新失败,将消息放入重试队列(如延迟队列),多次重试后仍失败则放入死信队列,人工处理。定期扫描数据库 binlog(如使用 Canal),对比缓存数据,自动补偿不一致的记录。4. 读写分离场景的一致性优化主从数据库延迟可能导致从库读到旧数据,进而更新缓存为旧值。解决方案:写操作后强制读主库(如通过业务逻辑判断,写操作后 5 秒内读主库)。使用数据库中间件(如 MyCat)实现读写分离,并提供强制读主库的接口。三、一致性级别与适用场景一致性级别 实现方式 典型场景强一致性 Write-Through(同步更新数据库和缓存) 金融交易、库存扣减最终一致性 Cache-Aside + 消息队列异步更新 + 重试机制 商品详情页、用户信息展示弱一致性 仅删除缓存,依赖读操作重建(允许短时间不一致) 首页推荐、实时统计(如点赞数)四、实践建议优先保证数据库一致性:缓存是提升性能的手段,而非数据存储核心。所有写操作必须以数据库成功为前提,缓存可通过补偿机制最终修正。监控与报警:监控缓存命中率、数据库慢查询、队列积压量等指标。配置报警规则,如缓存与数据库不一致率超过阈值时触发告警。定期全量同步:每天凌晨低谷期,通过定时任务全量扫描数据库,重建缓存(如使用 Redis Pipeline 批量写入),确保冷数据一致性。分场景设计:对一致性要求高的核心数据(如订单状态),采用同步更新策略或分布式事务(如 TCC 模式)。对非核心数据(如用户积分显示),允许秒级不一致,通过异步机制补偿。五、总结Redis 与 MySQL 的数据一致性是最终一致性问题,无法在所有场景下做到强一致。解决方案需结合业务需求,在性能与一致性间权衡:读多写少:优先使用 Cache-Aside + 删除缓存 + 异步重试。写多读少:考虑 Write-Behind + 批量异步更新,或引入搜索中间件(如 Elasticsearch)分担压力。高一致性场景:避免过度依赖缓存,直接操作数据库或使用专业分布式事务框架(如 Seata)。通过合理的缓存策略、补偿机制和监控体系,可将不一致性控制在业务可接受的范围内。
  • [技术干货] MySQL 查询语句的执行顺序
    ​整理了下MySQL查询语句的执行顺序。(1) FROM(2) ON(3) JOIN(4) WHERE(5) GROUP BY(6) WITH (CUBE|ROLLUP)(7) HAVING(8) SELECT(9) DISTINCT(10) ORDER BY(11) LIMIT(1) FROM 子句 - 首先执行FROM employees eMySQL 会先读取 FROM 子句中的表信息(2) ON 条件 - 连接条件过滤JOIN departments d ON e.dept_id = d.id对连接表的行进行匹配只有满足 ON 条件的行才会被保留(3) JOIN 操作 - 执行表连接MySQL 支持多种连接方式:INNER JOIN、LEFT/RIGHT JOIN、CROSS JOIN(4) WHERE 条件 - 行级过滤WHERE e.salary > 5000 AND d.location = 'NY'此时不能使用 SELECT 中的别名不能使用聚合函数(如 COUNT, SUM 等)(5) GROUP BY - 分组操作GROUP BY d.name, e.position可以 GROUP BY 不在 SELECT 中的列分组后每组生成一行结果(6) WITH CUBE/ROLLUP - 生成超组GROUP BY d.name WITH ROLLUP生成小计和总计行(7) HAVING - 分组后过滤HAVING AVG(e.salary) > 6000可以使用聚合函数可以使用 SELECT 中的别名(8) SELECT - 选择输出列SELECT d.name, AVG(e.salary) as avg_sal计算表达式和函数调用定义列别名(9) DISTINCT - 去重操作SELECT DISTINCT departmentMySQL 可能在 GROUP BY 时就已经去重(10) ORDER BY - 结果排序ORDER BY avg_sal DESC可以使用 SELECT 中定义的别名对最终结果集排序,性能消耗较大(11) LIMIT - 结果限制LIMIT 10 OFFSET 5MySQL 特有语法,其他数据库可能用不同方式限制返回的行数转载自https://www.cnblogs.com/yanshajiuzhou/p/18903288
  • [公告] 没有任何备份和其他信息,除了一个表名,某把数据文件删了,看看MySQL布道师Frédéric Descamps是怎么拯救数据库
    现在正值MySQL 30年庆典之际,MySQL布道师Frédéric Descamps 发表了一篇标题为MySQL InnoDB Data Recovery的演讲,基于对演讲内容的兴趣,做了相关测试,并制作视频,分享给大家cid:link_0
  • [技术干货] 从此,SQL 不写一行,智能体全帮我搞定!
    最近我零成本在本地搭了一个 SQL 智能体,不接入云、不付费、支持自然语言问答,简直是我日常开发提效的天花板。原来那些写 SQL 查业务数据、调接口前找字段、优化复杂 JOIN 的痛点,现在统统交给 AI 来搞定,精准又高效。全程本地运行,无需担心数据外泄,也不需要依赖第三方平台,更重要的是 —— 完全开源、零成本,硬核好玩!本篇文章就来分享我如何用最简单的方式,把自己的数据库“喂”给一个懂 SQL 的 AI,打造一个真正为开发者量身定制的“本地数据助理”。SQL 再也不是负担,而是乐趣。👨‍💻🚀what❓在平常的开发工作中,我们常常需要根据业务需求写各种 SQL 查询。尤其在面对复杂的数据库时,编写 SQL 语句时要查找表结构、字段类型、外键关系等,往往需要花费大量时间和精力。虽然 SQL 写得多了,但还是容易出错,特别是写复杂的联合查询(JOIN)和子查询时。再加上开发过程中需求变化频繁,修改 SQL 成了必不可少的工作。于是,我开始思考:有没有一种方式,可以让 AI 代替我写 SQL,自动理解我的需求并给出精准的查询语句?首先是基于安全,其次都是其次how❓经过一些调研和实验,我决定结合 Ollama + 阿里 Qwen2.5:7B 模型,以及 Anything LLM + nomic-embed-text 来搭建这个“SQL 智能体”。最酷的是:整个过程完全是本地化运行,不需要依赖云服务、无需付费、不会有数据泄露的风险。简直是开发者的福音!实现第一步:下载Ollama和所需大模型nomic-embed-text 是一个用于将文本数据嵌入到向量空间的工具,它可以将文本转化为向量表示。通过这种方式,你可以将自然语言文本转化为数值向量,以便进行计算和比较,常用于信息检索、文本相似度计算、聚类、分类等任务。根据你的电脑配置选择下载阿里的模型,当让这里你也可以选择别的模型,看自己需求。第二步:下载Anything LLM并配置首先配置为Ollama+自己所需大模型其次配置首选项第三步:新建工作区并投喂在完成以上步骤后,可以在Anything LLM中新建一个工作区,并投喂DDL信息,进行相关测试进行问答:
  • [交流吐槽] 【话题交流】大家觉得AI驱动数据库可取吗
    网上看到一个帖子说他们公司部署了一个基于AI去操作数据库的功能,然后用了10分钟后发现数据库被删了,大家觉得AI驱动数据库可取吗?
  • MySQL中实现主备架构
    在MySQL中实现主备架构(主从复制)是提升数据库高可用性和读写分离能力的核心方案。以下是分步骤的完整实现指南,涵盖配置、验证、优化及故障处理:一、核心实现原理MySQL主备架构基于**二进制日志(Binary Log)**的异步/半同步复制机制:主库(Master):记录所有数据变更操作到二进制日志。从库(Slave):I/O线程:从主库拉取二进制日志并写入中继日志(Relay Log)。SQL线程:解析并执行中继日志中的SQL语句,实现数据同步。二、配置步骤(以MySQL 8.0为例)1. 前期准备角色IP地址关键配置项主库192.168.1.10server-id=1, log_bin=ON从库192.168.1.11server-id=2, read_only=ON2. 主库配置修改配置文件 /etc/my.cnf:[mysqld] server-id = 1 # 唯一ID,主从不能重复 log_bin = mysql-bin # 启用二进制日志 binlog_format = ROW # 推荐使用ROW格式(数据一致性最佳) expire_logs_days = 7 # 日志保留7天 sync_binlog = 1 # 每次事务提交都同步到磁盘(可选,影响性能)创建复制专用用户:CREATE USER 'repl'@'192.168.1.%' IDENTIFIED BY 'SecurePass123!'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.1.%'; FLUSH PRIVILEGES; 获取二进制日志位置(后续从库配置需用到):SHOW MASTER STATUS; -- 输出示例: -- +------------------+----------+ -- | File | Position | -- +------------------+----------+ -- | mysql-bin.000003 | 154 | -- +------------------+----------+ 3. 从库配置修改配置文件 /etc/my.cnf:[mysqld] server-id = 2 # 唯一ID relay_log = mysql-relay-bin # 中继日志路径 read_only = 1 # 设置为只读(防止误操作) log_slave_updates = 1 # 级联复制时需要(可选)配置复制关系:STOP SLAVE; -- 确保从库处于停止状态 CHANGE MASTER TO MASTER_HOST='192.168.1.10', MASTER_USER='repl', MASTER_PASSWORD='SecurePass123!', MASTER_LOG_FILE='mysql-bin.000003', -- 主库SHOW MASTER STATUS输出的File MASTER_LOG_POS=154; -- 主库SHOW MASTER STATUS输出的Position START SLAVE; 验证复制状态:SHOW SLAVE STATUS\G -- 关键指标: -- Slave_IO_Running: Yes # I/O线程状态 -- Slave_SQL_Running: Yes # SQL线程状态 -- Seconds_Behind_Master: 0 # 延迟(0表示实时同步) 三、生产环境优化建议1. 半同步复制(提升数据安全性)主库配置:[mysqld] rpl_semi_sync_master_enabled = 1 rpl_semi_sync_master_timeout = 1000 # 毫秒,超时后自动降级为异步复制从库配置:[mysqld] rpl_semi_sync_slave_enabled = 1 2. 多线程复制(提升从库性能)[mysqld] slave_parallel_workers = 4 # 根据CPU核心数调整 slave_parallel_type = LOGICAL_CLOCK # 基于组提交的多线程复制(MySQL 5.7+)3. GTID复制(简化复制管理)主库配置:[mysqld] gtid_mode = ON enforce_gtid_consistency = ON 从库配置:CHANGE MASTER TO MASTER_AUTO_POSITION = 1; -- 使用GTID自动定位 四、常见问题与解决方案问题现象可能原因解决方案Slave_IO_Running: No网络不通/权限不足检查防火墙、SELinux、用户权限Last_SQL_Error: Duplicate主键冲突跳过错误:SET GLOBAL sql_slave_skip_counter=1延迟持续增大从库负载过高优化查询、增加复制线程数复制中断主库二进制日志被清理重新配置复制(需主库保留足够日志)五、高可用架构扩展1. 监控脚本示例#!/bin/bash STATUS=$(mysql -uroot -pYourPass -e "SHOW SLAVE STATUS\G" | grep -E "Slave_IO_Running|Slave_SQL_Running|Seconds_Behind_Master") if echo "$STATUS" | grep -q "No"; then echo "ALERT: Replication failed!" | mail -s "MySQL Replication Alert" admin@example.com fi 2. 自动化故障切换(MHA方案)BinlogVIP FailoverReplicationReplicationMasterMHA ManagerCandidate MasterSlave1Slave2六、总结与最佳实践配置要点:确保server-id全局唯一。主从节点间网络畅通(10000/3306端口)。合理设置binlog_expire_logs_seconds(避免日志堆积)。生产环境建议:使用GTID模式简化管理。部署半同步复制防止数据丢失。监控Seconds_Behind_Master和复制错误。扩展方向:结合ProxySQL实现读写分离。使用Orchestrator实现自动化故障切换。通过以上步骤,MySQL主备架构能够为企业级应用提供可靠的数据冗余和故障恢复能力。根据实际业务需求,可进一步扩展为多主多从、级联复制等复杂拓扑。
  • [技术干货] MySQL主备架构搭建指南:从原理到实战
    MySQL主备架构搭建指南:从原理到实战一、引言在企业级应用中,数据库的高可用性是保障业务连续性的核心。MySQL主备架构通过"一主多从"的复制机制,实现了数据冗余、读写分离和故障切换。本文将系统梳理MySQL主备搭建的完整流程,涵盖传统二进制日志复制与GTID复制两种模式,结合生产环境实践案例,提供可落地的技术方案。二、主备架构核心原理1. 复制机制MySQL主备复制基于二进制日志(Binary Log)实现,其工作流程如下:主库操作:所有DML/DDL操作被记录到二进制日志日志传输:从库通过I/O线程请求主库日志中继存储:日志被写入从库的中继日志(Relay Log)SQL重放:SQL线程解析并执行中继日志中的事件2. 关键组件server-id:全局唯一标识符,主从不能重复log_bin:启用二进制日志记录binlog_format:建议使用ROW格式保证数据一致性relay_log:从库中继日志存储路径3. 复制拓扑Binlog EventsRelay LogMaster ServerSlave I/O ThreadSlave SQL ThreadReplicated Database三、传统二进制日志复制模式搭建1. 环境准备角色IP地址操作系统MySQL版本主库192.168.1.10CentOS 7.98.0.28从库192.168.1.11CentOS 7.98.0.282. 主库配置2.1 修改配置文件# /etc/my.cnf [mysqld] server-id = 1 log_bin = /var/lib/mysql/mysql-bin binlog_format = ROW expire_logs_days = 7 binlog_do_db = business_db # 可选:指定同步数据库2.2 创建复制用户CREATE USER 'repl'@'192.168.1.%' IDENTIFIED BY 'SecurePass123!'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.1.%'; FLUSH PRIVILEGES; 2.3 获取二进制日志位置SHOW MASTER STATUS; -- 输出示例: -- +------------------+----------+--------------+------------------+ -- | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | -- +------------------+----------+--------------+------------------+ -- | mysql-bin.000003 | 154 | business_db | | -- +------------------+----------+--------------+------------------+ 3. 从库配置3.1 修改配置文件# /etc/my.cnf [mysqld] server-id = 2 relay_log = /var/lib/mysql/mysql-relay-bin read_only = 1 # 确保从库只读3.2 配置复制关系STOP SLAVE; -- 确保从库处于停止状态 CHANGE MASTER TO MASTER_HOST='192.168.1.10', MASTER_USER='repl', MASTER_PASSWORD='SecurePass123!', MASTER_LOG_FILE='mysql-bin.000003', MASTER_LOG_POS=154; START SLAVE; 3.3 验证复制状态SHOW SLAVE STATUS\G -- 关键指标: -- Slave_IO_Running: Yes -- Slave_SQL_Running: Yes -- Seconds_Behind_Master: 0 # 延迟应接近0 四、GTID复制模式搭建(MySQL 5.6+)1. 主库配置# /etc/my.cnf [mysqld] server-id = 10 gtid_mode = ON enforce_gtid_consistency = ON log_bin = mysql-bin binlog_format = ROW 2. 从库配置# /etc/my.cnf [mysqld] server-id = 20 gtid_mode = ON enforce_gtid_consistency = ON log_slave_updates = 1 # 允许级联复制3. 配置复制(简化版)CHANGE MASTER TO MASTER_HOST='192.168.1.10', MASTER_USER='repl', MASTER_PASSWORD='SecurePass123!', MASTER_AUTO_POSITION = 1; -- GTID模式自动定位 五、生产环境优化实践1. 半同步复制配置# 主库配置 [mysqld] rpl_semi_sync_master_enabled = 1 rpl_semi_sync_master_timeout = 1000 # 毫秒 # 从库配置 [mysqld] rpl_semi_sync_slave_enabled = 1 2. 多线程复制配置(MySQL 5.7+)[mysqld] slave_parallel_workers = 4 # 根据CPU核心数调整 slave_parallel_type = LOGICAL_CLOCK # 基于组提交的多线程复制3. 监控脚本示例#!/bin/bash # 检查主从复制状态 STATUS=$(mysql -uroot -pYourPassword -e "SHOW SLAVE STATUS\G" | grep -E "Slave_IO_Running|Slave_SQL_Running|Seconds_Behind_Master") if echo "$STATUS" | grep -q "No"; then echo "ALERT: Replication failed!" echo "$STATUS" | mail -s "MySQL Replication Alert" admin@example.com else echo "Replication OK: $STATUS" fi 六、故障排查指南1. 常见问题及解决方案现象原因解决方案Slave_IO_Running: Connecting网络不通/权限不足检查防火墙、SELinux、用户权限Last_SQL_Error: Duplicate entry主键冲突使用SET GLOBAL sql_slave_skip_counter=1跳过错误Seconds_Behind_Master持续增大从库负载过高优化从库查询、增加复制线程数2. 复制中断恢复-- 1. 停止复制 STOP SLAVE; -- 2. 跳过特定错误(谨慎使用) SET GLOBAL sql_slave_skip_counter = 1; -- 3. 重新定位(传统模式) CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000005', MASTER_LOG_POS=107; -- 4. 启动复制 START SLAVE; 七、高可用架构扩展1. MHA(Master High Availability)方案BinlogVIP FailoverReplicationReplicationMasterMHA ManagerCandidate MasterSlave1Slave22. ProxySQL实现读写分离# ProxySQL配置示例 mysql_servers = ( { address="192.168.1.10" port=3306 hostgroup=10 max_connections=1000 }, { address="192.168.1.11" port=3306 hostgroup=20 max_connections=2000 } ) mysql_users = ( { username="app_user" password="AppPass123" default_hostgroup=20 } ) mysql_query_rules = ( { rule_id=1 active=1 match_pattern="^SELECT.*FOR UPDATE" destination_hostgroup=10 }, { rule_id=2 active=1 match_pattern="^SELECT" destination_hostgroup=20 } ) 八、总结MySQL主备架构的搭建需要关注以下关键点:唯一标识:确保所有节点的server-id和UUID不重复网络连通:主从节点间10000/3306端口需互通日志配置:合理设置binlog_expire_logs_seconds参数监控机制:建立完善的复制监控和告警体系在实际生产环境中,建议结合以下技术方案:使用GTID模式简化复制管理部署半同步复制提升数据安全性配置多线程复制应对高并发场景引入MHA或Orchestrator实现自动化故障切换通过合理的架构设计和持续的运维优化,MySQL主备系统能够为企业级应用提供99.99%以上的可用性保障。
  • [技术干货] Mysql之存储过程-转载
    1. 视图视图是一个虚拟表,其内容由查询定义。与实际的物理表类似,视图也包含一系列具有名称的列和行数据。视图的数据变化会影响基表,反之,基表的数据变化也会影响视图。1.1 基本使用创建视图创建视图的基本语法如下:CREATE VIEW 视图名 AS SELECT 查询语句;示例:查看学生的学号、姓名、成绩和课程号:SELECT s1.sno, snme, sdept, grade, cno FROM student s1 JOIN score s2 ON s1.sno = s2.sno; 创建视图 v_s_s,该视图包含学生学号、姓名、成绩和课程号:CREATE VIEW v_s_s AS SELECT s1.sno, snme, sdept, grade, cno FROM student s1 JOIN score s2 ON s1.sno = s2.sno; 修改视图中的数据:假设我们希望修改马小燕课程号 001 的成绩为 100,若视图支持更新操作,可以修改原表数据:UPDATE v_s_s SET grade = 100 WHERE sno = '马小燕' AND cno = '001'; 删除视图删除视图的语法如下:DROP VIEW 视图名;1.2 视图的规则与限制视图与基表之间存在紧密的关系,视图数据的修改会影响基表的数据,反之亦然。为了确保系统的稳定性,使用视图时需要特别注意以下限制:数据更新限制:并非所有视图都支持数据更新操作。特别是当视图涉及多个表的连接、聚合函数、分组(GROUP BY)等操作时,修改视图中的数据可能会受到限制。例如,包含聚合函数或联合查询的视图通常不支持更新。性能考虑:虽然视图可以简化查询,但如果查询的视图非常复杂且涉及大量数据,可能会导致性能问题。因此,在设计视图时应避免过于复杂的查询,特别是涉及大量数据的视图。不支持索引:视图本身不支持索引,因此在使用视图时,查询性能可能不如直接查询基表。如果视图查询包含复杂的计算或连接操作,可能会对查询性能产生影响。只读视图:一些视图被设计为只读的,无法修改其中的数据。这通常发生在视图涉及多表连接、聚合操作或复杂计算时。对于这种只读视图,修改视图中的数据将会失败。1.3 视图与查找数据创建表的比较视图和基于查询结果创建的表在以下方面有所不同:视图:视图是动态的,它始终基于最新的查询结果。当视图中的数据发生变化时,实际的数据表也会发生变化。视图不存储数据本身,而是存储查询逻辑。当查询视图时,实际上是执行视图定义中的查询语句。语法示例:CREATE VIEW t_name AS SELECT 查询数据;创建表:使用 CREATE TABLE 可以将查询结果保存为一个物理表。与视图不同,创建的表会将数据永久存储在数据库中,数据修改不会影响原始数据表。创建的表可以具有索引等性能优化。语法示例:CREATE TABLE t_name AS SELECT 查询数据; 1.4 视图添加限制在 MySQL 中,视图虽然提供了极大的便利,但在某些情况下需要对其进行适当的限制,以确保数据的一致性和完整性。以下是常见的视图限制及其应用:视图的修改限制当视图涉及多个表、聚合函数、分组等操作时,视图通常为只读,无法直接修改。只有在视图基于单一表且没有涉及复杂计算时,视图才通常支持数据更新操作。若需要限制视图中数据的修改,可以使用 WITH CHECK OPTION,该选项确保通过视图进行的更新操作符合视图中的条件,否则修改会被拒绝。例如,创建一个只允许修改 grade >= 60 的视图:CREATE VIEW v_students AS SELECT sno, snme, grade FROM student WHERE grade >= 60WITH CHECK OPTION;视图查询限制视图能够简化复杂的查询,但也需要根据实际需求进行适当限制。为了确保不暴露敏感数据,可以设计只包含非敏感字段或经过加密/脱敏处理的视图。权限控制与安全性权限设置示例:GRANT SELECT ON v_employee_view TO 'user1';使用视图时,应当考虑权限控制,通过为不同用户分配不同的视图访问权限,可以确保数据安全。视图可以提供一个中介层,使得用户仅能访问特定数据,而不暴露整个表的数据。对于敏感数据,视图的设计应遵循最小权限原则,避免直接暴露敏感信息。2. 存储过程的基本语法存储过程是一组 SQL 语句的集合,它被存储在数据库中,并可根据需要执行,可以接收输入参数并返回结果。2.1 创建存储过程存储过程的创建需要修改语句分隔符,以避免与 SQL 语句的结束符(;)发生冲突:DELIMITER $$  -- 修改分隔符以避免与语句结束符冲突CREATE PROCEDURE procedure_name (parameters)BEGIN   -- SQL 语句END$$DELIMITER ;  -- 恢复分隔符存储过程的参数包括:IN:输入参数,用于向存储过程传递值。OUT:输出参数,用于存储过程返回数据。INOUT:输入输出参数,既可以接收输入数据,又可以返回结果。不改变分隔符会出现报错:2.2 调用存储过程调用存储过程的语法如下:CALL procedure_name(parameters);2.3 查看存储过程信息查看所有数据库的存储过程:SHOW PROCEDURE STATUS;查看当前数据库的存储过程:SHOW PROCEDURE STATUS WHERE db = 'db_name';Db:存储过程所在的数据库Name:存储过程的名称Type:存储过程类型(例如 PROCEDURE)Definer:存储过程的定义者Modified:最后修改时间Created:创建时间Security_type:安全类型Comment:存储过程的注释2.4 查看存储过程定义查看存储过程定义的语法:SHOW CREATE PROCEDURE procedure_name;2.5 删除存储过程删除存储过程的语法如下:DROP PROCEDURE procedure_name; 3. 变量3.1 查看系统变量​​​​​​​ 3.1.1查看所有系统变量 查看当前会话的系统变量:SHOW SESSION VARIABLES; 查看全局系统变量:SHOW GLOBAL VARIABLES;3.1.2系统变量的模糊匹配show session variables like '...';​show global variables like '...'; 3.1.3查看指定变量select @@global.tname;----查看指定全局环境变量select @@session.tname;----查看当前会话环境变量3.2 设置全局变量与会话变量Aspect全局隔离权限会话隔离权限作用范围系统范围,决定了系统的默认行为和限制仅对当前会话有效,独立于全局权限初始化与导入在系统初始化时从全局设置导入在新会话启动时从全局导入配置修改的时效性修改后不会立即影响现有会话,需重新启动会话才会生效当前会话的隔离级别修改不会影响其他会话对系统设计的影响确保系统权限的统一性,易于集中管理确保每个会话可以根据需要调整权限,而不影响其他会话3.2.1全局变量设置SET GLOBAL transaction_isolation_level = 'READ COMMITTED'; 重新启动一个新的会话:3.2.2当前会话变量设置set session transaction isolation level read committed;重新启动一个会话:3.3 用户定义变量用户定义变量是会话级别的临时变量,用户可以在 SQL 语句中使用它们来存储数据或进行计算。变量名以 @ 开头。例如: 使用 SET 语句定义变量:SET @variable_name = value;-----方法一SET @variable_name := value;----方法二例如,定义一个名为 @age 的变量并赋值为 25:SET @age = 25;也可以直接在查询语句中进行赋值:SELECT @variable_name := expression;例如,将查询结果赋值给变量:SELECT @age := age FROM users WHERE name = 'John';-----方法一 SELECT age into @age FROM users WHERE name = 'John';---方法二3.4 局部变量局部变量是在存储过程、函数或触发器内部定义的变量,作用范围仅限于该存储过程、函数或触发器的执行期间。它们通常用于临时存储数据、进行计算或传递信息。3.4.1 局部变量的声明在 MySQL 中,局部变量通过 DECLARE 语句在存储过程、函数或触发器中声明。局部变量的作用范围仅限于声明它们的存储过程、函数或触发器内部,并且不能在 SQL 查询的其他地方使用。局部变量的特点:局部性:局部变量仅在存储过程、函数或触发器的执行期间有效。当存储过程或函数执行完毕后,局部变量会被自动销毁。无法在查询外部使用:局部变量只能在其所在的存储过程、函数或触发器内使用,不能在 SQL 查询的其他部分引用。生命周期:当存储过程或函数执行结束时,局部变量的值会丢失。每次执行存储过程或函数时,局部变量会重新创建,并可以为其赋予初始值(如果指定了初始值)。3.4.2 局部变量的使用局部变量常用于存储中间计算结果、执行逻辑运算或在存储过程/函数中临时存储查询结果。它们的使用受到以下限制:声明位置:DECLARE 语句必须在存储过程、函数或触发器的开头部分,也就是在 BEGIN 语句之前声明。命名规则:局部变量不能使用以 @ 开头的命名方式。@ 是用于用户定义会话变量的前缀,局部变量不允许使用此命名规则。初始值:如果没有为局部变量指定初始值,则其默认值为 NULL。因此,在使用局部变量时,开发者需要考虑 NULL 的处理,确保程序的逻辑正确。 语法:DECLARE variable_name data_type [DEFAULT value];variable_name:变量的名称。data_type:变量的数据类型(如 INT, VARCHAR, DATE 等)。[DEFAULT value]:可选,设置默认值。如果不指定,则默认值为 NULL。例子:DECLARE @user_id INT DEFAULT 100;DECLARE @user_name VARCHAR(255) DEFAULT 'John';————————————————                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。                        原文链接:https://blog.csdn.net/2301_81831423/article/details/147447771
  • [问题求助] redis为什么要自己定义SDS
    Redis自己本身是通过C语言实现的,但是他并没有直接使用C语言中的字符数组的方式来实现字符串,而是自己实现了一个SDS(Simple Dynamic Strings),即简单动态字符串,这是为什么呢?
  • [技术干货] 【开发者空间实践指导】搭建WordPress博客平台
    概述案例介绍WordPress是一款个人博客系统,也可以把 WordPress当作一个内容管理系统(CMS)来使用,它是使用PHP语言和MySQL数据库开发的,用户可以在支持PHP和MySQL数据库的服务器上搭建自己的博客。本案例借助开发者空间提供的免费云上资源环境,直观地展示如何在开发者空间部署一套个人博客系统。通过实际操作,让大家深入了解如何通过命令在开发者空间进行资源搭建的流程方法,体验其在应用开发中的优势。适用对象企业个人开发者高校学生案例时间本案例总时长预计60分钟。案例流程说明:用户开通开发者空间;下载WordPress软件包到开发者空间;在开发者空间上构建LNMP环境并运行WordPress网站。资源总览本案例预计花费总计0元。资源名称规格单价(元)时长(分钟)开发者空间—云主机2 vCPUs | 4 GB RAM免费60GitCode服务免费免费60开发者空间搭建WordPress博客平台云主机申请本案例中,使用开发者空间为环境搭建平台,开发者空间为开发者提供的免费云上资源环境,方便开发者进行环境搭建和项目部署。登录开发者空间页面,点击“配置云主机”进行云主机申请。搭建LNMP应用运行环境WordPress博客系统最新版本需要PHP7.4和MySQL 8.0或者MariaDB 10.5以上的版本来进行运行, 因此本次操作实战决定采用经典架构环境LNMP,L代表Linux,N代表Nginx,M代表MySQL或者MariaDB,P代表PHP。从官方建议网页中可知,虽然还是可以安装低一点版本的PHP和数据库版本,但官方提示担心各种漏洞而受到威胁,因此肯定按着官方建议,安装所要求的版本。安装Nginx登录云主机之后,在云主机桌面单击鼠标右键,选择“Open Terminal Here”,打开终端。本文章以 root 用户来执行操作命令。云主机登录默认账户为developer,所以理论上在每条命令前使用 sudo才有root权限执行,所以我们可使用命令 sudo -i 直接登录到 root 用户。在终端中输入:sudo -i回车,即可切换到root账户。然后在终端中输入:yum -y install nginx回车,进行nginx安装,待终端出现Complete表示 Nginx 安装完成。以下命令进行启动并设置开机自启动:systemctl start nginxsystemctl enable nginx在云主机的浏览器访问地址http://127.0.0.1/,若Nginx 安装成功,则会显示如下页面。安装MySQL在终端中输入:yum -y install mysql-server回车,待终端出现Complete表示 mysql 安装完成。然后输入:systemctl start mysqld启动mysql。在mysql 8.0的后续版本中,初次安装完成后可使用空密码来登录,输入:mysql -uroot -p回车,在“Enter password”时按回车即可登录。登录mysql后,再执行:ALTER USER 'root'@'localhost' IDENTIFIED BY 'Huawei@123';来修改数据库root账户的密码。(本案例使用Huawei@123,开发者可自定义)然后执行:flush privileges;quit刷新并退出mysql。最后在终端中执行:systemctl enable mysqld将数据库设置为开机自启动,然后执行:systemctl status mysqld查看mysql数据库状态显示如下即完成mysql的安装和配置,按ctrl+c退出。安装PHP在终端中输入以下命令:yum -y install php php-tidy php-common php-devel php-pdo php-mysql* php-gd php-ldap php-mbstring php-fpm来安装 PHP 和一些所需的 PHP 扩展,显示如下即表示安装成功。输入:php -v可查看php的版本,然后执行:systemctl start php-fpmsystemctl enable php-fpm来启动php,并将其设置为开机自启动。如果想查看php的监听端口,可通过执行:netstat -l | grep php来查看,执行:grep -v ";\|^$" /etc/php-fpm.d/www.conf | grep listen可从配置文件中可查出具体侦听配置。默认在安装旧的PHP版本后,需要在Nginx中配置好对应的PHP支持,但云主机集成的高版本的yum源安装后,会自动安装好对应的配置支持文件,因此开发者无需自行配置。通过执行:cat /etc/nginx/conf.d/php-fpm.confcat /etc/nginx/default.d/php.conf即可查看对应的配置文件,显示如下。最后测试LNMP的PHP支持,在终端输入:echo "<?php phpinfo(); ?>" > /usr/share/nginx/html/index.php来编辑PHP测试页面,修改完后输入:systemctl reload nginx来对php服务进行重载。使用浏览器访问http://127.0.0.1/index.php,显示如下图页面,说明PHP安装成功。数据库数据初始化登录数据库并创建WordPress系统所用的数据库wordpress和对应的用户wordpressuser,并使用密码Huawei@123。在终端输入:mysql -uroot -p在Enter password处输入root的密码“Huawei@123”,登录数据库后,执行:create database wordpress;创建数据库wordpress,执行:create user 'wordpressuser'@'localhost' identified by 'Huawei@123';创建用户wordpressuser并设置密码为Huawei@123,然后执行:grant all privileges on wordpress.* to 'wordpressuser'@'localhost';来进行授权,最后执行:flush privileges;quit刷新退出即可。然后输入:mysql -uwordpressuser -p回车,使用我们新建的wordpressuser账户登录数据库,密码为“Huawei@123”,登录成功后,输入:show databases;显示如下即完成了数据库的初始化配置。输入:quit退出,至此,WordPress所需要的运行环境已经搭建完毕,接下来可以进行WordPress博客系统的安装。安装并配置WordPress打开WordPress官网的下载页面:https://cn.wordpress.org/download/ ,下载wordpress-6.7.1软件包至本地。跳转到软件包目录。然后输入:cp -a /home/developer/下载/wordpress-6.7.1-zh_CN.zip .将软件包复制到当前目录,然后执行:unzip wordpress-6.7.1-zh_CN.zip来解压zip包,然后执行:mv wordpress /usr/share/nginx/html/chown -R apache:apache /usr/share/nginx/html/wordpress/将解压出来的项目目录移动至nginx页面目录下,并设置目录权限。接下来进行WordPress配置。首先执行:cd /usr/share/nginx/html/wordpress进入到WordPress 项目目录,然后执行:cp -a wp-config-sample.php wp-config.php将wp-config-sample.php文件复制名为wp-config.php的文件用作配置文件,并保留示例配置文件以作备份。然后开始编辑WordPress的配置文件,输入:vim wp-config.php按 “i”进入编辑模式来编辑配置文件,按照下图把DB_NAME(数据库名称)、DB_USER(数据库用户名)、DB_PASSWORD(数据库密码)更改为之前所配置的设置,参数如下:/** The name of the database for WordPress */define( 'DB_NAME', 'wordpress' );/** Database username */define( 'DB_USER', 'wordpressuser' );/** Database password */define( 'DB_PASSWORD', 'Huawei@123' );修改完后,按Esc,输入“:wq”,回车,保存并退出配置文件,然后执行:grep -n "^[a-z]\|^[A-Z]" wp-config.php来查看修改是否成功,显示如下即可。接下来进行安装WordPress。在浏览器地址栏输入http://127.0.0.1/wordpress,即可跳转至安装页面,然后按照提示填写对应的表单信息后,即可点击安装WordPress。若WordPress安装完成,会如下图所示,然后点击登录,输入用户名和密码,即可登录wordpress管理台,可在页面见到网站仪表盘,如下图所示。在浏览器输入http://127.0.0.1/wordpress 即可查看wordpress主页.可以在管理界面选择想要的主题和插件,可使用在线安装的方式进行安装,也可以在线更新各种插件(PS:前提是设置好此前所说的访问权限,不然会弹出授权界面)。安装完成后,点击启用即可使用,并可在已安装插件中查看。至此,已完成整个WordPress项目的部署。更多案例,点击案例中心查看~
  • [技术干货] MySQL多列IN查询的实现【转】
    在 MySQL 中,多列 IN 查询是一种强大的筛选工具,它允许通过多字段组合快速过滤数据。相较于传统的 OR 连接多个条件,这种语法更简洁高效,尤其适合批量匹配复合键或联合字段的场景。本文将深入解析其用法,并探讨性能优化与实战技巧。一、基础语法:多列 IN 的两种写法1. 直接值列表123456-- 查询 (name, age, role) 匹配任意一组值的记录SELECT * FROM users WHERE (name, age, role) IN (    ('jinzhu', 18, 'admin'),    ('jinzhu2', 19, 'user')); 2. 子查询1234567-- 查询与指定订单相关的用户SELECT * FROM users WHERE (name, email) IN (    SELECT customer_name, customer_email     FROM orders     WHERE status = 'paid'); 二、对比传统 OR 的写法假设需要匹配三组值,传统写法冗长且难以维护:123SELECT * FROM usersWHERE (name = 'jinzhu' AND age = 18 AND role = 'admin')   OR (name = 'jinzhu2' AND age = 19 AND role = 'user');多列 IN 的优势:• 简洁性:条件组集中管理• 可读性:直观表达“多字段组合匹配”• 性能:数据库可能优化执行计划三、性能分析与优化1. 索引利用• 若 (name, age, role) 是联合索引,查询效率最高。• 单列索引可能无法生效,需结合执行计划(EXPLAIN)分析。2. 数据量影响• 小数据量(如 < 1000 组):多列 IN 效率优异。• 大数据量:考虑分页或临时表优化:1234567-- 使用临时表CREATE TEMPORARY TABLE tmp_filters (name VARCHAR(255), age INT, role VARCHAR(255));INSERT INTO tmp_filters VALUES ('jinzhu', 18, 'admin'), ('jinzhu2', 19, 'user'); SELECT u.* FROM users uJOIN tmp_filters f ON u.name = f.name AND u.age = f.age AND u.role = f.role; 3. 分批次查询1234567-- 每批最多 100 组条件(示例使用伪代码逻辑)SELECT * FROM usersWHERE (name, age, role) IN (('jinzhu',18,'admin'), ... /* 100组 */); -- 下一批次SELECT * FROM usersWHERE (name, age, role) IN (('jinzhu101',20,'user'), ...); 四、兼容性与注意事项1. 数据库支持• MySQL:全支持• PostgreSQL:语法相同• SQLite:3.15+ 版本支持• SQL Server:需转换为 WHERE EXISTS 子查询:123456SELECT * FROM users uWHERE EXISTS (  SELECT 1   FROM (VALUES ('jinzhu',18,'admin'), ('jinzhu2',19,'user')) AS t(name, age, role)  WHERE u.name = t.name AND u.age = t.age AND u.role = t.role); 2. 常见错误• 占位符数量限制:MySQL 的 max_prepared_stmt_count 限制,需分批处理。• 字段顺序:必须与 IN 子句中的字段顺序一致。• NULL 值处理:(col1, col2) IN ((1, NULL)) 可能不如预期。五、动态生成条件(通用编程示例)1. 参数化查询(防止 SQL 注入)以 Python 为例(语言无关逻辑):12345678filters = [('jinzhu', 18, 'admin'), ('jinzhu2', 19, 'user')]placeholders = ', '.join(['(%s, %s, %s)'] * len(filters))query = f"""    SELECT * FROM users     WHERE (name, age, role) IN ({placeholders})"""# 展开参数:flattened = [x for tpl in filters for x in tpl]cursor.execute(query, flattened) 2. 命名参数(增强可读性)123-- 使用命名参数(需数据库驱动支持,如 PostgreSQL)SELECT * FROM users WHERE (name, age, role) IN %(filters)s; 六、最佳实践总结优先使用联合索引确保 (col1, col2, col3) 的查询顺序与索引一致。控制条件组数量单次查询避免超过 1000 组值。监控执行计划定期用 EXPLAIN 验证索引使用情况:1EXPLAIN SELECT * FROM users WHERE (name, age, role) IN (...);避免全表扫描若未命中索引,考虑优化查询条件或数据结构。事务中谨慎使用长时间持有锁可能导致并发问题。七、高级技巧:与其他操作结合1. 联合 JOIN 查询1234567SELECT u.*, o.order_id FROM users uJOIN (    VALUES ('jinzhu', 18, 'admin'), ('jinzhu2', 19, 'user')) AS filter(name, age, role)ON u.name = filter.name AND u.age = filter.age AND u.role = filter.roleLEFT JOIN orders o ON u.id = o.user_id; 2. 与 CASE 语句结合1234567SELECT    name,    CASE        WHEN (name, age, role) IN (('jinzhu',18,'admin')) THEN 'VIP'        ELSE 'Standard'    END AS user_typeFROM users; 通过合理利用多列 IN 查询,可以显著简化复杂条件的代码逻辑,同时兼顾性能与可维护性。无论是简单的批量筛选还是联合业务键校验,这种语法都能成为你 SQL 工具箱中的利器
  • [技术干货] MySQL新增字段后Java实体未更新的潜在问题与解决方案【转】
    1. 问题背景:数据库与 Java 实体不同步1.1 常见场景数据库新增字段(如 ALTER TABLE ADD COLUMN),但 Java 实体类未更新。程序继续运行,调用 saveBatch()、insert()、查询等方法。是否会报错? 取决于字段约束和 ORM 框架行为。1.2 示例代码假设有一个 StatisticsData 实体类(使用 MyBatis-Plus):1234567@Data@TableName("statistics_data")public class StatisticsData extends BaseModel {    private String agentId;    private Long click;    // 其他字段...}然后数据库新增一个字段:1ALTER TABLE statistics_data ADD COLUMN new_column INT NOT NULL;此时,如果 Java 代码未更新,会有什么影响?2. 不同操作的影响分析2.1 查询操作(SELECT)默认情况下,MyBatis-Plus 会忽略数据库中存在但实体类没有的字段,查询不会报错。但如果使用 SELECT * 或手动映射全部字段,可能会触发警告(取决于日志级别)。2.2 插入操作(INSERT)如果新增字段允许 NULL 或有默认值:1ALTER TABLE statistics_data ADD COLUMN new_column INT DEFAULT 0;✅ save() 或 saveBatch() 不会报错,插入时该字段会用 NULL 或默认值填充。如果新增字段是 NOT NULL 且无默认值:1ALTER TABLE statistics_data ADD COLUMN new_column INT NOT NULL;❌ saveBatch() 会报错:1ERROR 1364 (HY000): Field 'new_column' doesn't have a default value因为 MyBatis-Plus 生成的 SQL 不包含未定义的字段,导致 MySQL 拒绝插入。2.3 批量插入(saveBatch)saveBatch() 的底层逻辑:1234567// MyBatis-Plus 默认实现(简化版)public boolean saveBatch(Collection<T> entityList) {    for (T entity : entityList) {        baseMapper.insert(entity); // 生成 INSERT SQL,仅包含实体类定义的字段    }    return true;}如果 new_column 是 NOT NULL,由于 SQL 不包含该字段,MySQL 会报错。如果允许 NULL 或设置默认值,则正常执行。3. 解决方案3.1 临时修复(不推荐长期使用)(1)修改数据库字段约束12345-- 允许 NULLALTER TABLE statistics_data MODIFY new_column INT NULL; -- 或设置默认值ALTER TABLE statistics_data MODIFY new_column INT DEFAULT 0; (2)避免自动映射,手动指定 SQL1234567// 使用 @TableField(exist = false) 忽略未知字段@TableField(exist = false)private String ignoredField; // 或自定义 SQL(明确指定插入字段)@Insert("INSERT INTO statistics_data (agent_id, click) VALUES (#{agentId}, #{click})")void customInsert(StatisticsData data); 3.2 长期最佳实践(推荐)(1)同步更新 Java 实体类1234567@Data@TableName("statistics_data")public class StatisticsData extends BaseModel {    private String agentId;    private Long click;    private Integer newColumn; // 新增字段} (2)使用数据库迁移工具(如 Flyway/Liquibase)12345-- V1__init.sqlCREATE TABLE statistics_data (...); -- V2__add_new_column.sqlALTER TABLE statistics_data ADD COLUMN new_column INT DEFAULT 0; (3)自动化检查(可选)通过单元测试或 Schema 校验工具,确保数据库与实体类一致:123// 示例:使用 Hibernate Validator 检查(如果适用)@Column(nullable = false)private Integer newColumn; 4. 完整代码示例4.1 更新后的 Java 实体1234567891011@Data@TableName("statistics_data")public class StatisticsData extends BaseModel {    private String agentId;    private Long click;    private Integer newColumn; // 新增字段     @TableField("`date`")    private String date;    // 其他字段...} 4.2 安全的批量插入方法12345678// 检查数据完整性后再插入public void safeBatchInsert(List<StatisticsData> dataList) {    if (dataList == null || dataList.isEmpty()) {        return;    }    // 可在此处做字段校验    statisticsDataService.saveBatch(dataList);} 4.3 数据库变更脚本(Flyway 示例)123-- V2__add_new_column.sqlALTER TABLE statistics_data ADD COLUMN new_column INT NOT NULL DEFAULT 0 COMMENT '新增字段'; 5. 总结场景是否报错解决方案新增字段允许 NULL 或 DEFAULT❌ 不报错可暂时不更新实体类新增字段 NOT NULL 且无默认值✅ 报错更新实体类 或 修改表结构使用 saveBatch()取决于约束同步实体类或调整 SQL
  • [技术干货] 浅谈mysql的sql_mode可能会限制你的查询【转】
    场景:现在我们常用数据库有哪些?一想到的就是mysql,oracle吧,今天说的是mysql中我们写sql语句时候常见的一个问题,相信挺多朋友在执行一些复杂的分组查询的时候,都会遇到一个查询错误,大佬们自然不存在了,但相信小猿们还是会碰到的;错误内容大致为:。123Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column '某列字段' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by问题描述这个问题主要说明的是,我们写的sql查询语句违背了聚合函数group by的规则,他要求SELECT列表中的所有列都必须是聚合函数的参数或者包含在GROUP BY子句中;简单的说,也就是select后的字段列,和group by 之后的字段列没有对应上。原因分析:提示:为什么会出现这个问题呢?我们会好奇,好像以前执行这个类似的查询的时候没有这种限制啊,问题就在于mysql的sql_mode变量的设置有关;但是这个只针对5.7版本之后的mysql,若大家还在用早期的mysql的话,不会有这个问题,这个是后面版本加的强制规范模式;什么是sql_mode,sql_mode 是一个用于控制 MySQL 服务器操作模式的系统变量。它允许用户定义 SQL 语言语法、数据校验和存储引擎行为的一些规则。通过设置不同的 sql_mode 值,你可以定制 MySQL 服务器的行为,以符合特定的 SQL 标准、增强数据完整性或满足特定的应用需求解决方案:问题找到了,我们就来验证一下是不是sql_mode的设置有问题;查询mysql的sql_mode变量值。123// 在navicat中,查询语句输入// 没有navicat的也可以直接dos进入命令行登录mysql后,输入语句也是一样的select @@global.sql_mode在结果中,我们可以看到有ONLY_FULL_GROUP_BY的内容,说明在数据库中我们设置了该语法的强制校验规则,所以导致我们的查询不通过。因此,我们只要将这个值去掉即可;修改该变量值通常的做法有两个方式:第一种:修改后,只有当前生效,若是mysql服务重启,就会失效;123//  set global sql_mode = 'select @@global.sql_mode 得到返回值中,去掉group by 限制' set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';第二种:需要修改mysql的配置文件;但是效果则是永久的;我们只要找到我们的mysql配置文件即可,打开在【mysqld】下加上一句话;sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION设置后需要重启mysql服务才会生效;这里需要注意的是,若是windows系统,配置文件找到my.ini修改即可,但若是跟博主一样的mac电脑,则是找到my.cnf,有时候可能也叫(mysql-deafault.cnf)甚至有的版本并不会生成这个配置文件,需要我们自行生成,具体根据安装mysql的方式有关系,你用homebrew和正常dmg安装的就不一样,所以这块一定要注意别找错配置文件,不然配置就不会生效
  • [技术干货] MySQL使用SHOW PROCESSLIST的实现【转】
    1、SHOW PROCESSLIST 显示进程列表SHOW [FULL] PROCESSLIST 用于查看当前MySQL服务器上的所有运行中的进程列表信息。这个命令可以帮助我们了解哪些查询正在执行,它们的状态是什么,以及它们已经执行了多长时间。示例:1234567mysql> SHOW PROCESSLIST;+----+------+-----------+----+---------+------+-------+------------------+| Id | User | Host      | db | Command | Time | State | Info             |+----+------+-----------+----+---------+------+-------+------------------+| 5  | root | localhost |    | Query   | 0    | init  | show processlist |+----+------+-----------+----+---------+------+-------+------------------+1 row in set (0.00 sec)其中每行显示的信息包括:Id: 线程的唯一标识符。User: 执行该命令的用户名。Host: 用户的主机名。通常是客户端IP地址、端口号或者都有。db: 当前线程正在工作的数据库。如果没有选定数据库,则为NULL。Command: 线程正在执行的命令类型。例如:Sleep,Query,Locked等。Time: 命令开始执行以来的秒数。对于'Sleep'命令,这是线程进入睡眠状态的时间。State: 显示线程的状态信息。这对找出性能问题特别有用。Info: 显示线程正在执行的查询。若没有查询在执行则该列为NULL。如果没有 FULL 关键字, SHOW PROCESSLIST 则仅显示 Info 字段中每个语句的前 100 个字符。2、线程Command有以下值:Binlog Dump:这是用于将二进制日志内容发送到副本的复制源上的线程。Change user:线程正在执行更改用户操作。Close stmt:线程正在关闭预备语句。Connect:被连接到源的复制接收器线程以及复制工作器线程使用。Connect Out:副本正在连接到其源。Create DB:线程正在执行创建数据库操作。Daemon:此线程对服务器内部而言,不是为客户端连接提供服务的线程。Debug:线程正在生成调试信息。Delayed insert:线程是一个延迟插入处理器。Drop DB:线程正在执行删除数据库操作。Error:Execute:线程正在执行预备语句。Fetch:线程正在获取执行预备语句的结果。Field List:线程正在检索表列的信息。Init DB:线程正在选择默认数据库。Kill:线程正在杀死另一个线程。Long Data:线程正在检索执行预备语句结果中的长数据。Ping:线程正在处理服务器ping请求。Prepare:线程正在准备预备语句。Processlist:线程正在生成关于服务器线程的信息。Query:用户客户端在执行查询时使用,由单线程复制应用程序线程使用,以及由复制协调器线程使用。Quit:线程正在终止。Refresh:线程正在刷新表、日志或缓存,或重置状态变量或复制服务器信息。Register Slave:线程正在注册副本服务器。Reset stmt:线程正在重置预备语句。Set option:线程正在设置或重置客户端语句执行选项。Shutdown:线程正在关闭服务器。Sleep:线程正在等待客户端发送新的语句给它。Statistics:线程正在生成服务器状态信息。Time:未使用。3、线程状态State分类有以下值以下列表描述了与通用查询处理相关的线程State值,并且不涉及更专门的活动,如复制。其中许多对于在服务器中查找错误非常有用。After create:当线程创建一个表(包括内部临时表)时,会出现这种情况,在创建表的函数结束时。即使由于某些错误无法创建表,也会使用此状态。altering table:服务器正在执行就地ALTER TABLE。Analyzing:线程正在计算MyISAM表键分布(例如,用于ANALYZE TABLE)。checking permissions:线程正在检查服务器是否具有执行语句所需的权限。Checking table:线程正在执行表检查操作。cleaning up:线程已处理一条命令,并准备释放内存并重置某些状态变量。closing tables:线程正在将更改后的表数据刷新到磁盘并关闭已使用的表。这应该是一个快速的操作。如果不是,验证你是否没有满磁盘,并且磁盘没有在非常繁重的使用中。committing alter table to storage engine:服务器已完成就地ALTER TABLE并正在提交结果。converting HEAP to ondisk:线程正在将内部临时表从MEMORY表转换为磁盘上的表。copy to tmp table:线程正在处理ALTER TABLE语句。在已创建新结构的表之后但在将行复制进去之前发生此状态。对于此状态的线程,可以使用性能模式来获取复制操作的进度。Copying to group table:如果语句具有不同的ORDER BY和GROUP BY条件,则将按组排序行并复制到临时表中。Copying to tmp table:服务器正在将数据复制到内存中的临时表。Copying to tmp table on disk:服务器正在将数据复制到磁盘上的临时表。临时结果集已经变得过大。因此,线程正在将临时表从内存格式更改为基于磁盘的格式以节省内存。Creating index:线程正在处理MyISAM表的ALTER TABLE ... ENABLE KEYS。Creating sort index:线程正在处理使用内部临时表解析的SELECT。creating table:线程正在创建表。这包括创建临时表。Creating tmp table:线程正在在内存或磁盘上创建临时表。如果在内存中创建了表,但稍后将其转换为磁盘上的表,则在该操作期间的状态为Copying to tmp table on disk。deleting from main table:服务器正在执行多表删除的第一部分。它只从第一个表中删除,并保存列和偏移量以用于从其他(引用)表中删除。deleting from reference tables:服务器正在执行多表删除的第二部分,并从其他表中删除匹配的行。discard_or_import_tablespace:线程正在处理ALTER TABLE ... DISCARD TABLESPACE或ALTER TABLE ... IMPORT TABLESPACE语句。end:在ALTER TABLE,CREATE VIEW,DELETE,INSERT,SELECT或UPDATE语句的结束但在清理之前发生。对于结束状态,可能正在发生以下操作:将事件写入二进制日志释放内存缓冲区,包括blob:executing:线程已开始执行语句。Execution of init_command:线程正在执行init_command系统变量的值中的语句。freeing items:线程已执行一条命令。这个状态通常在cleaning up之前出现。FULLTEXT initialization:服务器正在准备进行自然语言全文搜索。init:在初始化ALTER TABLE,DELETE,INSERT,SELECT或UPDATE语句之前发生。在这种状态下,服务器采取的操作包括刷新二进制日志和InnoDB日志。Killed:有人向线程发送了一个KILL语句,它应该在下次检查kill标志时中止。该标志在MySQL的每一个主要循环中都会被检查,但在某些情况下,线程可能还需要短暂的时间才能死亡。如果线程被其他线程锁定,则在其他线程释放其锁定后立即生效。Locking system tables:线程正在尝试锁定一个系统表(例如,一个时区或日志表)。logging slow query:线程正在将语句写入慢查询日志。login:连接线程的初始状态,直到客户端成功进行身份验证。manage keys:服务器正在启用或禁用表索引。Opening system tables:线程正在尝试打开一个系统表(例如,一个时区或日志表)。Opening tables:线程正在尝试打开表。这应该是非常快速的过程,除非有什么阻止打开。例如,ALTER TABLE或LOCK TABLE语句可以阻止打开表,直到语句完成。还值得检查您的table_open_cache值是否足够大。对于系统表,使用Opening system tables状态代替。optimizing:服务器正在为查询执行初始优化。preparing:此状态在查询优化期间发生。preparing for alter table:服务器正在准备执行就地ALTER TABLE。Purging old relay logs:线程正在删除不需要的中继日志文件。query end:处理查询后但在freeing items状态之前发生此状态。Receiving from client:服务器正在从客户端读取数据包。Removing duplicates:查询正在以SELECT DISTINCT的方式使用,以致MySQL无法在早期阶段优化掉DISTINCT操作。由于此原因,MySQL需要一个额外的阶段来移除所有重复的行,然后再将结果发送给客户端。removing tmp table:线程在处理完SELECT语句后正在移除内部临时表。如果没有创建临时表,则不使用此状态。rename:线程正在重命名表。rename result table:线程正在处理ALTER TABLE语句,已经创建了新表,并正将其重命名以替换原始表。Reopen tables:线程获取了表的锁,但在获取锁后发现表的底层结构已更改。它已释放了锁,关闭了表,正在尝试重新打开它。Repair by sorting:修复代码使用排序来创建索引。Repair done:线程已完成MyISAM表的多线程修复。Repair with keycache:修复代码使用一次通过键缓存创建一个键。这比Repair by sorting慢得多。Rolling back:线程正在回滚事务。Saving state:对于MyISAM表操作,如修复或分析,线程正在将新表状态保存到.MYI文件头。状态包括行数、AUTO_INCREMENT计数器和键分布等信息。Searching rows for update:线程正在进行第一阶段,查找所有匹配的行,然后更新它们。如果UPDATE改变了用于查找所涉及行的索引,则必须这样做。Sending data:在MySQL 8.0.17之前:线程正在读取和处理SELECT语句的行,并将数据发送给客户端。因为在此状态期间发生的操作倾向于执行大量的磁盘访问(读取),所以它通常是给定查询在其生命周期内运行时间最长的状态。MySQL 8.0.17及更高版本:此状态不再单独指示,而是包含在Executing状态中。Sending to client:服务器正在将数据包写入客户端。setup:线程开始进行ALTER TABLE操作。Sorting for group:线程正在执行排序以满足GROUP BY。Sorting for order:线程正在执行排序以满足ORDER BY。Sorting index:线程正在对索引页进行排序,以便在MyISAM表优化操作期间更有效地访问。Sorting result:对于SELECT语句,此为与Creating sort index类似,但适用于非临时表。starting:语句执行开始的第一阶段。statistics:服务器正在计算统计信息以制定查询执行计划。如果线程在此状态下停留了很长时间,那么服务器可能在磁盘绑定中执行其他工作。System lock:线程已调用mysql_lock_tables()并且自那时起线程状态未更新。这是一个非常通用的状态,可能出于许多原因。例如,线程将请求或正在等待表的内部或外部系统锁。当InnoDB在执行LOCK TABLES期间等待表级锁时,可能会发生这种情况。如果由于请求外部锁而导致这种状态,并且您没有使用访问相同MyISAM表的多个mysqld服务器,则可以使用--skip-external-locking选项禁用外部系统锁。然而,默认情况下是禁用外部锁定的,所以有可能这个选项没有效果。对于SHOW PROFILE,此状态意味着线程正在请求锁(不是等待它)。对于系统表,使用Locking system tables状态代替。update:线程准备开始更新表。Updating:线程正在搜索要更新的行并更新它们。updating main table:服务器正在执行多表更新的第一部分。它只更新第一个表,并保存列和偏移量以用于更新其他(引用)表。updating reference tables:服务器正在执行多表更新的第二部分,并更新其他表中的匹配行。User lock:线程将请求或正在等待使用GET_LOCK()调用请求的咨询锁。对于SHOW PROFILE,这种状态意味着线程正在请求锁(而不是等待它)。User sleep:线程已调用SLEEP()。Waiting for commit lock:FLUSH TABLES WITH READ LOCK正在等待提交锁。waiting for handler commit:线程正在等待事务提交,与查询处理的其他部分相比。Waiting for tables:线程收到通知,表的底层结构已经更改,它需要重新打开表以获取新的结构。但是,要重新打开表,它必须等待所有其他线程都关闭了所述表。如果另一个线程在所述表上使用了FLUSH TABLES或以下语句之一:FLUSH TABLES tbl_name,ALTER TABLE,RENAME TABLE,REPAIR TABLE,ANALYZE TABLE,OPTIMIZE TABLE,则会发生此通知。Waiting for table flush:线程正在执行FLUSH TABLES并等待所有线程关闭其表,或者线程收到通知说表的底层结构已经更改,它需要重新打开表以获取新的结构。但是,要重新打开表,它必须等待所有其他线程都关闭了所述表。如果另一个线程在所述表上使用了FLUSH TABLES或以下语句之一:FLUSH TABLES tbl_name,ALTER TABLE,RENAME TABLE,REPAIR TABLE,ANALYZE TABLE,OPTIMIZE TABLE,则会发生此通知。Waiting for lock_type lock:服务器正在等待获得THR_LOCK锁或元数据锁定子系统的锁,其中lock_type指示锁的类型。这种状态表示等待一个THR_LOCK:Waiting for table level lock:这些状态表示等待元数据锁:Waiting for event metadata lock:Waiting for global read lock:Waiting for schema metadata lock:Waiting for stored function metadata lock:Waiting for stored procedure metadata lock:Waiting for table metadata lock:Waiting for trigger metadata lock:有关表锁指标的信息。有关元数据锁定的信息。要查看哪些锁阻止了锁请求。Waiting on cond:线程在等待某个条件变为真的通用状态。没有特定的状态信息可用。Writing to net:服务器正在将数据包写入网络。
  • [问题求助] 什么是数据库的锁升级,InnoDB支持锁升级吗?
    什么是数据库的锁升级,InnoDB支持锁升级吗?