[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WENN08Sk-1645522464477)(image/202109181204910.gif)]
如果要使用CMD窗口作为客户端,需要配置环境变量,在path中添加如下变量值:Program Files\MySQL\MySQL Server 5.5\bin;
注意:使用数据库之前一定启动服务
MySQL的语法规范
DDL data definition language 数据定义语句 (create alter drop)
DML data manipulation language 数据操作语句 (insert update delete)
DQL data query language 数据查询语句(select)
DCL data control lanugage 数据控制语句(grant revoke commit rollback)
登录:mysql 【-h 主机名 -P 端口号】 -u 用户名 -p密码
退出:exit或ctrl+C
方式一:通过dos窗口
net start 服务名
net stop 服务名
方式一:登录到mysql服务端
select version();
方式二:没有登录到mysql服务端
mysql --version 或 mysql --V
explain
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IsgWayg2-1645522464478)(image/202109181205723.jpg)]
int(4):配合zerofill进行使用,显示占4位宽度,不够会补零,需要是无符号
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rnrKQvBr-1645522464479)(image/202109181205465.jpg)]
DECIMAL(max(65),max(30)):最大数字位数和最大小数位数
如果精确运算,使用DECIMAL,没有精确运算的需求,建议使用float double
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iWQHAEWJ-1645522464479)(image/202109181205912.jpg)]
char和varchar的区别
enum只能从列出来的值中选择一个作为数据,set可以从列出来的值中选择多个值作为数据。
http://dev.mysql.com/downloads/mysql/5.5.html#downloads
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ehvau1mX-1645522464482)(image/202109181205560.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ADbl435m-1645522464482)(image/202109181205633.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nUEYS99e-1645522464482)(image/202109181205104.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c6D76rDw-1645522464483)(image/202109181205937.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oqLDeK2o-1645522464483)(image/202109181205992.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aZii0oXI-1645522464483)(image/202109181206506.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eQoJ74JE-1645522464484)(image/202109181206196.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cvu7dV3s-1645522464484)(image/202109181206608.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qyY9guTW-1645522464484)(image/202109181206449.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IOJmuVwl-1645522464485)(image/202109181206025.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zKtTLKdH-1645522464485)(image/202109181206480.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kZNT4tRp-1645522464486)(image/202109181206347.png)]
此处选择详细配置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qPjUMPNZ-1645522464486)(image/202109181206050.png)]
此处选择开发机
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4rVSyjOh-1645522464486)(image/202109181206516.png)]
此处选择多功能数据库
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pHcvUP8S-1645522464487)(image/202109181206992.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZffQgZ4Q-1645522464487)(image/202109181206306.png)]
直接下一步
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XirkidhX-1645522464488)(image/202109181206984.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xGw69hIv-1645522464488)(image/202109181206961.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RpXGGsN6-1645522464489)(image/202109181207594.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BI7OkJ37-1645522464489)(image/202109181207714.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q8YCdZJ9-1645522464490)(image/202109181207751.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ug1GhCw5-1645522464490)(image/202109181207654.png)]
#创建数据库(默认字符集编码)
create database test20210420
#创建数据库的时候指定字符集编码以及字符校验规则
create database test20210420 CHARACTER set = utf8 COLLATE utf8_general_ci
#切换可用数据库(建表之前一定要切换)
use test20210420
#查看服务器的所有数据库
show databases
#删除数据库
drop database test20210420
#修改数据库字符集编码以及字符校验规则
alter database test20210420 CHARACTER set = utf8 COLLATE utf8_general_ci
#查看数据库信息
show create database test20210420
#创建表:创建表的格式
create table student( student_id int, student_name varchar(20), student_birth int )
#插入数据的命令
insert into student values(1,'姚明',20)
#查询
select * from student
#删除表
drop table student
#结构和数据一起复制(有创建表)
create table testchar1 as select * from testchar
#结构复制(有创建表)
create table testchar2 like testchar
#1.给表中增加列
alter table testchar add t_age int
#2.给修改列名及列定义
alter table testchar change t_name1 t_name2 varchar(50)
#3.修改列定义
alter table testchar modify t_name2 varchar(100)
#4.删除列
alter table testchar drop t_age
#查看当前数据库中所有的表
SHOW TABLES;
#查看表的定义信息
SHOW CREATE TABLE testchar
#删除表
drop table testchar
#表重新命名
Rename table testchar to testchar3
NOT NULL:非空,该字段的值必填
UNIQUE:唯一,该字段的值不可重复
DEFAULT:默认,该字段的值不用手动插入有默认值
CHECK:检查,mysql不支持
PRIMARY KEY:主键,该字段的值不可重复并且非空 unique+not null
FOREIGN KEY:外键,该字段的值引用了另外的表的字段
区别:
①一个表至多有一个主键,但可以有多个唯一
②主键不允许为空,唯一可以为空
相同点
①都具有唯一性
②都支持组合键,但不推荐
主表(父表)被引用字段所在的表
在数据库中建立的表格即Table,其中存在主键(primary key)用于与其它表相关联,并且作为在主表中的唯一性标识。
从表(子表)
以主表的主键(primary key)值为外键(Foreign Key)的表,可以通过外键与主表进行关联查询。从表与主表通过外键进行关联查询。
#1、非空
#添加非空
alter table 表名 modify column 字段名 字段类型 not null;
#删除非空
alter table 表名 modify column 字段名 字段类型 ;
#2、默认
#添加默认
alter table 表名 modify column 字段名 字段类型 default 值;
#删除默认
alter table 表名 modify column 字段名 字段类型 ;
#3、主键
#添加主键
alter table 表名 add【constraint 约束名】 primary key(字段名);
#删除主键
alter table 表名 drop primary key;
#4、唯一
#添加唯一
alter table 表名 add【 constraint 约束名】 unique(字段名);
#删除唯一
alter table 表名 drop index 索引名;
#5、外键
#添加外键
alter table 表名 add【 constraint 约束名】 foreign key(字段名) references 主表(被引用列);
#删除外键
alter table 表名 drop foreign key 约束名;
#自增长列
#添加自增长列
alter table 表 modify column 字段名 字段类型 约束 auto_increment
#删除自增长列
alter table 表 modify column 字段名 字段类型 约束
语法:
insert into 表名 (字段名,...) values (值,...);
特点:
1、要求值的类型和字段的类型要一致或兼容
2、字段的个数和顺序不一定与原始表中的字段个数和顺序一致
但必须保证值和字段一一对应
3、假如表中有可以为null的字段,注意可以通过以下两种方式插入null值
①字段和值都省略
②字段写上,值使用null
4、字段和值的个数必须一致
5、字段名可以省略,默认所有列
语法:
insert into 表名 set 字段=值,字段=值,...;
1.方式一支持一次插入多行,语法如下:
insert into 表名(字段名,..) values(值,..),(值,...),...;
2.方式二支持子查询,语法如下:
insert into 表名
查询语句;
一、修改单表的记录
语法:
update 表名 set 字段=值,字段=值 where 筛选条件;`
二、修改多表的记录【补充】
语法:
update 表1 别名
left|right|inner join 表2 别名
on 连接条件
set 字段=值,字段=值
where 筛选条件;
一、删除单表的记录
语法:
delete from 表名 where 筛选条件 limit 条目数
二、级联删除[补充]
语法:
delete 别名1,别名2 from 表1 别名
inner|left|right join 表2 别名
on 连接条件
where 筛选条件
语法:
truncate table 表名
select 列名1, ... ,列名n from 表名
where 条件 -- 1、条件
group by 列名 -- 2、分组
having 条件 -- 3、条件
order by 列名 -- 4、排序
limit 开始,条数 -- 5、分页
select * from 表名
#多列列名使用,隔开
select 列名 from 表名
select 列名 [as] 别名,列名n [as] 别名n
#列和固定数值
select 列名+\-\*\/\%数值 from 表名
#列和列
select 列名+\-\*\/\%列名 from 表名
select concat(列名1,列名2,...)合并后列名 from 表名
select * ,'常量' 列名 from 表名
(=,>,<,>=,<=,!=<>,如果是null,需要写为is\is not )
select * from 表名 where 列名=值
select * from 表名 where 列名1=值 and 列名2=值
#不同列
select * from 表名 where 列名1=值 or 列名2=值
#同一列的不同值
select * from 表名 where 列名 in (值1,值2,...)
select * from 表名 where 列名 not in (值1,值2,...)
#查询l开头的名字,任意长度
select * from 表名 where 列名 like 'l%'
#查询l开头的名字,固定长度
select * from 表名 where 列名 like 'l__'
#查询包含o的名字
select * from 表名 where 列名 like '%o%'
select * from 表名 where 列名 between 下界值 and 上界值
select * from 表名 order by 列名
select * from 表名 order by 列名 asc
select * from 表名 order by 列名 desc
select * from 表名 order by 列名1 desc,列名2 desc
#起始位置默认为0,查询不包括起始位置
select * from 表名 limit 起始位置,每页条目数
#假如要显示的页数为page,每一页条目数为size
select 查询列表
from 表
limit (page-1)*size,size;
关于某一列进行操作,和行没有关系
count() | 返回结果集中行的数目 |
---|---|
max() | 返回结果集中所有值的最大值 |
min() | 返回结果集中所有值的最小值 |
sum() | 返回结果集中所有值的总和 |
avg() | 返回结果集中所有值的平均值 |
聚合函数null值不参与运算,如果希望null值也参与那么需要**ifnull()**函数处理
select 函数名(列名) from 表名
select 分组列名,聚合函数 from 表名 group by 分组列名
#一般和聚合函数一起使用
#如,查询student表中的男女两个分组中的最大年龄和最小年龄
select ssex,max(sage),min(sage) from student group by ssex
group by后不可以使用where进行筛选,需要使用having关键字
如果能用where筛选数据的话,绝不使用having
#如,查询年龄大于11的各个年龄段的人数
select sage,count(sage) from student group by sage having sage > 11
#可以使用where就不要用having
select sage,count(sage) from student where sage > 11 group by sage
1. 将2个表的数据进行拼接,针对拼接后的重复数据 去重显示
select 列名 from 表名1 where 条件
union
select 列名 from 表名2 where 条件
2. 将2个表的数据进行拼接,针对拼接后的重复数据 不去重显示
select 列名 from 表名1 where 条件
union all
select 列名 from 表名2 where 条件
#sql92
select * from 表1,表2;
#sql99
select * from 表1 cross join 表2;
笛卡尔积组合,形成数据没有价值
select 列名 from A表
inner join B表 on 关联条件;
select 列名 from A表
left join B表 on 关联条件;
select 列名 from A表
right join B表 on 关联条件;
#查询1号课程成大于2号课程的学生id
select * from sc s1
inner join sc s2
on s1.sno=s2.sno
where s1.cno=1 and s2.cno=2 and s1.score>s2.score
select distinct 列名 from 表名;
嵌套查询,就是指一个sql语句里面还有一条sql语句
将查询的结果(可以作为值,也可以作为表),再次被sql语句使用
#查询李华老师所带课程
select * from course where tno =
(
select tno from teacher where tname = '李华'
)
#查询李华老师所带学生的信息
-- 1 获取李华老师的编号
select tno from teacher where tname = '李华'
-- 2 根据老师的编号获取所带学科的编号
select cno from course where cno in
(
select tno from teacher where tname = '李华'
)
-- 3 根据学科编号获取学生的编号
select sno from sc where cno in
(
select cno from course where cno in
(
select tno from teacher where tname = '李华'
)
)
-- 4 根据学生编号,获取学生的信息
select * from student where sno in
(
select sno from sc where cno in
(
select cno from course where cno in
(
select tno from teacher where tname = '李华'
)
)
)
#查询学生表中,年龄大于张三或tony的学生信息
select * from student where sage > any(
select sage from student where sname = '张三' or sname = 'tony'
)
#查询学生表中,年龄大于张三并且大于tony的学生信息
select * from student where sage > all(
select sage from student where sname = '张三' or sname = 'tony'
)
#查询student表中,按照年龄显示是否成年
select *,
case
when sage >= 18 then '成年'
else '未成年'
end
from student
直接在cmd窗口中直接输入,结束不需要输入;
mysqldump -h端口号 -u用户名 -p密码 数据库名>备份地址
在cmd窗口中进行
1、连接数据库
mysql -u用户名 -p密码
2、创建数据库
create database 库名
3、切换到可用数据库
use 库名
4、进行恢复
source 备份文件地址
1.创建用户:
# 指定ip:192.118.1.1的用户登录
create user '用户名'@'192.118.1.1' identified by '密码';
# 指定ip:192.118.1.开头的用户登录
create user '用户名'@'192.118.1.%' identified by '密码';
# 指定任何ip的用户登录
create user '用户名'@'%' identified by '密码';
2.删除用户
drop user '用户名'@'IP地址';
3.修改用户
rename user '用户名'@'IP地址' to '新用户名'@'IP地址';
4.修改密码
set password for '用户名'@'IP地址'=Password('新密码');
#查看用户权限
show grants for '用户名'@'IP地址'
1、授权
#授权用户仅对某文件有查询、插入和更新的操作
grant select,insert,update on 文件名 to '用户名'@'IP地址';
#授权所有的权限,除了grant这个命令,这个命令是root才有的。用户对db1下的t1文件有任意操作
grant all privileges on db1.t1 to '用户名'@'IP地址';
#授权用户可以对db1数据库中的所有文件执行任何操作
grant all privileges on db1.* to '用户名'@'IP地址';
#授权用户可以对所有数据库中文件有任何操作
grant all privileges on *.* to '用户名'@'IP地址';
2、取消权限
# 取消用户对db1的t1文件的任意操作
revoke all on db1.t1 from '用户名'@'IP地址';
# 取消来自远程服务器的mjj用户对数据库db1的所有表的所有权限
revoke all on db1.* from '用户名'@'IP地址';
# 取消来自远程服务器的mjj用户所有数据库的所有的表的权限
revoke all privileges on *.* from '用户名'@'IP地址';
多表的联合查询,最多也才3张表,如果面临更多的表,为了简化连表操作,可以使用MySQL中的视图
1、简化sql语句
2、提高了sql的重用性
3、保护基表的数据,提高了安全性
create view 视图名
as
查询语句;
create or replace view 视图名
as
查询语句;
alter view 视图名
as
查询语句
drop view 视图1,视图2,...;
desc 视图名;
show create view 视图名;
关键字 | 是否占用物理空间 | 使用 | |
---|---|---|---|
视图 | view | 占用较小,只保存sql逻辑 | 一般用于查询 |
表 | table | 保存实际的数据 | 增删改查 |
索引用于快速找出在某个列中有一特定值的行,避免全表扫描
MySQL索引,默认是B+树索引
show index from 表名
优点:
1、所有的MySQL列类型(字段)都可以被索引,也就是可以给任意字段设置索引
2、大大加快数据的查询速度
缺点:
1、创建索引和维护索引要耗费时间,并且随着数据量的增加所耗费的时间也会增加
2、索引也需要占空间,如果有大量的索引,索引文件可能会比数据文件更快达到上限值
3、当对表中的数据进行增、删、改时,索引也需要动态的维护,降低了数据的维护速度
单列索引(普通索引、唯一索引、主键索引)、组合索引、全文索引、空间索引
alter table table_name add index index_name(column_name) using btree;
create unique index index_name on table_name(column_name);
事务是作为单个逻辑单元执行的一系列操作
多个操作作为一个整体向系统提交,要么执行、要么都不执行,事务是一个不可分割的工作工作逻辑单元
原子性(A – Atomicity):原子是参与化学反应中最小的粒子,不能再分割了,也就是说事务就是最小的,不能再分割了,如果把事务都分割了,就会出现问题
一致性(C – Consistency):在事务执行前数据库的数据处于正确的状态,而事务执行完成后数据库的数据还是处于正确的状态,即数据完整性约束没有被破坏
隔离性(I – Isolation):事务与事务之间互不干扰
持久性(D – Durability):通过事务进行操作后的数据,是永久保存的
注意:在实际开发中,经常会打破隔离性,当多个事务共同操作同一张表的时候,一旦打破了隔离性,就会出现安全问题
存储引擎:RDBMS中,决定了数据如何存储,如何获取,如何控制事务,如何控制外键等一系列功能的一套程序
**常用引擎:**InnoDB,MyIsam
开启事务:start transaction;
提交事务:commit;
注意:当事务开启之后,只有执行了commit,数据才会真的改变,如果没有执行commit,数据还原
回滚事务:rollback;
修改默认的提交方式,默认是自动提交,我们要改成手动提交
show variables like '%autocommit%'
set @@autocommit=0
(默认为1,自动提交;0,手动提交)
隔离级别 | 读数据一致性及允许的并发副作用 | 备注 |
---|---|---|
读未提交(Read uncommitted) | 最低级别,只能保证不读取物理上损坏的数据,事务可以看到其他事务没有被提交的数据(脏数据) | |
读已提交(Read commited) | 语句级,事务可以看到其他事务已经提交的数据 | Oracle数据库默认 |
可重复读(Repeatable read) | 事务级,事务中两次查询的结果相同 | MySql数据库默认 |
可串行读(序列化Serializable) | 最高级别,事务级。顺序执行 |
隔离等级越高,数据库事务并发执行能力越差,能处理的操作越少。因此在实际项目开发中为了考虑并发性能一般使用读已提交隔离级别,他能避免丢失更新和脏读,尽管不可重复读和幻读不能避免,但可以在可能出现的场合使用悲观锁或乐观锁来解决这些问题。
1、脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据,读取到未提交的数据。
2、不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果不一致。
3、幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读
隔离级别 | 脏读 | 不可重复读 | 幻读 | 第一类丢失更新 | 第二类丢失更新 |
---|---|---|---|---|---|
Read uncommitted | √ | √ | √ | × | √ |
Read commited | × | √ | √ | × | √ |
Repeatable read | × | × | √ | × | × |
Serializable | × | × | × | × | × |
set session transaction isolation level 隔离级别
select @@tx_isolation
默认存在,什么都不做,就是乐观锁。总是乐观的认为,在维护这个数据的时候,没有其他人来维护。
insert update delete 在执行SQL的同时,才给数据加上了乐观锁。
age:12
A用户:update table set age=32 where id=1
B用户:update table set age=12 where id=1
A用户:select * from table where id=1
这个时候,A用户查看的数据为B修改过的,自己的修改已经被覆盖
总是担心,在自己修改数据的时候,有其他人,将这个数据修改,所以在修改数据之前,提前锁住数据
默认没有开启,需要自己开启
#在查询语句后加for update就可以开启(悲观排他锁)
select * from book for update
优点:准确性高,更加安全
缺点:效率太低,一旦一个用户执行悲观锁,那么其他用户都无法查看这个表的数据,也无法进行修改,除非执行悲观锁的用户commit
只会锁住一行数据
select * from book where id=1 for update
会锁住整个的一个表
select * from book for update
A用户在给表加排他锁以后,那么其他用户都无法对表进行操作、查看、加锁
//表级排他锁
lock table book write
//解锁
unlock table
所有的用户都可以对表进行加锁,但是,所有的用户都无法对表进行操作,包括上锁的用户
//表级共享锁
lock table book read
//解锁
unlock table
两个线程自己各自持有自己数据的锁,但互相都想锁住被对方锁住的数据,就产生了死锁
系统检索到死锁,会自动释放一个锁
数据持久化就是将内存中的数据模型转换为存储模型,以及将存储模型转换为内存中的数据模型的统称。数据模型可以是任何数据结构或对象模型,存储模型可以是关系模型、XML、二进制流等。
保存在内存的程序数据,程序退出,数据就消失了
保存在磁盘上的程序数据,程序退出后依然存在
Hibernate、JPA、==JDBC(Java Datebase Connectivity)==等
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a19x0KJX-1645522331453)(image/202109181208806.gif)]
java.sql.Driver 接口是所有 JDBC 驱动程序需要实现的接口。这个接口是提供给数据库厂商使用的,不同数据库厂商提供不同的实现
在程序中不需要直接去访问实现了 Driver 接口的类,而是由**驱动程序管理器类(java.sql.DriverManager)**去调用这些Driver实现
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qzX1KIF4-1645522331455)(image/202109181208475.gif)]
Connection conn = null;
Statement st=null;
ResultSet rs = null;
try {
//获得Connection
//创建Statement
//处理查询结果ResultSet
}catch(Exception e){
e.printStackTrance();
} finally {
//释放资源ResultSet, Statement,Connection
}
1、在项目中创建lib文件夹
2、将jar文件放置到lib文件夹
3、集成到项目中,右键build(eclipse)、add as library(idea)
将com.mysql.jdbc包下的Driver类的字节码文件从本地磁盘加载到方法区中
Oracle的驱动:oracle.jdbc.driver.OracleDriver
mySql的驱动: com.mysql.jdbc.Driver
方式一:加载 JDBC 驱动需调用 Class 类的静态方法 forName(),向其传递要加载的 JDBC 驱动的类名
//将com.mysql.jdbc包下的Driver类的字节码文件从本地磁盘加载到方法区中
Class.forname("com.mysql.jdbc.Driver")
方式二:DriverManager 类是驱动程序管理器类,负责管理驱动程序
DriverManager.registerDriver(com.mysql.jdbc.Driver);
通常不用显式调用 DriverManager 类的 registerDriver() 方法来注册驱动程序类的实例,原因:
1、该方法,过于依赖jar包的存在
2、该方法,会造成二次注册
3、使用Class.forname可以降低耦合性
//本机IP:localhost 本机端口号:3306
String url = "jdbc:mysql://IP地址:端口号/库名?serverTimezone=Asia/Shanghai&characterEncoding=utf-8";
String user = "用户名";
String passWord = "密码";
Connection conn = DriverManager.getConnection(url,user,passWord);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ua1UJT6D-1645522331455)(image/202109181208986.gif)]
协议:JDBC URL中的协议总是jdbc
子协议:子协议用于标识一个数据库驱动程序
子名称:一种标识数据库的方法。子名称可以依不同的子协议而变化,用子名称的目的是为 了定位数据库提供足够的信息。包含主机名(对应服务端的ip地址),端口号,数据库名
对于 Oracle 数据库连接,采用如下形式:
jdbc:oracle:thin:@localhost:1521:库名
对于 SQLServer 数据库连接,采用如下形式:
jdbc:microsoft:sqlserver//localhost:1433; DatabaseName=库名
对于 MYSQL 数据库连接,采用如下形式:
jdbc:mysql://localhost:3306/库名
Statement statement = conn.createStatement();
int result = statement.executeUpdate("sql语句字符串对象")
//使用Statement类的方法ResultSet executeQuery(String sql);获得结果集类型的对象
ResultSet set = statement.executeQuery(sql);
while(set.next()){
//形参可以直接写字段名,字段名不区分大小写
String id = set.getInt("book_id");
//也可以写字段索引,索引从1开始
String id = set.getInt(1);
}
resultSet.close();
statement.close();
connection.close();
将获取连接和关闭资源等公共、重复的代码封装成一个工具类
import java.sql.*;
public class JDBCUtil {
private static String driver;
private static String url;
private static String user;
private static String passWord;
//解析配置文件.properties
static {
try {
Properties properties = new Properties();
properties.load(new FileInputStream(".properties文件路径"));
driver = (String) properties.get("driver");
url = (String) properties.get("url");
user = (String) properties.get("user");
passWord = (String) properties.get("passWord");
}catch (Exception e){
e.printStackTrace();
}
}
//获得Connection对象
public static Connection getConnection(){
Connection connection = null;
try{
Class.forName(driver);
connection = DriverManager.getConnection(url,user,passWord);
}catch (Exception e){
e.printStackTrace();
}
return connection;
}
//关闭资源 -- 针对查询
public static void close(ResultSet resultset,Statement statement,Connection connection){
try {
if (resultset != null) {
resultset.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
//关闭资源 -- 针对增删改
public static void close(Statement statement,Connection connection){
close(null,statement,connection);
}
//针对DML语句--增删改
public static boolean executeUpdate(String sql,List<Object> list){
Connection connection = getConnection();
PreparedStatement pre = null;
try {
pre = connection.prepareStatement(sql);
for (int i = 0;i < list.size();i++){
pre.setObject(i + 1,list.get(i));
}
return (pre.executeUpdate() > 0)? true : false;
}catch (Exception e){
e.printStackTrace();
}finally {
close(pre,connection);
}
return false;
}
//针对查DQL语句
public static <T> List<T> executeQuery(String sql,List<Object> list,Class<T> tClass){
Connection connection = getConnection();
PreparedStatement statement = null;
ResultSet resultSet = null;
List<T> li = new ArrayList<>();
try {
statement = connection.prepareStatement(sql);
for (int i = 0;i < list.size();i++){
statement.setObject(i + 1,list.get(i));
}
resultSet = statement.executeQuery();
ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
//获取列数
int count = resultSetMetaData.getColumnCount();
//遍历所有行
while (resultSet.next()){
T t = tClass.newInstance();
for (int i = 1;i <= count;i++){
//获取每一列列名
String keyName = resultSetMetaData.getColumnLabel(i);
//获取每一列对应的值
Object value = resultSet.getObject(keyName);
//T中对应的属性
Field key = tClass.getDeclaredField(keyName);
key.setAccessible(true);
key.set(t,value);
}
li.add(t);
}
}catch (Exception e){
e.printStackTrace();
}finally {
close(connection,statement,resultSet);
}
return li;
}
}
List<Map> list = JDBCUtils.executeQuery(sql,new ArrayList());
for (Map<String,Object> map : list){
for (Map.Entry<String,Object> entry : map.entrySet()){
String s = entry.getKey();
Object o = entry.getValue();
System.out.print(s + "=" + o + ",");
}
System.out.println();
}
SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在 用户输入数据中注入非法的 SQL 语句段或命令,如下,从而利用系统的 SQL 引擎完成恶意行为的做法。
SELECT user, password FROM user_table WHERE user='a' OR 1 = ' AND password = ' OR '1' = '1'
对于 Java 而言,要防范 SQL 注入,只要用 PreparedStatement(继承于Statement) 取代 Statement 就可以了
1、可以通过调用 Connection 对象的 preparedStatement() 方法获取 PreparedStatement 对象
2、PreparedStatement 接口是 Statement 的子接口,它表示一条预编译过的 SQL 语句
1、代码的可读性和可维护性
2、PreparedStatement 能最大可能提高性能
3、PreparedStatement 可以防止 SQL 注入
4、如果拼接表名、列名、关键字,必须使用Statement,防止sql语句错误
1、通过调用 PreparedStatement 对象的 excuteQuery() 方法创建该对象
2、代表结果集
3、ResultSet 返回的实际上就是一张数据表.,有一个指针指向数据表的第一条记录的前面。
1、通过调用ResultSet对象的getMetaData()方法创建改对象
2、可用于获取关于 ResultSet 对象中列的类型和属性信息的对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yytazs2B-1645522331456)(image/202109181209018.gif)]
**DAO (Data Access objects 数据存取对象)**是指位于业务逻辑和持久化数据之间实现对持久化数据的访问。通俗来讲,就是将数据库操作都封装起来。能够是代码的结构更加清晰化。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tDUYButJ-1645522338213)(image/image-20211031174725105.png)]
查看MySQL中现在提供的存储引擎:
show engines;
查看MySQL现在默认使用的存储引擎:
show variables like '%storage_engine%';
MyISAM引擎和InnoDB引擎简单对比:
MyISAM引擎 | InnoDB引擎 | |
---|---|---|
外键 | 不支持 | 支持 |
事务 | 不支持 | 支持 |
行表锁 | 表锁.不适合高并发 | 行锁.适合高并发 |
缓存 | 只缓存索引 | 缓存索引和真实数据 |
表空间 | 小 | 大 |
关注点 | 性能.偏读 | 事务 |
默认安装 | 是 | 是 |
show variables like 'log%';
默认情况下,日志存放在C:\ProgramData\MySQL\MySQL Server 5.5\data
下,文件名是:当前主机名.err,默认错误日志打开,无法关闭
默认没有开启
SET GLOBAL slow_query_log=1; #开启了慢查询日志
SET GLOBAL long_query_time=3;
SHOW VARIABLES LIKE '%slow_query_log%';
修改MySQL安装目录中my.ini
文件
# General and Slow logging.
log-output=FILE
general-log=1
general_log_file="general.log"
slow-query-log=1
slow_query_log_file="slow.log"
long_query_time=3
SELECT SLEEP(3);
执行后,可以看见慢查询日志
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kcTmEZ84-1645522338214)(image/202109181209385.png)]
可以模拟优化器执行SQL语句,从而知道Mysql是如何处理你的SQL语句的,分析你的SQL语句或者表结构的性能瓶颈
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rs7vKQbJ-1645522338215)(image/202109181209681.png)]
验证表的读取和加载顺序,select查询的序列号,包含一组数字,表示查询中,执行select子句或操作表的顺序
查询的类型,主要是用于区别普通查询,联合查询,子查询等的复杂查询
select type | 解释 | 测试sql |
---|---|---|
simple | 简单的select | select * from tbl_student 简单的查询,查询中不包含子查询或者UNION。 |
primary | 需要union或者子查询 | EXPLAIN #年龄大于平均年龄的同学 SELECT * FROM tblstudent WHERE stuage>( SELECT AVG(stuage) FROM tblstudent t1 ) 查询中若包含任何复杂的子部分,最外层则被标记为PRIMARY,一般Primary也是最后被加载的那个 |
subquery | 在select或者Where包含的子查询 | 上面的SQL就有subquery |
derived | 派生表 | 在From列表中,包含的子查询被标记为derived,MYSQL会递归执行这些子查询,把结果放在哪临时表(变量内存交换)里面。 select * from (select * from tb_student) t #省市区 注意t1是一个虚表 EXPLAIN select t2.* from (SELECT cid FROM zone WHERE zname=‘未央区’) t1,city t2 where t1.cid=t2.cid |
union | union | 如第二个select出现在union之后,则被标记为UNION 若union包含在From子句的子查询中 ,外层select将被标记为Derived select * from tb_student union select * from tb_student |
union result | union结果集 | 两种结果的合并,临时表 select * from tb_student union select * from tb_student |
depend subquery | 类似depend union | select (select name from test.tb_student a where a.id=b.id) from test.tb_student b |
dependent union | 查询与外部相关 | (mysql优化器会将in优化成exists) select * from tb_student where id in(select id from tb_student union select id from tb_student) select * from tb_student a where EXISTS (select 1 from tb_student where id = a.id union select id from tb_student where id = a.id) |
显示可能应用在这张表中的索引,一个或多个
查询设计到的字段上若存在索引,则该索引将被列出。但不一定被查询实际使用。
实际使用到的索引,如果为null,则没有使用索引
查询中若是用了覆盖索引,则该索引仅出现在key列表中
表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。在不损失精确性的情况下,长度越短越好
Key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的
显示索引的那一列被使用了,如果可能的话,是一个常数。那些列或常量被用于查找索引列上的值
根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数。
每张表有多少行被优化器查询
包含不适合在其他列中显示,但是十分重要的信息
例如,有商品表goods
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A29ZX1Tz-1645522338216)(image/202109191754701.png)]
执行sql语句,查询所有状态为1且价格大于20的商品,并对库存进行排序
EXPLAIN
SELECT * FROM goods WHERE gstate=1 AND gprice>20 ORDER BY gcount
发现结果为,此时不仅类型为全表扫描,而且进行了文件内排序
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BiSCOD7B-1645522338216)(image/202109191755294.png)]
所以,建立索引,因为查询使用到的字段为gprice
,gcount
,gstate
,所以添加这三个字段的联合索引
CREATE INDEX goods_idx_all ON goods(gstate,gprice,gcount)
再次执行sql语句
EXPLAIN
SELECT * FROM goods WHERE gstate=1 AND gprice>20 ORDER BY gcount
发现此时,虽然命中索引了,而且type也为range,但是还是进行了文件内排序
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2sqLj5ph-1645522338217)(image/202109191800073.png)]
如果将sql语句中的范围查询改为固定常量
EXPLAIN
SELECT * FROM goods WHERE gstate=1 AND gprice=20 ORDER BY gcount
``
发现结果正常,没有文件内排序了,所以是范围查询引起的文件内排序,原因是:Btree的工作原理,在创建索引的时候,会先对gstate进行排序,如果gstate相同,对gprice进行排序,如果gprice相同,对gcount进行排序,而gprice处于联合索引中间的位置,如果进行范围查询,也就是range,那么范围查询字段后面的索引将失效
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9iWYixbC-1645522338217)(image/202109191802429.png)]
解决方法是
**需要范围查询的字段,不参与联合索引的创建**
## 多表
```sql
EXPLAIN
SELECT * FROM orders LEFT JOIN goods ON orders.git=goods.git
执行结果,orders表,进行了全表扫描,而goods表,因为有主键索引,索引命中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qXZhWEZb-1645522338218)(image/202109191957352.png)]
索引的建立规则
如果使用left join,那么关联字段的索引建立在右表上,right join,索引建立在左表上
1、最好全值匹配,索引怎么建立的,就怎么用,使用and连接的查询语句,可以不与索引顺序相同,因为sql优化器会自动进行优化
2、最佳左前缀法,查询时,要从索引建立的最左前列(第一列)开始,不可以跳过中间的列,例如
建立索引
CREATE INDEX goods_idx_all ON goods(gcount,gstate,gprice)
只查询前两列,gcount、gstate,结果正常
EXPLAIN
SELECT * FROM goods WHERE gcount=20 AND gstate=1
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p5hSzzh5-1645522338218)(image/202109192008994.png)]
只查询第一列,gcount,结果正常
EXPLAIN
SELECT * FROM goods WHERE gcount=20
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ix3W549m-1645522338219)(image/202109192009809.png)]
只查询第二列和第三列,gstate、gprice,进行了全表扫描,因为中间跳过了索引的第一列
EXPLAIN
SELECT * FROM goods WHERE gstate=1 AND gprice=35
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lcgX7Xru-1645522338219)(image/202109192013217.png)]
只查询第一列和第三列,gcount、gprice,虽然使用了索引,但是索引的长度只使用了一个索引,也就是第一列的索引,并没有使用第三列的索引
EXPLAIN
SELECT * FROM goods WHERE gcount=20 AND gprice=35
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G2jRAhpY-1645522338220)(image/202109192015022.png)]
3、不在索引列上做任何的操作(计算、函数、类型转换),会导致索引失效,全表扫描
4、不在索引列查询条件前面使用范围查询(>
,<
,between and
),也就是范围查询后的索引全部失效
5、查询结果尽量覆盖索引,也就是,尽量只查询建立索引的字段,少使用select *
6、在MySQL中使用除等于=
以外的运算符,会导致索引失效,在MySQL8以后,查询计划的type为all
7、is null
和is not null
会导致索引失效
8、like
中通配符位置除了在右边,其他都会索引失效,即like '%M'
、like '%M%'
9、字符串不加单引号,会索引失效,MySQL引擎会进行类型转换,和第三条意思一样
10、使用or
连接,会导致索引失效
sql分页:减少应用压力
Oracle通过使用rownum伪列来实现分页