文章目录
- 数据库基础
- 数据库概念
- 主流数据库
- 服务器,数据库,表关系
- 基本使用
- MySQL架构
- SQL语句分类
- 存储引擎
- 库的操作
- 创建数据库
- 创建数据库案例
- 字符集和校验规则
- 操纵数据库
- 表的操作
- 创建表
- 查看表结构
- 修改表
- 删除表
- 数据类型
- 数据类型分类
- 数值类型
- 字符串类型
- 表的约束
- 空属性
- 默认值
- 列描述
- zerofil
- 主键
- 复合主键
- 自增长
- 唯一键
- 外键
数据库基础
数据库概念
存储数据用文件就可以实现,但是使用文件存储数据具有如下的缺点:1.文件的安全性问题,2.文件不利于数据查询和管理,3.文件不利于存储海量数据,4.文件在程序中控制不方便。为了解决上述问题,专家们设计出更加利于管理数据的东西——数据库,它能更有效的管理数据。数据库的水平是衡量一个程序员水平的重要指标。
数据库是数据库专家统一编写的数据库服务,该服务以mysqld的形式呈现,在磁盘上有大量的文件保存数据库和数据库内部的数据,把数据库服务端和数据库及其内部的数据统称为数据库。 从狭义上来讲,数据库是以特定的格式保存好的文件,从广义上来讲,数据库是提供较为便捷的数据的存取服务的软件集合或解决方案。
数据库的存储介质是磁盘和内存,但是主要是磁盘为主,内存为辅。mysql也是一种文件系统,重点是针对文件内容。
主流数据库
- SQL Sever: 微软的产品,.Net程序员的最爱,中大型项目。
- Oracle: 甲骨文产品,适合大型项目,复杂的业务逻辑,并发一般来说不如MySQL。
- MySQL:世界上最受欢迎的数据库,属于甲骨文,并发性好,不适合做复杂的业务。主要用在电商,SNS,论坛。对简单的SQL处理效果好。
- PostgreSQL :加州大学伯克利分校计算机系开发的关系型数据库,不管是私用,商用,还是学术研究使用,可以免费使用,修改和分发。
- SQLite: 是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。
- H2: 是一个用Java开发的嵌入式数据库,它本身只是一个类库,可以直接嵌入到应用项目中。
服务器,数据库,表关系
所谓安装数据库服务器,只是在机器上安装了一个数据库管理系统程序,这个管理程序可以管理多个数据库,一般开发人员会针对每一个应用创建一个数据库。为保存应用中实体的数据,一般会在数据库中创建多个表,以保存程序中实体的数据。
数据库服务器、数据库和表的关系如下:
(DB———Database)
基本使用
连接数据库
mysql -h 127.0.0.1 -P 3306 -u root -p
如果没有写 -h 127.0.0.1 默认是连接本地,如果没有写 -P 3306 默认是连接3306端口号。
创建数据库
create database helloworld;
使用数据库
use helloworld;
创建数据库表
create table student(id int,name varchar(32),gender varchar(2)
);
表中插入数据
insert into student (id, name, gender) values (1, '张三', '男');
insert into student (id, name, gender) values (2, '李四', '女');
insert into student (id, name, gender) values (3, '王五', '男');
查询表中的数据
select * from student;
数据逻辑存储
MySQL架构
MySQL 是一个可移植的数据库,几乎能在当前所有的操作系统上运行,如 Unix/Linux、Windows、Mac 和 Solaris。各种系统在底层实现方面各有不同,但是 MySQL 基本上能保证在各个平台上的物理体系结构的一致性。
SQL语句分类
- DDL【data definition language】 数据定义语言,用来维护存储数据的结构,对数据库和表结构,更多是属性操作。代表指令: create, drop, alter
- DML【data manipulation language】 数据操纵语言,用来对数据进行操作,对数据库和表结构,更多的是数据内容操作。代表指令: insert,delete,update。DML中又单独分了一个DQL,数据查询语言,代表指令: select
- DCL【Data Control Language】 数据控制语言,主要负责权限管理和事务,操作整个MySQL的系统安全和账户管理工作。代表指令: grant,revoke,commit
存储引擎
存储引擎是数据库管理系统如何存储数据、如何为存储的数据建立索引和如何更新、查询数据等技术的实现方法。MySQL的核心就是插件式存储引擎,支持多种存储引擎。
查看存储引擎
show engines;
存储引擎对比
库的操作
创建数据库
语法:
CREATE DATABASE [IF NOT EXISTS] db_name [create_specification [,
create_specification] ...]create_specification:[DEFAULT] CHARACTER SET charset_name[DEFAULT] COLLATE collation_name
- 大写的表示关键字
- [] 是可选项
- CHARACTER SET: 指定数据库采用的字符集
- COLLATE: 指定数据库字符集的校验规则
创建一个数据库在Linux机器本质上是在做什么?
在mysql中建立一个数据库,create database本质上是在Linux机器下建立了一个目录。
创建数据库案例
创建名为 db1 的数据库
create database db1;
创建数据库没有指定字符集和校验规则时,系统使用默认字符集:utf8,校验规则是:utf8_ general_ ci
创建一个使用utf8字符集的 db2 数据库
create database db2 charset=utf8;
创建一个使用utf字符集,并带校对规则的 db3 数据库
create database db3 charset=utf8 collate utf8_general_ci;
字符集和校验规则
MySQL数据库的核心工作不外乎存数据和取数据,字符集保证按照特定的编码来存储数据,数据的校验编码用来取数据进行比较。一般字符集和检验规则(集)是匹配的。设置数据库的编码和校验规则, 其实是影响数据库的内部的表所对应的编码和校验规则。
查看系统默认字符集以及校验规则
show variables like 'character_set_database';
show variables like 'collation_database';
查看数据库支持的字符集
show charset;
查看数据库支持的字符集校验规则
show collation;
校验规则对数据库的影响
创建一个数据库test1,校验规则使用utf8_ general_ ci[不区分大小写];再创建一个数据库test2,校验规则使用utf8_ bin[区分大小写]。插入相同的数据 ‘a’ ,‘A’,‘b’,‘B’,进行查询,结果完全不同。
mysql> use test1;
mysql> select * from person where name='a';
+------+
| name |
+------+
| a |
| A |
+------+
2 rows in set (0.01 sec)
mysql> use test2;
mysql> select * from person where name='a';
+------+
| name |
+------+
| a |
+------+
2 rows in set (0.01 sec)
操纵数据库
查看数据库
show databases;
显示创建语句
show create database 数据库名;
mysql> show create database mytest;
+----------+----------------------------------------------------------------+
| Database | Create Database |
+----------+----------------------------------------------------------------+
| mysql | CREATE DATABASE `mytest` /*!40100 DEFAULT CHARACTER SET utf8 */ |
+----------+----------------------------------------------------------------+
- MySQL 建议我们关键字使用大写,但是不是必须的。
- 数据库名字的反引号``,是为了防止使用的数据库名刚好是关键字
- /*!40100 default… */ 这个不是注释,表示当前mysql版本大于4.01版本,就执行这句话。
修改数据库
ALTER DATABASE db_name
[alter_spacification [,alter_spacification]...]alter_spacification:
[DEFAULT] CHARACTER SET charset_name
[DEFAULT] COLLATE collation_name
对数据库的修改主要指的是修改数据库的字符集,校验规则。例如将 mytest 数据库字符集改成 gbk。MySQL不支持库名字的修改,但可以修改表名。
mysql> alter database mytest charset = gbk;
Query OK, 1 row affected (0.00 sec)
mysql> show create database mytest;
+----------+----------------------------------------------------------------+
| Database | Create Database |
+----------+----------------------------------------------------------------+
| mytest | CREATE DATABASE `mytest` /*!40100 DEFAULT CHARACTER SET gbk */ |
+----------+----------------------------------------------------------------+
数据库删除
DROP DATABASE [IF EXISTS] db_ name;
删除数据后,对应的数据库文件夹被删除,级联删除,里面的数据表全部被删,所以不要随意删除数据库。
数据库备份
数据库备份有两种方案,一种是对数据内容做备份,另外一种是对操作语句做备份,mysqldump 是对于操作语句做备份。
操作:
退出连接数据库后在命令行中输入
mysqldump -P3306 -u root -p 密码 -B 数据库名 > 数据库备份存储的文件路径
如果备份的是其中的一张表
mysqldump -u root -p 数据库名 表名1 表名2 > D:/mytest.sql
备份多个数据库
mysqldump -u root -p -B 数据库名1 数据库名2 ... > 数据库存放路径
如果备份一个数据库时,没有带上-B参数, 在恢复数据库时,需要先创建空数据库,然后使用数据库,再使用source来还原。
示例:将mytest库备份到文件
mysqldump -P3306 -u root -p123456 -B mytest > D:/mytest.sql
打开看看 mytest.sql 文件里的内容,其实把整个创建数据库,建表,导入数据的语句都装载这个文件中。
数据库还原
mysql > source D:/mysql-5.7.22/mytest.sql;
查看连接情况
show processlist
该语句可以告诉我们当前有哪些用户连接到我们的MySQL,如果查出某个用户不是你正常登陆的,很有可能你的数据库被人入侵了。当发现自己数据库比较慢时,可以用这个指令来查看数据库连接情况。
示例:
mysql> show processlist;
+----+------+-----------+------+---------+------+-------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+------+-----------+------+---------+------+-------+------------------+
| 2 | root | localhost | test | Sleep | 1386 | | NULL |
| 3 | root | localhost | NULL | Query | 0 | NULL | show processlist |
+----+------+-----------+------+---------+------+-------+------------------+
表的操作
创建表
语法:
CREATE TABLE table_name (field1 datatype,field2 datatype,field3 datatype
) character set 字符集 collate 校验规则 engine 存储引擎;
说明:
- field 表示列名
- datatype 表示列的类型
- character set 字符集,如果没有指定字符集,则以所在数据库的字符集为准。
- collate 校验规则,如果没有指定校验规则,则以所在数据库的校验规则为准。
创建表在Linux机器下是在做什么?
在mysql中,建立一个表本质上实在Linux机器下创建对应的文件。
创建表案例
create table users (id int,name varchar(20) comment '用户名',password char(32) comment '密码是32位的md5值',birthday date comment '生日'
) character set utf8 engine MyISAM;
不同的存储引擎,创建表的文件不一样。users 表存储引擎是 MyISAM ,在数据目中有三个不同的文件,分别是:users.frm:表结构;users.MYD:表数据;users.MYI:表索引。
查看表结构
desc 表名;
修改表
在项目实际开发中,经常修改某个表的结构,比如字段名字,字段大小,字段类型,表的字符集类型,表的存储引擎等等。还有需求,添加字段,删除字段等等,这时就需要修改表。
ALTER TABLE tablename ADD (column datatype [DEFAULT expr][,column
datatype]...);ALTER TABLE tablename MODIfy (column datatype [DEFAULT expr][,column datatype]...);ALTER TABLE tablename DROP (column);
- 案例:在users表添加二条记录
mysql> insert into users values(1,'a','b','1982-01-04'),(2,'b','c','1984-01-04');
- 案例:在users表添加一个字段,用于保存图片路径。(插入新字段后,对原来表中的数据没有影响,原来的数据仍然存在)
mysql> alter table users add assets varchar(100) comment '图片路径' after birthday;
- 案例:修改name,将其长度改成60
mysql> alter table users modify name varchar(60);
- 案例:删除password列(删除字段一定要小心,删除字段及其对应的列数据都没了)
mysql> alter table users drop password;
- 案例:修改表名为employee
mysql> alter table users rename to employee;//(to可以省掉)
- 案例:将name列修改为xingming。change 修改列名;rename 修改表名
mysql> alter table employee change name xingming varchar(60); --新字段需要完整定义
删除表
语法:
DROP TABLE [IF EXISTS] tbl_name [, tbl_name] ...
示例:
mysql> drop table t1;
数据类型
数据类型分类
数值类型
tinyint类型
mysql> create table tt1(num tinyint);
mysql> insert into tt1 values(128); -- 越界插入,报错
在MySQL中,整型可以指定是有符号的和无符号的,默认是有符号的,可以通过UNSIGNED来说明某个字段是无符号的。
mysql> create table tt2(num tinyint unsigned);
mysql> insert into tt2 values(-1); -- 无符号,范围是: 0 ~ 255
bit类型
语法:
bit[(M)] : 位字段类型。M表示每个值的位数,范围从1到64。如果M被忽略,默认为1
举例:
mysql> create table tt4 ( id int, a bit(8));
mysql> insert into tt4 values(10, 10);
mysql> select * from tt4; #发现很怪异的现象,a的数据10没有出现
+------+------+
| id | a |
+------+------+
| 10 | |
+------+------+
上述案例发现很怪异的现象,a的数据10没有出现,这是因为bit字段在显示时,是按照ASCII码对应的值显示。10表示的是换行符,当然不会显示。
建议:
有这样的值,只存放0或1,这时可以定义bit(1)。这样可以节省空间。
mysql> create table tt5(gender bit(1));
mysql> insert into tt5 values(0);
mysql> insert into tt5 values(1);
mysql> insert into tt5 values(2); -- 当插入2时,已经越界了
ERROR 1406 (22001): Data too long for column 'gender' at row 1
float
语法:
float[(m, d)] [unsigned] : M指定显示长度,d指定小数位数,占用空间4个字节
案例:
mysql> create table tt6(id int, salary float(4,2));
mysql> insert into tt6 values(100, -99.99);
mysql> insert into tt6 values(101, -99.991); #多的这一点被拿掉了
mysql> select * from tt6;
+------+--------+
| id | salary |
+------+--------+
| 100 | -99.99 |
| 101 | -99.99 |
+------+--------+
2 rows in set (0.00 sec)
小数 float(4,2)表示的范围是-99.99 ~ 99.99,MySQL在保存值时会进行四舍。如果定义的是float(4,2) unsigned 这时,因为把它指定为无符号的数,范围是0 ~ 99.99。
decimal
语法:
decimal(m, d) [unsigned] : 定点数m指定长度,d表示小数点的位数
- decimal(5,2) 表示的范围是 -999.99 ~ 999.99
- decimal(5,2) unsigned 表示的范围 0 ~ 999.99
- decimal和float很像,但是有区别:float和decimal表示的精度不一样,float表示的精度大约是7位,decimal整数最大位数m为65。支持小数最大位数d是30。如果d被省略,默认为0.如果m被省略,默认是10。如果希望小数的精度高,推荐使用decimal。
mysql> create table tt8 ( id int, salary float(10,8), salary2 decimal(10,8));
mysql> insert into tt8 values(100,23.12345612, 23.12345612);
mysql> select * from tt8;
+------+-------------+-------------+
| id | salary | salary2 |
+------+-------------+-------------+
| 100 | 23.12345695 | 23.12345612 |
+------+-------------+-------------+
字符串类型
char
语法:
char(L): 固定长度字符串,L是可以存储的长度,单位为字符,最大长度值可以为255
案例:
mysql> create table tt9(id int, name char(2));
mysql> insert into tt9 values(100, 'ab');
mysql> insert into tt9 values(101, '中国');
mysql> select * from tt9;
+------+--------+
| id | name |
+------+--------+
| 100 | ab |
| 101 | 中国 |
+------+--------+
说明:
char(2) 表示可以存放两个字符,可以是字母或汉字,但是不能超过2个,最多只能是255。mysql中的字符,说的就是一个字符,可以是abcd中任意一个字符或1234中任意一个字符,也可以是一个汉字。
varchar
语法:
varchar(L): 可变长度字符串,L表示字符长度,最大长度65535个字节
案例:
mysql> create table tt10(id int ,name varchar(6)); --表示这里可以存放6个字符
mysql> insert into tt10 values(100, 'hello');
mysql> insert into tt10 values(100, '我爱你,中国');
mysql> select * from tt10;
+------+--------------------+
| id | name |
+------+--------------------+
| 100 | hello |
| 100 | 我爱你,中国 |
+------+--------------------+
说明:
- 关于varchar(len),len到底是多大,这个len值,和表的编码密切相关。
- 一个字符串的长度有上限和它是变长的并不直接冲突。
- varchar长度可以指定为0到65535之间的值,但是有1 - 3 个字节用于记录数据大小,所以说有效字节数是65532。
- 当表的编码是utf8时,varchar(n)的参数n最大值是65532/3=21844[因为utf8中,一个字符占用3个字节,如果编码是gbk,varchar(n)的参数n最大65532/2=32766,因为gbk中,一个字符占用2字节。
char和varchar比较
如何选择定长或变长字符串?
- 如果数据确定长度都一样,就使用定长(char),比如:身份证,手机号,md5。
- 如果数据长度有变化,就使用变长(varchar), 比如:名字,地址,但是你要保证最长的能存的进去。
- 定长的磁盘空间比较浪费,但是效率高。
- 变长的磁盘空间比较节省,但是效率低。
- 定长的意义是,直接开辟好对应的空间。
- 变长的意义是,在不超过自定义范围的情况下,用多少,开辟多少。
日期和时间类型
常用的日期有如下三个:
- date :日期
'yyyy-mm-dd'
,占用三字节 - datetime 时间日期格式
'yyyy-mm-dd HH:ii:ss'
表示范围从 1000 到 9999 ,占用八字节 - timestamp :时间戳,从1970年开始的
yyyy-mm-dd HH:ii:ss
格式和 datetime 完全一致,占用四字节
案例:
//创建表
mysql> create table birthday (t1 date, t2 datetime, t3 timestamp);
//插入数据 添加数据时,时间戳自动补上当前时间
mysql> insert into birthday(t1,t2) values('1997-7-1','2008-8-8 12:1:1'); --插入两种时间
mysql> select * from birthday;
+------------+---------------------+---------------------+
| t1 | t2 | t3 |
+------------+---------------------+---------------------+
| 1997-07-01 | 2008-08-08 12:01:01 | 2017-11-12 18:28:55 |
+------------+---------------------+---------------------+
//更新数据, 时间戳会更新成当前时间
mysql> update birthday set t1='2000-1-1';
mysql> select * from birthday;
+------------+---------------------+---------------------+
| t1 | t2 | t3 |
+------------+---------------------+---------------------+
| 2000-01-01 | 2008-08-08 12:01:01 | 2017-11-12 18:32:09 |
+------------+---------------------+---------------------+
enum和set
语法:
enum:枚举,“单选” 类型;
enum('选项1','选项2','选项3',...);
该设定只是提供了若干个选项的值,最终一个单元格中,实际只存储了其中一个值;而且出于效率考虑,这些值实际存储的是“数字”,因为这些选项的每个选项值依次对应如下数字:1,2,3,…最多65535个;当我们添加枚举值时,也可以添加对应的数字编号。
set:集合,“多选”类型;
set('选项值1','选项值2','选项值3', ...);
该设定只是提供了若干个选项的值,最终一个单元格中,设计可存储了其中任意多个值;而且出于效率考虑,这些值实际存储的是“数字”,因为这些选项的每个选项值依次对应如下数字:1,2,4,8,16,32,…最多64个。但是不建议在添加枚举值,集合值的时候采用数字的方式,因为不利于阅读。
案例:
有一个调查表votes,需要调查人的喜好, 比如(登山,游泳,篮球,武术)中去选择[可以多选],(男,女)[单选]。
mysql> create table votes(-> username varchar(30),-> hobby set('登山','游泳','篮球','武术'), -> gender enum('男','女'));
mysql>insert into votes values('雷锋', '登山,武术', '男');
mysql>insert into votes values('Juse','登山,武术',2);
mysql>select * from votes where gender=2;
+----------+---------------+--------+
| username | hobby | gender |
+----------+---------------+--------+
| Juse | 登山,武术 | 女 |
+----------+---------------+--------+
集合查询使用 find_ in_ set 函数:
find_in_set(sub,str_list) :如果 sub 在 str_list 中,则返回下标;如果不在,返回0;str_list 用逗号分隔的字符串。
- 案例:查询爱好登山的人
mysql> select * from votes where find_in_set('登山', hobby);
+----------+---------------+--------+
| username | hobby | gender |
+----------+---------------+--------+
| 雷锋 | 登山,武术 | 男 |
| Juse | 登山,武术 | 女 |
| LiLei | 登山 | 男 |
+----------+---------------+--------+
表的约束
数据类型可以约束数据,但是数据类型约束很单一,需要有一些额外的约束,更好的保证数据的合法性,从业务逻辑角度保证数据的正确性。
空属性
有两个值:null(默认的)和not null(不为空)。数据库默认字段基本都是字段为空,但是实际开发时,尽可能保证字段不为空,因为数据为空没办法参与运算。NULL和空的区别:NULL代表的是没有,空代表的是有,但是是空串。
- 案例:创建一个班级表,包含班级名和班级所在的教室。
站在正常的业务逻辑中:如果班级没有名字,你不知道你在哪个班级,如果教室名字可以为空,就不知道在哪上课。所以我们在设计数据库表的时候,一定要在表中进行限制,满足上面条件的数据就不能插入到表中。这就是“约束”。
mysql> create table myclass(-> class_name varchar(20) not null,-> class_room varchar(10) not null);
mysql> desc myclass;
+------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| class_name | varchar(20) | NO | | NULL | |
| class_room | varchar(10) | NO | | NULL | |
+------------+-------------+------+-----+---------+-------+
//插入数据时,没有给教室数据插入失败:
mysql> insert into myclass(class_name) values('class1');
ERROR 1364 (HY000): Field 'class_room' doesn't have a default value
默认值
默认值是某一种数据会经常性的出现某个具体的值,可以在一开始就指定好,在需要真实数据的时候,用户可以选择性的使用默认值。not null和defalut一般不需要同时出现,因为default本身有默认值,不会为空。default的约束其实降低了,但是可以保证表中数据的完整性。default 表示当用户不显示的向指定列中插入,default会自动起效果。
mysql> create table tt10 (-> name varchar(20) not null,-> age tinyint unsigned default 0,-> sex char(2) default '男'-> );
mysql> desc tt10;
+-------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra|
+-------+---------------------+------+-----+---------+-------+
| name | varchar(20) | NO | | NULL | |
| age | tinyint(3) unsigned | YES | | 0 | |
| sex | char(2) | YES | | 男 | |
+-------+---------------------+------+-----+---------+-------+
当数据在插入的时候不给该字段赋值,就使用默认值。只有设置了default的列,才可以在插入值的时候,对列进行省略。
mysql> insert into tt10(name) values('zhangsan');
mysql> select * from tt10;
+----------+------+------+
| name | age | sex |
+----------+------+------+
| zhangsan | 0 | 男 |
+----------+------+------+
列描述
列描述:comment,没有实际含义,专门用来描述字段,会根据表创建语句保存,用来给程序员或DBA来进行了解。
mysql> create table tt12 (-> name varchar(20) not null comment '姓名',-> age tinyint unsigned default 0 comment '年龄',-> sex char(2) default '男' comment '性别'-> );
通过desc查看不到注释信息,通过show可以看到:
mysql> show create table tt12\G
*************************** 1. row ***************************Table: tt12
Create Table: CREATE TABLE `tt12` (`name` varchar(20) NOT NULL COMMENT '姓名',`age` tinyint(3) unsigned DEFAULT '0' COMMENT '年龄',`sex` char(2) DEFAULT '男' COMMENT '性别'
) ENGINE=MyISAM DEFAULT CHARSET=gbk
1 row in set (0.00 sec)
zerofil
mysql> show create table tt3\G***************** 1. row *****************Table: tt3Create Table: CREATE TABLE `tt3` (`a` int(5) unsigned zerofill DEFAULT NULL,`b` int(10) unsigned DEFAULT NULL) ENGINE=MyISAM DEFAULT CHARSET=gbk1 row in set (0.00 sec)
show看看tt3表的建表语句,可以看到int(5),这个代表什么意思呢?整型不是4字节码?这个5又代表什么呢?当在tt3中插入(1,2),再看结果。
mysql> select * from tt3;
+-------+------+
| a | b |
+-------+------+
| 00001 | 2 |
+-------+------+
可以看到a的值由原来的1变成00001,这就是zerofill属性的作用,如果宽度小于设定的宽度(这里设置的是5),自动填充0。如果没有zerofill这个属性,括号内的数字是毫无意义的要注意的是,这只是最后显示的结果,在MySQL中实际存储的还是1,00001只是设置了zerofill属性后的一种格式化输出而已。
主键
primary key用来唯一的约束该字段里面的数据,不能重复,不能为空,一张表中最多只能有一个主键;主键所在的列通常是整数类型。结合你的业务,可以选择一个唯一的列属性作为主键。并且选择与业务无关的唯一值。这样设计,主键值与业务无关,业务调整就不会影响整体主键的表结构。
- 案例:创建表的时候直接在字段上指定主键
mysql> create table tt13 (-> id int unsigned primary key comment '学号不能为空',-> name varchar(20) not null);
mysql> desc tt13;
+-------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| id | int(10) unsigned | NO | PRI | NULL | |
| name | varchar(20) | NO | | NULL | |
+-------+------------------+------+-----+---------+-------+
- 案例:主键对应的字段中不能重复,一旦主键重复,操作失败
mysql> insert into tt13 values(1, 'aaa');
mysql> insert into tt13 values(1, 'aaa');
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
- 案例:当表创建好以后但是没有主键的时候,可以再次追加主键
alter table 表名 add primary key(字段列表)
- 案例:删除主键
alter table 表名 drop primary key;
mysql> alter table tt13 drop primary key;
复合主键
在创建表的时候,在所有字段之后,使用primary key来创建主键,如果有多个字段作为主键,可以使用复合主键。
mysql> create table tt14(-> id int unsigned,-> course char(10) comment '课程代码',-> score tinyint unsigned default 60 comment '成绩',-> primary key(id, course) -- id和course为复合主键-> );
mysql> desc tt14;
+--------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------------------+------+-----+---------+-------+
| id | int(10) unsigned | NO | PRI | 0 | |
| course| char(10) | NO | PRI | | |
| score | tinyint(3) unsigned | YES | | 60 | |
+--------+---------------------+------+-----+---------+-------+mysql> insert into tt14 (id,course)values(1, '123');
Query OK, 1 row affected (0.02 sec)
mysql> insert into tt14 (id,course)values(1, '123');
ERROR 1062 (23000): Duplicate entry '1-123' for key 'PRIMARY' -- 主键冲突
自增长
auto_increment:当对应的字段,不给值,会自动的被系统触发,系统会从当前字段中已经有的最大值+1操作,得到一个新的不同的值。通常和主键搭配使用,作为逻辑主键。
自增长的特点 : 1.设定为自增长,一定是主键。2.自增长字段必须是整数。3.一张表最多只能有一个自增长。
mysql> create table tt21(-> id int unsigned primary key auto_increment,-> name varchar(10) not null default ''-> );
mysql> insert into tt21(name) values('a');
mysql> insert into tt21(name) values('b');
mysql> select * from tt21;
+----+------+
| id | name |
+----+------+
| 1 | a |
| 2 | b |
+----+------+
在插入后获取上次插入的 AUTO_INCREMENT 的值,批量插入获取的是第一个值。
mysql > select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
| 1 |
+------------------+
索引
在关系数据库中,索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。索引的作用相当于图书的目录,可以根据目录中的页码快速找到所需的内容。
索引提供指向存储在表的指定列中的数据值的指针,然后根据您指定的排序顺序对这些指针排序。数据库使用索引以找到特定值,然后顺指针找到包含该值的行。这样可以使对应于表的SQL语句执行得更快,可快速访问数据库表中的特定信息。
唯一键
一张表中有往往有很多字段需要唯一性,数据不能重复,但是一张表中只能有一个主键,唯一键就可以解决表中有多个字段需要唯一性约束的问题。**唯一键和主键并不冲突,反而是相互补充的,用来共同维护表的完整性。**主键只是众多具有唯一性的属性列中被选择成为主键而已,其他字段的唯一性,在建表的时候也需要保证,但是主键只能有一个,所以MySQL提供了另一种保证数据列信息唯一性的方案——唯一键。
关于唯一键和主键的区别,可以简单理解成 主键更多的是标识唯一性的。而唯一键更多的是保证在业务上,不要和别的信息出现重复。 主键更多的是为了保证我们在查找的时候,找到唯一的一条记录。唯一键更多的是为了保证在表中,各个不同的值,一定要在mysql层面保证该值的唯一性。unique 作用的字段允许为NULL,而primary key的字段不允许为NULL;并且一张表中最多只能有一个主键,而唯一键可以有多个。
mysql> create table student (-> id char(10) unique comment '学号,不能重复,但可以为空',-> name varchar(10)-> );
mysql> insert into student(id, name) values('01', 'aaa');
mysql> insert into student(id, name) values('01', 'bbb'); --唯一约束不能重复
ERROR 1062 (23000): Duplicate entry '01' for key 'id'
mysql> insert into student(id, name) values(null, 'bbb'); -- 但可以为空
mysql> select * from student;
+------+------+
| id | name |
+------+------+
| 01 | aaa |
| NULL | bbb |
+------+------+
外键
MySQL属于关系型数据库,在表和表之间也一定会产生某种关系。外键用于定义主表和从表之间的关系,维护主表和从表之间的约束。外键约束主要定义在从表上,主表则必须是有主键约束或unique约束。当定义外键后,要求外键列数据必须在主表的主键列存在或为null。
语法:
foreign key (字段名) references 主表(列)
案例:
先创建主键表
create table myclass (id int primary key,name varchar(30) not null comment'班级名'
);
再创建从表
create table stu (id int primary key,name varchar(30) not null comment '学生名',class_id int,foreign key (class_id) references myclass(id)
);
正常插入数据
mysql> insert into myclass values(10, 'C++大牛班'),(20, 'java大神班');
mysql> insert into stu values(100, '张三', 10),(101, '李四',20);
插入一个班级号为30的学生,因为没有这个班级,所以插入不成功
mysql> insert into stu values(102, 'wangwu',30);
ERROR 1452 (23000): Cannot add or update a child row:a foreign key constraint fails (mytest.stu, CONSTRAINT stu_ibfk_1 FOREIGN KEY (class_id) REFERENCES myclass (id))
插入班级id为null,比如来了一个学生,目前还没有分配班级
mysql> insert into stu values(102, 'wangwu', null);
理解外键约束
首先这个世界是数据很多都是相关性的。理论上,上面的例子,我们不创建外键约束,就正常建立学生表,以及班级表,该有的字段我们都有。此时,在实际使用的时候,可能会出现什么问题?有没有可能插入的学生信息中有具体的班级,但是该班级却没有在班级表中。因为此时两张表在业务上是有相关性的,但是在业务上没有建立约束关系,那么就可能出现问题。解决方案就是通过外键完成的。建立外键的本质其实就是把相关性交给mysql去审核了,提前告诉mysql表之间的约束关系,那么当用户插入不符合业务逻辑的数据的时候,mysql不允许你插入。