# MySQL安装和基础数据类型

loading

# 一,安装

这里介绍在 Linux 下的安装。

首先去官网下载 MySQL 的压缩包,官网地址 https://downloads.mysql.com/archives/community/,将下载好的 MySQL 安装包解压到 /usr/local 目录下,我这里使用的是 mysql-5.7.9-linux-glibc2.5-x86_64.tar.gz

tar -zxvf mysql-5.7.9-linux-glibc2.5-x86_64.tar.gz -C /usr/local
1

进入刚才解压好的目录,可以看到有这么一个文件 INSTALL-BINARY ,这个其实就是 MySQL 的安装文档。下面根据这个安装文档进行操作安装:

# 1、安装依赖

yum install -y libaio
1

# 2、添加组

groupadd mysql
1

# 3、添加用户

useradd -r -g mysql mysql
1

# 4、创建软连接

进入 /usr/local 目录下

ln -s /usr/local/mysql-5.7.9-linux-glibc2.5-x86_64/ mysql
1

# 5、创建目录

mkdir mysql-files
1

# 6、授权

chmod 770 mysql-files
chown -R mysql .
1
2

# 7、切换组

chgrp -R mysql .
1

# 8、初始化

bin/mysqld --initialize --user=mysql
bin/mysql_ssl_rsa_setup # 这行命令会产生一个临时密码,注意记录,方便后面修改密码
1
2

# 9、继续授权

chown -R root .
chown -R mysql data mysql-files # 此时如果提示没有data文件夹就需要先创建一下,再执行这个命令
1
2

此时,进入目录 data,如果发现目录里面有数据,就说明初始化成功了

# 10、启动

bin/mysqld_safe --user=mysql &
1

在这一步启动可能会报错,提示没有权限,此时就是读取配置文件 my.cnf 错误的问题。使用命令 /usr/local/mysql/bin/mysqld --verbose --help | grep -A 1 'Default options' 可以查看配置文件的优先读取顺序。执行后可以看到顺序如下:

Default options are read from the following files in the given order:
/etc/my.cnf /etc/mysql/my.cnf /usr/local/mysql/etc/my.cnf ~/.my.cnf
1
2

有可能这一步还是没法找到配置文件,那么去 /usr/local/mysql/support-files/ 下找找是否有一个 my-default.cnf 文件,将这个文件复制到 /etc 下,并重命名为 my.cnf。

# 11、查看是否启动成功

ps -ef | grep mysqld
1

出现如下:

root     20528 17748  0 23:05 pts/0    00:00:00 /bin/sh bin/mysqld_safe --user=mysql
mysql    20610 20528  0 23:05 pts/0    00:00:00 /usr/local/mysql/bin/mysqld --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data --plugin-dir=/usr/local/mysql/lib/plugin --user=mysql --log-error=/usr/local/mysql/data/yjtravel-bring.err --pid-file=/usr/local/mysql/data/yjtravel-bring.pid
root     21277 17748  0 23:15 pts/0    00:00:00 grep --color=auto mysqld
1
2
3

说明启动成功了

# 12、配置服务默认开启

cp support-files/mysql.server /etc/init.d/mysql.server
1

# 13、查看目前配置的开机启动的程序

chkconfig --list
1

# 14、配置开机启动

chkconfig mysql.server on
1

# 15、配置环境变量

编辑文件 /etc/profile,给文件末尾添加:

export PATH=/usr/local/mysql/bin:$PATH
1

刷新配置文件:

source /etc/profile
1

# 16、测试连接

mysql -uroot -p'MaZI.yGp*2Su' # 刚才安装时生成的密码
1

# 17、连接成功后,修改密码,配置允许远程连接

set password = '123456';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456';
flush privileges;
1
2
3

% 表示所有 ip

# 18、重启mysql

先停止服务,然后再启动服务即可。

/etc/inint.d/mysql stop
/etc/inint.d/mysql start
1
2

# 二、多实例安装

首先修改配置文件如下:

[mysqld]
sql_mode="STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER"

[mysqld_multi]
mysqld=/usr/local/mysql/bin/mysqld_safe
mysqladmin=/usr/local/mysql/bin/mysqladmin
log=/var/log/mysqld_multi.log

[mysqld1]
server-id=11
socket=/tmp/mysql.sock1
port=3307
datadir=/usr/local/mysql/data1
user=mysql
performance_schema=off
innodb_buffer_pool_size=32M
skip_name_resolve=1
log_error=error.log
pid-file=/usr/local/mysql/data1/mysql.pid1

[mysqld2]
server-id=12
socket=/tmp/mysql.sock2
port=3308
datadir=/usr/local/mysql/data2
user=mysql
performance_schema=off
innodb_buffer_pool_size=32M
skip_name_resolve=1
log_error=error.log
pid-file=/usr/local/mysql/data2/mysql.pid2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

在 /usr/local/mysql 目录下创建 data1 和 data2目录。并给予权限 chown mysql.mysql /usr/local/mysql/data1 和 chown mysql.mysql /usr/local/mysql/data2

接下来初始化;

mysqld --initialize --user=mysql --datadir=/usr/local/mysql/data1
mysqld --initialize --user=mysql --datadir=/usr/local/mysql/data2
1
2

同时不要忘记记录两个实例生成的密码。

接来下配置开机启动:

cp /usr/local/mysql/support-files/mysqld_multi.server /etc/init.d/mysqld_multid
1

然后修改 mysqld_multid 文件,在文件顶部加入环境变量:export PATH=$PATH:/usr/local/mysql/bin

然后再执行:

chkconfig mysqld_multid on
1

启动多实例:mysqld_multi start

查看启动状态:mysqld_multi report,如果现实两个服务器都是 running 状态就说明成功了,如果不是 running 状态的话,可以去 /data1 或者 /data2 目录下查看下错误的日志信息,日志存放在 error.log 文件中。

至此,多实例的安装和启动就已经完成了,这个多实例和之前的单实例互相独立,互不影响。

接下来服务器登录两个实例进行修改密码和允许远程访问:

mysql -u root -S /tmp/mysql.sock1 -p -P3307
1
set password = '123456';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456';
flush privileges;
1
2
3

然后重复这个操作对第二个实例进行操作。

# 三、MySQL权限

使用 root 用户通过工具远程登录,创建数据库 mall,给用户 dev 授予查询 mall 数据库的权限:

GRANT SELECT ON mall.* TO 'dev'@'%' IDENTIFIED BY '123456'; # 这个密码可以和root用户的密码不一致
1

在执行这条语句的时候可能会提示 Access denied for user 'root'@'%' to database 'mall',这是由于多个 root 用户在登录的时候产生了多个进程,所以在开始给 root 用户授权的时候系统并不知道具体给哪个 root 授权,此时需要将所有root 相关进程进行结束,命令如下:

SELECT concat('KILL ',id,';') FROM information_schema.processlist WHERE user='root';
1

然后重新登录授权就没问题了。 具体原因可以查看这篇帖子:https://blog.csdn.net/gu_wen_jie/article/details/89242255

查看 dev 用户目前的权限:

SHOW GRANTS FOR 'dev'@'%'
1

# 1、权限粒度

其实在 MySQL 中,权限是可以精确到字段级别的。

创建表语句:

CREATE TABLE `account` (
	`id` INT(11) NOT NULL,
	`name` VARCHAR(50) DEFAULT NULL,
	`balance` INT(255) DEFAULT NULL,
	PRIMARY KEY (`id`),
	KEY `idx_balance` (`balance`)
) ENGINE=INNODB DEFAULT CHARSET=UTF8
1
2
3
4
5
6
7

随便插入几条数据:

INSERT `account` VALUE ('1', 'lilei', '900');
INSERT `account` VALUE ('2', 'hanmei', '100');
INSERT `account` VALUE ('3', 'lucy', '250');
INSERT `account` VALUE ('5', 'tom', '0');
1
2
3
4

mysql 库中的 user 表存储了 用户+ip 所对应的权限。db 表存储了用户对库所具有的权限。tables_priv 和 columns_priv 可以控制表和列级别的权限。

移除给用户分配的权限:

REVOKE SELECT ON mall.* FROM 'dev'@'%';
1

只给用户分配指定字段的查询权限:

GRANT SELECT(id, name) ON mall.account to 'dev'@'%'; # 只能访问id和name字段
1

此时使用 dev 用户登录就只能访问 mall 数据库的 id 和 name 字段了。

# 2、角色概念

在 MySQL 中是没有明确的角色概念的,但是可以将用户理解成为一个角色的概念。

设置开启角色功能和密码加密:

SET GLOBAL check_proxy_users = 1;
SET GLOBAL mysql_native_password_proxy_users = 1;
1
2

创建用户(理解成角色)

CREATE USER 'dev_role'; // 看成是角色
CREATE USER 'deer'; // 看成是用户
CREATE USER 'enjoy'; // 看成是用户
1
2
3

此时需要给 root 用户授权的权限,需要在 MySQL 控制台进行授权,然后在进行授权。

GRANT PROXY ON ''@'' TO 'root'@'%';
GRANT PROXY ON 'dev_role' to 'deer';
GRANT PROXY ON 'dev_role' to 'enjoy';
flush privileges;
1
2
3
4

这时只要给 dev_role 角色授权,另外两个用户就自动有权限了。

GRANT SELECT(id, name) ON mall.account to 'dev_role'@'%';
1

这时使用 deer 和空密码进行登录,可以查询到 account 表的 id 和 name 字段了。

SELECT id, name FROM account;
1

在 proxies_priv 表中可以看到刚才给用户授予角色的信息。

# 四、MySQL数据类型

# 1、INT 类型

类型 字节 最小值 最大值
有符号 TINYINT 1 -128 127
无符号 TINYINT 1 0 255
有符号 SMALLINT 2 -32768 32767
无符号 SMALLINT 2 0 65535
有符号 MEDIUMINT 3 -8388608 8388607
无符号 MEDIUMINT 3 0 16777215
有符号 BIGINT 8 -92233720368547758080 92233720368547758087
无符号 BIGINT 8 0 18446744073709551615

创建个无符号表,并插入数据:

CREATE TABLE test_unsigned (a INT UNSIGNED, b INT UNSIGNED);
INSERT test_unsigned VALUE(1, 2);
1
2

做如下查询:

SELECT b - a FROM test_unsigned;
1

可以正常查询,再做如下查询:

SELECT a - b FROM test_unsigned;
1

可以发现查询结果是null或者报错了,因为超出了最大精度。

创建表并插入数据:

CREATE TABLE test_int_n(a INT(4) ZEROFILL);

INSERT test_int_n VALUE(1);
INSERT test_int_n VALUE(123456);
1
2
3
4

这个INT(4) 表示如果没有达到长度位数4,会在前面补零。

此时使用终端进行查询:

SELECT * FROM test_int_n;
1

就会发现显示结果是:

+--------+
| a      |
+--------+
|   0001 |
| 123456 |
+--------+
1
2
3
4
5
6

要想创建逐渐自动增长的表,一定要指明主键:

CREATE TABLE test_auto_increment(a INT AUTO_INCREMENT PRIMARY KEY);
1

插入数据:

INSERT test_auto_increment VALUES(null), (100), (null), (10), (null);
1

查询:

SELECT * FROM test_auto_increment;
1

结果:

1
10
100
101
102
1
2
3
4
5

再插入一条数据:

INSERT test_auto_increment VALUE(-1), (-3), (0);
1

查询

SELECT * FROM test_auto_increment;
1

结果:

-3
-1
1
10
100
101
102
104
1
2
3
4
5
6
7
8

# 2、字符类型

类型 说明 N的含义 是否有字符集 最大长度
CHAR(N) 定长字符 字符 是 255
VARCHAR(N) 变长字符 字符 是 16348
BINARY(N) 定长二进制字节 字节 否 255
VARBINARY(N) 变长二进制字节 字节 是 16348
TINYBLOB(N) 二进制大对象 字节 是 256
BLOB(N) 二进制大对象 字节 是 16K
MEDIUMBLOB(N) 二进制大对象 字节 是 255
LONGBLOB(N) 二进制大对象 字节 否 4G
TINYTEXT(N) 大对象 字节 是 256
TEXT(N) 大对象 字节 是 16K
MEDIUMTEXT(N) 大对象 字节 是 16M
LONGTEXT(N) 大对象 字节 是 4G

除了 CHAR 和 VARCHAR 保存的是字符,其它保存的都是字节

默认情况下,当数据库的排序规则是 utf8_general_ci 的时候:

SELECT 'a' = 'A';
1

执行的结果是:

1
1

utf8_general_ci 排序规则会忽略大小写,而 utf8_bin 排序规则不会忽略大小写。

修改数据库的排序规则:

SET NAMES utf8mb4 COLLATE utf8mb4_bin;
1

此时再执行:

SELECT 'a' = 'A';
1

执行的结果是:

0
1

# 3、日期类型

日期类型 占用空间 表示范围
DATETIME 8 1000-01-01 00:00:00 ~ 9999-12-31 23:59:59
DATE 3 1000-01-01 ~ 9999-12-31
TIMESTAMP 4 1970-01-01 00:00:00UTC ~ 2038-01-19 03:14:07UTC
YEAR 1 YEAR(2):1970-2070, YEAR(4):1901-2155
TIME 3 -838:59:59 ~ 838:59:59

创建表,添加数据:

CREATE TABLE test_time(a TIMESTAMP, b DATETIME);

INSERT test_time VALUES (now(), now());


SELECT @@time_zone;

SET time_zone = '+00:00';
1
2
3
4
5
6
7
8

此时查询:

SELECT * FROM test_time;
1

结果:

2020-04-19 22:25:00	2020-04-19 22:25:00
1

如果修改了时区:

SET time_zone = '+00:00';
# 查询时区可以用这个
SET time_zone = '+00:00';
1
2
3

此时查询:

SELECT * FROM test_time;
1

结果:

2020-04-19 14:25:00	2020-04-19 22:25:00
1

发现时间不一样了,这说明 TIMESTAMP 类型是带有时区信息的,而 DATETIME 没有时区信息。

# 4、json类型

json 数据类型是从 mysql 5.7才引入的类型。

创建表:

CREATE TABLE json_user ( uid INT AUTO_INCREMENT, data json, PRIMARY KEY ( uid ) );
1

插入数据:

INSERT json_user
VALUES
	( NULL, '{ "name":"lison", "age":18, "address":"enjoy"
	}' );
INSERT json_user
VALUES
	( NULL, '{"name":"james", "age":28, "mail":"james@163.com"
	}' );
1
2
3
4
5
6
7
8

这里如果 json 格式有问题,是无法插入成功的。

# (1) 常用函数

# json_extract 抽取
SELECT	json_extract ( '[10, 20, [30, 40]]', '$[1]' );
1

执行结果是:20

如果想要查询 json_user 表中 data 字段 json 的 name 列和 address 列,可以这么写:

SELECT
	json_extract ( data, '$.name' ),
	json_extract ( data, '$.address' ) 
FROM
	json_user;
1
2
3
4
5
# json_object 对象转json

这个函数会将给定的参数两两匹配,组成一个 json 对象。

SELECT	json_object ( "name", "enjoy", "email", "enjoy.com", "age", 35 );
1

执行结果是:{"age": 35, "name": "enjoy", "email": "enjoy.com"}

给 json_user 表添加数据:

INSERT json_user 
VALUE
	( NULL, json_object ( "name", "enjoy", "email", "enjoy.com", "age", 35 ) );
1
2
3
# json_insert 插入数据

首先讲一个知识点。@ 和 @@,前者是查询局部变量的,后者是查询全局变量的。

例如 SHOW VARIABLES LIKE '%datadir%'; 可以查询存放数据的目录,同样使用 SELECT @@datadir; 也可以完成同样的效果。

那么此时设置一个局部变量:

SET @json = '{ "a": 1, "b": [2, 3]}';
1

然后:

SELECT	json_insert ( @json, '$.a', 10, '$.c', '[true, false]' );
1

执行结果是:{"a": 1, "b": [2, 3], "c": "[true, false]"}。

因为原本的 @json 中,a 字段已经有值了,所以插入的时候10是不能插入成功的,而字段 c 因为在原本的 json 中不存在,所以可以将 c 字段追加插入到 json 中。

看下面这个语句:

UPDATE json_user 
SET data = json_insert ( data, "$.address_2", "xiangxue" ) 
WHERE
	uid = 1;
1
2
3
4

这个就给原来 data 字段的 json 中新增了一个 address_2 字段,并且值是 xiangxue

# json_merge 合并数据并返回
SELECT	json_merge ( '{"name": "enjoy"}', '{"id": 47}' );
1

执行结果:{"id": 47, "name": "enjoy"}

那么语句:

SELECT
	json_merge ( json_extract ( data, '$.address' ), json_extract ( data, '$.address_2' ) ) 
FROM
	json_user 
WHERE
	uid = 1;
1
2
3
4
5
6

的意思就是将 data 字段 json 中的 address 和 address2 字段进行合并并返回。

结果:["enjoy", "xiangxue"]

其它关于 json 的更多函数可以在官网查询:https://dev.mysql.com/doc/refman/5.7/en/json-function-reference.html

# (2) json索引

json 类型数据本身无法直接创建索引,需要将需要索引的 json 数据重新生成虚拟列(Virtual Columns)之后,对该列进行索引。

创建表:

CREATE TABLE test_index_1 ( 
data json, 
gen_col VARCHAR ( 10 ) generated always AS ( json_extract ( data, '$.name' ) ), 
INDEX idx ( gen_col ) 
);
1
2
3
4
5

这个语句创建的表有2个字段,一个字段是 data,另一个字段 gen_col 的值是来自 data 字段中 name 字段的值。

插入数据:

INSERT test_index_1 ( data )
VALUES
	( '{"name":"king", "age":18, "address":"cs"}' );
INSERT test_index_1 ( DATA )
VALUES
	( '{"name":"peter", "age":28, "address":"zz"}' );
1
2
3
4
5
6

查询即可看到 gen_col 字段就有了值。

于是,也就可以实现 where 语句的查询功能:

SELECT
	json_extract ( data, "$.name" ) AS username 
FROM
	test_index_1 
WHERE
	gen_col = '"king"';
1
2
3
4
5
6

注意,这里生成的 gen_col 列的值是带有 " 的,查询的时候不要忘记了。但是这样似乎有些麻烦,有什么办法可以让查询的时候不用输入 " 呢?

只需要在创建的时候使用如下语句:

CREATE TABLE test_index_2 (
	 data json, 
	 gen_col VARCHAR ( 10 ) generated always AS ( json_unquote( json_extract( DATA, "$.name" ) )), 
	 INDEX idx ( gen_col ) 
);
1
2
3
4
5

这里使用到了 json_unquote() 函数,它将 " 去掉了。


上次更新: 2020-08-21 09:02:51(10 小时前)