MySQL notes
@hunternotgod
@肥猫叉烧
@死猫不烫自然卷
1.0 外键(了解即可)
2.0 DML语言(重点,全记)
DML语言:数据操作语言
inser
update
delete
1.1 添加 (insert)
语法:Insert into 表名 ([字段名1,字段名2,字段名3]) values('值1'),('值2'),('值3') ;
insert into grade(gradename) values ('大二'),('大三'); insert into student(name,pwd,sex) values ('hunter','1234','man'),('trista','666','woman');
⚠️注意事项:
1.字段和字段之间使用 英文逗号 隔开
2.字段是可以省略的,但是后面的值必须要一一对应,不能少
3.可以同时插入多条数据,values后面的值,需要使用 英文逗号 隔开即可 (示例:values(),() )
1.2 修改 (update)
语法:update 表名 set column_name(列名) = value(值) ,[colnum_name2=value2,...] where [条件]
update student set name = '小航' where id = 1; -- 不指定条件情况下,会改动所有表! update student set name = '帅哥'; -- 修改多个属性,逗号隔开 update student set name = '小航', email = '1215462706@qq.com' where id =1;
条件:where子句 运算符 id等于某个值,大于某个值,在某个区间修改...
操作符 | 含义 | 范围 | 结果 |
---|---|---|---|
= | 等于 | 5=6 | false |
<> 或 != | 不等于 | 5<>6 | true |
> | |||
< | |||
>= | |||
<= | |||
between...and | 在某个范围内 | [2,5] | |
and | 和 && | 5>1 and 1>2 | false |
or | 或 || | 5>1 or 1>2 | true |
-- 通过多个条件定位数据 update `student` set `name` = 'hunter' where `name` ='小航' and='男';
注意:
-
Column_name 是数据库的列,尽量带上``
-
条件,筛选的条件,如果没有指定,则会修改所有的列
-
value,是一个具体的值,也可以是一个变量
1.3 删除 (delete)
语法:delete from 表名 [where 条件]
-- 删除数据(避免这样写,会全部删除) delete from `student`; -- 删除指定 delete from `student` where id = 1;
truncate 命令
作用:完全清空一个数据库,表的结构和索引约束不会变!
-- 清空student表 truncate `student`;
delete 和 truncate 的区别
相同点:都能删除数据,都不会删除表结构
不同点:
-
truncate 重新设置 自增列 计数器会归零
-
truncate 不会影响事务
3.0 DQL查询数据(最重点)
3.1 DQL
(Data Query LANGUANGE :数据查询语言)
1.所有的查询都用它 select
2.数据库中最核心的语言,最重要的语句
-
使用频率最高的语句
3.2 查询 (select)
语法:select 字段 , ... from 表
-- 查询全部的学生 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;
有的时候,列名字不是那么见名知意。我们起别名 as 字段名 as 表名 as 别名
去重 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 `student`,`studentResult`+1 as `提分后` from result;
数据库表达式:文本值,列,Null,函数,计算表达式,系统变量...
select 表达式
from 表
3.2.1 select 完整语法 (重要)
select [all | distinct] {* | table.* |[table.field1[as alias1],[table.field2[as alias2]],[...]]} from table_name [as table_alias] [left | right | inner join table_name2] -- 联表查询 [where ...] -- 指定结果需满足的条件 [group by ...] -- 指定结果按照哪几个字段来分组 [having] -- 过滤分组的记录必须满足次要条件 [order by ...] -- 指定查询记录按一个或多个条件排序 [limit {[offset,]row_count | row_countOFFSET offset}]; -- 指定查询记录从哪条至哪条
⚠️注意:[ ] 括号代表可选的,{ } 括号代表必选的。
简化版:
3.3 where条件子句
作用:检索数据中符合条件
的值
搜索的条件由一个或多个表达式组成 结果:布尔值
逻辑运算符
运算符 | 语法 | 描述 |
---|---|---|
and && | a and b a&&b | 逻辑与,两个都为真,结果为真 |
or || | a or b a ||b | 逻辑或,其中一个为真,则结果为真 |
Not ! | not a !a | 逻辑非,真为假,假为真 |
尽量使用英文字母
-- 查询 考试成绩在95到100之间 -- and (&&) select studentno ,`studentresult` from result where studentresult>=95 and studentresult<=100; -- 模糊查询 select studentno,`studentresult` from result where studentresult between 95 and 100;
-- 查询 除了1000号学生之外的同学的成绩 -- not (!=) select studentNo, `studentResult` from result where not studentNo = 1000; select studentNo, `studentResult` from result where studentNo !=1000;
模糊查询:比较运算符
运算符 | 语法 | 描述 |
---|---|---|
Is null | a is null | 如果操作符为null,结果为真 |
is not null | a is not null | 如果操作符不为null,结果为真 |
between | a between b and c | 若 a 在 b 和 c 之间,则结果为真 |
like | a like b | SQL匹配,如果 a 匹配 b,则结果为真 |
in | a in (a1,a2,a3...) | 假设 a 在 a1,或者 a2... 其中的某一个值中,结果为真 |
3.4 连接查询 (join)
数据库的七种连接( join )方式
-- 查询参加了考试的同学(学号,姓名,科目编号,分数) /* 思路: 1.分析需求:查询的字段来自哪些表(连接查询) 来自两张表(student和result) 2.确定交叉点(这两个表中哪个数据是相同的) 判断的条件:学生表中的 studentNo = 成绩表中的 studentNo */ -- inner join select s.studentNo,studentName,subjectNo,studentResult -- 查询的字段 -> from student as s -- 给student这张表取个别名(两张表有相同字段`studentNo`,需要取个别名来区分)(as可以省略) -> inner join result as r -- 给result这张表取个别名 -> where s.studentNo = r.studentNo; -- right join select s.studentNo,studentName,subjectNo,studentResult -> from student as s -> right join result as r -> on s.studentNo = r.studentNo; -- left join select s.studentNo,studentName,subjectNo,studentResult -> from student as s -> left join result as r -> on s.studentNo = r.studentNo;
操作 | 描述 |
---|---|
inner join | 如果表中至少有一个匹配,就返回行 |
left join | 查询左表全部数据和右表的交集数据 |
right join | 查询右表全部数据和左表的交集数据 |
join on 和 where
join 要连接的表 on 判断条件 连接查询 | 作用于查询时的条件判断 |
---|---|
where 等值查询 | 作用于查询出来后对初始结果进行再次筛选 |
-- 查询参加考试的同学的信息:学号,学生姓名,科目名,分数(studentNo,studentName,subjectName,studentResult) select s.studentno , studentname,subjectname,studentresult -> from `student` as s -> right join `result` as r -> on s.studentno = r.studentno -> inner join `subject` as sub -> on sub.subjectno = r.subjectno;
自连接
自己的表和自己连接,核心:一张表拆成两张一样的表
练习
-- 查询了参加 数据库结构-1 考试的同学信息:学号,学生姓名,科目名,分数(来自三张表) select s.studentno,studentname,subjectname,studentresult -> from `student` s -> inner join `result` r -> on s.studentno = r.studentno -> inner join `subject` sub -> on s.subjectno = sub.subjectno -> where subjectname = '数据库结构-1';
3.5 分列和排序 (order by 和 limit)
排序(order by)
-- 排序: 升序 asc , 降序 desc -- order by 通过哪个排,怎么排 -- 练习: 查询的结果根据 成绩降序 排序 select s.studentid,studentname,subjectname,studentresult -> from `student` s -> inner join `result` r -> on s.studentno = r.studentno -> inner join `subject` sub -> on s.subjectno = sub.subjectno -> where subjectname = '数据库结构-1' -> order by studentResult desc; -- 根据 成绩降序 排序
分页(limit)
-- 为什么要分页? -- 缓解数据库压力,以及给人体验更好 -- 分页,每页只显示五条数据 -- 语法: limit 起始值,页面的大小 -- limit 0,5 1~5 -- limit 1,5 2~5 select s.studentid,studentname,subjectname,studentresult -> from `student` s -> inner join `result` r -> on s.studentno = r.studentno -> inner join `subject` sub -> on s.subjectno = sub.subjectno -> where subjectname = '数据库结构-1' -> order by studentResult desc -- 根据 成绩降序 排序 -> limit 5,5; -- 第二页 -- 第一页 limit 0,5 (1-1)*5 -- 第二页 limit 5,5 (2-1)*5 -- 第三页 limit 10,5 (3-1)*5 -- 第N页 limit (n-1),5 (n-1)*pageSize -- [pageSize:页面大小] -- [(n-1)*pageSize:起始值] -- [n:当前页] -- [数据总数/页面大小 = 总页数]
-- 练习 -- 查询 Java程序设计-1 课程成绩排名前十的学生,并且分数要大于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程序设计-1' and `studentresult`>=80 -> order by studentresult desc -> limit 0,10;
3.6 子查询
什么是子查询?
子查询是指嵌套在其他sql语句中的select语句,也叫嵌套查询
单行子查询
单行子查询是指只返回一行数据的子查询语句
多行子查询
多行子查询是指返回多行数据的子查询,使用关键字 in
-- 查询工资比 abel 高的员工 select name ,salary from employees where salary > ( -- 括号里的部分是子查询 select salary from employees where name = 'abel' );
3.7 分组和过滤(group by 和 having)
-- 查询不同课程的平均分,最高分,最低分,平均分大于80 -- 核心:(根据不同的课程分组) 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;
4.0 MySQL函数
4.1 常用函数
-- 数学运算 select abs(-8); -- 绝对值 select ceiling(9.4); -- 向上取整 select floor(9.4); -- 向下取整 select rand(); -- 返回一个 0~1 之间的随机数 select sign(10) -- 判断一个数的符号 0返回 0 负数返回 -1 正数返回 1 -- 时间和日期函数(记住) select current_date() -- 获取当前日期 select curdate() -- 获取当前的时间 select now() -- 获取当前的时间 select localtime() -- 本地时间 select sysdate() -- 系统时间 select year(now()); select month(now()); select day(now()); select hour(now()); select minute(now()); select second(now()); -- 系统 select system_user(); select user(); select version() -- 查询版本;
4.2 聚合函数(常用)
函数名称 | 描述 |
---|---|
count() | 计数 |
sum() | 求和 |
avg() | 平均值 |
max() | 最大值 |
min() | 最小值 |
... | ... |
count(1)、count(*)、count(列名)的含义、区别、执行效率
都能统计表中数据(想查询一个表中,有多少个 a 的记录,就用 count(a) )
count | 是否忽略null值 |
---|---|
count(列名) | 会忽略null值 |
count(*) | 不会忽略null值 |
count(1) | 不会忽略null值 |
效率总结:
1.列名为主键,count(列名)会比count(1)快
2.列名不为主键,count(1)会比count(列名)快
3.如果表多个列并且没有主键,则 count(1) 的执行效率优于 count(*)
4.如果有主键,则 select count(主键)的执行效率是最优的
5.如果表只有一个字段,则 select count(*)最优
原文链接:count(1),count(*),count(主键) 性能对比及辟谣_pg count(1)和count(*)-CSDN博客
4.3 数据库级别的MD5加密(扩展内容)
什么是MD5?
MD5:英文全称是 Message-Digest Algorithm 5。 中文名为 消息摘要算法第五版。它是消息摘要算法,属于 Hash 算法的一种。
MD5主要特点:
不可逆
主要作用:
增强算法的复杂度和不可逆性
5.0 事务
5.1 什么是事务
特点:要么都成功,要么都失败
—————
-
SQL 执行: A给B 转账200元 A 1000 ---转200---> B 100
-
SQL 执行: B收到A 转账的200元 A 800 B 100
—————
假设在 1 中执行失败,那么 2 也会执行失败,则B不会收到A所转账的200元,那B此时余额还是100元
也就是将 一组SQL 放在 一个批次 中去 执行
事务原则(ACID原则):原子性,一致性,隔离性,持久性
原子性(Atomicity)
要么都成功,要么都是失败。比如 A向B 转账失败,则 B无法收到A的转账。
一致性(Consistency) 事务前后的数据完整性要保持一致。比如 事务执行前 A和B的余额总和是1100,事务执行后 A和B的余额总和还是1100。
隔离性(Isolation) 隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。 同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。 持久性(Durability)
事务一旦提交则不可逆,被持久化到数据库中。所以即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
原文链接:事务四大特性(ACID)原子性、一致性、隔离性、持久性_事务包含的所有操作要么全部成功,要么全部失败回滚-CSDN博客
隔离所导致的一些问题
脏读:
指一个事务读取了另一个事务未提交的数据。
不可重复读:
在一个事务内读取表中的某一行数据,多次读取结果不同。(这个不一定是错误,只是某些场合不对)
虚读(幻读):
是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。
6.0 索引(index)
索引是帮助MySQL快速获取数据的数据结构。
6.1 索引的分类
在一个表中,主键索引只能有一个,唯一索引可以有多个
主键索引(primary key)
唯一的标识。主键不可重复,只能有一个列作为主键
唯一索引(unique key)
避免重复列出现。可以多个列 标识为 唯一索引
常规索引(key/index)
默认的。用key或index关键字来设置
全文索引(fulltext)
特定的数据库引擎下才有,MyISAM
快速定位数据
基础语法
-- 索引的使用 -- 1、在创建表的时候给字段增加索引 -- 2、创建完毕后,增加索引 -- 显示所有的索引信息 show index from student; -- 增加一个全文索引(索引名) 列名 alter table school.student add fulltext index `studentName`(`studentName`); -- explain 分析sql执行的状况 explain select * from student;
索引在小数据量时,区别不大,但是在大数据的时候,区别十分明显。
6.2 索引原则
-
索引不是越多越好
-
不要对经常变动的数据加索引
-
小数据量的表不需要加索引
-
索引一般加在常用来查询的字段上
索引的数据结构
Hash 类型的索引
Btree:innoDB的默认数据结构
阅读文章:CodingLabs - MySQL索引背后的数据结构及算法原理
7.0 权限管理和备份
7.1 用户管理
-- 创建用户 create user 用户名 identified by '密码' create user hunter identified by '123456'; -- 修改密码 (修改当前用户密码) set password = password('123456'); -- 给hunter修改密码 set password for hunter = password('123456'); -- 重命名 rename user 原来名字 to 新的名字 rename user hunter to hunter258; -- 用户授权 all privileges 全部的权限, 库.表 -- all privileges 除了给别人授权,其他都能够干 grant all privileges on *.* to hunter; -- 查询权限 show grants for hunter; -- root用户权限:grant all privileges on *.* to 'root@'localhost with grant option -- 撤销权限 revoke 哪些权限,在哪个库撤销,给谁撤销 revoke all privileges on *.* from hunter; -- 删除用户 drop user hunter;
7.2 MySQL备份
为什么要备份?
-
保证重要的数据不丢失
-
数据转移
MySQL 数据库备份的方式
-
直接拷贝物理文件
-
在可视化工具中手动导出
-
使用命令行导出 mysqldump
8.0 规范数据库设计
8.1 为什么需要设计数据库
当数据库比较复杂的时候,我们就需要设计了
糟糕的数据库设计:
-
数据冗余,浪费空间
-
数据库插入和删除都很麻烦、异常[屏蔽使用物理外键]
-
程序的性能差
良好的数据库设计
-
节省内存空间
-
保证数据库的完整性
-
方面我们开发系统
软件开发中,关于数据库的设计
-
分析需求:分析业务和需要处理的数据库的需求
-
概要设计:设计关系E-R图
8.2 三大范式
为什么需要数据规范化?
-
信息重复
-
更新异常
-
插入异常
无法正常显示信息
-
删除异常
丢失有效信息
三大范式
-
第一范式(1nf)
原子性:保证每一列不可再分
-
第二范式(2nf)
前提:满足第一范式
每张表只描述一件事
-
第三范式(3nf)
前提:满足第一范式和第二范式
确保数据表中每一列数据都和主键直接相关,而不能间接相关
规范性 和 性能的问题
关联查询的表不得超过三张表
-
考虑商业化的需求和目标,(成本,用户体验)数据库的性能更加重要
-
在规范性能的问题的时候,适当考虑一下规范性
-
故意给某些表增加冗余的字段。(从多表查询中变为单表查询)
-
故意增加一些计算列(从大数据量降低为小数据量的查询:索引)
9.0 JDBC (重点)
9.1 数据库驱动
9.2 JDBC
SUN 公司为了简化 开发人员的(对数据库的统一)操作,提供了一个(JAVA操作数据库的)规范,俗称 JDBC
这些规范的实现由具体厂商去做
对于开发人员,只需要掌握 JDBC 接口的操作即可
9.3 第一个 JDBC 程序
-- 创建一个测试数据库 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','zs@sina.com','1980-12-04'), ('2','lisi','123456','lisi@sina.com','1981-12-04'), ('3','wangwu','123456','wangwu@sina.com','1979-12-04');
-
创建一个普通项目
-
导入数据库驱动
-
编写测试代码
⚠️ 注意 : jar包要放入lib包!
package com.hunter; import java.sql.*; import com.mysql.cj.jdbc.Driver; import static java.sql.DriverManager.getConnection; public class jdbc01 { public static void main(String[] args) throws ClassNotFoundException, SQLException { // 1.加载驱动 Class.forName("com.mysql.cj.jdbc.Driver"); // 固定写法,加载驱动 // 2.用户信息和url String url = "jdbc:mysql://127.0.0.1:3306/jdbcStudy?useUnicode=true&characterEncoding=UTF-8&userSSL=false&serverTimezone=GMT%2B8"; String username = "root"; String password = "123456789"; // 3.连接成功,数据库对象 Connection 代表数据库 Connection connection = getConnection(url, username, password); // 4.执行SQL对象 Statement 执行sql对象 Statement statement = connection.createStatement(); // 5.去执行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("pwd=" + resultSet.getObject("PASSWORD")); System.out.println("email=" + resultSet.getObject("email")); System.out.println("birth=" + resultSet.getObject("birthday")); System.out.println("----------------------------------"); } // 6.释放连接 resultSet.close(); statement.close(); connection.close(); } }
步骤总结:
-
加载驱动
-
连接数据库DriverManager
-
获得执行 SQL 的对象 Statement
-
获得返回的结果集
-
释放连接
9.4 statement对象
JDBC 中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。
statement.executeUpdate 方法,用于向数据库发送 增 删 改 查 的 SQl 语句,executeUpdate执行完后,将会返回一个整数(即增删改查语句导致了数据库几行数据发生了变化)。
statement.executeQuery方法用于向数据库发送 查询 的 SQL语句,executeUpdate执行完后,将会返回代表查询结果的 ResultSet对象。
CRUD操作-create
使用executeUpdate(String sql)方法完成数据添加操作,示例:
Statement statement = connection.createStatement(); String sql = "insert into user(...) values(...)"; int num = statement.executeUpdate(sql); if(num>0){ System.out.println("插入成功!!!"); }
CRUD操作-delete
使用executeUpdate(String sql)方法完成数据删除操作,示例:
Statement statement = connection.createStatement(); String sql = "delete from user where id=1"; int num = statement.executeUpdate(sql); if(num>0){ System.out.println("删除成功!!!"); }
CRUD操作-create
使用executeUpdate(String sql)方法完成修改添加操作,示例:
Statement statement = connection.createStatement(); String sql = "update user set name = '' where name =''"; int num = statement.executeUpdate(sql); if(num>0){ System.out.println("修改成功!!!"); }
CRUD操作-read
使用executeQuery(String sql)方法完成数据查询操作,示例:
Statement statement = connection.createStatement(); String sql = "select * from user where id = 1"; ResultSet resultset = resultset.executeQuery(sql); while(resultset.next()){ //根据获取列的数据类型,分别调用resultset的相应方法映射到JAVA对象中 }
代码实现
javaUtils.java
//javaUtils.java package com.hunter.utils; import com.mysql.jdbc.Driver; import java.io.IOException; import java.io.InputStream; import java.sql.*; import java.util.Properties; public class jdbcUtils { private static String driver = null; private static String url = null; private static String username = null; private static String password = null; static { try { InputStream in = jdbcUtils.class.getClassLoader().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 (IOException e) { throw new RuntimeException(e); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } // 获取连接 public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url, username, password); } public static void release(Connection connection, Statement statement, ResultSet resultSet) { if (resultSet != null) { try { resultSet.close(); } catch (SQLException e) { throw new RuntimeException(e); } } if (statement != null){ try { statement.close(); } catch (SQLException e) { throw new RuntimeException(e); } } if (connection != null){ try { connection.close(); } catch (SQLException e) { throw new RuntimeException(e); } } } }
TestInsert.java (测试类)
package com.hunter; import com.hunter.utils.jdbcUtils; import com.mysql.cj.jdbc.JdbcConnection; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class TestInsert { public static void main(String[] args) { Connection connection = null; Statement statement = null; ResultSet resultSet = null; try { connection = jdbcUtils.getConnection(); // 获取数据库连接 statement = connection.createStatement(); // 获得SQL的执行对象 // SQL /*插入数据*/ // String sql = "insert into users(id,`name`,`password`,`email`,`birthday`)\n" + "values(5,'hunter777','123456','1585469601@qq.com','2024-06-02')"; // // int i = statement.executeUpdate(sql); // if (i > 0) { // System.out.println("插入成功!"); // } /*插入数据*/ /*查询数据*/ String sql = "select * from users where id = 4"; resultSet = statement.executeQuery(sql); // 查询完毕会返回一个结果集 while (resultSet.next()) { System.out.println(resultSet.getString("name")); } /*查询数据*/ } catch (SQLException e) { throw new RuntimeException(e); } finally { jdbcUtils.release(connection, statement, resultSet); } } }
db.properties (配置文件)
driver=com.mysql.jdbc.Driver url=jdbc:mysql://127.0.0.1:3306/jdbcStudy?useUnicode=true&characterEncoding=UTF-8&userSSL=false&serverTimezone=GMT%2B8 username=root password=123456789
9.5 SQL注入
sql存在漏洞,会被攻击导致数据泄漏
例子:在登陆 username 或 password 处 用 ‘ ’ or '1=1' 拼接,获取全部数据。
package com.hunter; import com.hunter.utils.jdbcUtils; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class sqlZhuRu { public static void main(String[] args) { // login("hunter666","123456"); // sql注入 login(" ' or '1=1 ", "123456"); } // 登陆业务 public static void login(String username, String password) { Connection connection = null; Statement statement = null; ResultSet resultSet = null; try { connection = jdbcUtils.getConnection(); // 获取数据库连接 statement = connection.createStatement(); // 获得SQL的执行对象 // SQL String sql = "select * from users where `NAME` = '" + username + "' AND `password` = '" + password + "' "; // String sql ="select * from users where `NAME` = 'hunter666' AND `password` = '123456' "; 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) { throw new RuntimeException(e); } finally { jdbcUtils.release(connection, statement, resultSet); } } }
9.6 PreparedStatement对象
PreparedStatement 可以防止SQL注入。效率更好!
9.7 使用idea连接数据库
9.8 事务
-
开启事务 conn.setAutoCommit(false);
-
一组业务执行完毕,提交事务
-
可以在catch语句中显示的定义回滚语句,但默认失败就会回滚
9.9 数据库连接池
数据库连接 --- 执行完毕 --- 释放
连接 --- 释放 十分浪费资源
池化技术:准备一些预先的资源,过来就连接预先准备好的
编写连接池,实现一个接口 DateSource
开源数据源
例如:DBCP、C3P0、Druid...
使用这些数据源连接池后,我们在项目开发中就不需要编写连接数据库的代码了!