前言
本篇博客主要记录博主日常所学的MySQL知识点
1、MySQL(我们要学的数据库 主要优势:开源免费 主要应用场景:中小公司 占据市场份额也是很大的 但现在已经被Oracle收购了)
2、Oracle(数据库圈最牛逼的大佬 主要优势:公认最好 主要应用场景:大厂,银行等不差钱且需要数据绝对安全的公司 占据市场份额在逐渐减少但依旧很大 主要缺点:贵!!!)
介绍一下Oracle公司:Oracle是Java的爸爸,Java是后端和安卓端开发的主力语言,前短时间的Oracle与谷歌的侵权案以Oracle胜诉谷歌败诉为结局,后来谷歌就开发了谷歌自研的Dart语言作为Java的第二代安卓开发的替代品,现在已经演变了好多年了就差一个机会!!!(其语法和Java相差不大)
3、SQL Server(微软出品 大多数高校中学习的也是这个 市场份额相比以上数据库来说比较少但数据库的性能与服务都是业界顶点 未火起来的原因:1.收费~~ 2.捆绑销售(SQL Server必须和Windows Sever同时使用,但大多数企业中使用的都是Linux系统,所以.......)与微软搞的另一个编程语言C#(读作C sharp)同病相怜)
4、SQLite(非常轻量的数据库,嵌入到安卓系统内部,现在市场上很多App都在使用,相比以上数据库占用内存极少总共就500多KB)
5、Redis
6、MongoDB
7、HBase
对于存储的数据在格式上有严格的要求,类似于execl的存储形式.
相比关系型数据库功能较少,但其优势是速度更快,性能更好,能够更好的适应分布式环境.
高并发、大数据、分布式、微服务等都是在描述分布式环境
简单来讲分布式环境就是:数据量太大一台机器存不下了需要多台机器来存(需要更多的硬件资源来存储或提供服务).
计算机中最重要的组成体系:冯诺依曼体系、二进制(沿用至今)----->冯诺依曼及其团队制造计算机
计算机发展史上最重要的两个人:冯诺依曼 、图灵.
外存:硬盘、软盘(早就没了)、光盘、U盘.
注:手机也是计算机(也遵循冯诺依曼体系结构),手机常说的内存其实不是实际意义上的内存,而是运存.
1.读写速度上是内存快,外存慢.(内存比外存速度快的很多,能到3~4个数量级)
2.内存空间小,外存空间大.
3.内存贵!!!
4.内存数据是"易失"的,断电之后,数据就会丢失;外存数据是"持久"的,断电之后,数据还在.
MySQL是一个 客户端 服务器 结构的软件. (客户端 client 服务器 server)
咱们在安装MySQL的时候就已经把客户端和服务器安装好了
我去餐馆吃饭,要了个蛋炒饭.这里我就是客户端(主动发送数据的一方).餐馆就是服务器(被动接受并处理数据的一方)
"来个蛋炒饭":客户端给服务器发送的数据,称为"请求"request"."端上来了":服务器给客户端返回的数据,称为响应"response".
客户端和服务器是通过网络来进行通信的.
而一个餐馆不可能只给一个人提供饭菜,所以说一个服务器可以给多个客户端提供响应.
因为服务器不知道客户端啥时候来,所以必须7*24小时待机,等待客户端的请求.
客户端和服务器可以在一台主机上也可以在不同主机上.但不管客户端和服务器是不是在一台主机上通信都是通过网络(数据库的使用:电脑上有个特殊的硬件叫做环回网卡,可以在不通过WiFi或者有线网络的情况下在一台主机上实现客户端与服务器之间的通信)
除了命令行客户端之外,还有图形化客户端,但是用图形化客户端会减少代码的练习.(尽量不用)
(1)创建数据库
语法格式:
create database 2022_12_5;
成功案例:
注意:创建的数据库名字不能是SQL的关键字.
另外,利用SQL语句还能够设置数据库的字符集,那么在计算机中,一个汉字占几个字节呢?
答案:utf-8 3个字节
C --------------------------ASCII(以数字形式表示,具体见ASCII)----------------一个字节
Java --------------------------unicode(可以输入汉字)----------------------------------两个字节
然后,在MySQL中最常用的编码方式是:utf-8(内置多种语言)---------------------三个字节
但是,utf-8表示不了表情(emoji),后期mysql又出了个utf-8mb4(完全体)
语法格式:
create database `2022` charset utf8;
成功案例:
(2)if not exists
语法格式:
create database if not exists `2022`;
成功案例:
if not exists可以把错误转变为警告,在程序进行中SQL都是写到文件中的,但其中某一语句报错会导致后续代码都无法继续执行.这时就需要if not exists
(3)查找数据库
语法格式:
show databases;
成功案例:
这些数据库是在服务器上永久存在的(只要不删)
注意:不能乱删系统库(否则要重装数据库);数据库可以分行写(效果一样)如:
(4)选中指定数据库
语法格式:
use java;
成功案例:
(5)删除数据库(简称:删库)
语法格式:
drop database 数据库名;
成功案例:
注意:千万不要乱删(公司中删库损失不可估量!!!)
关系型数据库的表每一列都是带有类型的.(所有行对应的列的类型都是一样的)
(1)普通类型
float和double后面的(M表示有效数字的位数,D表示小数点后保留几位),且浮点数遵循IEEE 754标准(该标准决定了数据无法精确保存),为了解决精确存储问题就有了decimal(其牺牲了存储空间,换来了精准的表示方式)
但一般在表示钱的时候,主要用int表示单位以分为基本单位.(因为精准)
(2)字符串类型
最常用的类型:varchar(128)----------128指的是这个字符串最多能够存储128个字节.
(3)时间日期类型
另外,时间类型是伪随机的,生成一个随机的整数可以利用时间戳.
Timestamp类型在2038年将会失效
(1)创建表
语法格式:
create table 表名(列名 类型,列名 类型,列名 类型.......);
注意:想要进行表操作之前,首先要选中数据库.(use 数据库);同一个数据库不能有同名表.
成功案例:
(2)查看指定数据库下的所有表
语法格式:
show tables;
成功案例:
(3)查看指定表的结构
语法格式:
desc 表名;
成功案例:
(4)删除表
语法格式:
drop table 表名;
成功案例:
C--------create(新增)
U--------update(修改)
R--------retrieve(查询)
D--------delete(删除)
(1)新增
SQL中用insert表示新增
注意:进行增删改查的时候务必要选中数据库.
语法格式:
insert into 表名 values(列,列,列.......);
成功案例:
指定列插入:
语法格式:
insert into 表名(列名,列名,列名......) values(列......);
指定多个列就使用 , 分割列名即可.
成功案例:
同时插入多个数据:
语法格式:
insert into student values(列),(列),(列)......;
成功案例:
另外,在MySQL中一次存入多条数据比多次存入一条数据要快,开销要小.
原因1:由于网络请求和响应的时间的开销引起.
原因2:由于数据库服务器的数据是存在硬盘上面的,但硬盘的IO速度较慢.
原因3:MySQL关系型数据库,每进行一个sql操作,内部就会开启一个事务,每次开启事务有一定的开销.
(2)修改(Update)
语法格式:
update 表名 set 列名 = 值 where 条件;
成功案例:
另外,如果想要全局修改需要使用这种格式:(但空值是无法计算的)
(3)查询(sql中最复杂的操作语句)
全列查询:
语法格式:
select * from 表名;
成功案例:
存储数据量大的表绝对不能这样查找,这样又可能导致硬盘IO吃满,或者把网络带宽吃满,导致服务器无法访问,对生产环境造成极大的影响.
指定列查询:
语法格式:
select 列名 from 表名;
成功案例:
查询的列为表达式(在查询的过程中在列与列之间进行一个简单的计算):
语法格式:
select 列,列,列...... from 表名;
成功案例:
另外,还可以在原有列的基础上进行计算.
注:这里的查看操作只是搭建了个临时表,不管怎么计算都不会修改硬盘里的数据.
另外,还可完成列与列之间的计算.
给查询的信息起个别名:
语法格式:
select 列 as (别名),列 as (别名),列 as (别名)...... from 表名;
成功案例:
distinct关键字去重:
语法格式:
select distinct 列名 from 表名;
成功案例:
注:多列去重需要多列完全相同才能去重.
针对查询结果进行排序:
语法格式:
order by 字句,字句......;
注意:默认升序排列,想要降序排列需要使用desc字句.
升序关键字:asc
降序关键字:desc
成功案例:
另外,也可以根据前面讲的表达式进行排序:
另外,指定列排序可以选择多个列为标准,并设定升序或者降序.
(4)删除(delete)
语法格式:
delete from 表名 where 条件;
注意:如果不写条件就会删除表内全部内容!!!
成功案例:
通过where指定一个"条件"带入到查询中,判断是真还是假,保留真的结果作为临时表的结果.
(1)比较运算符
like要配合通配符'%'或者'_'使用.
_需要确定通配符位数.
%可以是任意位数.
(2)逻辑运算符
(3)limit.......offset......
这组关键字能够限制查询的条数以防查询数量太多超出可承受范围.
语法格式:
select * from 表名 limit 限制数量 offset 开始的条数;
成功案例:
或者也可以这样使用:
约束的目的其实就是帮助程序员检查数据库是否正确(校验数据合法性).在数据库添加约束会影响数据库执行顺序,进而影响数据库执行速度.
(1)NOT NULL - 指示某列不能存储 NULL 值。
语法格式:
not null
成功案例:
此时,就不能在id列添加null了.
(2)UNIQUE - 保证某列的每行必须有唯一的值。
语法格式:
unique
成功案例:
上面两个数据库是可以同时使用的:
这里的PRI就是primary key的意思,也就是主键约束的意思.
(3)PRIMARY KEY
NOT NULL 和 UNIQUE 的结合。确保某列(或两个列多个列的结合)有唯一标 识,有助于更容易更快速地找到表中的一个特定的记录。
这里可以看到和上面那个not null unique一摸一样.
注意:一个表中只能有一个主键.
(4)自增主键
数据库自动帮助程序员生成不需手动添加且不会重复的数据.
语法格式:
primary key auto_increment
成功案例:
注:自增主键是在上面数据的基础上+1.
(5)DEFAULT - 规定没有给列赋值时的默认值。
语法格式:
default'默认值'
成功案例:
(6)FOREIGN KEY - 保证一个表中的数据匹配另一个表中的值的参照完整性。
为了让MySQL能够帮我们将两个表相关联,完成两表中内容不重复和不能超出所限定的范围的操作,在这里引入外键约束.
语法格式:
foreign key (列名) references (列名);
成功案例:
在最后面classId=100插入失败,因为student里的数据必须要依赖class表里的数据
因为班级表中没有id=100的班级,在这里起到约束作用的class表就叫做'父表',被约束的表就叫做'子表'.
在父表约束子表的同时,子表也在约束着父表,在删除或修改父表的时候如果未更改子表也会报错.
(7)CHECK - 保证列中的值符合指定的条件。对于MySQL数据库,对CHECK子句进行分析,但是忽略CHECK子句(MySQL5不支持)。
设计表的基本思路:
(1)一对一(eg.一个学生对应一个班级)
(2)一对多(eg.一个班级对应多个学生)
(3)多对多(eg.多个学生对应多节课)
这个操作就是把查询表的结果插入到另一个表中.
注意:要求查询结果临时表的列数的列的类型,要和插入的表相同.
语法格式:
insert into 要插入的表名 select 列名 from 插入的表名;
成功案例:
本质上是针对行和行之间的计算.
(1)聚合查询
语法格式:
select 聚合函数(列名) from 表名;
注意:聚合函数和括号之间不能有空格.
可以使用group by对行进行分组
语法格式:
group by 列名;
成功案例:
如要进行平均工资的计算,最好通过职位来分组,再进行平均工资的计算.否则就会:
现在有三个人要计算平均工资,
直接计算会,
'我'一分不挣,就有10000000的平均工资,所以依照职位分组.
having
子句通常与group by子句一起使用,以根据指定的条件过滤分组。如果省略group by子句,则having
子句的行为与where
子句类似。
用法跟where一样也是添加限定条件,注意:两个可以同时使用.
现在总结一下SQL语句的执行过程:
首先,创建student和class表.
语法格式:
select * from 表名,表名......;
成功案例:
这就是笛卡尔积的基本上的结果.
但是,上述笛卡尔积的结果中有很多无用数据,所以需要加限定条件排除掉无用数据.
这里直接限定classId=classId会报错,说程序是模棱两可的,所以要指定到表.
这些就是有用的笛卡尔积数据了.
另外,联合查询还有一种写法就是使用join...on...或者inner join...on...
(1)内连接
这里我们使用图的形式来解释内连接与外连接.
首先准备好两个表:
这里发现同学3'王五'没有考试的成绩,而成绩70没有人认领,此时我们多表联合查询.
只能成功打印两组数据,这里的打印就是内连接.
(2)外连接
外连接分为左外连接和右外连接.
左外连接:
语法格式:
left join......on......
成功案例:
根据左表student从左边对其.(会把左表中内容尽量列出来)
右外连接:
语法格式:
right join......on......
成功案例:
根据右表score从右边对其.(会把右表中内用尽量列出来)
就是指自己和自己连接,效果就是把行转成列
语法格式:
select * from 表名 as s1,同一表名 as s2;
成功案例:
首先准备一个表
然后将它自连接,
一般使用在列与列之间的比较.
4.子查询
本质上是套娃,但尽量别用,会严重影响运行效率,进而对程序造成毁灭性打击,很容易达到运行瓶颈导致程序跑不动.(炫技)
(1)单行子查询
语法格式:
select 列名 from 表名 where 列名=(另一个sql语句);
成功案例:
这里准备一个表:
我们现在要在其中寻找乙的同班同学.
我们首先利用两部sql语句即可寻找到乙的同班同学:
我们也可以选择运用子查询手法将两个字句合为一个:
就是把查询里面嵌套查询,也就是'套娃';
(2)多行子查询
就是要嵌套的内容位于不同的表而且结果不唯一时,需要使用到多行子查询:
语法格式:
select 列名 from 表名 where 列名 in(另一个sql语句);
5.合并查询
本质上就是把两个查询的结果集合并为一个.
语法格式:
select 列名 from 表名 where 条件 union select 列名 from 表名 where 条件;
成功案例:
union于or的区别:
or必须要来自同一个表,而union可以来自不同的表也可以来自同一表,更加灵活.
另外,还有一种查询方式时union all.
union自带去重功能,而union all可以保留多份,用法和union一样.
索引就是书的目录.能够加快查找速度.
要知道,MySQL中大多数的功能都和查有关系,增加查的速度就是增加所有的速度.但会增加开销,并增加增删改的速度.
(1)查看索引
语法格式:
show index from 表名;
成功案例:
名字列插有主键,因为主键有查重功能,而每加入一个新的记录就需要根据索引检验这个记录是否在与数据库中存在,加入索引后不需要重新遍历数据库,节省了资源.另外,外键与unique也是如此.
(2)创建索引
语法格式:
create index 索引名称 on 表名(列名);
索引需要创建在尽量没有重复的列,因为如果'目录'都一样,那就跟没有一样.
成功案例:
(3)删除索引
语法格式:
drop index 索引名称 on 表名;
成功案例:
(1)B叉搜索树
通过在一个节点存储多个元素的方式极大程度上的减少了硬盘的IO次数,但比较次数与速度都未曾减少.
虽然B数已经能解决一些效率上的问题,但之后科学家有研究出了更加适合数据库的N叉搜索树.
(2)N叉搜索树
1. B+搜索树也是一个N叉搜索树,每个节点上可能包含N个key,N个key包含N个区间,最后一个key就相当于最大值了
2. 父节点中的值会在子节点中重新出现,并且是最大值,这样重复出现就导致了叶子节点就包含了数据的全集,并且非叶子节点的值也会在叶子节点中体现出来.
3. 在N叉搜索树形成后会把每个叶子节点首位相连,形成链表,这样的好处有很多:
第一,最为一个N叉搜索树高度下降,使得硬盘的IO次数减少.
第二,能够更加有利于范围搜索,而范围搜索则是数据库中最常用的操作.
第三,所有的查询操作,最终都是落在叶子节点上的,无论要查询哪个元素,中间比较的次数都差不多,查询操作比较均衡.
第四,由于所有的key都在叶子节点中集中体现,因此非叶子节点在N叉树中不必存在真实的值(不必寻储数据行),只需要把所有的数据都放到叶子节点上即可,非叶子节点只需要存索引列的值(比如说存id就行)
由于非叶子节点中只存了id,而id占用内存很少,故有可能存入内存中使用,既减少了硬盘的IO又提升了读取速度.
3.事务
把多个事务打包成一个整体,要么就都执行完,要么就一个都不执行,这就是事务的功能.
所以要给指定事务整体设定'原子性'.来完成事务的功能.
如:转帐:余额-50与存款+50应当设置为一个事务,保持他们的'原子性'.
如果在转账中出错,就涉及到了'回滚'操作,回溯到50转出账户之前.
语法格式:
start transaction;//开启事务
中间可以写多个sql语句
commit;
开启事务后,中间的sql不会立即执行,而是现攒着,等待commit后一起统一执行.
下面介绍数据库的事务的四大特性:
1. 原子性(事务的初心)
2. 一致性,事务执行前后都得保持数据合法的状态,不能让某一部分单独执行.
3. 持久性 当事务运行一半并写入硬盘时,就算断电等操作都不会影响事务的进程.(通过commit也可恢复)
4. 隔离性 多个事务同时进行时不会互相影响.
在平时的程序运行中,为了不让程序与程序之间互相影响,需要提升模块与模块之间隔离的程度,而提升隔离性则会降低运行速度和运行效率,所以在编程中需要掌握隔离程度的高低,以谋求最为平衡的代码体验.
故mysql提供了四个隔离程度:
1.read uncommitted
不做任何约束,事务之间都是随意并发执行的,并发程度最高隔离性最低,会出现"脏读"(几个并发程序同时运行导致读取到了未完全结束的程序的错误的内容)和"幻读"(并发程度中等的几个程序在读取中读到了不同的结果集).
2.read committed
对写操作加锁了,并发程度降低了,隔离性提高了,解决了"脏读"问题,但仍然存在 不可重复读+幻读
3.repeatable read
对写和读都加锁了,并发程度降低了,隔离性又降低了,解决了 脏读+不可重复读,可能存在幻读问题
4.serializable
严格串行化,并发程度最低,串行度最高.牺牲了执行效率,但解决了所有问题.
可以通过调整MySQL的配置文件来调整隔离性挡位.
通过idea操控MySQL数据库,可以实现循环插入等功能,能够极大的便利使用MySQL的过程(能够让不会使用MySQL的人也能够顺利使用),主要通过调用JDBC的api进行使用.
JDBC是MySQL的应用厂商Oracle出品的数据库连接程序,目的是让MySQL能够正常作为Java的数据库连接idea.
这是JDBC的全貌,使用粘贴键将它粘贴至新创建目录上.
右键目录点击Add as Library(库)这里将lib目录作为库使用将jar包添加至库中.
出现这种情况就说明JDBC已经正常导入了
首先是insert部分,要准备好一个表.
这里我们准备好了数据库:java,也准备好了表:student.接下来的插入操作总共分为五部:
(1)创建数据源,描述了数据库服务器在哪.
这个操作书要是未了让MysqlDataSource类不扩散:也就是说让后续代码使用的引出api的实例是dataSource而不是MysqlDataSource,这就是俗称的"高内聚",方便日后如若更改数据库或者修改数据库代码时只需要改这几行即可,是经验之谈.
接下来介绍这个,url------->唯一资源地址符,也就是咱们俗称的网址.
这里我们应该这样填写里面的内容:
jdbc:mysql://127.0.0.1:3306/java?characterEncoding=utf8&useSSL=false
这个地址不用改每个人都几乎一样.
这里我们还需要输入MySQL的用户名和密码:
用户名只要输入默认的root密码则是自己设定的数据库密码.
注意:现在只是输入了地址,用户名,密码,还并没有建立连接.
(2)和数据库建立网络连接,写的代码实际上是MySQL客户端,需要通过网络来通信.
建立连接需要使用Connection(连接),而Connection需要使用第二个.
这样就完成了建立连接操作.
(3)构建一个sql语句,完成插入操作.
这里的PreparedStatement翻译为预处理的语句,这里的语句的作用是解析sql语句,让他能够真正在idea中使用.
(4) 执行sql语句,控制客户端给服务器发送请求.
注意:这里的statement.executeUpdate()的作用是执行sql语句,也就是给服务器发出请求
这里的返回值ret指的是这个操作影响了多少行的内容.
(5)断开与数据库的连接,释放必要的资源.
这里的内存释放遵循一个规则:
就是先创建的后释放,后创建的先释放.
就比如进出房门,先进大门后进二门,想要出来就得先出二门后出大门,原理是一样的.
最后代码就可以正确运行了:
MySQL中也可以正常插入数据.
这里我们想要通过idea控制台输入数据插入表格,就需要使用到占位符.
首先输入操控控制台代码:
之后继续使用PreparedStatement中的api并使用占位符'?'进行sql语句中的替换.
之后程序依然能够正常运行:
代码全貌:
public class JDBCInsertDome {
public static void main(String[] args) throws SQLException {
DataSource dataSource=new MysqlDataSource();//向上转型,将原本是MysqlDataSource类的dataSource转为其子类DataSource.
((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/java?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("2404868224a");
Scanner scanner=new Scanner(System.in);
System.out.print("请输入学号:");
int id =scanner.nextInt();
System.out.print("请输入姓名:");
String name=scanner.next();
//向下转型,将DataSource类的dataSource重新转为MysqlDataSource类
Connection connection=dataSource.getConnection();
String sql="insert into student values(?,?)";
//JDBC中还需要搭配一个特定的对象,来描述这里的sql情况.
PreparedStatement statement=connection.prepareStatement(sql);
statement.setInt(1,id);
statement.setString(2,name);
int ret=statement.executeUpdate();
System.out.println("ret="+ret);
statement.close();
connection.close();
}
}
查找代码与新增代码的不停在于:查找代码需要使用ResultSet的api进行遍历表.
申请结果集合
使用循环语句对每一列进行遍历.
这里的括号中写的是列名.
其他的都和新增代码一样.
这样查找代码就完成了:
public class JDBCSelectDome {
public static void main(String[] args) throws SQLException {
DataSource dataSource=new MysqlDataSource();
((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/java?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("2404868224a");
Connection connection=dataSource.getConnection();
String sql="select * from student";
PreparedStatement statement=connection.prepareStatement(sql);
// 结果集合
ResultSet resultSet=statement.executeQuery();
while(resultSet.next()){
int id=resultSet.getInt("id");
String name=resultSet.getString("name");
System.out.println("id:"+id+" "+"name:"+name);
}
resultSet.close();
statement.close();
connection.close();
}
}
注意:项目中操作MySQL99%都是使用代码完成.
小细节:1.按ctrl+C即可快速终止本行,也可快速结束运行时间过长的程序.
2.在MySQL和Linux中复制时enter,粘贴是鼠标右键.
MySQL中还有一些高级索引等知识就不在此叙述,在项目中MySQL只是充当数据库的作用不会在此上面写类似循环之类的代码降低程序整体的阈值.因此要合理掌握MySQL的定位,在项目中的占比是尤为重要,在此作者祝所有看到这里的程序猿们代码不出bug,生活中事事顺利,身体健康!!!