狂神说java视频
关系型数据库(SQL)
非关系型数据库(NoSQL)
MySQL百度百科
MySQL最新版本安装下载地址
MySQL旧版本安装下载地址
配置文件ini
# mysql配置文件ini
[mysqld]
# 目录一定要换成自己的 最后的 "\"也要加上
basedir=D:\Environment\mysql-5.7.19\
# data目录在D:\Environment\mysql-5.7.19\下找不到,不要自己新建,配置文件写好了,到时候自动生成。否则初始化的时候可能会失败。
datadir=D:\Environment\mysql-5.7.19\data\
port=3306
# 跳过密码验证
skip-grant-tables
注意:
操作数据库>操作数据库中的表>操作数据库中表的数据
MySQL关键字不区分大小写
#修改密码
update user set password=password('123456')where user='root';
#刷新数据库
flush privileges;
#显示所有数据库
show databases;
#打开某个数据库
use dbname;
#显示数据库mysql中所有的表
show tables;
#显示表mysql数据库中user表的列信息
describe user;
#创建数据库
create database name;
#选择数据库
use databasename;
exit; 退出Mysql
? 命令关键词 : 寻求帮助
#查看数据库的所有存储引擎
show engines;
#查看当前默认的存储引擎
show variables like '%storage_engine%';
#查看表的存储引擎
use db_waremanage;
show table status like "ware";
#操作数据库
#1、新建数据库
CREATE DATABASE[ IF NOT EXISTS] 数据库名 数据库选项
数据库选项:
CHARACTER SET charset_name(字符集)
COLLATE collation_name(排序规则)
CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE IF NOT EXISTS `TEST1`;
#2、使用数据库
USE `TEST1`;
#3、查询所有数据库
SHOW DATABASES[ LIKE 'PATTERN']
SHOW DATABASES;
#4、删除数据库(同时删除该数据库相关的目录及其目录内容)
DROP DATABASE[ IF EXISTS] 数据库名
DROP DATABASE TEST1;
SHOW DATABASES;
#查看当前数据库
SELECT DATABASE();
#查看创建数据库语句
SHOW CREATE DATABASE `数据库名`
#修改库的选项信息
ALTER DATABASE 库名 选项信息
#显示当前时间、用户名、数据库版本
SELECT now(), user(), version();
utf8_general_ci
MyISAM是MySQL的默认数据库引擎(5.5版之前)。虽然性能极佳,而且提供了大量的特性,包括全文索引、压缩、空间函数等,但MyISAM不支持事务和行级锁,而且最大的缺陷就是崩溃后无法安全恢复。不过,5.5版本之后,MySQL引入了InnoDB(事务性数据库引擎),MySQL 5.5版本后默认的存储引擎为InnoDB。
两者的对比:
扩展:
每一个表,都必须存在以下五个字段!未来做项目用的,表示一个记录存在意义!
id:主键
version:乐观锁
is_delete:伪删除
time_create:创建时间
time_update:修改时间
/* 建表规范 */ ------------------
-- Normal Format, NF
- 每个表保存一个实体信息
- 每个具有一个ID字段作为主键
- ID主键 + 原子表
-- 1NF, 第一范式
字段不能再分,就满足第一范式。
-- 2NF, 第二范式
满足第一范式的前提下,不能出现部分依赖。
消除复合主键就可以避免部分依赖。增加单列关键字。
-- 3NF, 第三范式
满足第二范式的前提下,不能出现传递依赖。
某个字段依赖于主键,而有其他字段依赖于该字段。这就是传递依赖。
将一个实体信息的数据放在一个表内实现。
/*
目标:创建一个school数据库
创建学生表(列,字段)使用SQL创建
学号int 登录密码varchar(20) 姓名,性别varchar(2),出生日期datatime 家庭住址email
注意点:
-- 使用英文(),表的名称和字段尽量使用` `括起来
-- AUTO_INCREMENT 自增
-- 字符串使用单引号括起来!
-- 所有的语句后面加,(英文的),最后一个不用加
-- PRIMARY KEY主键,一般一个表只有一个唯一的主键!
*/
#创建一个school数据库
CREATE DATABASE if not EXISTS `school` CHARACTER SET UTF8 COLLATE UTF8_GENERAL_CI;
#使用school数据库
use `school`;
-- 创建学生表
CREATE TABLE IF NOT EXISTS `student`(
`id` INT(10) not null AUTO_INCREMENT comment '学号',
`name` varchar(20) not null default '匿名' comment '姓名',
`pwd` varchar(20) not null default '123456'comment '密码',
`sex` varchar(4) NOT null DEFAULT '男' comment '性别',
`birthday` datetime default NULL comment '出生日期',
`address` varchar(255) default NULL comment '地址',
`email` varchar(50) default null comment '邮箱',
PRIMARY key(`id`)
) engine=INNODB DEFAULT charset=utf8
-- 查看所有表
SHOW TABLES[ LIKE 'pattern']
SHOW TABLES FROM 库名
-- 查看表结构
SHOW CREATE TABLE 表名 (信息更详细)
SHOW CREATE TABLE `student`;
DESC 表名 / DESCRIBE 表名 / EXPLAIN 表名 / SHOW COLUMNS FROM 表名 [LIKE 'PATTERN']
DESC `student`;
SHOW TABLE STATUS [FROM db_name] [LIKE 'pattern']
SHOW TABLE STATUS FROM school LIKE 'student';
在物理控件存在的位置
设置数据库表的字符编码
-- 修改表
-- 修改表本身的选项
ALTER TABLE 表名 表的选项
eg: ALTER TABLE 表名 ENGINE=MYISAM;
ALTER TABLE `student` ENGINE=INNODB;
-- 对表进行重命名
RENAME TABLE 原表名 TO 新表名
RENAME TABLE 原表名 TO 库名.表名 (可将表移动到另一个数据库)
RENAME TABLE `student1` to school.student;
-- RENAME可以交换两个表名
-- 修改表的字段机构(13.1.2. ALTER TABLE语法)
ALTER TABLE 表名 操作名
-- 操作名
ADD[ COLUMN] 字段定义 -- 增加字段
AFTER 字段名 -- 表示增加在该字段名后面
FIRST -- 表示增加在第一个
ADD PRIMARY KEY(字段名) -- 创建主键
ADD UNIQUE [索引名] (字段名)-- 创建唯一索引
ADD INDEX [索引名] (字段名) -- 创建普通索引
DROP[ COLUMN] 字段名 -- 删除字段
MODIFY[ COLUMN] 字段名 字段属性 -- 支持对字段属性进行修改,不能修改字段名(所有原有属性也需写上)
CHANGE[ COLUMN] 原字段名 新字段名 字段属性 -- 支持对字段名修改
DROP PRIMARY KEY -- 删除主键(删除主键前需删除其AUTO_INCREMENT属性)
DROP INDEX 索引名 -- 删除索引
DROP FOREIGN KEY 外键 -- 删除外键
ALTER TABLE `student` ADD age int(4) after id;
ALTER TABLE `student` ADD age1 int(4) FIRST;
ALTER TABLE `student` MODIFY age1 varchar(4);
DESC `student`;
ALTER TABLE `student` CHANGE age1 age2 int(4);
ALTER TABLE `student` DROP age2;
-- 删除表
DROP TABLE[ IF EXISTS] 表名 ...
DROP TABLE IF EXISTS `test2`;
-- 清空表数据
TRUNCATE [TABLE] 表名
-- 复制表结构
CREATE TABLE 表名 LIKE 要复制的表名
CREATE TABLE test1 LIKE `student`;
DESC test1;
-- 复制表结构和数据
CREATE TABLE 表名 [AS] SELECT * FROM 要复制的表名
CREATE TABLE test2 SELECT * FROM student;
-- 检查表是否有错误
CHECK TABLE tbl_name [, tbl_name] ... [option] ...
CHECK TABLE `student`;
-- 优化表
OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...
-- 修复表
REPAIR [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ... [QUICK] [EXTENDED] [USE_FRM]
-- 分析表
ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...
不足:删除有外键关系的表的时候,必须要先删除引用别人的表(从表),再删除被引用的表(主表*)
注意:以上的操作都是物理外键,数据库级别的外键,我们不建议使用!(避免数据库过多造成困扰)
数据库意义:数据存储,数据管理
DML语言:数据操作语言
insert
/* 数据操作 */ ------------------
-- 增
INSERT [INTO] 表名 [(字段列表)] VALUES (值列表)[, (值列表), ...]
REPLACE 与 INSERT 完全一样,可互换。
INSERT [INTO] 表名 SET 字段名=值[, 字段名=值, ...]
use school;
DESC student;
INSERT INTO `student`(`age`)VALUES(1);
replace into `student`(age)VALUES(2);
-- 一般写插入语句,我们一定要数据和字段一一对应
-- 插入多个字段
insert into student (`age`,`name`,`pwd`,`sex`)VALUES(3,'san','san','男'),(4,'si','si','男');
注意事项:
update 修改谁(条件),set原来的值=新值。
-- 改
UPDATE 表名 SET 字段名=新值[, 字段名=新值] [更新条件]
-- 查看表中的数据
select * from student;
-- 修改id为1的学生的姓名
update `student` set name='yi' where id=1;
-- 在不指定条件的情况下,会将表中所有name字段都修改为yi
update student set name='yi';
delete
-- 删
DELETE FROM 表名[ 删除条件子句]
没有条件子句,则会删除全部
-- 删除全部数据(避免这样写,会全部删除)
delete from student;
-- 删除指定数据
delete from student where id=2;
-- 查询所有数据
select * from student;
truncate命令
作用:完全清空一个数据库表中的数据,但是表的结构和索引约束都不变。
select * from student;
create table test3 select * from student;
select * from test3;
truncate test3;
/* TRUNCATE */ ------------------
TRUNCATE [TABLE] tbl_name
清空数据
删除重建表
delete与truncate的区别:
相同点:都能删除数据,都不会删除表结构
区别:
1.truncate 是删除表再创建,delete 是逐条删除
2.truncate 重置auto_increment的值。而delete不会
3.truncate 不知道删除了几条,而delete知道。
4.当被用于带分区的表时,truncate 会保留分区
5.truncate 不会影响事务
/* SELECT */ ------------------
SELECT [ALL|DISTINCT] select_expr FROM -> WHERE -> GROUP BY [合计函数] -> HAVING -> ORDER BY -> LIMIT
a. select_expr
-- 可以用 * 表示所有字段。
select * from tb;
-- 可以使用表达式(计算公式、函数调用、字段也是个表达式)
select stu, 29+25, now() from tb;
-- 可以为每个列使用别名。适用于简化列标识,避免多个列标识符重复。
- 使用 as 关键字,也可省略 as.
select stu+10 as add10 from tb;
b. FROM 子句
用于标识查询来源。
-- 可以为表起别名。使用as关键字。
SELECT * FROM tb1 AS tt, tb2 AS bb;
-- from子句后,可以同时出现多个表。
-- 多个表会横向叠加到一起,而数据会形成一个笛卡尔积。
SELECT * FROM tb1, tb2;
-- 向优化符提示如何选择索引
USE INDEX、IGNORE INDEX、FORCE INDEX
SELECT * FROM table1 USE INDEX (key1,key2) WHERE key1=1 AND key2=2 AND key3=3;
SELECT * FROM table1 IGNORE INDEX (key3) WHERE key1=1 AND key2=2 AND key3=3;
c. WHERE 子句
-- 从from获得的数据源中进行筛选。
-- 整型1表示真,0表示假。
-- 表达式由运算符和运算数组成。
-- 运算数:变量(字段)、值、函数返回值
-- 运算符:
=, <=>, <>, !=, <=, <, >=, >, !, &&, ||,
in (not) null, (not) like, (not) in, (not) between and, is (not), and, or, not, xor
is/is not 加上ture/false/unknown,检验某个值的真假
<=>与<>功能相同,<=>可用于null比较
d. GROUP BY 子句, 分组子句
GROUP BY 字段/别名 [排序方式]
分组后会进行排序。升序:ASC,降序:DESC
以下[合计函数]需配合 GROUP BY 使用:
count 返回不同的非NULL值数目 count(*)、count(字段)
sum 求和
max 求最大值
min 求最小值
avg 求平均值
group_concat 返回带有来自一个组的连接的非NULL值的字符串结果。组内字符串连接。
e. HAVING 子句,条件子句
与 where 功能、用法相同,执行时机不同。
where 在开始时执行检测数据,对原数据进行过滤。
having 对筛选出的结果再次进行过滤。
having 字段必须是查询出来的,where 字段必须是数据表存在的。
where 不可以使用字段的别名,having 可以。因为执行WHERE代码时,可能尚未确定列值。
where 不可以使用合计函数。一般需用合计函数才会用 having
SQL标准要求HAVING必须引用GROUP BY子句中的列或用于合计函数中的列。
f. ORDER BY 子句,排序子句
order by 排序字段/别名 排序方式 [,排序字段/别名 排序方式]...
升序:ASC,降序:DESC
支持多个字段的排序。
g. LIMIT 子句,限制结果数量子句
仅对处理好的结果进行数量限制。将处理好的结果的看作是一个集合,按照记录出现的顺序,索引从0开始。
limit 起始位置, 获取条数
省略第一个参数,表示从索引0开始。limit 获取条数
h. DISTINCT, ALL 选项
distinct 去除重复记录
默认为 all, 全部记录
-- 查询全部的学生 SELECT 字段 FROM 表
SELECT * FROM student
-- 查询指点字段
SELECT `studentno`,`studentname` FROM student
-- 别名,给结果起一个名字 AS 可以给字段起别名,也可以给表起别名
SELECT `studentno` as 学号,`studentname` as 学生姓名 FROM student as s
-- 函数 Concat(a,b)
SELECT CONCAT('姓名:',studentname) as 新名字 FROM student
SELECT * FROM student
SELECT `studentno`,`studentname` FROM student
SELECT `studentno` as 学号,`studentname` as 学生姓名 FROM student as s
SELECT CONCAT('姓名:',studentname) as 新名字 FROM student
去重 distinct
作用:去除SELECT查询出来的结果中重复的数据,重复的数据只显示一条
-- 查询一下有哪些同学参加了考试,成绩
SELECT * FROM result -- 查询全部的考试成绩
-- 查询有哪些同学参加了考试
SELECT `studentno` FROM result
-- 发现重复数据,去重
SELECT DISTINCT `studentno` FROM result
数据库的列(表达式)
-- 查看系统的版本
SELECT VERSION()
-- 用来计算
SELECT 100*3-1 as 计算结果
-- 查询自增的步长(变量)
SELECT @@auto_increment_increment
-- 学员考试成绩 + 1 分查看
SELECT `studentno`,`studentresult`+1 as '提分后' FROM result
数据库中的表达式:文本值,列,NULL,函数,计算表达式,系统变量。。。
select 表达式 from 表
作用:检索数据中符合条件的值
-- ================================ where ======================================
SELECT studentno,`studentresult` FROM result
-- 查询考试成绩再 95-100 分之间
-- and
SELECT studentno,`studentresult` FROM result WHERE studentresult>=95 AND studentresult<=100
-- &&
SELECT studentno,`studentresult` FROM result WHERE studentresult>=95 && studentresult<=100
-- 模糊查询(区间) BETWEEN AND
SELECT studentno,`studentresult` FROM result WHERE studentresult BETWEEN 95 AND 100
-- 除了1000号学生之外的同学的成绩
SELECT studentno,`studentresult` FROM result WHERE studentno!=1000;
-- != not
SELECT studentno,`studentresult` FROM result WHERE not studentno=1000;
测试:
-- ============================= 模糊查询 ================================
-- 查询姓刘的同学
-- like结合 %(代表0到任意个字符) _(一个字符)
SELECT `studentno`,`studentname` FROM `student` WHERE studentname like '刘%';
-- 查询姓刘的同学,名字后面只有一个字的
SELECT `studentno`,`studentname` FROM `student` WHERE studentname like '刘_';
-- 查询姓刘的同学,名字后面只有两个字的
SELECT `studentno`,`studentname` FROM `student` WHERE studentname like '刘__';
-- 查询名字中有嘉字的同学 %嘉%
SELECT `studentno`,`studentname` FROM `student` WHERE studentname like '%嘉%';
-- ======================== in(具体的一个或者多个值) ==============================
-- 查询 1001 1002 1003 号学员
SELECT `studentno`,`studentname` FROM `student` WHERE studentno in (1001,1002,1003);
-- 查询在北京的学生
SELECT `studentno`,`studentname` FROM `student` WHERE `address` in ('北京朝阳');
-- ========================null not null ==============================
-- 查询地址为空的学生 null ''
SELECT `studentno`,`studentname` FROM `student` WHERE `address`='' or address is null;
-- 查询有出生日期的同学 不为空
SELECT `studentno`,`studentname` FROM `student` WHERE `borndate`is not null;
-- 查询没有出生日期的同学 为空
SELECT `studentno`,`studentname` FROM `student` WHERE `borndate` is null;
/* 连接查询(join) */ ------------------
将多个表的字段进行连接,可以指定连接条件。
-- 内连接(inner join)
- 默认就是内连接,可省略inner。
- 只有数据存在时才能发送连接。即连接结果不能出现空行。
on 表示连接条件。其条件表达式与where类似。也可以省略条件(表示条件永远为真)
也可用where表示连接条件。
还有 using, 但需字段名相同。 using(字段名)
-- 交叉连接 cross join
即,没有条件的内连接。
select * from tb1 cross join tb2;
-- 外连接(outer join)
- 如果数据不存在,也会出现在连接结果中。
-- 左外连接 left join
如果数据不存在,左表记录会出现,而右表为null填充
-- 右外连接 right join
如果数据不存在,右表记录会出现,而左表为null填充
-- 自然连接(natural join)
自动判断连接条件完成连接。
相当于省略了using,会自动查找相同字段名。
natural join
natural left join
natural right join
select info.id, info.name, info.stu_num, extra_info.hobby, extra_info.sex from info, extra_info where info.stu_num = extra_info.stu_id;
-- ============================= 联表查询 join ==============================
-- 查询参加了考试的同学(学号,姓名,科目编号,分数)
/*思路:
1.分析需求,分析查询的字段来自哪些表,(连接查询)
2.确定使用哪些连接查询?7种
3.确定交叉点(这两个表中哪个数据是相同的)
4.判断的条件:学生表中的 studentno=成绩表中的 studentno
*/
-- INNER Join
SELECT s.studentno,studentname,subjectno,studentresult FROM student as s INNER JOIN result as r
WHERE s.studentno =r.studentno
-- on 和 where的区别:on是先筛选后关联,where是先关联后筛选。on用于批量,where用于单个
-- join(连接的表) on(判断的条件) 连接查询
-- where 等值查询
-- Right Join
SELECT s.studentno,studentname,subjectno,studentresult FROM student s RIGHT JOIN result r
on s.studentno =r.studentno
-- Left Join
SELECT s.studentno,studentname,subjectno,studentresult FROM student s LEFT JOIN result r
on s.studentno =r.studentno
student表数据:
result表数据:
-- INNER Join
SELECT s.studentno,studentname,subjectno,studentresult FROM student as s INNER JOIN result as r
WHERE s.studentno =r.studentno
测试结果:
-- Right Join
SELECT s.studentno,studentname,subjectno,studentresult FROM student s RIGHT JOIN result r
on s.studentno =r.studentno
测试结果:
-- Left Join
SELECT s.studentno,studentname,subjectno,studentresult FROM student s LEFT JOIN result r
on s.studentno =r.studentno
测试结果:
-- 查询缺考的同学
SELECT s.studentno,studentname,subjectno,studentresult FROM student s LEFT JOIN result r
on s.studentno =r.studentno
WHERE studentresult is null;
测试结果:
-- 思考题(查询了参加考试的同学信息:学号,学生姓名,科目名,分数)
/*思路:
1.分析需求,分析查询的字段来自哪些表,student,result,`subject`(连接查询)
2.确定使用哪些连接查询?7种
3.确定交叉点(这两个表中哪个数据是相同的)
4.判断的条件:学生表中的 studentno=成绩表中的 studentno
*/
SELECT s.studentno,studentname,subjectname,studentresult
FROM student s
RIGHT JOIN result r
on s.studentno =r.studentno
INNER JOIN `subject` sub
on r.subjectno=sub.subjectno
-- 我要查询哪些数据 select ...
-- 从那几个表中查FROM 表 XXX join 连接的表 on 交叉条件
-- 假设存在一种多张表查询,慢慢来,先查询两张表然后再慢慢增加
-- FROM a LEFT JOIN b
-- FROM a RIGHT JOIN b
subject表数据:
测试结果:
自连接:
自己的表和自己的表连接,核心:一张表拆为两张一样的表即可
category表数据:
-- 查询category表中父子信息
SELECT a.`categoryname` as '父栏目',b.`categoryname` as '子栏目'
FROM `category` as a,`category` as b
WHERE a.categoryid=b.pid
-- 查询学员所属的年级(学号,学生的姓名,年级名称)
SELECT studentno,studentname,gradename
FROM student s
INNER Join grade g
on s.gradeid=g.gradeid
-- 查询科目所属的年级(科目名称,年级名称)
SELECT subjectname,gradename
FROM subject sub
INNER JOIN grade g
on sub.gradeid=g.gradeid
-- 查询了参加 数据库结构-1 考试的同学信息:学号,学生姓名,科目名,分数
SELECT s.studentno,studentname,subjectname,studentresult
FROM student s
INNER JOIN result r
on s.studentno=r.studentno
INNER JOIN `subject` sub
on r.subjectno=sub.subjectno
WHERE subjectname='数据库结构-1'
-- ============================= 分页 limit 和排序 order by ===============================
-- 排序:升序 ASC,降序 DESC
-- ORDER BY 通过哪个字段排序,怎么排
-- 查询的结果根据 成绩降序排序
SELECT s.studentno,studentname,subjectname,studentresult
FROM student s
INNER JOIN result r
on s.studentno=r.studentno
INNER JOIN `subject` sub
on r.subjectno=sub.subjectno
WHERE subjectname='数据库结构-1'
ORDER BY studentresult ASC
-- ========================== 排序 ORDER BY ====================
-- 100万
-- 为什么要分页?
-- 缓解数据库压力,给人的体验更好,瀑布流
-- 分页,每页只显示2条数据
-- 语法:limit 起始值,页面大小
-- 网页应用:当前,总的页数,页面的大小
-- LIMIT 0,2 1-2
-- LIMIT 1,2 2-3
-- LIMIT 3,5
SELECT s.studentno,studentname,subjectname,studentresult
FROM student s
INNER JOIN result r
on s.studentno=r.studentno
INNER JOIN `subject` sub
on r.subjectno=sub.subjectno
WHERE subjectname='数据库结构-1'
ORDER BY studentresult ASC
LIMIT 2,5
语法:limit(查询起始下标,pageSize)
-- 思考:
-- 查询JAVA第一学年 课程成绩排名前十的学生,并且分数要大于80的学生信息(学号,姓名,课程名称,分数)
SELECT s.studentno,studentname,subjectname,studentresult
FROM student s
INNER JOIN result r
on s.studentno=r.studentno
INNER JOIN subject sub
on r.subjectno=sub.subjectno
WHERE subjectname='Java第一学年' AND r.studentresult>=80
ORDER BY studentresult DESC
LIMIT 0,10
subject表的数据:
result表数据:
SELECT studentno,subjectno,studentresult
FROM result
WHERE subjectno = (
SELECT subjectno FROM `subject`
WHERE subjectname='数据库结构-1'
)
-- 错误:
-- Subquery returns more than 1 row
-- 解决方法:
-- 1)如果是写入重复,去掉重复数据。然后写入的时候,可以加逻辑判断(php)或者外键(mysql),防止数据重复写入。
-- (我实际开发中遇到的就是数据重复写入的情况,在数据库查到有相同的数据两条,这不符原本的原本的业务需求)
-- 2)在子查询条件语句加limit 1,找到一个符合条件的就可以了(只是找到子查询中的一个符合条件,但是符合该条件的数据可能在result表中不存在,因此该方法可能查出数据为空)
SELECT studentno,subjectno,studentresult
FROM result
WHERE subjectno = (
SELECT subjectno FROM `subject`
WHERE subjectname='数据库结构-1'
LIMIT 1
)
-- 错误:没有数据显示。将=改为IN
SELECT studentno,subjectno,studentresult
FROM result
WHERE subjectno IN (
SELECT subjectno FROM `subject`
WHERE subjectname='数据库结构-1'
LIMIT 1
)
-- 错误:This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery' 改为如下,子查询多嵌套一层
SELECT studentno,subjectno,studentresult
FROM result
WHERE subjectno IN (
SELECT sub.subjectno FROM (
SELECT * FROM `subject`
WHERE subjectname='数据库结构-1'
LIMIT 1
)as sub
)
-- 错误:也是没有数据显示,原因是limit 1使得当找到一条subjectname='数据库结构-1'时就返回subjectno,但是这个编号在result表中找不到对应的,所有显示数据为空。正确的做法应该是第三中,在子查询前加any关键字。还可以只要in不要limit,如下:
SELECT studentno,subjectno,studentresult
FROM result
WHERE subjectno IN (
SELECT subjectno FROM `subject`
WHERE subjectname='数据库结构-1'
)
-- 3)在子查询前加any关键字
select * from table1 where table1.colums=any(select columns from table2);
-- ============================= 子查询练习1 ==============================
-- 1、查询数据库结构-1的所有考试结果(学号,科目编号,成绩),降序排列
-- 方式一:使用连接查询
SELECT studentno,r.subjectno,studentresult
FROM result r
INNER JOIN `subject` sub
on r.subjectno=sub.subjectno
WHERE subjectname='数据库结构-1'
ORDER BY studentresult DESC
-- 方式二:使用子查询(由里及外)
-- 查询所有数据库结构-1 的学生学号
SELECT studentno,subjectno,studentresult
FROM result
WHERE subjectno in(
SELECT subjectno FROM `subject`WHERE subjectname='数据库结构-1'
)
ORDER BY studentresult DESC
-- =============================== 子查询练习2 ============================
-- 2.分数不小于80分的学生的学号和姓名
-- 在这个基础上增加一个科目,高等数学-2
-- 查询高等数学-2的编号
-- 方式一:
SELECT s.studentno,studentname
FROM student s
INNER JOIN result r
ON s.studentno=r.studentno
INNER JOIN `subject` sub
ON sub.subjectno=r.subjectno
WHERE r.studentresult>=80 AND sub.subjectname='高等数学-2'
-- 方式二:
-- 分数不小于80分的学生的学号和姓名
SELECT DISTINCT s.studentno,studentname
FROM student s
INNER JOIN result r
ON r.studentno=s.studentno
WHERE studentresult >=80
-- 在这个基础上增加一个科目,高等数学-2
-- 查询高等数学-2的编号
SELECT DISTINCT s.studentno,studentname
FROM student s
INNER JOIN result r
ON r.studentno=s.studentno
WHERE studentresult >=80 AND subjectno IN(
SELECT subjectno FROM `subject` WHERE subjectname='高等数学-2'
)
-- 方式三:(由里及外)
SELECT studentno,studentname FROM student WHERE studentno IN (
SELECT studentno FROM result WHERE studentresult >=80 AND subjectno =ANY(
SELECT subjectno FROM `subject` WHERE subjectname='高等数学-2'
)
)
-- ============================== 子查询练习三 =====================================
-- 查询C语言-1 前5名同学的成绩的信息(学号,姓名,分数)
-- 方式一:
SELECT s.studentno,studentname,studentresult
FROM student s
INNER JOIN result r
ON s.studentno=r.studentno
INNER JOIN `subject` sub
ON r.subjectno=sub.subjectno
WHERE sub.subjectname='C语言-1'
ORDER BY studentresult DESC
LIMIT 0,5
-- 方式二:
SELECT s.studentno,studentname,studentresult
FROM student s
INNER JOIN result r
ON s.studentno=r.studentno
WHERE subjectno = ANY(
SELECT subjectno FROM `subject` WHERE subjectname='C语言-1'
)
ORDER BY studentresult DESC
-- 查询不同课程的平均分,最高分,最低分
-- 核心:(根据不同的课程分组)
SELECT subjectname, AVG(studentresult) as 平均分,MAX(studentresult) as 最高分,MIN(studentresult) as 最低分
FROM result r
INNER JOIN `subject` sub
ON r.subjectno=sub.subjectno
GROUP BY r.subjectno -- 通过什么字段来分组
HAVING 平均分>80
/* UNION */ ------------------
将多个select查询的结果组合成一个结果集合。
SELECT ... UNION [ALL|DISTINCT] SELECT ...
默认 DISTINCT 方式,即所有返回的行都是唯一的
建议,对每个SELECT查询加上小括号包裹。
ORDER BY 排序时,需加上 LIMIT 进行结合。
需要各select查询的字段数量一样。
每个select查询的字段列表(数量、类型)应一致,因为结果中的字段名以第一条select语句为准。
/* 备份与还原 */ ------------------
备份,将数据的结构与表内数据保存起来。
利用 mysqldump 指令完成。
-- 导出
mysqldump [options] db_name [tables]
mysqldump [options] ---database DB1 [DB2 DB3...]
mysqldump [options] --all--database
1. 导出一张表
mysqldump -u用户名 -p密码 库名 表名 > 文件名(D:/a.sql)
2. 导出多张表
mysqldump -u用户名 -p密码 库名 表1 表2 表3 > 文件名(D:/a.sql)
3. 导出所有表
mysqldump -u用户名 -p密码 库名 > 文件名(D:/a.sql)
4. 导出一个库
mysqldump -u用户名 -p密码 --lock-all-tables --database 库名 > 文件名(D:/a.sql)
可以-w携带WHERE条件
-- 导入
1. 在登录mysql的情况下:
source 备份文件
2. 在不登录的情况下
mysql -u用户名 -p密码 库名 < 备份文件
什么是视图:
视图是一个虚拟表,其内容由查询定义。同真实的表一样,视图包含一系列带有名称的列和行数据。但是,视图并不在数据库中以存储的数据值集形式存在。行和列数据来自由定义视图的查询所引用的表,并且在引用视图时动态生成。
视图具有表结构文件,但不存在数据文件。
对其中所引用的基础表来说,视图的作用类似于筛选。定义视图的筛选可以来自当前或其它数据库的一个或多个表,或者其它视图。通过视图进行查询没有任何限制,通过它们进行数据修改时的限制也很少。
视图是存储在数据库中的查询的sql语句,它主要出于两种原因:安全原因,视图可以隐藏一些数据,如:社会保险基金表,可以用视图只显示姓名,地址,而不显示社会保险号和工资数等,另一原因是可使复杂的查询易于理解和使用。
-- 创建视图
CREATE [OR REPLACE] [ALGORITHM = {
UNDEFINED | MERGE | TEMPTABLE}] VIEW view_name [(column_list)] AS select_statement
- 视图名必须唯一,同时不能与表重名。
- 视图可以使用select语句查询到的列名,也可以自己指定相应的列名。
- 可以指定视图执行的算法,通过ALGORITHM指定。
- column_list如果存在,则数目必须等于SELECT语句检索的列数
-- 查看结构
SHOW CREATE VIEW view_name
-- 删除视图
- 删除视图后,数据依然存在。
- 可同时删除多个视图。
DROP VIEW [IF EXISTS] view_name ...
-- 修改视图结构
- 一般不修改视图,因为不是所有的更新视图都会映射到表上。
ALTER VIEW view_name [(column_list)] AS select_statement
-- 视图作用
1. 简化业务逻辑
2. 对客户端隐藏真实的表结构
-- 视图算法(ALGORITHM)
MERGE 合并
将视图的查询语句,与外部查询需要先合并再执行!
TEMPTABLE 临时表
将视图执行完毕后,形成临时表,再做外层查询!
UNDEFINED 未定义(默认),指的是MySQL自主去选择相应的算法。
官网:http://www.searchdoc.cn/rdbms/mysql/dev.mysql.com/doc/refman/5.7/en/func-op-summary-ref.com.coder114.cn.html
-- =============================== 常用函数 ============================
-- 数学运算
SELECT ABS(-8) -- 绝对值
SELECT CEILING(9.4) -- 向上取整
SELECT FLOOR(9.4) -- 向下取整
SELECT RAND() -- 返回一个0-1之间的随机数
SELECT SIGN(10) -- 判断一数的符号 0-0 负数返回-1 整数返回1
-- 字符串函数
SELECT CHAR_LENGTH('即使再小的帆也能远航') -- 字符串的长度
SELECT CONCAT('我','爱','你们') -- 拼接字符串
SELECT INSERT('我爱变成helloworld',1,2,'超级热爱') -- 查询,从某个位置开始替换某个长度
SELECT LOWER('KuangShen') -- 小写字母
SELECT UPPER('KuangShen') -- 大写字母
SELECT INSERT('kuangshen','h') -- 返回第一次出现的子串的索引
SELECT REPLACE('狂神说坚持就能成功','坚持','努力') -- 替换出现的指定字符串
SELECT SUBSTR('狂神说坚持就能成功',4,6) -- 返回指定的子字符串(源字符串,截取的位置,截取的长度)
SELECT REVERSE('清晨我上马') -- 反转
-- 查询姓 周的同学,名字,刘
SELECT REPLACE(studentname,'刘','周')FROM student
WHERE studentname LIKE '刘%'
SELECT * FROM student
-- 时间和日期函数(记住)
SELECT CURRENT_DATE() -- 获取当前日期
SELECT CURDATE() -- 获取当前日期
SELECT NOW() -- 获取当前的时间
SELECT LOCALTIME() -- 本地时间
SELECT SYSDATE() -- 系统时间
SELECT YEAR(NOW()) -- 年
SELECT MONTHNAME(NOW()) -- 月
SELECT DAY(NOW()) -- 日
SELECT HOUR(NOW()) -- 小时
SELECT MINUTE(NOW()) -- 分钟
SELECT SECOND(NOW()) -- 秒
-- 系统
SELECT SYSTEM_USER()
SELECT USER()
SELECT VERSION()
-- =============================== 聚合函数 ============================
-- 都能够统计 表中的数据(想查询一个表中有多少个记录,就使用这个count())
SELECT COUNT(identitycard) FROM student; -- Count(指定列),会忽略所有的null值
SELECT COUNT(*) FROM `subject`; -- Count(*),不会忽略null值,本质,计算行数
SELECT COUNT(1) FROM `subject`; -- Count(1),不会忽略所有的null值
SELECT SUM(studentresult) as 总和 FROM result
SELECT AVG(studentresult) as 平均分 FROM result
SELECT MAX(studentresult) as 最高分 FROM result
SELECT MIN(studentresult) as 最低分 FROM result
-- 查询不同课程的平均分,最高分,最低分
-- 核心:(根据不同的课程分组)
SELECT subjectname, AVG(studentresult) as 平均分,MAX(studentresult) as 最高分,MIN(studentresult) as 最低分
FROM result r
INNER JOIN `subject` sub
ON r.subjectno=sub.subjectno
GROUP BY r.subjectno -- 通过什么字段来分组
HAVING 平均分>80
MD5百度百科
-- =============================== 测试MD5 加密 ============================
CREATE TABLE `testmd5`(
`id` int(4) not null,
`name` VARCHAR(20) not null,
`pwd` VARCHAR(50) not null,
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
-- 明文密码
INSERT INTO testmd5 VALUES(1,'zhangsan','123456'),(2,'lisi','123456'),(3,'wangwu','12345')
-- 查询
SELECT * FROM testmd5
-- 加密指定id
UPDATE testmd5 set pwd=MD5(pwd) WHERE id=1
-- 加密全部
UPDATE testmd5 set pwd=MD5(pwd)
-- 插入的时候加密
INSERT INTO testmd5 VALUES (4,'XIAOMING',MD5('123456'))
-- 如何校验:将用户传递进来的密码,进行md5加密,然后对比加密后的值
SELECT * FROM testmd5 WHERE `name`='XIAOMING' AND pwd=MD5('123456')
事务是指逻辑上的一组操作,组成这组操作的各个单元,要不全成功要不全失败。
- 支持连续SQL的集体成功或集体撤销。
- 事务是数据库在数据完整性方面的一个功能。
- 需要利用 InnoDB 或 BDB 存储引擎,对自动提交的特性支持完成。
- InnoDB被称为事务安全型引擎。
-- 事务开启
START TRANSACTION; 或者 BEGIN;
开启事务后,所有被执行的SQL语句均被认作当前事务内的SQL语句。
-- 事务提交
COMMIT;
-- 事务回滚
ROLLBACK;
如果部分操作发生问题,映射到事务开启前。
-- 事务的特性
1. 原子性(Atomicity)
事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
2. 一致性(Consistency)
事务前后数据的完整性必须保持一致。
- 事务开始和结束时,外部数据一致
- 在整个事务过程中,操作是连续的
3. 隔离性(Isolation)
多个用户并发访问数据库时,一个用户的事务不能被其它用户的事物所干扰,多个并发事务之间的数据要相互隔离。
4. 持久性(Durability)
一个事务一旦被提交,它对数据库中的数据改变就是永久性的。
-- 事务的实现
1. 要求是事务支持的表类型
2. 执行一组相关的操作前开启事务
3. 整组操作完成后,都成功,则提交;如果存在失败,选择回滚,则会回到事务开始的备份点。
-- 事务的原理
利用InnoDB的自动提交(autocommit)特性完成。
普通的MySQL执行语句后,当前的数据提交操作均可被其他客户端可见。
而事务是暂时关闭“自动提交”机制,需要commit提交持久化数据操作。
-- 注意
1. 数据定义语言(DDL)语句不能被回滚,比如创建或取消数据库的语句,和创建、取消或更改表或存储的子程序的语句。
2. 事务不能被嵌套
-- 保存点
SAVEPOINT 保存点名称 -- 设置一个事务保存点
ROLLBACK TO SAVEPOINT 保存点名称 -- 回滚到保存点
RELEASE SAVEPOINT 保存点名称 -- 删除保存点
-- InnoDB自动提交特性设置
SET autocommit = 0|1; 0表示关闭自动提交,1表示开启自动提交。
- 如果关闭了,那普通操作的结果对其他客户端也不可见,需要commit提交后才能持久化数据操作。
- 也可以关闭自动提交来开启事务。但与START TRANSACTION不同的是,
SET autocommit是永久改变服务器的设置,直到下次再次修改该设置。(针对当前连接)
而START TRANSACTION记录开启前的状态,而一旦事务提交或回滚后就需要再次开启事务。(针对当前事务)
要么都成功,要么都失败
1、SQL执行 A给B转账 A 1000 —》200 B200
2、SQL执行 B收到A的钱 A 800 —-》 B400
将一组SQL放在一个批次中去执行
原子性,一致性,隔离性,持久性
事务ACID理解
-- ============================= 事务 ================================
-- mysql是默认开启事务自动提交的
SET autocommit = 0 /* 关闭 */
SET autocommit = 1 /* 开启(默认的) */
-- 手动处理事务
-- 事务开启
SELECT TRANSACTION -- 标记一个贰拾伍的开始,从这个之后的sql都在同一个事务内
INSERT xx
INSERT xx
-- 提交:持久化(成功!)
COMMIT
-- 回滚:回到原来的样子(失败!)
ROLLBACK
-- 事务结束
SELECT autocommit=1 -- 开启自动提交
-- 了解
SAVEPOINT 保存点名 -- 设置一个事务的保存点
ROLLBACK TO SAVEPOINT 保存点名 -- 回滚到保存点
RELEASE SAVEPOINT 保存点名 -- 撤销保存点
-- ============================= 模拟场景 ====================================
-- 转账
CREATE DATABASE shop_qinjiang CHARACTER SET utf8 COLLATE utf8_general_ci
use shop_qinjiang
CREATE TABLE `account`(
`id` int(3) not null auto_increMent,
`name` varchar(30) not null,
`money` DECIMAL(9,2) not null,
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT charset=utf8
INSERT INTO account(`name`,`money`)
VALUES('A',2000.00),('B',10000.00)
SELECT * FROM `account`
-- 模拟转账:事务
SET autocommit =0; -- 关闭自动提交
START TRANSACTION -- 开启一个事务
UPDATE account SET money=money-500 WHERE `name`='A' -- A减500
UPDATE account SET money=money+500 WHERE `name`='B' -- A加500
COMMIT; -- 提交事务,就被持久化了,再回滚也没用了
ROLLBACK; -- 回滚
SET autocommit =1;-- 恢复默认值
MySQL索引背后的数据结构及算法原理
MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构。
提取句子主干,就可以得到索引的本质:索引是数据结构。
唯一索引:唯一表示的是字段唯一,比如个人账户不能重复。不允许索引的字段具有相同的索引值。在一个列中避免有重复的数据。
基础语法
-- 索引的使用
-- 1、在创建表的时候给字段增加索引
-- 2、创建完毕后,增加索引
-- 显示所有的索引信息
SHOW INDEX FROM student
-- 增加一个索引(索引名)(列名)
ALTER TABLE school_qinjiang.student ADD FULLTEXT INDEX studentname(studentname)
-- EXPLAIN 分析sql执行的状况
EXPLAIN SELECT * FROM student -- 非全文索引
SELECT * FROM student WHERE MATCH(studentname) AGAINST('刘')
【MySQL优化】——看懂explain
use school_qinjiang
CREATE TABLE `app_user`(
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) DEFAULT'' COMMENT'用户昵称',
`email` VARCHAR(50) NOT NULL COMMENT'用户邮箱',
`phone` VARCHAR(20) DEFAULT'' COMMENT'手机号',
`gender` TINYINT(4) UNSIGNED DEFAULT '0' COMMENT '性别(0:男,1:女)',
`password` VARCHAR(100) NOT NULL COMMENT '密码',
`age` TINYINT(4) DEFAULT'0' COMMENT '年龄',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
`update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT = 'app用户表'
-- 插入一百万条数据
DELIMITER $$ -- 写函数之前必须要写,标志
CREATE FUNCTION mock_data()
RETURNS INT
BEGIN
DECLARE num INT DEFAULT 1000000;
DECLARE i INT DEFAULT 0;
WHILE i<num DO
-- 插入语句
INSERT INTO app_user(`name`,`email`,`phone`,`gender`,`password`,`age`)
VALUES(CONCAT('用户',i),'[email protected]',CONCAT('18',FLOOR(RAND()*((999999999-100000000)+100000000))),FLOOR( RAND()*2),UUID(),FLOOR(RAND()*100));
set i=i+1;
END WHILE;
RETURN i;
END;
-- 使用函数
SELECT mock_data();
-- 查询用户,注意看查询用时
SELECT * FROM app_user WHERE `name`='用户99999';
EXPLAIN SELECT * FROM app_user WHERE `name` ='用户99999';
SELECT * FROM student
-- 给表创建普通索引,创建索引之后查询用户时注意对比没有加入索引之前的用时
-- id_表名_字段名
-- CREATE INDEX 索引名 on 表(字段)
CREATE INDEX id_app_user_name ON app_user(`name`);
-- 查询用户
SELECT * FROM app_user WHERE `name`='用户99999';
EXPLAIN SELECT * FROM app_user WHERE `name` ='用户99999';
-- 总结:索引本质其实就是去找对应的ID,没加索引前是遍历
EXPLAIN SELECT * FROM app_user WHERE `name` ='用户99999';
-- 没有加索引前执行代码结果如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-onMcHuN2-1615651477819)(D:\笔记\java\狂神说java\MySQL\MySQL.assets\image-20210217171431484.png)]
EXPLAIN SELECT * FROM app_user WHERE `name` ='用户99999';
-- 加索引后执行代码结果如下:
索引在小数据量的时候,用处不大,但是在大数据的时候,区别十分明显
索引的数据结构
Hash类型的索引
Btree:InnoDB默认数据结构
MySQL索引背后的数据结构及算法原理
mysql授予远程连接的权限
SQL命令操作
用户表:mysql.user
本质:读这张表进行增删改查
-- 刷新权限
flush privileges;
-- 创建用户 CREATE USER 用户名 IDENTIFIED BY '密码'
CREATE USER kuangshen identified BY '123456'
-- 修改密码(修改当前用户密码)
SET PASSWORD=PASSWORD('111111')
-- 修改密码(修改指定用户密码)
SET PASSWORD FOR kuangshen=PASSWORD('123456')
-- 重命名 RENAME USER 旧名字 TO 新名字
RENAME USER kuangshen TO kuangshen2
-- 分配权限/添加用户
GRANT 权限列表 ON 表名 TO 用户名 [IDENTIFIED BY [PASSWORD] 'password']
-- 用户授权 ALL PRIVILEGES 全部权限,库,表
-- ALL PRIVILEGES 除了给别人授权,其它都可以
GRANT ALL PRIVILEGES ON *.* TO kuangshen
-- 远程数据库授权连接本地数据库
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%'WITH GRANT OPTION
-- 查询权限
SHOW GRANTS FOR kuangshen
-- 查看指定用户的权限
SHOW GRANTS FOR root@localhost
-- ROOT用户权限:GRANT ALL PRIVILEGES ON *.* TO 'root@localhost' WITH GRANT OPTION
-- 撤销权限 REVOKE 哪些权限,在哪个库撤销,给谁撤销
REVOKE 权限列表 ON 表名 FROM 用户名
-- 撤销所有权限
REVOKE ALL PRIVILEGES ON *.* FROM kuangshen
-- 删除用户
DROP USER kuangshen
/* 表维护 */
-- 分析和存储表的关键字分布
ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE 表名 ...
-- 检查一个或多个表是否有错误
CHECK TABLE tbl_name [, tbl_name] ... [option] ...
option = {
QUICK | FAST | MEDIUM | EXTENDED | CHANGED}
-- 整理数据文件的碎片
OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...
为什么要备份(备份重要性):
MySQL数据库备份的方式
-- 导出单个文件
-- mysqldump -h主机 -u用户名 -p密码 数据库 表名 >物理磁盘位置/文件名
mysqldump -hlocalhost -uroot -p123456 school student >D:/a.sql
-- 导出多个文件
-- mysqldump -h主机 -u用户名 -p密码 数据库 表1 表2 表3 >物理磁盘位置/文件名
mysqldump -hlocalhost -uroot -p123456 school student >D:/b.sql
-- 导出数据库(所有表)
-- mysqldump -h主机 -u用户名 -p密码 数据库>物理磁盘位置/文件名
mysqldump -hlocalhost -uroot -p123456 school >D:/c.sql
-- 导入
-- 连接用户
mysql -uroot -p123456
-- 使用数据库
use school
-- 导入a.sql文件;登录的情况下,切换到指定的数据库
source d:/a.sql
-- 没有登录的情况下
mysql -u用户名 -p密码 库名<备份文件
当数据库比较复杂的时候,我们就需要设计了
三大范式通俗理解
我们的程序会通过数据库驱动和数据库打交道!
java.sql
javax.sql
还需要导入一个数据库驱动包:mysql-connector-java-5.1.47.jar
数据库驱动包可在maven官网下载:https://mvnrepository.com/
创建测试数据库
CREATE DATABASE `jdbcStudy` CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `jdbcStudy`;
CREATE TABLE `users`(
`id` INT PRIMARY KEY,
`NAME` VARCHAR(40),
`PASSWORD` VARCHAR(40),
`email` VARCHAR(60),
birthday DATE
);
INSERT INTO `users`(`id`,`NAME`,`PASSWORD`,`email`,`birthday`)
VALUES(1,'zhangsan','123456','[email protected]','1980-12-04'),
(2,'lisi','123456','[email protected]','1981-12-04'),
(3,'wangwu','123456','[email protected]','1979-12-04')
1、创建一个普通项目
2、导入数据库驱动
3、编写测试代码
package cn.dxj1016.lesson01;
import java.sql.*;
//我的第一个JDBC程序
public class JdbcFirstDemo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 1、加载驱动
Class.forName("com.mysql.jdbc.Driver");//固定写法,加载驱动
// 2、用户信息和url
// useUnicode=true:中文;characterEncoding=utf8:编码;useSSL=trueuseUnicode=true:SSL连接;
// jdbc:mysql://localhost:3306/mydb3?serverTimezone=GMT%2B8&useSSL=false
// jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false";
String username = "root";
String password = "980413dxj";
// 3、连接成功,数据库对象 Connection 代表数据库
Connection connection = DriverManager.getConnection(url, username, password);
// 4、执行SQL的对象 Statement 执行sql的对象
Statement statement = connection.createStatement();
// 5、执行SQL的对象去执行SQL,可能存在结果,查看返回结果
String sql = "SELECT * FROM users";
ResultSet resultSet = statement.executeQuery(sql);// 返回的结果集,结果集中封装了我们全部的查询出来的结果
while (resultSet.next()) {
System.out.println("id="+resultSet.getObject("id"));
System.out.println("NAME="+resultSet.getObject("NAME"));
System.out.println("PASSWORD="+resultSet.getObject("PASSWORD"));
System.out.println("email="+resultSet.getObject("email"));
System.out.println("birthday="+resultSet.getObject("birthday"));
System.out.println("=====================================================");
}
// 6、释放连接
resultSet.close();
statement.close();
connection.close();
}
}
错误:Exception in thread “main” com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
将useSSL=true改为false就可以了。
.getResourceAsStream("db.properties");
Properties properties = new Properties();
properties.load(in);
driver=properties.getProperty("driver");
url=properties.getProperty("url");
username=properties.getProperty("username");
password=properties.getProperty("password");
// 1、驱动只用加载一次
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}
}
// 获取连接
public static Connection getConnenction() throws SQLException {
return DriverManager.getConnection(url, username, password);
}
// 释放资源连接
public static void release(Connection conn, Statement st, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (st != null) {
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
2、编写增删改成的方法,executeUpdate
package cn.dxj1016.lesson02;
import cn.dxj1016.lesson02.utils.JdbcUtils;
import java.sql.*;
//增
public class TestInsert {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnenction();//获取数据库连接
statement = connection.createStatement();//获得SQL的执行对象
String sql = "INSERT INTO users(id,`NAME`,`PASSWORD`,email,birthday)" +
"VALUES (5,'kuagnshen','123456','[email protected]','2020-01-01')";
int i = statement.executeUpdate(sql);
if (i > 0) {
System.out.println("插入成功");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection,statement,resultSet);
}
}
}
package cn.dxj1016.lesson02;
import cn.dxj1016.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
//删
public class TestDelect {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnenction();//获取数据库连接
statement = connection.createStatement();//获得SQL的执行对象
String sql = "DELETE FROM users WHERE id=4;";
int i = statement.executeUpdate(sql);
if (i > 0) {
System.out.println("删除成功");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection,statement,resultSet);
}
}
}
package cn.dxj1016.lesson02;
import cn.dxj1016.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
//查
public class TestUpdate {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnenction();//获取数据库连接
statement = connection.createStatement();//获得SQL的执行对象
String sql = "UPDATE users SET `NAME`='dxj1016' WHERE id=5";
int i = statement.executeUpdate(sql);
if (i > 0) {
System.out.println("修改成功");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection,statement,resultSet);
}
}
}
3、查询 executeQuery
package cn.dxj1016.lesson02;
import cn.dxj1016.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestSelect {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnenction();//获取数据库连接
statement = connection.createStatement();//获得SQL的执行对象
String sql = "SELECT * FROM users ";
resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
System.out.println(resultSet.getString("NAME"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection,statement,resultSet);
}
}
}
sql存在漏洞,会被攻击导致数据泄露,SQL会被拼接
sql注入基础原理(超详细
SQL注入百度百科
package cn.dxj1016.lesson02;
import cn.dxj1016.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class SQL注入 {
public static void main(String[] args) {
// login("dxj1016","123456");
login(" 'or '1=1"," 'or '1=1");
}
// 登录业务
public static void login(String username, String password) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnenction();//获取数据库连接
statement = connection.createStatement();//获得SQL的执行对象
String sql = "SELECT * FROM users WHERE `NAME`='"+username+"' AND `PASSWORD`='"+password+"';";
resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
System.out.println(resultSet.getString("NAME"));
System.out.println(resultSet.getString("PASSWORD"));
System.out.println("=============================================");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection,statement,resultSet);
}
}
}
/*
执行结果:
zhangsan
123456
=============================================
lisi
123456
=============================================
wangwu
123456
=============================================
dxj1016
123456
=============================================
*/
PreparedStatement对象防止数据泄露
新增
package cn.dxj1016.lesson03;
import cn.dxj1016.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Date;
public class TestInsert {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = JdbcUtils.getConnenction();//获取数据库连接
// 区别
// 使用?代替占位符参数
String sql = "INSERT INTO users(id,`NAME`,`PASSWORD`,email,birthday) values (?,?,?,?,?)";
preparedStatement = connection.prepareStatement(sql);//预编译SQL,先写SQL,然后不执行
// 手动给参数赋值
preparedStatement.setInt(1, 4);
preparedStatement.setString(2, "qinjiang");
preparedStatement.setString(3, "123456");
preparedStatement.setString(4, "[email protected]");
// 注意点:sql.Date 数据库 java.sql.Date()
// util.Date Java new Date().getTime() 获得时间戳
preparedStatement.setDate(5,new java.sql.Date(new Date().getTime()));
// 执行
int i = preparedStatement.executeUpdate();
if (i > 0) {
System.out.println("插入成功");
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection,preparedStatement,null);
}
}
}
删除
package cn.dxj1016.lesson03;
import cn.dxj1016.lesson02.utils.JdbcUtils;
import java.sql.*;
public class TestDelect {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = JdbcUtils.getConnenction();//获取数据库连接
// 区别
// 使用?代替占位符参数
String sql = "DELETE FROM users WHERE id=?;";
preparedStatement = connection.prepareStatement(sql);//预编译SQL,先写SQL,然后不执行
// 手动给参数赋值
preparedStatement.setInt(1, 4);
// 执行
int i = preparedStatement.executeUpdate();
if (i > 0) {
System.out.println("删除成功");
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection,preparedStatement,null);
}
}
}
更新
package cn.dxj1016.lesson03;
import cn.dxj1016.lesson02.utils.JdbcUtils;
import java.sql.*;
public class TestUpdate {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = JdbcUtils.getConnenction();//获取数据库连接
// 区别
// 使用?代替占位符参数
String sql = "UPDATE users SET `NAME`=?,`PASSWORD`=? WHERE id=?";
preparedStatement = connection.prepareStatement(sql);//预编译SQL,先写SQL,然后不执行
// 手动给参数赋值
preparedStatement.setString(1, "qinjiang");
preparedStatement.setString(2, "5678807");
preparedStatement.setInt(3, 5);
// 执行
int i = preparedStatement.executeUpdate();
if (i > 0) {
System.out.println("修改成功");
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection,preparedStatement,null);
}
}
}
查询
package cn.dxj1016.lesson03;
import cn.dxj1016.lesson02.utils.JdbcUtils;
import java.sql.*;
public class TestSelect {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnenction();//获取数据库连接
String sql = "SELECT * FROM users where id=?";
preparedStatement = connection.prepareStatement(sql);//获得SQL的执行对象
preparedStatement.setInt(1,1);
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
System.out.println(resultSet.getString("NAME"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection,preparedStatement,resultSet);
}
}
}
防止SQL注入
package cn.dxj1016.lesson03;
import cn.dxj1016.lesson02.utils.JdbcUtils;
import java.sql.*;
public class SQL注入 {
public static void main(String[] args) {
//login("zhangsan","123456");
login("'' or 1=1","123456");
}
// 登录业务
public static void login(String username, String password) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnenction();//获取数据库连接
// preparedStatement 防止SQL注入的本质,把传递进来的参数当做字符
// 假设其中存在转义字符,比如说 ' 会被直接转义
String sql = "SELECT * FROM users WHERE `NAME`=? AND `PASSWORD`=?";//Mybatis
preparedStatement = connection.prepareStatement(sql);//获得SQL的执行对象
preparedStatement.setString(1, username);
preparedStatement.setString(2, password);
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
System.out.println(resultSet.getString("NAME"));
System.out.println(resultSet.getString("PASSWORD"));
System.out.println("=============================================");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection,preparedStatement,resultSet);
}
}
}
/*
执行结果:
*/
package cn.dxj1016.lesson04;
import cn.dxj1016.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class TestTransaction2 {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = JdbcUtils.getConnenction();
// 关闭自动提交事务
connection.setAutoCommit(false);
String sql1 = "UPDATE account SET money=money-100 WHERE `NAME`='A';";
preparedStatement = connection.prepareStatement(sql1);
preparedStatement.executeUpdate();
int x = 1 / 0;//报错,回滚
String sql2 = "UPDATE account SET money=money+100 WHERE `NAME`='B';";
preparedStatement = connection.prepareStatement(sql2);
preparedStatement.executeUpdate();
// 业务完毕,提交事务
connection.commit();
System.out.println("成功");
} catch (Exception e) {
try {
connection.rollback();
System.out.println("捕获到异常,回滚");
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
}finally {
JdbcUtils.release(connection,preparedStatement,null);
}
}
}
/*
执行结果:
捕获到异常,回滚
java.lang.ArithmeticException: / by zero
at cn.dxj1016.lesson04.TestTransaction2.main(TestTransaction2.java:22)
*/
DBCP连接池
#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false
username=root
password=980413dxj
#
initialSize=10
#最大连接数量
maxActive=50
#
maxIdle=20
#
minIdle=5
#
maxWait=60000
#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:【属性名=property;】
#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=UTF8
#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true
#driver default 指定由连接池所创建的连接的只读(read-only)状态。
#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
defaultReadOnly=
#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED
package cn.dxj1016.lesson05.utils;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils_DBCP {
public static BasicDataSource basicDataSource = null;
static{
try {
InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
Properties properties = new Properties();
properties.load(in);
// 创建数据源 工厂模式--》创建
basicDataSource = BasicDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
// 获取连接
public static Connection getConnection() throws SQLException {
return basicDataSource.getConnection();
}
// 释放资源连接
public static void release(Connection conn, Statement st, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (st != null) {
try {
st.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
package cn.dxj1016.lesson05;
import cn.dxj1016.lesson05.utils.JdbcUtils_DBCP;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
public class TestDBCP {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = JdbcUtils_DBCP.getConnection();//获取数据库连接
// 区别
// 使用?代替占位符参数
String sql = "INSERT INTO users(id,`NAME`,`PASSWORD`,email,birthday) values (?,?,?,?,?)";
preparedStatement = connection.prepareStatement(sql);//预编译SQL,先写SQL,然后不执行
// 手动给参数赋值
preparedStatement.setInt(1, 4);
preparedStatement.setString(2, "qinjiang");
preparedStatement.setString(3, "123456");
preparedStatement.setString(4, "[email protected]");
// 注意点:sql.Date 数据库 java.sql.Date()
// util.Date Java new Date().getTime() 获得时间戳
preparedStatement.setDate(5,new java.sql.Date(new Date().getTime()));
// 执行
int i = preparedStatement.executeUpdate();
if (i > 0) {
System.out.println("插入成功");
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtils_DBCP.release(connection, preparedStatement, null);
}
}
}
/*
错误:Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class cn.dxj1016.lesson05.utils.JdbcUtils_DBCP
at cn.dxj1016.lesson05.TestDBCP.main(TestDBCP.java:37)
未解决
*/
执行 mysql -u root -p 123456出错:
提示
ERROR 2003 (HY000): Can’t connect to MySQL server on ‘localhost’ (10061)
在计算机管理->服务和应用程序->服务->Mysql 中发现MySQL启动之后总是马上停止
解决方法:在配置文件my.ini中注释掉 #skip-grant-tables
Navicat for MySQL在连接数据库时出现1045-Access denied for user ‘root’@‘localhost’(using password:YES)问题?
解决方法: https://www.huaweicloud.com/articles/69a429d8789d1c0fcb12263f7e6bc390.html
IDEA连接数据库出错解决方法:https://blog.csdn.net/gao_jun1/article/details/108213670
JDBC连接数据库时出错: