外观
MySQL
约 11540 字大约 38 分钟
2025-11-20
下载
MySQL :: Download MySQL Community Server
安装
Windows
下载和解压
# 下载 mysql-8.4.11-winx64.zip # 解压到指定目录,例如: D:\mysql-8.4.11-winx64配置环境变量(可选但推荐)
- 右键"此电脑" → 属性 → 高级系统设置 → 环境变量
- 在系统变量中找到
Path,点击编辑 - 添加 MySQL 的 bin 目录路径:
D:\mysql-8.4.11-winx64\bin创建配置文件
在 MySQL 根目录创建
my.ini文件:[mysqld] # 设置安装目录 basedir=D:/mysql-8.4.11-winx64 # 设置数据存放目录 datadir=D:/mysql-8.4.11-winx64/data # 设置端口号 port=3306 # 设置字符集 character-set-server=utf8mb4 # 设置默认存储引擎 default-storage-engine=INNODB # 设置SQL模式 sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES # 允许最大连接数 max_connections=200 # 允许连接失败的次数 max_connect_errors=10 # 服务端使用的字符集 collation-server=utf8mb4_general_ci [client] # 设置客户端字符集 default-character-set=utf8mb4 # 设置端口 port=3306 [mysql] # 设置mysql客户端默认字符集 default-character-set=utf8mb4初始化数据库
以管理员身份打开命令提示符(CMD):
# 切换到 MySQL bin 目录 cd D:\mysql-8.4.11-winx64\bin # 初始化数据库(会自动创建data目录) mysqld --initialize --console注意:初始化后,命令会显示一个临时密码,请保存!例如:
[Note] A temporary password is generated for root@localhost: xxxxxxxx安装 MySQL 服务
# 安装服务(服务名可自定义,默认为MySQL) mysqld --install MySQL # 或者指定服务名 mysqld --install MySQL84 # 指定 配置文件路径(即使没指定,因为上方已经新建了这个文件,按照优先级也会找到根目录的my.ini) mysqld --install MySQL84 --defaults-file="D:/mysql-8.4.11-winx64/my.ini"启动 MySQL 服务
# 方法一:使用命令启动 net start MySQL # 方法二:使用服务管理器 # Win+R → services.msc → 找到 MySQL 服务 → 右键启动登录并修改密码
# 使用临时密码登录 mysql -u root -p # 输入刚才保存的临时密码 # 修改密码 ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码'; # 或者使用更安全的密码策略 ALTER USER 'root'@'localhost' IDENTIFIED BY 'YourPassword123!'; # 刷新权限 FLUSH PRIVILEGES; # 退出 EXIT;验证安装
-- 登录后执行 SELECT VERSION(); SHOW DATABASES; SELECT USER(), CURRENT_USER();
常用管理命令
启动和停止服务
# 启动服务
net start MySQL
# 停止服务
net stop MySQL
# 移除服务
mysqld --remove MySQL连接数据库
# 本地连接
mysql -u root -p
# 指定端口连接
mysql -h localhost -P 3306 -u root -p
# 查看版本
mysql --version常见问题解决
端口被占用
# 查看端口占用 netstat -ano | findstr 3306 # 修改 my.ini 中的端口号 port=3307初始化失败
# 删除 data 目录后重新初始化 rmdir /s /q data mysqld --initialize --console忘记密码
# 停止服务 net stop MySQL # 跳过权限验证启动 mysqld --skip-grant-tables # 新窗口登录 mysql -u root # 修改密码 FLUSH PRIVILEGES; ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码';字符集问题
-- 查看字符集 SHOW VARIABLES LIKE 'character%'; SHOW VARIABLES LIKE 'collation%';
安全建议
- 设置强密码:包含大小写字母、数字和特殊字符
- 限制远程访问:默认只允许本地连接
- 定期备份:使用 mysqldump 定期备份数据
- 更新补丁:及时更新 MySQL 版本
Linux
下载和解压
# 下载 MySQL 8.4.11 Linux 版本 wget https://dev.mysql.com/get/Downloads/MySQL-8.4/mysql-8.4.11-linux-glibc2.28-x86_64.tar.xz # 或者使用 .tar.gz 版本 # wget https://dev.mysql.com/get/Downloads/MySQL-8.4/mysql-8.4.11-linux-glibc2.28-x86_64.tar.gz # 解压文件(根据实际格式选择) tar -xvf mysql-8.4.11-linux-glibc2.28-x86_64.tar.xz # 或 tar -zxvf mysql-8.4.11-linux-glibc2.28-x86_64.tar.gz # 移动到目标目录 sudo mv mysql-8.4.11-linux-glibc2.28-x86_64 /usr/local/mysql创建 MySQL 用户和组
# 创建 mysql 用户组 sudo groupadd mysql # 创建 mysql 用户并加入 mysql 组 sudo useradd -r -g mysql -s /bin/false mysql创建数据目录和设置权限
# 创建数据目录 sudo mkdir -p /usr/local/mysql/data sudo mkdir -p /usr/local/mysql/log sudo mkdir -p /usr/local/mysql/tmp # 设置目录权限 cd /usr/local/mysql sudo chown -R mysql:mysql . sudo chmod 750 data log tmp创建配置文件
# 创建 my.cnf 配置文件 sudo vim /etc/my.cnf添加以下内容:
[mysqld] # 设置 MySQL 安装目录 basedir=/usr/local/mysql # 设置数据存储目录 datadir=/usr/local/mysql/data # 设置 socket 文件位置 socket=/usr/local/mysql/mysql.sock # 设置端口 port=3306 # 设置 PID 文件 pid-file=/usr/local/mysql/mysql.pid # 设置日志文件 log-error=/usr/local/mysql/log/mysql-error.log # 设置临时目录 tmpdir=/usr/local/mysql/tmp # 设置字符集 character-set-server=utf8mb4 collation-server=utf8mb4_general_ci # 设置默认存储引擎 default-storage-engine=INNODB # 允许最大连接数 max_connections=200 # 设置 SQL 模式 sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES # 设置时区 default-time-zone='+8:00' # 禁用 DNS 反向解析 skip-name-resolve # 设置用户 user=mysql [client] # 设置 socket 文件位置 socket=/usr/local/mysql/mysql.sock # 设置默认字符集 default-character-set=utf8mb4 port=3306 [mysql] # 设置默认字符集 default-character-set=utf8mb4初始化数据库
cd /usr/local/mysql # 初始化数据库(不生成随机密码) sudo bin/mysqld --initialize-insecure --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data # 或者初始化并生成随机密码(推荐) sudo bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data注意:如果使用
--initialize,系统会生成临时密码,查看错误日志获取:sudo grep 'temporary password' /usr/local/mysql/log/mysql-error.log配置 SSL(可选但推荐)
# 自动生成 SSL 证书 sudo bin/mysql_ssl_rsa_setup --datadir=/usr/local/mysql/data设置系统服务
方法一:使用 systemd(推荐)
创建服务文件:
sudo vim /etc/systemd/system/mysql.service添加以下内容:
[Unit] Description=MySQL Server Documentation=man:mysqld(8) Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html After=network.target After=syslog.target [Install] WantedBy=multi-user.target [Service] User=mysql Group=mysql Type=notify TimeoutSec=0 PermissionsStartOnly=true ExecStartPre=/usr/local/mysql/bin/mysqld_pre_systemd ExecStart=/usr/local/mysql/bin/mysqld --daemonize --pid-file=/usr/local/mysql/mysql.pid EnvironmentFile=-/etc/sysconfig/mysql LimitNOFILE=10000 Restart=on-failure RestartPreventExitStatus=1 PrivateTmp=false重新加载 systemd 配置:
sudo systemctl daemon-reload sudo systemctl enable mysql方法二:使用 init.d 脚本
# 复制启动脚本 sudo cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysql # 设置执行权限 sudo chmod +x /etc/init.d/mysql # 添加到开机启动 sudo chkconfig --add mysql # CentOS/RHEL sudo update-rc.d mysql defaults # Ubuntu/Debian
启动 MySQL
# 使用 systemd sudo systemctl start mysql sudo systemctl status mysql # 或使用 service 命令 sudo service mysql start sudo service mysql status设置环境变量
编辑环境变量文件:
sudo vim /etc/profile添加以下内容:
# MySQL 环境变量 export MYSQL_HOME=/usr/local/mysql export PATH=$PATH:$MYSQL_HOME/bin使配置生效:
source /etc/profile安全配置
# 如果初始化时使用了 --initialize(生成了临时密码) mysql -u root -p # 如果使用了 --initialize-insecure(无密码) mysql -u root # 修改 root 密码 ALTER USER 'root'@'localhost' IDENTIFIED BY 'YourPassword123!'; FLUSH PRIVILEGES; # 运行安全配置脚本 sudo mysql_secure_installation安全配置脚本会引导你:
- 设置 root 密码
- 删除匿名用户
- 禁止 root 远程登录
- 删除测试数据库
- 重新加载权限表
创建软链接(可选)
# 创建软链接,方便升级 sudo ln -s /usr/local/mysql /usr/local/mysql-latest
验证安装
# 检查版本
mysql --version
mysqld --version
# 连接数据库
mysql -u root -p
# 查看状态
sudo systemctl status mysql
# 查看进程
ps aux | grep mysql
# 查看端口
sudo netstat -tlnp | grep 3306
# 或
sudo ss -tlnp | grep 3306常用管理命令
# 启动服务
sudo systemctl start mysql
sudo service mysql start
# 停止服务
sudo systemctl stop mysql
sudo service mysql stop
# 重启服务
sudo systemctl restart mysql
sudo service mysql restart
# 查看状态
sudo systemctl status mysql
sudo service mysql status
# 查看日志
sudo tail -f /usr/local/mysql/log/mysql-error.log防火墙配置(如需要远程访问)
# CentOS/RHEL (firewalld)
sudo firewall-cmd --permanent --add-port=3306/tcp
sudo firewall-cmd --reload
# Ubuntu/Debian (ufw)
sudo ufw allow 3306/tcp
sudo ufw reload配置远程访问(可选)
-- 登录 MySQL
mysql -u root -p
-- 创建远程用户
CREATE USER 'username'@'%' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON *.* TO 'username'@'%';
FLUSH PRIVILEGES;
-- 或者允许 root 远程访问(不推荐)
ALTER USER 'root'@'localhost' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'password';
FLUSH PRIVILEGES;常见问题解决
- 权限问题
# 检查并修复权限
sudo chown -R mysql:mysql /usr/local/mysql
sudo chmod 750 /usr/local/mysql/data- 端口被占用
# 检查端口
sudo lsof -i:3306
# 修改 /etc/my.cnf 中的端口号
port=3307- 无法启动
# 查看错误日志
sudo tail -50 /usr/local/mysql/log/mysql-error.log
# 检查 SELinux(CentOS/RHEL)
sudo setenforce 0 # 临时关闭
sudo vim /etc/selinux/config # 永久关闭
SELINUX=disabled- 字符集问题
-- 查看字符集
SHOW VARIABLES LIKE 'character%';
SHOW VARIABLES LIKE 'collation%';- 内存优化
在 /etc/my.cnf 中添加:
[mysqld]
# InnoDB 缓冲池大小(建议设置为物理内存的 50-70%)
innodb_buffer_pool_size=1G
# 查询缓存
query_cache_size=64M
# 临时表大小
tmp_table_size=64M
max_heap_table_size=64M卸载 MySQL
# 停止服务
sudo systemctl stop mysql
sudo systemctl disable mysql
# 删除服务文件
sudo rm /etc/systemd/system/mysql.service
sudo systemctl daemon-reload
# 删除 MySQL 目录
sudo rm -rf /usr/local/mysql
# 删除配置文件
sudo rm -f /etc/my.cnf
# 删除用户
sudo userdel mysql
sudo groupdel mysql修改密码
在 MySQL 中,用户密码保存在系统数据库 mysql 的 user 表里,通常以哈希值形式存储,不会以明文保存。因此,无法直接查询用户的原始密码,但可以通过重置密码的方式来修改。
使用用户 user01 为例:
使用
root账号登录 MySQL 服务器。切换到
mysql系统数据库:USE mysql;根据 MySQL 版本选择相应的修改方式:
MySQL 5.6 及更早版本,可使用
UPDATE语句:UPDATE user SET authentication_string = PASSWORD('new_password') WHERE User = 'user01';MySQL 5.7 及以上版本,推荐使用
ALTER USER命令:ALTER USER 'user01'@'localhost' IDENTIFIED BY 'new_password';
请将
new_password替换为你实际要设置的新密码。刷新权限,使更改立即生效:
FLUSH PRIVILEGES;
完成以上步骤后,user01 的密码即被重置为新密码。整个过程不会显示当前密码,因为密码以哈希形式存储,无法以明文形式查看。
只读账户
MySQL 5.7及以后
在MySQL 8中创建一个只读账号,你需要执行以下步骤:
登录MySQL服务器:
使用一个具有足够权限的MySQL账号登录到MySQL服务器。通常,这个账号是管理员账号,具有
CREATE USER和GRANT等权限。创建只读账号:
使用以下命令创建一个只读账号。在这个示例中,我们将创建一个名为
readonly_user的只读账号,并将其限制为只能访问特定的数据库:CREATE USER 'readonly_user'@'%' IDENTIFIED BY 'your_password';这将创建一个名为
readonly_user的账号,密码是your_password。'%'表示该账号可以从任何主机连接到MySQL服务器。如果你想限制只能从特定主机连接,可以将'%'替换为特定主机的IP地址或主机名。授予只读权限:
单个库:将
SELECT权限赋予该账号以使其只能读取数据,而不能修改或删除数据。在这个示例中,我们将授予SELECT权限给readonly_user账号,让它可以访问database_name数据库:GRANT SELECT ON database_name.* TO 'readonly_user'@'%';如果需要赋予多个权限,需要执行多条
GRANT语句所有数据库:
GRANT SELECT ON *.* TO 'readonly_user'@'%';
刷新权限:
最后,执行以下命令以刷新MySQL的权限缓存,以确保新的权限立即生效:
FLUSH PRIVILEGES;
MySQL 5.7之前
在MySQL 5.6及更早的版本中,创建只读账户需要使用不同的命令。在这些旧版本中,密码通常以 明文形式 存储在 mysql.user 表的 Password 列中,因此你可以使用以下方式创建只读账户:
使用具有足够权限的MySQL账号(例如,
root)登录到MySQL服务器。创建只读账户并设置密码:
GRANT USAGE ON *.* TO 'readonly_user'@'localhost' IDENTIFIED BY 'password';这将创建一个名为
readonly_user的账户,并设置密码为password。'localhost'意味着这个账户只能从本地主机连接到MySQL服务器。如果你想允许从任何主机连接,可以将'localhost'替换为'%'。授予只读权限:
接下来,你需要授予只读权限给
readonly_user账户。以下是一个示例,将授予SELECT权限给readonly_user,让它可以访问指定数据库(例如,mydatabae_name)中的数据:GRANT SELECT ON mydatabae_name.* TO 'readonly_user'@'localhost';如果你希望该账号只读其他数据库,可以替换
mydatabae_name为目标数据库的名称。刷新权限:
最后,执行以下命令以刷新MySQL的权限缓存,以确保新的权限立即生效:
FLUSH PRIVILEGES;
授予其他权限
除了 SELECT 权限,你还可以使用 GRANT 命令授予MySQL账号其他权限。以下是一些常见的权限以及相应的 GRANT 命令示例:
INSERT权限:允许在表中插入新数据。
GRANT INSERT ON database_name.table_name TO 'username'@'host';UPDATE权限:允许更新表中的数据。
GRANT UPDATE ON database_name.table_name TO 'username'@'host';DELETE权限:允许删除表中的数据。
GRANT DELETE ON database_name.table_name TO 'username'@'host';CREATE权限:允许创建新数据库或表。
GRANT CREATE ON database_name.* TO 'username'@'host';ALTER权限:允许修改表结构。
GRANT ALTER ON database_name.* TO 'username'@'host';DROP权限:允许删除数据库或表。
GRANT DROP ON database_name.* TO 'username'@'host';ALL权限:允许执行所有权限(除了GRANT权限以外)。
GRANT ALL ON database_name.* TO 'username'@'host';
-- 同时授予多个权限
-- 为数据库1授予SELECT权限
GRANT SELECT ON database1.* TO 'username'@'localhost';
-- 为数据库2授予INSERT和UPDATE权限
GRANT INSERT, UPDATE ON database2.* TO 'username'@'localhost';提示
username 和 host 应替换为你要授予权限的MySQL账号和主机。你还可以将 * 用于通配符,以表示所有数据库或所有表。
事务与问题详解
MySQL 提供了多种事务隔离级别,每种隔离级别都有不同的特性和影响。事务隔离级别用于控制事务之间的可见性和并发性,不同的隔离级别可能会导致一些并发问题。以下是四种常见的事务隔离级别及其详细解释以及可能导致的问题:
读未提交(Read Uncommitted):
- 允许事务读取未提交的修改,可能会看到其他事务尚未提交的数据变化。
- 可能导致脏读、不可重复读和幻读问题。
读已提交(Read Committed):
- 一个事务只能读取已经提交的数据,避免了脏读问题。
- 但是可能会导致不可重复读和幻读问题。
可重复读(Repeatable Read):
- 事务期间,对同一行的读操作会返回相同的结果,避免了不可重复读问题。
- 但是可能会导致幻读问题,即在一个事务中两次相同的查询得到的结果行数不一致。
串行化(Serializable):
- 最高隔离级别,确保了事务的完全隔离,防止脏读、不可重复读和幻读问题。
- 但是会导致并发性能降低,因为事务需要串行执行。
重要
不同隔离级别可能会导致的问题:
- 脏读(Dirty Read):一个事务读取了另一个事务尚未提交的数据,然后另一个事务回滚,导致第一个事务读取到了无效数据。
- 不可重复读(Non-Repeatable Read):一个事务内多次读取同一行数据,但在事务期间,另一个事务修改或删除了该行数据,导致不同的读取结果。
- 幻读(Phantom Read):一个事务内查询一定范围的数据,然后另一个事务插入或删除了符合查询条件的数据,导致第一个事务查询到了新增或删除的数据。
在选择事务隔离级别时,需要权衡数据的一致性和并发性能。不同的业务场景可能需要不同的隔离级别。通常情况下,读已提交或可重复读是常见的选择,但在一些特殊情况下,可能需要使用更高的隔离级别(如串行化)来保证数据的完全隔离性。
A方法内调用B和C,C不能读到B已经删除的数据
问:现在有一个需求,mysql是默认事务隔离级别,首先有一个删除A方法,A方法需要调用删除B方法紧接着调用查询C方法,C方法一定不能查询到B方法刚才已经删除的数据,@Transactional注解应该怎么加
答:
提示
简单一点的,和下方代码一样父方法和被调用方法均使用 @Translational 注解修饰,就是用默认参数,因为被调用的内部方法会加入外部事务,也就是 deleteA 方法开启的事务,同一事务内未提交的更改也可以被读取到。
注意
绝对不要直接 this.deleteB() 等调用方法,要是用 AOP代理 的对象,例如当前类中注入的 xxxService.deleteB() 这种,否则事务会不生效。
答:也可以在不同的方法上使用不同的事务传播行为(Propagation)和隔离级别
- 删除A方法:
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
public void deleteA() {
// 执行删除操作
// 调用删除B方法
deleteB();
// 调用查询C方法
queryC();
}- 删除B方法:
@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED)
public void deleteB() {
// 执行删除操作
}- 查询C方法:
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
public void queryC() {
// 执行查询操作
}将删除A方法和查询C方法都设置为 Propagation.REQUIRED 传播行为(共用同一个事务),并且隔离级别都为 Isolation.READ_COMMITTED,这意味着它们会在同一个事务中执行,而且查询操作只能看到已经提交的数据,不会看到B方法中已经删除的数据。
而删除B方法设置为 Propagation.REQUIRES_NEW 传播行为,这将会在一个新的事务中执行,它的隔离级别也为 Isolation.READ_COMMITTED,这样可以确保在删除B方法中的事务完成后,查询C方法不会看到B方法删除的数据。
行转列(多行转成列的数据)
定义:将同样key值的多行value数据,转换为使用一key值的多列数据,使每一行数据中,每一个key对应多个value;行转列完成后,视觉上的效果是,表的总行数变少了,但是列数增加了。
示例:同一个学生id每门学科成绩各占一行,转成一行内显示多列学科成绩。
使用聚合函数,CASE IF 等,把多行的数据转成列。
列转行(多列转成行的数据)
定义:将表中同一key值对应的多个value列,转换为多行数据,使每一行数据中,保证一个key只对应一个value;列转行完成后,视觉上的效果是,表的总列数变少了,但是行数增加了。
示例:一个学生id在一行内显示多列学科成绩,转成每门学科成绩各占一行。
使用UNION ALL将按列查询的行拼接。
MySQL四大特性
MySQL是一种关系型数据库管理系统(RDBMS),具有许多特性,其中四个主要特性是:
ACID属性:原子性(Atomicity): 事务是一个不可分割的工作单元,要么全部执行成功,要么全部失败。如果其中任何一部分失败,整个事务都会被回滚到起始点,保持数据的一致性。
一致性(Consistency): 事务执行的结果必须使数据库从一个一致性状态变到另一个一致性状态。事务执行的中间状态不能被其他事务访问。是编程过程中,想要达成的一种目的。保证事务只能从一个正确的状态转移到另一个正确的状态。
提示
数据库的“一致性”从底层来说,是一组约束。这组约束可以是约束条件、可以是触发器等,也可以是它们的组合。从更高的层面来说,“一致性”是一种目的,即保持数据库与真实世界之间的正确映射。此时,需要靠各种锁来达成“一致性”。
隔离性(Isolation): 多个事务同时执行时,每个事务都不会受到其他事务的干扰。隔离性保证每个事务能够在相对于其他事务的隔离环境中执行,从而防止并发事务之间的数据冲突。
持久性(Durability): 一旦事务被提交,它对数据库的修改就是永久性的,即使系统发生故障也能够保持。
事务支持:
- MySQL支持事务的概念,允许一组相关的操作作为单个操作单元执行。这保证了数据的完整性和一致性。
关系型数据库管理系统(RDBMS):
- MySQL是一个关系型数据库管理系统,采用了表格的形式来存储和管理数据。这意味着它支持事务、数据的完整性和关系型模型的查询语言SQL(Structured Query Language)。
多用户和并发控制:
- MySQL是一个多用户的数据库系统,多个用户可以同时访问数据库。为了保证数据的一致性,MySQL采用了并发控制机制,通过锁定机制和事务隔离级别来处理多个用户同时访问相同数据的情况,防止数据不一致和冲突。
这些特性使MySQL成为一个强大的数据库管理系统,适用于各种规模的应用程序,从小型网站到大型企业级系统。
事务隔离级别
| 隔离级别 | 脏读(Dirty Read) | 不可重复读(Non-repeatable Read) | 幻读(Phantom Read) |
|---|---|---|---|
| READ UNCOMMITTED(读已提交) | 可能发生 | 可能发生 | 可能发生 |
| READ COMMITTED(读未提交) | 不会发生 | 可能发生 | 可能发生 |
| REPEATABLE READ(可重复读) | 不会发生 | 不会发生 | 可能发生 |
| SERIALIZABLE(串行化) | 不会发生 | 不会发生 | 不会发生 |
重要
- 脏读(Dirty Read): 表示一个事务读取了另一个事务未提交的数据。
- 不可重复读(Non-repeatable Read): 表示一个事务多次读取同一行数据,但在两次读取之间,另一个事务修改了该行数据,导致两次读取的结果不一致。
- 幻读(Phantom Read): 表示一个事务多次执行相同的查询,但在两次查询之间,另一个事务插入、更新或删除了行,导致两次查询的结果不一致。
需要注意的是,随着隔离级别的增加,事务的并发性下降,但数据的一致性得到了保障。选择合适的隔离级别需要根据具体的业务需求和对并发性和一致性的权衡来决定。
引擎
MySQL 主要使用2种执行引擎:
- InnoDB引擎
- MyISAM引擎
MyISAM 不支持事务,MyISAM 中的锁是表级锁;而 InnoDB 支持事务,并且支持行级锁。
——————
增删改查
INSERT INTO table_name (column1, column2, column3, ...)
VALUES
(value1, value2, value3, ...),
-- 可以多条
(value1, value2, value3, ...);-- 直接删除表,不检查是否存在
DROP TABLE table_name ;
或
DROP TABLE [IF EXISTS] table_name;-- 仅删除数据
DELETE FROM table_name
WHERE condition;UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition;SELECT column1, column2, ...
FROM table_name
[WHERE condition]
[ORDER BY column_name [ASC | DESC]]
[LIMIT number];dump备份
https://www.cnblogs.com/letcafe/p/mysqlautodump.html
#MySQLdump常用
mysqldump -u root -p --databases 数据库1 数据库2 > xxx.sql——————
查询执行顺序
from > where > group(含聚合)> having > order > select
Functions and Operators 函数和运算符
mysql中的内置函数
IFNULL
SELECT `id`, IFNULL(`name`, '无名称') FROM `student`;CONCAT
拼接多个列
CONCAT(IFNULL(C1,''),IFNULL(C2,''))重要
⚠️ NULL 值问题:如果任意一个参数为 NULL,整个结果就是 NULL。
SELECT CONCAT('Hello', NULL, 'World');
-- 结果:NULL解决方案:使用 CONCAT_WS() 或 IFNULL() 处理:
-- 方式1:CONCAT_WS 会忽略 NULL
SELECT CONCAT_WS(' ', first_name, middle_name, last_name)
FROM users;
-- 方式2:IFNULL 转换
SELECT CONCAT(IFNULL(first_name, ''), ' ', IFNULL(last_name, ''))
FROM users;其他相关函数
CONCAT_WS(separator, str1, str2, ...):使用指定分隔符拼接,自动忽略 NULL。SELECT CONCAT_WS('-', '2024', '01', '15'); -- 结果:2024-01-15GROUP_CONCAT():将分组中的多行值拼接成一个字符串。SELECT GROUP_CONCAT(name) FROM users WHERE age > 18; -- 结果:张三,李四,王五
distinct
去重结果集:对所有查询的列同时生效,它会去除整行完全相同的记录。
SELECT DISTINCT `name`,`age` FROM `student`;>、<、=
BETWEEN
[NOT] BETWEEN 取值1 AND 取值2其中:
- NOT:可选参数,表示指定范围之外的值。如果字段值不满足指定范围内的值,则这些记录被返回。
- 取值1:表示范围的起始值(包含)。
- 取值2:表示范围的终止值(包含),必须不小于取值1。
- 闭区间
日期:
between '2020-1-12' and '2020-06-12';
-- 实际执行的是 2020-01-12 00:00:00 AND 2020-06-11 23:59:59
2017-07-25 24:00:00 晚上24点即为下一天00点 2017-07-26 00:00:00,数据库识别不出24点的信息;换成下一天00点即可以查询出正确结果。- 日期
select count(1) from user where regist_date between '2017-07-25 00:00:00' and '2017-07-25 24:00:00';
-- 这条sql语句查询出结果为0。实际上数据库有一条符合该查询条件的数据。
-- 错误原因:2017-07-25 24:00:00 晚上24点即为下一天00点 2017-07-26 00:00:00,数据库识别不出24点的信息;换成下一天00点即可以查询出正确结果。JOIN
SELECT * FROM A AS a
JOIN B AS b ON a.id = b.id;连表操作时:先根据查询条件和查询字段确定驱动表,确定驱动表之后就可以开始连表操作了,然后再在缓存结果中根据查询条件找符合条件的数据
INNER JOIN
仅包含A,B两表都匹配且都不为空的行(取交集)
INNER JOIN和 , (逗号) 在语义上是等同的JOIN是INNER JOIN的简写
LEFT [OUTER] JOIN
- 包含A中所有,B中不存在的填充NULL
RIGHT [OUTER] JOIN
- 包含B中所有,A中不存在的填充NULL
USING()
on a.c1 = b.c1 等同于 using(c1)LIKE
- 百分号通配符 %:
% 通配符表示零个或多个字符。例如,'a%' 匹配以字母 'a' 开头的任何字符串。
SELECT * FROM customers WHERE last_name LIKE 'S%';以上 SQL 语句将选择所有姓氏以 'S' 开头的客户。
- 下划线通配符 _:
_ 通配符表示一个字符。例如,'_r%' 匹配第二个字母为 'r' 的任何字符串。
SELECT * FROM products WHERE product_name LIKE '_a%';以上 SQL 语句将选择产品名称的第二个字符为 'a' 的所有产品。
- 组合使用 % 和 _:
SELECT * FROM users WHERE username LIKE 'a%o_';以上 SQL 语句将匹配以字母 'a' 开头,然后是零个或多个字符,接着是 'o',最后是一个任意字符的字符串,如 'aaron'、'apol'。
- 不区分大小写的匹配:
SELECT * FROM employees WHERE last_name LIKE 'smi%' COLLATE utf8mb4_general_ci;以上 SQL 语句将选择姓氏以 'smi' 开头的所有员工,不区分大小写。
LIKE 子句提供了强大的模糊搜索能力,可以根据不同的模式和需求进行定制。在使用时,请确保理解通配符的含义,并根据实际情况进行匹配。
聚合函数
MAX
最大值
SUM
总和
COUNT
COUNT(*)中包含NULL的数据COUNT(常量)和COUNT(*)表示的是直接查询符合条件的数据库表的行数。而
COUNT(列名)表示的是查询符合条件的列的值不为NULL的行数。性能:count(*) > count(1) > count(主键字段) > count(字段)
sum,min,max,avg,count
ORDER BY
MySQL排序时如果用的的字段为字符串型的,排序规则是这样的:如1,10,2,20,3,4,5,这种排序是按照字符从第一个字符开始比较出来的,但不是我想要的,我想要的是:1,2,3,4,5……,10,20这种。
把相应的字段转换成整型,使用CAST函数,如下:
SELECT * FROM `b_datatype` ORDER BY CAST(`c_no` AS UNSIGNED) ASC;ASC:正序DESC:倒序
GROUP BY
SELECT stu_id, ANY_VALUE(stu_name), AVG(score) FROM student GROUP BY stu_id;提示
逻辑:原始数据 → 按分组字段分组 → 每组内聚合计算 → 每组返回一行
- SELECT 中的非分组字段必须使用聚合函数,否则会报错或取到不确定的值
- 分组后,每组只返回一行结果
- 需要使用聚合函数(如
AVG、SUM、COUNT、MAX、MIN)来计算组内的统计 - 一些需要展示但数据值不太重要的,使用
ANY_VALUE任意取一个 - 可以多个字段共同分组:
GROUP BY col_1, col_2
GROUP_CONCAT
每个人的每门成绩为一条记录,根据姓名分组查询之后,会报错only_full_group_by错误,使用group_concat将分组之后的同一个字段的多条结果合成一条
SELECT
`name`,
group_concat(`class`,':',`score` SEPARATOR ',') as 'class:score'
FROM `t_score_line2column` GROUP BY `name`;| name | class:score |
|---|---|
| 张三 | 数学:78,英语:93,语文:65 |
| 李四 | 数学:87,英语:90,语文:76,历史:69 |
HAVING
HAVING执行顺序在GROUP_BY之后,GROUP_BY和WHERE后不能使用聚合函数,如果需要对查询之后的结果集使用聚合函数,应使用HAVING;例如:
对分组数据再次判断时要用having
select reports,count(*) from employees group by reports having count(*) > 4;
-- 在分组数据上查询`count() > 4`的数据LIMIT
LIMIT num[, offset]不写
offset:查询前num条数据写
offset:从indexnum(包括)开始,查询offset条数据
另一种用法
SELECT * FROM t_student LIMIT 1, 3
# 另一种写法,但意思一样,都代表取第2、3、4条数据
SELECT * FROM t_student LIMIT 3 OFFSET 1LIMIT: 查3条OFFSET: 从第1条开始
IN
重要
适用于子查询(内查询)结果集比主查询的结果集少的查询语句
原理:先执行子查询,然后将子查询的结果集与主查询的结果集做一个笛卡尔乘积,然后通过子查询的结果集去和主查询的c_no匹配
[NOT] INselect * from `b_datatype` where `c_no` IN ('2','4','6');- IN 相当于 =any()
select * from `b_datatype` where `c_no` =any (select '2' UNION ALL select '4' UNION ALL select '6');- NOT IN 相当于 <>all()
EXISTS
重要
适用于主查询结果集比子查询的结果集少的查询语句
原理:先执行主查询,然后根据主查询结果集的以此用每条记录做子查询,如果子查询返回TRUE,则显示该条记录
SQL语句中exists和in的区别 - 白白的白浅 - 博客园 (cnblogs.com)
[NOT] EXISTSSELECT * FROM `student` AS s EXISTS(
SELECT id FROM `best_class` AS c WHERE s.id = c.sid
)CAST
语法
CAST(expression AS datatype)expression是需要转换的表达式或值。datatype是目标数据类型,可以是 MySQL 支持的任何数据类型,如CHAR,VARCHAR,INT,FLOAT,DATE,TIME等。
如果有列使用的varchar类型存储的数字,在使用ORDER BY排序时候是:1、10、2、20而不是想要的1、2、3,就要将列使用CAST进行转换。例如:
SELECT * FROM `b_datatype` ORDER BY CAST(`c_no` AS UNSIGNED) ASC;UNION
- 可以将多个结果集拼接在一起。例如:
SELECT 2 AS num
UNION ALL
SELECT 2 AS num
UNION ALL
SELECT 3 AS num;- 如果不想保留相同的值,就用
UNION而不是UNION ALL
运算符优先级
从最高优先级到最低优先级。一起显示在一行上的运算符具有相同的优先级。
INTERVAL
BINARY, COLLATE
!
- (unary minus), ~ (unary bit inversion)
^
*, /, DIV, %, MOD
-, +
<<, >>
&
|
= (comparison), <=>, >=, >, <=, <, <>, !=, IS, LIKE, REGEXP, IN, MEMBER OF
BETWEEN, CASE, WHEN, THEN, ELSE
NOT
AND, &&
XOR
OR, ||
= (assignment), :=比较运算符
| Name | Description |
|---|---|
> | Greater than operator 大于运算符 |
>= | Greater than or equal operator 大于或等于运算符 |
< | Less than operator 小于运算符 |
<>, != | Not equal operator 不等于运算符 |
<= | Less than or equal operator 小于或等于运算符 |
<=> | NULL-safe equal to operator NULL 安全等于运算符 |
= | Equal operator 等于运算符 |
BETWEEN ... AND ... | Whether a value is within a range of values 值是否在某个值范围内 |
COALESCE() | Return the first non-NULL argument 返回第一个非 NULL 参数 |
GREATEST() | Return the largest argument 返回最大的参数 |
IN() | Whether a value is within a set of values 一个值是否在一组值之内 |
INTERVAL() | Return the index of the argument that is less than the first argument 返回小于第一个参数的参数的索引 |
IS | Test a value against a boolean 针对布尔值测试值 |
IS NOT | Test a value against a boolean 针对布尔值测试值 |
IS NOT NULL | NOT NULL value test NOT NULL 值测试 |
IS NULL | NULL value test NULL值测试 |
ISNULL() | Test whether the argument is NULL 测试参数是否为NULL |
LEAST() | Return the smallest argument 返回最小的参数 |
LIKE | Simple pattern matching 简单的模式匹配 |
NOT BETWEEN ... AND ... | Whether a value is not within a range of values 值是否不在某个值范围内 |
NOT IN() | Whether a value is not within a set of values 某个值是否不在一组值之内 |
NOT LIKE | Negation of simple pattern matching 简单模式匹配的否定 |
STRCMP() | Compare two strings 比较两个字符串 |
日期和时间
| Name | Description |
|---|---|
ADDDATE() | Add time values (intervals) to a date value 将时间值(间隔)添加到日期值 |
ADDTIME() | Add time |
CONVERT_TZ() | Convert from one time zone to another 从一个时区转换到另一时区 |
CURDATE() | Return the current date 返回当前日期 |
CURRENT_DATE(), CURRENT_DATE | Synonyms for CURDATE() CURDATE() 的同义词 |
CURRENT_TIME(), CURRENT_TIME | Synonyms for CURTIME() CURTIME() 的同义词 |
CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP | Synonyms for NOW() NOW() 的同义词 |
CURTIME() | Return the current time 返回当前时间 |
DATE() | Extract the date part of a date or datetime expression 提取日期或日期时间表达式的日期部分 |
DATE_ADD() | Add time values (intervals) to a date value 将时间值(间隔)添加到日期值 |
DATE_FORMAT() | Format date as specified 按照指定的格式设置日期(点击链接查看参数格式) |
DATE_SUB() | Subtract a time value (interval) from a date 从日期中减去时间值(间隔)DATE_SUB(NOW(), INTERVAL 6 MONTH) |
DATEDIFF() | Subtract two dates 减去两个日期 |
DAY() | Synonym for DAYOFMONTH() DAYOFMONTH() 的同义词 |
DAYNAME() | Return the name of the weekday 返回工作日的名称 |
DAYOFMONTH() | Return the day of the month (0-31) 返回月份中的第几天 (0-31) |
DAYOFWEEK() | Return the weekday index of the argument 返回参数的工作日索引 |
DAYOFYEAR() | Return the day of the year (1-366) 返回一年中的第几天 (1-366) |
EXTRACT() | Extract part of a date 提取日期的一部分 |
FROM_DAYS() | Convert a day number to a date 将天数转换为日期 |
FROM_UNIXTIME() | Format Unix timestamp as a date 将 Unix 时间戳格式化为日期 |
GET_FORMAT() | Return a date format string 返回日期格式字符串 |
HOUR() | Extract the hour 提取小时 |
LAST_DAY | Return the last day of the month for the argument 返回参数所在月份的最后一天 |
LOCALTIME(), LOCALTIME | Synonym for NOW() NOW() 的同义词 |
LOCALTIMESTAMP, LOCALTIMESTAMP() | Synonym for NOW() NOW() 的同义词 |
MAKEDATE() | Create a date from the year and day of year 根据年份和年份创建日期 |
MAKETIME() | Create time from hour, minute, second 从时、分、秒创建时间 |
MICROSECOND() | Return the microseconds from argument 从参数返回微秒 |
MINUTE() | Return the minute from the argument 返回参数的分钟数 |
MONTH() | Return the month from the date passed 返回从过去的日期算起的月份 |
MONTHNAME() | Return the name of the month 返回月份名称 |
NOW() | Return the current date and time 返回当前日期和时间 |
PERIOD_ADD() | Add a period to a year-month 为年月添加一个期间 |
PERIOD_DIFF() | Return the number of months between periods 返回期间之间的月数 |
QUARTER() | Return the quarter from a date argument 从日期参数返回季度 |
SEC_TO_TIME() | Converts seconds to 'hh:mm:ss' format 将秒转换为“hh:mm:ss”格式 |
SECOND() | Return the second (0-59) 返回第二个 (0-59) |
STR_TO_DATE() | Convert a string to a date 将字符串转换为日期 |
SUBDATE() | Synonym for DATE_SUB() when invoked with three arguments 使用三个参数调用时 DATE_SUB() 的同义词 |
SUBTIME() | Subtract times 减去次数 |
SYSDATE() | Return the time at which the function executes 返回函数执行的时间 |
TIME() | Extract the time portion of the expression passed 提取传递的表达式的时间部分 |
TIME_FORMAT() | Format as time 格式化为时间 |
TIME_TO_SEC() | Return the argument converted to seconds 返回转换为秒的参数 |
TIMEDIFF() | Subtract time 减去时间 |
TIMESTAMP() | With a single argument, this function returns the date or datetime expression; with two arguments, the sum of the arguments 使用单个参数,该函数返回日期或日期时间表达式;有两个参数,参数之和 |
TIMESTAMPADD() | Add an interval to a datetime expression 向日期时间表达式添加间隔 |
TIMESTAMPDIFF() | Return the difference of two datetime expressions, using the units specified 使用指定的单位返回两个日期时间表达式的差值 |
TO_DAYS() | Return the date argument converted to days 返回转换为天数的日期参数 |
TO_SECONDS() | Return the date or datetime argument converted to seconds since Year 0 返回自 0 年以来转换为秒数的日期或日期时间参数 |
UNIX_TIMESTAMP() | Return a Unix timestamp 返回 Unix 时间戳 |
UTC_DATE() | Return the current UTC date 返回当前 UTC 日期 |
UTC_TIME() | Return the current UTC time 返回当前 UTC 时间 |
UTC_TIMESTAMP() | Return the current UTC date and time 返回当前 UTC 日期和时间 |
WEEK() | Return the week number 返回周数 |
WEEKDAY() | Return the weekday index 返回工作日索引 |
WEEKOFYEAR() | Return the calendar week of the date (1-53) 返回日期的日历周 (1-53) |
YEAR() | Return the year 返回年份 |
YEARWEEK() | Return the year and week 返回年份和星期 |
数学函数
数字函数和运算符
| Name | Description |
|---|---|
%, MOD | Modulo operator 模运算符 |
* | Multiplication operator 乘法运算符 |
+ | Addition operator 加法运算符 |
- | Minus operator 减号运算符 |
- | Change the sign of the argument 改变参数的符号 |
/ | Division operator 分部操作员 |
ABS() | Return the absolute value 返回绝对值 |
ACOS() | Return the arc cosine 返回反余弦值 |
ASIN() | Return the arc sine 返回反正弦值 |
ATAN() | Return the arc tangent 返回反正切值 |
ATAN2(), ATAN() | Return the arc tangent of the two arguments 返回两个参数的反正切 |
CEIL() | Return the smallest integer value not less than the argument 返回不小于参数的最小整数值 |
CEILING() | Return the smallest integer value not less than the argument 返回不小于参数的最小整数值 |
CONV() | Convert numbers between different number bases 在不同数基之间转换数字 |
COS() | Return the cosine 返回余弦值 |
COT() | Return the cotangent 返回余切值 |
CRC32() | Compute a cyclic redundancy check value 计算循环冗余校验值 |
DEGREES() | Convert radians to degrees 将弧度转换为度数 |
DIV | Integer division 整数除法 |
EXP() | Raise to the power of 提升至 的力量 |
FLOOR() | Return the largest integer value not greater than the argument 返回不大于参数的最大整数值 |
LN() | Return the natural logarithm of the argument 返回参数的自然对数 |
LOG() | Return the natural logarithm of the first argument 返回第一个参数的自然对数 |
LOG10() | Return the base-10 logarithm of the argument 返回参数以 10 为底的对数 |
LOG2() | Return the base-2 logarithm of the argument 返回参数以 2 为底的对数 |
MOD() | Return the remainder 返回余数 |
PI() | Return the value of pi 返回 pi 的值 |
POW() | Return the argument raised to the specified power 返回参数的指定次方 |
POWER() | Return the argument raised to the specified power 返回参数的指定次方 |
RADIANS() | Return argument converted to radians 返回转换为弧度的参数 |
RAND() | Return a random floating-point value 返回一个随机浮点值 |
ROUND() | Round the argument 围绕论证 |
SIGN() | Return the sign of the argument 返回参数的符号 |
SIN() | Return the sine of the argument 返回参数的正弦值 |
SQRT() | Return the square root of the argument 返回参数的平方根 |
TAN() | Return the tangent of the argument 返回参数的正切值 |
TRUNCATE() | Truncate to specified number of decimal places 截断至指定的小数位数 |
数据库操作语句类型(DQL、DML、DDL、DCL)简介
https://www.cnblogs.com/study-s/p/5287529.html
SQL语言共分为四大类:数据查询语言DQL,数据操纵语言DML,数据定义语言DDL,数据控制语言DCL。
数据查询语言(DQL)
基本结构是由SELECT子句,FROM子句,WHERE 子句组成的查询块:
SELECT <字段名表> FROM <表或视图名> WHERE <查询条件>数据操纵语言(DML) 主要有三种形式:
- 插入:
INSERT - 更新:
UPDATE - 删除:
DELETE
- 插入:
数据定义语言(DDL)
用来创建数据库中的各种对象:表、视图、索引、同义词、聚簇等:
表 视图 索引 同义词 聚簇 CREATE TABLE CREATE VIEW CREATE INDEX CREATE SYN CREATE CLUSTER 重要
DDL操作是隐性提交的,不能Rollback!
数据控制语言(DCL)
用来授予或回收访问数据库的某种特权,并控制数据库操纵事务发生的时间及效果,对数据库实行监视等。如:
GRANT:授权。ROLLBACK [WORK] TO [SAVEPOINT]:回退到某一点。 回滚命令使数据库状态回到上次最后提交的状态。其格式为:SQL>ROLLBACK;
COMMIT [WORK]:提交。在数据库的插入、删除和修改操作时,只有当事务在提交到数据 库时才算完成。在事务提交前,只有操作数据库的这个人才能有权看 到所做的事情,别人只有在最后提交完成后才可以看到。 提交数据有三种类型:显式提交、隐式提交及自动提交。下面分 别说明这三种类型。
- 显式提交 用
COMMIT命令直接完成的提交为显式提交。其格式为:SQL>COMMIT; - 隐式提交 用SQL命令间接完成的提交为隐式提交。这些命令是:
ALTER,AUDIT,COMMENT,CONNECT,CREATE,DISCONNECT,DROP,EXIT,GRANT,NOAUDIT,QUIT,REVOKE,RENAME。 - 自动提交 若把
AUTOCOMMIT设置为ON,则在插入、修改、删除语句执行后,系统将自动进行提交,这就是自动提交。其格式为:SQL>SET AUTOCOMMIT ON;
- 显式提交 用
DB Link
需要操作其他数据库实例的部分表,但又不想系统连接多库。此时我们就需要用到数据表映射。如同Oracle中的DBlink一般。
1.开启FEDERATED引擎
若需要创建FEDERATED引擎表,则目标端实例要开启FEDERATED引擎。
提示
从MySQL5.5开始FEDERATED引擎默认安装,只是没有启用,进入命令行输入show engines; FEDERATED行状态为NO。
- 在配置文件
[mysqld]中加入一行:federated,然后重启数据库,FEDERATED引擎就开启了。
2. 创建FEDERATED表
使用CONNECTION创建FEDERATED表
-- 创建一个与源表结构相同的表(推荐与源端结构一致)
CREATE TABLE (......)
ENGINE =FEDERATED CONNECTION='mysql://username:password@hostname:port/database/tablename';
-- 注意ENGINE=FEDERATED CONNECTION后为源端地址 避免使用带@的密码3.使用CREATE SERVER
使用 CREATE SERVER 创建FEDERATED表
如果要在同一服务器上创建多个FEDERATED表,或者想简化创建FEDERATED表的过程,则可以使用该 CREATE SERVER 语句定义服务器连接参数,这样多个表可以使用同一个server。
CREATE SERVER创建的格式是:
CREATE SERVER link_name
FOREIGN DATA WRAPPER mysql
OPTIONS (USER 'fed_user', PASSWORD '123456', HOST 'remote_host', PORT 3306, DATABASE 'db_name');验证:
select * from mysql.servers之后创建FEDERATED表可采用如下格式:
CREATE TABLE (......)
ENGINE =FEDERATED CONNECTION='link_name/tablename'使用总结
- 目标端建表结构可以与源端不一样 推荐与源端结构一致
- 源端DDL语句更改表结构 目标端不会变化
- 源端DML语句目标端查询会同步
- 源端drop表 目标端结构还在但无法查询
- 目标端不能执行DDL语句
- 目标端执行DML语句 源端数据也会变化
- 目标端truncate表 源端表数据也会被清空
- 目标端drop表对源端无影响
非官方使用规范
- 源端专门创建只读权限的用户来供目标端使用。
- 目标端建议用CREATE SERVER方式创建FEDERATED表。
- FEDERATED表不宜太多,迁移时要特别注意。
- 目标端应该只做查询使用,禁止在目标端更改FEDERATED表。
- 建议目标端表名及结构和源端保持一致。
- 源端表结构变更后 目标端要及时删除重建。
