MySQL学习笔记
1、初识MySQL
javaEE:企业级java开发 Web
前端:(页面:展示,数据)
后台:数据库(DB、DataBase)
数据库是所有软件体系中最核心的存在:DBA
数据库分类
- 关系型数据库(SQL):
- MySQL、Oracle、Sql Server、DB2、SQLlite
- 通过表和表之间,行和列之间的关系进行数据的存储,(学员信息表、考勤表……)
- 非关系型数据库(NoSQL):
- Redis、MongoDB
- 非惯性数据库,对象存储,通过对象的自信属性来决定(热点信息);
DBMS数据库管理软件
- 数据库的管理软件,科学有效的管理数据(维护 和获取);
MySQL安装
尽量不要使用exe,(否则卸载难)
1.1、连接数据库
命令行连接:
mysql -u root -proot -- 连接数据库
-- 修改密码
update mysql.user set authentication_string=password('123456') where user='root' and Host = 'localhost';
-- 刷新权限
flush privileges;
--------------------------------------------------------------------------------------
-- 所有sql语句都用分号(;)结尾
show databases; -- 查看所有数据库
mysql> use school -- 切换数据库(use 数据库名)
Database changed
show tables; -- 查看数据库中所有的表
describe student; -- 显示数据库中所有表的信息;
create database westos; -- 创建一个数据库
exit; -- 退出连接
-- 单行注释(SQL的注释)
/*
(SQL的多行注释)
*/
2、操作数据库
2.1、基本操作
-
创建数据库:
CREATE DATABASE IF NOT EXISTS westos -
删除数据库:
DROP DATABASE IF EXISTS westos -
选择数据库:
-- `` 如果表名或字段名是特殊字符,就用反引号包裹; USE `school` SELECT `user` FROM student -
查看数据库:
SHOW DATABASES -- 查看所有的数据库
2.2、数据库数据类型
数值
- tinyint 十分小的数据 1B
- smallint 较小的数据 2B
- mediumint 中等较大的数据 3B
- int 标准的整数 4B
- bigint 较大的数据 8B
- float 浮点数 4B
- double 浮点数 8B
- decimal 字符串形式的浮点数 金融计算的时候,一般是使用decimal
字符串
- char 字符串固定大小的 0~255
- varchar 可变字符串 0~65535 常用的变量 String
- tinytext 微型文本 2^8-1
- text 文本串 2^16-1 保存大文本
时间日期
java.util.Date
- date YYYY-MM-DD 日期格式
- time HH:mm:ss 时间格式
- datetime YYYY-MM-DD HH:mm:ss 最常用的时间格式
- timestamp 时间戳(常用)
- year 年份表示
NULL
- 注意:不要使用NULL进行运算,结果为null
2.3、数据库的字段属性(重点)
- Unsigned:
- 无符号的整数
- 声明了该列的数不能为负数
- zerrofill:
- 0填充。不足的位置用0填充
- 自增:
- 自动在上一条的基础上+1(默认)
- 通常用来设计唯一的主键、index,必须是整数类型;
- 可以自定义设计主键自增的起始值和步长;
- 非空:
- 假设设置为not null ,如果不赋值,就会报错;
- NULL,如果不写值,默认就是null!
- 默认:
- 设置默认的值
拓展:
-
/* 每一个表,都必须存在以下5个字段!做项目用,表示一个记录存在意义! id 主键 `version` 乐观锁 is_delete 伪删除 gmt_create 创建时间 gmt_update 修改时间 */
2.4、创建数据库表(重点)
格式:
CREATE TABLE [IF NOT EXISTS] `表名`(
`字段名` 列类型 [属性] [索引] [注释],
`字段名` 列类型 [属性] [索引] [注释],
.......
`字段名` 列类型 [属性] [索引] [注释]
)[表类型][字符集设置][注释]
2.5、数据表的类型
查询创表语句:
SHOW CREATE DATABASE XXXXX
SHOW CREATE TABLES XXXX
DESC XXXXX -- 显示表的具体结构
关于数据库引擎
INNODB (默认使用)
MYISAM (早些年使用)
MYISAM INNODB 事务支持 N Y 数据行锁定 N Y 外键约束 N Y 全文索引 Y N(5.6.4后---Y) 表空间的大小 较小 较大(约2倍) 节约空间,速度快 完全性高,支持事务处理 在物理空间存在的位置:
所有的数据库文件都存在data目录下,一个文件夹对应一个数据库,本质上还是文件存储;
MySQL引擎在物理文件上的区别:
- InnoDB在数据库表中只有一个*.frm文件,以及上级目录下的ibdata1文件
- MyISAM对应文件结构:
- *.frm -表结构的定义文件;
- *.MYD 数据文件(data);
- *.MYI 索引文件(index);
设置数据库的字符集编码
CHARSET=utf8
不设置的话,会是MySQL的默认字符集编码(Latin1,不支持中文!)
也可以在my.ini中配置默认的编码(Windows平台,不推荐,兼容问题)
character-set-server=utf8
2.6、修改删除表
修改:(
alter)
-- 修改表名: ALTER TABLE 旧表名 RENAME AS 新表名
ALTER TABLEteacher RENAME AS teacher1
-- 增加表的字段: ALTER TABLE 表名 ADD 字段名 列属性
ALTER TABLE teacher1 ADD age INT(11)
-- 修改表的字段(重命名,修改约束)
-- ALTER TABLE 表名 MODIFY 字段名 列属性[]
ALTER TABLE teacher1 MODIFY age VARCHAR(11) -- 修改约束
-- ALTER TABLE 表名 CHANGE 旧名字 新名字 列属性[]
ALTER TABLE teacher1 CHANGE age age1 INT(1) -- 字段重命名
-- 删除表的字段: ALTER TABLE 表名 DROP 字段名
ALTER TABLE teacher1 DROP age1
删除
-- 删除表
DROP TABLE IF EXISTS teacher1
- 注意:
- 字段名用反引号包裹:`
- 注释:-- /**/
- sql关键字大小写不敏感,建议小写;
3、MySQL数据管理
3.1、外键
方式一:在创建表的时候,增加约束(麻烦,比较复杂)
CREATE TABLE `grade` (
`gradeid` int(10) NOT NULL AUTO_INCREMENT COMMENT '年级id',
`gradename` varchar(50) COLLATE utf8mb4_bin NOT NULL COMMENT '年级名称',
PRIMARY KEY (`gradeid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
-- 学生表的gradeid 字段 ,要去引用年级表的 gradeid 字段
-- 1、定义外键key
-- 2、给这个外键key添加约束(执行引用) references 引用
CREATE TABLE `student` (
`id` int(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
`pwd` varchar(20) COLLATE utf8mb4_bin NOT NULL DEFAULT '123456' COMMENT '密码',
`sex` varchar(2) COLLATE utf8mb4_bin NOT NULL DEFAULT '女' COMMENT '性别',
`birthday` datetime DEFAULT NULL COMMENT '出生日期',
`gradeid` int(10) NOT NULL COMMENT '学生的年级',
`address` varchar(100) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '家庭住址',
`email` varchar(50) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (`id`),
KEY `FK_gradeid` (`gradeid`),
CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade` (`gradeid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
注意:删除有外键关系的表的时候,必须先删除引用别人的表(从表),再删除被引用的表(主表);
方式二:创建表的时候 没有外键关系,添加外键属性;
ALTER TABLE `student`
ADD CONSTRAINT `FK_gradeid` FOREIGN KEY(`gradeid`) REFERENCES `grade`(`gradeid`);
-- ALTER TABLE 表 ADD CONSTRAINT 约束名 FOREIGN KEY(作为外键的列) REFERENCES 被引用表(被引用字段);
以上的操作都是属于物理外键,数据库级别的外键,不建议使用!!(避免耦合过多造成困扰)
最佳实现:
- 数据库就是单纯的表,仅用来存数据;
- 用程序去实现外键(代码层面);
3.2、DML语言(全部记住)
数据库意义:数据存储、数据管理
DML语言:数据操作语言
- insert;
- update;
- delete;
3.3、添加(insert)
insert
-- 插入语句(添加)
-- insert into 表名([字段名1],[字段名2],....) values('值1','值2',....),('值1','值2',....);
insert into `grade`(`gradename`) values('大一');
-- 如果省略表的字段,它就会根据默认的顺序一一匹配;
insert into `grade` values('2','大二');
-- 一次插入多个行数据
insert into `grade`(`gradename`) values('大三'),('大四');
语法:insert into 表名([字段名1],[字段名2],....) values('值1','值2',....),('值1','值2',....);
3.4、修改(update)
update 表名 set column_name=value [,column_name=value,....] where [条件];
条件:where 子句 --运算符;
| 操作符 | 含义 | 范围 | 返回值 |
|---|---|---|---|
| = | 等于 | ||
| <>或 != | 不等于 | ||
| > | |||
| < | |||
| >= | |||
| <= | |||
| between .... and ... | 再....和...之间 | [2,5] | |
| and | && | ||
| or | || |
注意:
- column_name 是数据库的列,尽量带上
``号; - 条件,筛选的条件,若没有指定,则会修改所有的列!!!
- value 是一个具体的值,也可以是一个变量;
- 多个设置的属性之间,使用英文逗号隔开;
3.5、删除
delete命令
语法:delete from 表名 [where 条件]
-- 删除数据 (避免这样写,会全部删除)
DELETE FROM `student`
-- 删除指定数据
DELETE FROM `student` WHERE id=1;
TRUNCATE 专门清空命令
作用:完全清空一个数据库表,表的结构和索引约束不会变!
-- 清空student表
TRUNCATE `student`
delete 和 TRUNCATE 对比
- delete:
- DML语言;
- 本质操作:逐条删除原表中的数据;
- 不会影响自增;
- truncate:
- DDL语言;
- 本质操作:删除原表,并重新建立一张同样的无数据的新表。
- 重新设置自增列,计数器归零;
了解:delete删除问题,重启数据库后:
- InnoDB 自增列会从1重新开始(它存在内存中,断电易失);
- MyISAM 继续从上一个自增量开始(存在文件中,不会丢失);
4、DQL查询数据(最重点!!)
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}]; -- 指定查询的记录从哪条到哪条注意:[] 括号代表可选的,{} 代表必须词。
4.1、DQL
(Data Query Language:数据查询语言)
- 所有的查询操作都用它
select - 简单的查询,复杂的查询都能做
- 数据库中最核心的语言,最重要的语句;
- 使用频率最高的语句;
4.2、指定查询字段
-- 查询全部的学生 select 字段 from 表
SELECT * FROM student
-- 查询指定字段
SELECT `StudentNo`, `StudentName` FROM student
-- 别名,给结果起一个名字 AS 可以给字段(或表)起别名(备注)
SELECT `StudentNo` AS 学号,`TdentName` AS 学生姓名 FROM student AS stu
-- 函数 concat(a,b)
SELECT CONCAT(`姓名:`,StudentName) AS 新名字 FROM student;
语法:select 字段,... from 表
有时候,列名字不方便阅读时,可以使用
AS添加备注~
去重
distinct
语法: SELECT 列名称 FROM 表名称
作用:删除select查询出来的结果中重复的数据;
-- 查询一下有哪些同学参加了考试
SELECT * FROM result -- 查询全部的考试成绩
SELECT `StudentNo` FROM result -- 查询有哪些同学参加了考试
SELECT DISTINCT `StudentNo` FROM result -- 去重
数据库的列(表达式)
一些特殊的用法:
SELECT VERSION(); -- 查询系统版本(函数)
SELECT 100*C-1 AS 计算结果; -- 用来计算 (表达式)
SELECT @@auto_increment_increment -- 查询自增的步长
-- 学员考试成绩 + 1分查看
SELECT `StudentNo`,`StudentResult`+1 AS `提分后的成绩` FROM result;
数据库中的表达式:文本值,列,Null,函数,计算表达式,系统变量……
4.3、where 条件子句
作用:检索数据中符合条件的值;
逻辑运算符
| 运算符 | 语法 |
|---|---|
| and && | 与 |
| or || | 或 |
| not ! | 非 |
注意:尽量使用英文;
模糊查询:比较运算符
| 运算符 | 语法 | 描述 |
|---|---|---|
| is null | a is null | 若操作符为null ,结果为真 |
| is not null | a is not null | 若非空,为真 |
| between | a between b and c | 若操作符位于b、c之间,为真 |
| like | a like b | SQL 匹配,若a匹配b,为真 |
| in | a in (a1,a2,a3...) | 操作符为 (a1,a2,a3...) 中的某一值,为真 |
实例:like
-- 查询姓刘的同学
-- 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 '%嘉%';
实例: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
-- 查询地址为空的学生
select `StudentNo`,`StudentName` from `student`
where `Address`=null or `Address` is null;
-- 查询出生日期不为空的同学
select `StudentNo`,`StudentName` from `student`
where `BornDate` is not null;
-- 查询出生日期为空的同学
select `StudentNo`,`StudentName` from `student`
where `BornDate` is null;
4.4、联表查询(join on)
作用:join 用于根据两个或多个表中的列之间的关系,从这些表中查询数据。
引用两个表:
方法一:
SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo FROM Persons, Orders WHERE Persons.Id_P = Orders.Id_P方法二:
SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo FROM Persons INNER JOIN Orders ON Persons.Id_P = Orders.Id_P ORDER BY Persons.LastName
join 使用:
JOIN等同于inner join(内连接): 如果表中有至少一个匹配,则返回行;LEFT JOIN: 即使右表中没有匹配,也从左表返回所有的行;RIGHT JOIN: 即使左表中没有匹配,也从右表返回所有的行;FULL JOIN: 只要其中一个表中存在匹配,就返回行;
on和where区别:在使用 left join 时,on 和 where 条件的区别如下:
on条件是在生成临时表时使用的条件,它不管on中的条件是否为真,都会返回左边表中的记录。
where条件是在临时表生成好后,再对临时表进行过滤的条件。这时已经没有left join的含义(必须返回左边表的记录)了,条件不为真的就全部过滤掉。(先生成临时表,再筛选结果)其实以上结果的关键原因就是 left join,right join,full join 的特殊性。
- 不管 on 上的条件是否为真都会返回 left 或 right 表中的记录,full 则具有 left 和 right 的特性的并集。
- 注意:而
inner jion没这个特殊性,则条件放在 on 中和 where 中,返回的结果集是相同的。
自连接:
实质上,就是把自己的表和自己的表重新组合连接成一张新表;
实例:
select a.`categoryname` as '父栏目',b.`categoryname` as '子栏目'
from `category` as a,`category` as b
where a.`categoryid`=b.`pid`
4.5、分页和排序
分页:
limit
- 语法:
limit 起始页,分页数- 分成N页:第N页--
limit (n-1)*pageSize,pageSize;
排序:
order by
升序:
asc,ORDER BY 语句默认按照升序对记录进行排序;降序:
desc;
实例:
SELECT Company, OrderNumber FROM Orders ORDER BY Company, OrderNumber;
-- 以字母顺序显示公司名称(Company),并以数字顺序显示顺序号(OrderNumber):
4.6、子查询
在where中再嵌套查询子语句:where (select * frome table ...)
注意:执行顺序是:由里及外!
实例:
子查询方式:
-- 使用子查询方式:
SELECT `StudentNo`,`SubjectNo`,`StudentResult`
FROM `result`
WHERE SubjectNo=(
SELECT SubjectNo FROM `subject`
WHERE SubjectName = '数据库结构-1'
)
结果等同于:
联表查询方式:
SELECT `StudentNo`,`SubjectNo`,`StudentResult`
FROM `result` AS r
INNER JOIN `subject` AS sub
ON r.SubjectNo = sub.SubjectNo
WHERE SubjectName = '数据库结构-1'
ORDER BY StudentResult DESC
4.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 -- 分组后的过滤条件
5、函数
可以查询官方文档。
5.1、常用函数
很多类似java中存在的方法。
数学运算
- 绝对值:
select abs() - 向上取整:
select ceiling() - 向下取整:
select follr - 返回0~1之间的随机数:
select rand() - 判断一个数的符号:
select sign()
字符串函数:
- 字符串长度:
select char_length() - 拼接字符串:
select concat() - 插入,从某个位置开始插入(替换)某个长度的字符:
select insert() - 转换成小写:
select lower() - 转换成大写:
select upper() - 返回第一次出现的子串的索引:
select instr() - 替换出现的指定字符串:
select replace() - 返回指定的字串(源字符串,截取的位置,截取长度):
select substr() - 反转字符串:
select reverse()
事件和日期函数(记住)
- 获取当前日期:
select current_date()( 等价于:select curdate()) - 获取当前时间:
select now() - 本地时间:
select localtime() - 系统时间:
select sysdate() - 获得年/月/日/时/分/秒:
select year/month/day/hour/minute/second (date)
系统:
select system_user()select user()select version()
5.2、聚合函数(常用)
count()sum()avg()max()min()
-- 聚合函数
-- 统计表中数据
SELECT COUNT(`BornDate`) FROM student; -- count(字段),会忽略所有的null值
SELECT COUNT(*) FROM student; -- count(*) ,不会忽略null值。本质:计算行数
SELECT COUNT(1) FROM student; -- count(1) ,不会忽略null值。本质:计算行数
5.3、数据库级别的MD5加密(扩展)
测试:
-- 明文密码
INSERT INTO testmd5 VALUES(1,'zhangsan','123456'),(2,'lisi','123456'),(3,'wangwu','123456');
-- 加密
UPDATE testmd5 SET pwd=MD5(pwd) WHERE id=1
UPDATE testmd5 SET pwd=MD5(pwd) -- 加密全部的密码
-- 插入的时候加密
INSERT INTO testmd5 VALUES(4,'xiaoming',MD%('123456'));
-- 校验:将用户传过来的密码,进行md5加密,然后比对加密后的值
SELECT * FROM testmd5 WHERE `name`='xiaoming' AND pwd=MD5('123456');
6、事务
6.1、什么是事务?
解释:同生共死
事务原则:-- ACID原则:
- 原子性(Atomicity):
- 一致性(Consistency):
- 隔离性(Isolation):
- 持久性(Durability):
数据读取存在的问题:
- 脏读:
- 虚读(幻读):
- 不可重复读:
7、索引
什么是索引?
MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构。提取句子主干,就可以得到索引的本质:索引是数据结构。
7.1、索引的分类
在一个表中,主键索引只能有一个,唯一索引可以有多个;
- 主键索引
primary key:- 唯一的标识,主键不可重复,只能有一个列作为主键;
- 唯一索引
unique key:- 避免重复出现的列,多个列都可以标识为唯一索引;
- 常规索引
key/index:- 默认的,index。key关键字来设置;
- 全文索引
fulltext:- 在特定的数据库引擎下才有,MyISAM;
- 用于快速定位数据;
基础语法:
-- 索引的使用
-- 1.创建表的时候添加索引
-- 2.创建完毕后,在增加索引
-- 显示所有的索引信息
SHOW INDEX FROM student;
-- 增加一个全文索引(索引名) 列名
ALTER TABLE school.student ADD FULLTEXT INDEX `studentName`(`StudentName`);
-- EXPLAIN 分析sql执行的情况
EXPLAIN SELECT * FROM student; -- 非全文索引
EXPLAIN SELECT * FROM student WHERE MATCH(studentName) AGAINST('刘')
8、权限管理和备份
8.1、用户管理
本质:操作用户表----- mysql.user
-- 创建用户CREATE USER 用户名 INDENTIFIED BY `密码`
CREATE USER kuangshen INDENTIFIED BY `123456`;
-- 修改密码(修改当前用户密码)
SET PASSWORD = PASSWORD('123456');
-- 修改密码(修改指定用户密码)
SET PASSWORD FOR kuangshen = PASSWORD('123456');
-- 重命名 RENAME USER 原来名字 TO 新名字
RENAME USER kuangshen TO kuangshen2;
-- 用户授权 ALL PRIVILEGES 全部权限 , 库.表
-- ALL PRIVILEGES 除了给别人授权,其他都能干
GRANT ALL PRIVILEGES ON *.* TO kuangshen2;
-- 查询权限
SHOW GRANTS FOR kuangshen2 -- 查看指定用户的权限
-- ROOT用户权限:GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION
-- 撤销权限 REVOKE 哪些权限,在哪个库撤销,给谁撤销
REVOKE ALL PRIVILEGES ON *.* FROM kuangshen2;
-- 删除用户
DROP USER kuangshen;
8.2、备份
方式一:通过可视化软件备份
方式二:通过命令行导出,
mysqldump
# mysqldump -h 主机 -u 用户名 -p 密码 数据库 表1 表2 ...> 物理磁盘位置/文件名 mysqldump -hlocalhost -uroot -p123456 school student >D:/a.sql #导入(恢复) #登录的情况下,切换到指定的数据库 #source 备份文件 source d:/a.sql mysql -u用户名 -p密码 库名< 备份文件
9、规范数据库设计
9.1、为什么需要设计
当数据库比较复杂的时候,就需要设计
糟糕的数据库设计:
- 数据冗余,浪费空间;
- 数据库插入和删除非常麻烦、异常【屏蔽使用物理外键】;
- 程序的性能差;
良好的数据库设计:
- 节省内存空间;
- 保证数据库的完整性;
- 方便我们开发系统;
软件开发中关于数据库的设计:
- 分析需求:分析业务和需要处理的数据库的需求;
- 概要设计:设计关系图E-R图;
设计数据库步骤:
-
收集信息,分析需求:
-
标识实体:(把需求落地到每个字段)
-
标识实体之间的关系:
9.2、三大范式
- 第一范式(1NF)
- 原子性:保证每一列不可再分;
- 第二范式(2NF)
- 每张表只描述一件事情;
- 第三范式(3NF)
- 需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关;
(规范数据库的设计)
规范性 和 性能 之间的问题
在商业过程中,一般规定:
- 关联查询的表不得超过三张;
- 数据库的性能更重要(成本、用户体验);
- 尽量权衡规范性和性能之间的处理;
- 有时会故意增加一些冗余的字段,减少数据表的量;(例如订单和商品信息集成在一个表)
10、JDBC(重点)
10.1、什么是JDBC?
SUN公司为了简化开发人员对数据库的操作,提供了一个(java操作数据库的)的规范,俗称JDBC;
各数据库厂商只需去实现JDBC和数据库的接口即可;
对于开发人员来讲,只需熟悉掌握JDBC接口的操作即可!
10.2、第一个JDBC程序
需要:mysql-connector-java-5.1.47.jar 包
测试第一个JDBC程序:
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver"); //固定写法,加载驱动
//2.用户信息和url
//问号后面接参数: 使用Unicode编码(支持中文)&utf8编码集(防止乱码)&使用安全的连接
// ?useUnicode=true&characterEncoding=utf8&useSSL=true
//*****常见问题:MySQL版本高于JDBC时:useSSL=true ;否则会报错;
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
String username= "root";
String password = "123456";
//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("pwd=" + resultSet.getObject("PASSWORD"));
System.out.println("email=" + resultSet.getObject("email"));
System.out.println("birth=" + resultSet.getObject("birth"));
System.out.println("===========================");
}
//6.释放连接
resultSet.close();
statement.close();
connection.close();
DriverManager //注册驱动
DriverManager.registerDriver(new com.mysql.jdbc.Driver()); //原生写法
Class.forName("com.mysql.jdbc.Driver"); //固定写法,加载驱动
Connection 对象 ---代表数据库
Connection connection = DriverManager.getConnection(url,username,password);
//数据库级别的操作就用这个对象
//数据库设置自动提交、事务提交、回滚等
URL
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
// 协议://主机地址:端口号/数据库名?参数1&参数2&参数3
// mysql -- 3306
// oracle -- 1521
// jdbc:oracle:thin:@localhost:1521:sid
Statement 对象 ----执行SQL的对象 (PrepareStatement也可以执行SQL)
statement.execute(); //执行任何SQL但是效率没有专门方法高
statement.executeQuery(); //执行查询语句 返回resultSet
statement.executeUpdate(); //更新、插入、删除,都是用这个方法。返回受影响的行数
ResultSet--查询返回的结果集:封装了所有的查询结果
resultSet.getObject(); //在不知道返回值得类型情况下使用,效率不如对应类型的结果集
resultSet.getString();
//遍历
resultSet.next();
resultSet.previous();
resultSet.absolute(row);
resultSet.beforeFirst(); //移动到最前
resultSet.afterLast(); //移动到最后
释放资源
resultSet.close();
statement.close();
connection.close(); //connection对象最耗资源!
提取成工具类
- 创建一个
db.properties类文件; - 编写一个
JdbcUtils工具类,通过JdbcUtils.class.getClassLoader().getResourceAsStream(db.properties)来获取db.properties 的信息。(内含:加载驱动,释放资源的静态方法); - 编写增删改查、插入方法(Update);/编写查询方法(query);
10.3、SQL注入问题
SQL注入即:SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。
本质上是通过拼接字符串,强行获取信息!
例如:
//原本正常的SQL
String sql = "select * from user where name = '"+username+"' and password='"+password+"'";
//利用漏洞的SQL,只要给方法传入的参数拼接上特定的字符串;
//例如
username = "'or'1=1";
password = "'or'1=1";
//此时SQL就变为:
//---->select * from user where name='' or '1=1' and password = '' or '1=1';
//该语句永远成立,可以穿过漏洞获得信息;
10.5、PreparedStatement对象(更安全,更高效)
PreparedStatement对象使用区别:
//PreparedStatement防注入例子
public static void main(String[] args){
login("'or'1=1","'or'1=1"); //输入漏洞sql
}
//登录业务
public static void login(String username,String password){
Connection conn =null;
PreparedStatement st=null;
ResultSet rs=null;
try {
conn = JdbcUtils.getConnection(); //这个 JdbcUtils 是自己建的工具类
//1.使用 ? 占位符替代参数
String sql="select * from users where name=? and password=?";
//2.预编译SQL
st = conn.preparedStatement(sql);
//3.手动给参数赋值
st.setString(1,username); //传入参数分别是:(parameterIndex,value)
st.setString(2,password);
//4.执行
rs = st.executeQuery(); //获得返回的结果集
while (rs.next()){
System.out.println("NAME=" + resultSet.getObject("NAME"));
System.out.println("pwd=" + resultSet.getObject("PASSWORD"));
}
}catch(SQLException e){
e.printStackTrace();
}finally{
JdbcUtils.release(conn,st,rs);
}
}
执行结果:
最终什么也没有返回。
解释:PreparedStatement对象本质上就是把传递进来的参数当做字符,如果其中存在转义字符会直接忽略,会把SQL中的 引号 ' 直接转义。
10.6、使用IDEA连接数据库
10.7、事务
用jdbc操作事务:
try {
conn = JdbcUtils.getConnection();
//关闭数据库的自动提交,就会自动开启事务
conn.setAutoCommit(false);//开启事务
String sql="update account set money = money-100 where name='A'";
st = conn.preparedStatement(sql);
rs = st.executeUpdate();
String sql2="update account set money = money+100 where name='B'";
st = conn.preparedStatement(sql2);
rs = st.executeUpdate();
//业务完毕,提交事务
conn.commit();
System.out.println("成功!");
}catch(SQLException e){
//若业务失败,就回滚事务(其实这里默认就会失败回滚,不写回滚也行)
try{
conn.rollback();
} catch (SQLException e1){
e1.printStackTrace();
}
e.printStackTrace();
}finally{
JdbcUtils.release(conn,st,rs);
}
10.9、数据库连接池
数据库连接 --- 执行完毕 --- 释放;
连接---释放 十分浪费系统资源;
池化技术:准备一些预先的资源,过来就连接预先准备好的;
编写连接池,只需要实现一个DataSource接口就行;
开源数据源实现:(拿来即用)
DBCP:
C3P0:
Druid:
使用了这些数据库连接池之后,我们在项目开发过程中就不需要编写连接数据库的代码了!
DBCP:
注意:需要用到的jar包: ---> commons-dbcp-1.4、commons-pool-1.6;
此外他还有专门的配置文件:dbcpconfig.properties
JdbcUtils_DBCP工具类:
private DataSource dataSource=null;
static{
try{
InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
Properties properties = new Properties();
properties.load(in);
//创建数据源 工厂模式--->工厂创建工人
dataSource = BasicDataSourceFactory.createDataSource(properties); //传入一个配置文件,返回一个DataSource数据源对象
}catch(SQLException e){
e.printStackTrace();
}
}
//从数据源中获取连接Connection对象
public static Connection getConnection() throws SQLException{
return dataSource.getConnection;
}
C3P0:
注意:需要用到的jar包: ---> c3p0-0.9.5.5、mchange-commons-java-0.2.19;
此外他还有专门的配置文件:c3p0-config.xml
xml文件可以直接被读取!
private ComboPooledDataSource dataSource=null;
static{
try{
//创建数据源 工厂模式--->工厂创建工人
//1.通过对象代码配置
dataSource = new ComboPooledDataSource();
dataSource.setDriverClass();
dataSource.setUser();
dataSource.setPassword();
dataSource.setJdbcUrl();
dataSource.setMaxPoolSize();
dataSource.setMinPoolSize();
//2.配置文件的写法(推荐)
dataSource = new ComboPooledDataSource("MySQL"); //传入参数 configName。若不穿参数则选择默认值
}catch(SQLException e){
e.printStackTrace();
}
}
//从数据源中获取连接Connection对象
public static Connection getConnection() throws SQLException{
return dataSource.getConnection;
}
结论:
无论使用什么数据源,本质上只是改变了实现DataSource接口实现,方法不会变!!

浙公网安备 33010602011771号