tip: windows 系统下的MySQL学习
参考资料: 菜鸟教程
1.安装
按照网上的许多教程安装好了MySQL(百度有许多,不重复了~)
2. 基本概念
- 数据库是按照数据结构来组织、存储和管理数据的仓库;
- 关系型数据库: 建立在关系模型基础上的数据库,借助于集合代数等数学概念和方法来处理数据库中的数据。(这句话有点抽象,看看经过后面的学习能不能有自己的理解~);
- RDBMS 即关系数据库管理系统(Relational Database Management System)的特点:
- 数据以表格的形式出现;
- 每行为各种记录名称
- 每列为记录名称所对应的数据域
- 许多行和列组成一张表单
- 若干的表单组成database
(这样子理解:有一个数据库叫school,存放学校的各种数据。school数据库中有很多张表,比如有一张表叫teacher来存放教师数据,有一张表叫student存放学生数据等。在student数据表中有很多行,每行是一个学生,每列是学生的各种属性例如姓名、年龄、班级、分数等)
3. RDBMS 术语
- 数据库: 数据库是一些关联表的集合。.
- 数据表: 表是数据的矩阵。在一个数据库中的表看起来像一个简单的电子表格。
- 列: 一列(数据元素) 包含了相同的数据, 例如邮政编码的数据。
- 行:一行(=元组,或记录)是一组相关的数据,例如一条用户订阅的数据。
- 冗余:存储两倍数据,冗余降低了性能,但提高了数据的安全性。
- 主键:主键是唯一的。一个数据表中只能包含一个主键。你可以使用主键来查询数据。
- 外键:外键用于关联两个表。
- 复合键:复合键(组合键)将多个列作为一个索引键,一般用于复合索引。
- 索引:使用索引可快速访问数据库表中的特定信息。索引是对数据库表中一列或多列的值进行排序的一种结构。类似于书籍的目录。
- 参照完整性: 参照的完整性要求关系中不允许引用不存在的实体。与实体完整性是关系模型必须满足的完整性约束条件,目的是保证数据的一致性。
4. 数据类型
数值类型
5. 以下是命令行SQL语句的学习
命令行切换到 MySQL 安装目录下,命令行输入 mysql
,进入MySQL命令输入模式。
-
查看有哪些数据库(
show databases;
)
出现一个箭头? 其实是忘记输入分号就按了回车,如果忘记输入分号,代表这句命令还没有结束,可以继续输入,这时可以在箭头后面继续输入分号。
-
创建数据库:
create database 库名;
插入后看看数据库:
是不区分大小写吗? -
删除数据库
drop database 库名;
-
切换数据库
use 库名;
-
在数据库中创建一张表:
create table 表名(列名 列类型(n),列名 列类型(n)....);
一个简单的例子:
- 列名即属性,比如id,名字,年龄等;
- 列类型即数据类型比如
varchar(变长字符型),char(字符型),int(整型)
等; - 列类型括号中的数字 n 代表为它分配多少存储空间,就好像C语言定义数组那样定义了数组的长度就会为它分配一定的空间,不足就不满,超过就会溢出。有一篇参考文章:https://www.cnblogs.com/loren-Yang/p/7512258.html
- 当不希望插入的列数据为
NULL
时,可以在创建表示定义列类型加上NOT NULL
;这样如果插入NULL
的数据时就会报错; -
AUTO_INCREMENT
定义列为自增的属性,一般用于主键,数值会自动加1; -
PRIMARY KEY
关键字用于定义列为主键; -
ENGINE
设置存储引擎,CHARSET
设置编码(编码大概知道是什么,存储引擎是啥后面看看能不能学到,先放着);
一个复杂的例子:
创建了一个表,名为
student
,包含 id,name,enter_date
等属性,分别定义了数据类型,id
是整型无符号自增的主键;name
是变长字符型,最多不能超过100字节,不能为 null
;enter_date
是日期类型;存储引擎为 innodb
,默认字符编码为 utf8
。-
查看表中的字段:
show columns from 表名;
可以看到字段名,字段数据类型,默认值等信息。 -
查看数据表类型:
show table status like '表名';
尴尬,有点乱。 -
删除表:
drop table 表名;
-
在表中插入记录:
看起来有两种格式:
insert into 表名(fields1,fields2,...)values(value1,value2);
或者可以省略fields
。
fields
代表字段名,即属性即列名;value
代表各列的值;目测省略字段名就按照表中字段顺序对应插入;
如果value
值是字符型或者日期,需要用单引号或者双引号括住。
可以看到日期如果没有用引号的话,查询到的结果为0000-00-00;
可以看到插入的时候没有为id字段赋值,但是它是自增的。 -
查询表中记录:
刚创建的表中没有记录:
select * from 表名; //*代表返回表中所有字段;
select 字段名1,字段名2 from 表名 [where 条件] [limit n] [offset n];
- select后面的字段名表示要返回的字段名;
- where包含限制条件;
- limit限制返回记录的数目;
-
offset设置偏移量,即从第几条记录开始查询,默认为0即从最开始开始查询。
-
where 子句
- 可以用and 或者 or指定多个查询条件;
- where 子句对记录的查询不区分大小写;
- where binary 加查询条件则区分大小写;
操作符列表:
-
update 子句
update 表名 set 字段名1=newValue,字段名2=newValue2 [可以配合where子句];
-
delete 子句
delete from 表名 [where子句];
没有where子句表示删除全部记录:
-
like 子句:模糊查询
SQLLIKE
子句中使用百分号%
字符来表示任意字符,类似于UNIX或正则表达式中的星号*
;
如果没有使用百分号%
,LIKE
子句与等号=
的效果是一样的;
可以使用AND
或者OR
指定一个或多个条件;
-
union 操作符
连接两个以上的select
结果到同一个结果集中;
select 字段 from 表名 union [all或者distinct] select 字段 from 表名;
union
默认不返回重复数据,distinct
即默认选项,all
即返回全部数据包含重复数据;
两张表中的数据:
返回两张表中的全部姓名name
:
-
排序
select 字段 from 表名 order by 字段 [asc或者desc];
asc
:升序,不加默认升序;
desc
:降序;
-
分组
举个例子:
该表代表道具清单,表中,name
代表道具名,number
代表道具数量,price
代表道具单价,buy_date
代表道具购买日期,同一个名字的道具可能有不同价格的品种,例如杯子cup
单价3元的购买了100个,单价5元的购买了200个。
以下按照道具名name进行分组:
group by name
代表按照name
分组,count( * )
代表记录计数。所以结果列出了name
这一列和count( * )
这一列。按照名字分组的结果应该是chair, cup,cup, desk,flower
。所以cup
的count( * )
是2,其他都是1。
以下按照道具购买数量number
进行分组:
同上分析,购买数量为100的有chair和cup(price=3)
,所以count
为2,购买数量为200的有desk和cup(price=5)
,所以count
为2,购买数量为500的有flower
,所以count
为1。
以下按照name
分组并分别统计购买数量:
sum(number)
代表对购买数量number
进行求和,即:将分组后的同名记录的number
值进行求和。所以对于cup
这一种道具有两个同名记录,number
求和为300。
加上with rollup
会对结果进行求和,如图是将sum(number)
加起来的总数,但是他没有名字,所以是null
,可以为他取一个名字:
coalesce
的作用是:如果记录的第一个参数为null
,就用第二个参数,如果第二个参数也为null
,就用第三个参数,以此类推。所以对于总数这一项没有name
,就会使用第二个参数“总数”。
也可以把分别算一下总价再加起来,如上图。 -
mysql 连接(内连接、左连接、右连接)
这是两个表的数据:
内连接(怎么解释呢)就是a表关联b表的数据,这个数据在两个表中都是存在的。例如:
select
要列出的项是 a 表的id
,a 表的name
,b 表的age
,因为 a b 表一起才能包含比较完全的信息,例如 a 表student
有id
和
name
,但是没有age
信息,可以从 b 表teacher
找到age
信息(此处举例不太恰当,可以把 b 表换成一个person
表而字段不变,这样就不会有又是teacher
又是学生的疑惑)from
表示从 a 表找,inner join
代表关联 b 表的信息,on
代表关联的条件。所以从
student
表第一项列出id,name
,再去teacher
表找到
name
相同的age
值,如果teacher
没有找到同名项,则不列出student
表这一项。类似交集。-
还有一种格式可以不用写a和b:
左连接:获取左表所有记录,即使右表没有对应匹配的记录。右表没有的项用 null
填充。
右连接:与
LEFT JOIN
相反,用于获取右表所有记录,即使左表没有对应匹配的记录。-
null 值处理
正如JavaScript
里的NaN
,NaN === NaN
返回的是false
,在 MySQL 中,某个值为null
时,不能通过value = null
或者value != null
来判断,因为 MySQL 中null=null
也是返回false
。在 JavaScript 中判断是否为NaN
可以通过isNaN
函数来判断,在 MySQL 中,可以通过value is null
或者value is not null
来返回 null 值或者 非null 值。例如:
正则表达式
可以用在where
子句中(emmm,我的正则不太好,每次要用的时候都是要再去查的,此处就忽略正则的例子):
select * from 表名 where 字段 regexp 正则表达式;
上面的命令会按照正则表达式匹配对应的内容返回。-
事务
- 根据 菜鸟教程的解释和举例我觉得可以理解为事务是一组操作;事务开始,然后进行了一组操作,最后可以确认,这样就影响了数据库中的数据,也可以在一组操作之后不确认,使用回滚来放弃这组操作。
- 原子性:整一组操作,要么确认了一起生效,要么回滚了一起失效;
- 稳定性 :有非法数据(外键约束之类),事务撤回(emmm,不懂);
- 隔离性:事务独立运行。一个事务处理后的结果,影响了其他事务,那么其他事务会撤回。事务的100%隔离,需要牺牲速度(emmm,不懂);
- 可靠性:软、硬件崩溃后,InnoDB数据表驱动会利用日志文件重构修改。可靠性和高速度不可兼得, innodb_flush_log_at_trx_commit 选项 决定什么时候把事务保存到日志里(emmm,不懂);
- 在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务;
- 在我们之前的使用命令行模式的时候都可以看作自动提交的事务;
- 显示开启事务:
begin;
执行一组操作:insert,update,delete
等;
提交:commit;
或者 回滚:rollback;
关于事务应该还有更多的操作,后续补充;
-
alter 命令:修改、添加、删除字段名、字段类型或者表名等信息
添加字段:alter table 表名 add 字段名 字段数据类型;
添加字段的位置:关键字first
可将字段插在第一列,after
关键字可将字段插在某字段后面;
在使用after
关键字将新字段插入name
字段后面时遇到了错误,后来将gender
的数据类型改为char
类型时就成功了。
应该是varchar
是变长的,没有默认大小,所以 MySQL 不知道要给它分配多少空间,因此报错,而char
或者int
是固定长度的,默认分配一个字节。所以在新增字段的时候定义数据类型时还是为它分配好所需的空间好,以免出错。
修改字段:alter table 表名 change 旧字段名 新字段名 新字段数据类型;
删除字段:
alter table 表名 drop 字段名;
修改字段类型:
modify
或者 change
即
change
可以同时用来修改字段名和字段类型。
设置null值和默认值:
把gender设置为非null值和默认值为female,从第一次设置失败可见,female六个字节已经超过了gender的长度5个字节,所以要修改大一些。
可见设置默认值不会影响之前已经存在的记录,但是对新添加的记录有影响。
可见除了用
modify
也可以使用 alter table tablename alter field set default value;
来修改默认值。
删除默认值:alter table tablename alter field drop default;
修改表名:alter table 旧表名 rename to 新表名
MySQL索引
看了菜鸟教程的MySQL索引后依然不知道这个是什么作用,只是说创建了索引可以提高查询速度,并不知道为什么以及怎么个提高法。于是去网上搜了一些其他的文章,大概看了和B-tree和哈希索引的一些东西有关,由于这部分和数据结构有关,而我的数据结构又是极其的菜,所以等我后面补了数据结构的知识就回来部MySQL的索引。mysql临时表
当我们需要临时在MySQL保存一些数据用完就马上销毁时,可以创建MySQL临时表。MySQL临时表只在当前连接有效,连接关闭后临时表就会被自动销毁。
create temporary table 表名(fields type);
手动销毁临时表:drop table 表名
MySQL复制表
有大概三种形式,一二种只复制结构不复制表中的记录,第三种复制结构和记录:-
way1:
show create table 源表名
//显示要复制的源表的创建语句
然后把那段create
语句复制后即可创建(= = 我的命令行不知道怎么复制就没有演示了); -
way 2:
首先create table 目标表名 like 源表名;
//复制源表的结构
show tables;
//可以看到已经创建了一个新表
show columns from 目标表名;
//可以看到目标表和源表拥有相同的字段等信息
select * from 目标表名;
//看到新复制的目标表并没有记录内容
insert into 目标表名 select * from 源表名;
//从源表复制内容到目标表
select * from 目标表名;
//可以看到新复制的目标表已经有了源表的内容
也可以用create table 目标表名 select * from 目标表名 where 1=2;
取代create table 目标表名 like 源表名;
命令复制源表结构:
-
way 3:
create table 目标表名 select * from 源表名;
//复制源表结构并且复制源表中的数据:
-
MySQL自增序列
student表的id字段是一个定义时为auto_increment的序列,但是在删除了一些记录之后并没有重新补回序号的空缺,所以上图没有id为1234的记录。可以通过将id字段先删除然后重新添加自增序列。
也可以为自增序列设置一个起始值:
设置起始值不会影响已有记录只会影响新的记录。
-
mysql处理重复数据
在MySQL数据表中设置指定的字段为PRIMARY KEY
(主键) 或者UNIQUE
(唯一) 索引来保证数据的唯一性。
insert ignore into
与insert into
的区别就是insert ignore into
会忽略数据库中已经存在的数据,如果数据库没有数据,就插入新的数据,如果有数据的话就跳过这条数据。这样就可以保留数据库中已经存在数据,达到在间隙中插入数据的目的。
insert ignore into
当插入数据时,在设置了记录的唯一性后,如果插入重复数据,将不返回错误,只以警告形式返回。 而replace into
如果存在 primary 或 unique 相同的记录,则先删除掉。再插入新记录。- 过滤重复数据:使用
distinct
关键字
- 过滤重复数据:使用
SQL注入
情况大致就是恶意用户在用户输入中输入了SQL语句,SQL语句被执行后带来不好的后果。
所以永远认为用户输入是不安全的,永远不要信任用户输入,对用户输入进行过滤和转义等。
具体如何注入和如何防止在我进行了实例学习后会举例说明~-
导出数据到文件
select ... into outfile 文件路径 [fields terminated by 分隔符] [lines terminated by 分隔符];
tmp 文件夹如果不存在会报错。
全部数据连成一行了~
格式化一下:每个字段用引号包住,用逗号隔开,每行回车换行:
不要引号和逗号:
-
mySQL数据导入
load data local infile 文件路径 into table 表名 [fields terminated by 分隔符] [lines terminated by 分隔符];
用上面数据导出的文件导入到一个新的表格中:
6. 遇到的问题
(1)MySQL 初次安装没有自己设置密码,打开命令行直接输入“mysql
”之后就可以进入 MySQL 的命令模式,一开始可以正常使用 show databases
和 create database name
等命令,但是突然某一次开始使用 create
命令创建数据库一直报权限错误:
查看网上教程很多与我的情况有相似又有不同,找到了一篇是使用安装
MySQL 的时候一起安装的 MySQL workbench(MySQL可视化工作台)解决了这个问题。附上链接:http://blog.csdn.net/a19881029/article/details/37809209
我的做法是修改了 root 的密码,然后之后全部使用 root 身份登录 MySQL
进行命令操作。结合网络教程,猜测之前报权限错误的原因是用匿名身份登录了 MySQL,匿名身份缺乏相关创建数据库的权限吧= =?(欢迎知道原因的胖友告诉我~)
(2)事务回滚问题:
- 在使用alter重命名表名时使用了事务,修改了表名后想要回滚发现还是被修改了。在网上查了之后觉得可能一个是因为使用了alter是ddl语句(关于DDL语句是什么以及哪些语句会自动提交可以参考:http://blog.csdn.net/sunshixingh/article/details/50920119)会隐式提交,另一个是因为事务中出现了错误。
-
于是使用控制变量法对这两个原因进行了测试:
首先是测试DDL语句的因素:
可见teacher不在,即事务中不存在错误也被修改了,回滚失败了。
对事务中发生错误的因素:
可见即使事务中发生了错误也没有插入新数据,回滚成功。
根据上面的测试,应该是因为事务中的DDL语句导致了隐式的提交。
再次查询了相关资料后进行相关的测试(不包含隐式提交语句的):
-
事务开始,如果全部执行了正确的操作并且commit就是全部提交:
-
事务开始,如果执行了正确的操作然后执行了错误的操作又执行了正确的操作,然后commit,会提交成功的操作:
-
事务开始,如果执行了正确的操作然后执行了错误的操作又执行了正确操作,然后rollback,会全部回滚:
-
set autocommit=0
似乎不起作用?
关于MySQL事务的理解欢迎大神指正~
(3)两个MySQL服务:
今天打开命令行如往常一样mysql -u root -p
然后输入密码的时候发现密码错误,打开MySQLworkbench发现也需要输入密码,结果输入和以往一样的密码无法登陆成功,后来试了很多常用密码就登进去了。一开始以为是我记错密码了,但当我用命令行查看test数据库下的数据表时却发现没有昨天练习的数据表,又看了数据库好像多了其他数据库名称。觉得很奇怪。以为是数据库数据丢失,去看了安装目录下的data文件夹,是存在我之前的数据表的。后来看了网上教程说会不会连接错了数据库,就打算用任务管理器关掉数据库服务再看看怎么连接。但是我在任务管理器中发现了两个MySQL服务,一个叫MySQL56(正在运行),一个叫MySQL(已停止),于是我启用了MySQL服务又停掉MySQL56,就找回自己的数据表了,发现原来我的密码也没有记错!
之前好像也有安装过MySQL但是好像安装失败了,后来卸载掉。过了很久重新按照网上教程按照的MySQL就可以用了。
所以是因为我安装了两次MySQL吗还是什么原因?
MySQL和MySQL56对应不同的密码,安装目录下的数据是MySQL不是MySQL56的,所以MySQL56是什么???用MySQL56的时候data文件夹又在哪里??
发现每次开机自启的MySQL服务是那个MySQL56的。。。???
以上是MySQL入门学习,更多复杂操作,待使用更新~
理论上会学Nodejs+MySQL,而且这些语句,也是要结合实例多多使用多多踩坑才更容易记住和学会的,emmmm