//复制粘贴警告

MySQL

MySQL


1. 初识MySQL

前端(页面:展示,数据)
后台(连接点:连接数据库JDBC,控制前端)
数据库(存数据)


1.1 学习目的

  1. 岗位需求
  2. 大数据时代
  3. 数据存取需求
  4. 数据库是所有软件体系中最核心的存在

1.2 概念

数据库(DB,DateBase)
概念:数据仓库,软件,安装在操作系统上。SQL是语句
作用:数据存取和管理


1.3 数据库分类

  • 关系型数据库:Excel (SQL)
    • MySQL,Oracle,SQL Server,DB2,SQLlite
    • 通过表和表之间、行和列之间的关进行数据的存储 学员表,考勤表.......
  • 非关系型数据库:{key: value} (NoSQL)
    • Redis,MongDB
    • 对象存储,通过对象的自身属性来决定

DBMS(数据库管理系统)

数据库管理软件,通过可视化操作,科学有效的管理和操作数据

image-20210923233855238


1.4 MySQL简介

官网

  1. open-source relational database management system (RDBMS)
  2. MySQL was owned and sponsored by the Swedish company MySQL AB, which was bought by Sun Microsystems (now Oracle Corporation).
  3. MySQL is a component of the LAMP web application software stack (and others), which is an acronym for Linux, Apache, MySQL, Perl/PHP/Python.

1.5 安装MySQL

MySQL安装教程
Navicat安装教程


1.6 SQL基础语句

mysql -uroot -p 命令行连接数据库!

flush privileges; -- 刷新权限
show databases; --查看所有数据库
use test  -- test是数据库名 切换数据库(命令)
show tables; --查看表
describe 图书管理系统; --查看表中字段信息
create database student; --创建数据库
exit; --退出连接
/*
多行注释
*/

数据库语言

DDL:数据库定义语言
DML:数据库操作管理语言
DQL:数据库查询语言
DCL:数据库控制语言

CRUD程序猿
CV程序猿
API程序猿


2. 操作数据库

SQL关键字不区分大小写
操作数据库 > 操作数据库的表 > 操作数据库的表的数据

创建数据库

create DATAbase if not exists test; --创建test数据库

删除数据库

Drop DATABASE if EXISTS test; --删除test数据库

使用数据库

use test --使用test数据库
select `user` from student; --如果表名或者字段名是特殊字符段,就需要使用``包裹

查看数据库

show databases;

2.1 MySQL 数据类型

数值类型

  • tinyint 1字节

  • smallint 2字节

  • int 4字节(常用)

  • bigint 8字节

  • float 4字节

  • double 8字节

  • decimal 字符串形式的浮点数(精度问题,金融常用)

字符串

  • char 0~255

  • varchar 0~65535 常用的变量

  • tinytext 255

  • text 65535 储存大文章

日期

  • date YY-MM-DD

  • time HH-mm-ss

  • datetime YYYY-MM-DD-HH-mm-ss 最常用的时间格式

  • timestamp 时间戳(1970-01-01 00:00:00到现在的时间)

  • year

null

不要使用null进行运算,结果始终为null


2.2 数据库的字段属性

  • Unsigned:无符号整数

  • zerofill:0填充

  • 自增:

    • 自动在上一条记录的基础上+1
    • 通常用来设置唯一的主键,必须是整数类型
    • 可以自定义自增的起始值和步长
  • 非空:如果不赋值,会报错

  • 默认default:设置默认的值

拓展

/*每一个表都必须包含以下5个字段
id 主键
`version`  乐观锁
is_delete 伪删除
gmt_create 创建时间
gmt_update 修改时间
*/

2.3 创建数据库表

-- 表的名称和字段尽量使用``括起来 ,避免被识别为关键字
-- AUTO_INCREMENT自增
-- 字符串用单引号括起来
-- 所有的语句用逗号隔开,最后一个字段不用加
-- primary key 主键, 一般只有一个
create table if not exists `student`(
		`id` int(4) not null auto_increment COMMENT '学号',
		`name` varchar(30) not null default '匿名' comment '姓名',
		`pwd` varchar(20) not null default '123456' comment '密码',
		`sex` varchar(2) not null default '男' comment '性别',
		`birthday` date DEFAULT null comment '出生日期',
		`address` varchar(100) default null comment '家庭地址',
		`email` varchar(100) default null comment '邮箱',
		primary key(`id`)
)engine=innodb default charset=utf8

show create database school --  查看创建数据库的语句
show create table student -- 查看student表的定义语句 

2.4 数据库表的类型

MYISAM与INNODB区别

MYISAM INNODB
事务支持 不支持 支持
数据行锁定 不支持 支持
外键约束 不支持 支持
全文索引 支持 5.6.4后支持
表空间的大小 较小 较大,2倍

常规使用操作:

  • MYISAM:节约空间,速度较快
  • INNODB:安全性高,事务的处理,多表多用户操作

在物理空间的存储位置

所有的数据库文件都存在data目录下,一个文件夹对应一个数据库

本质还是文件的存储!

MYSQL引擎在物理文件上的区别

  • INNODB在数据库表中只有一个*.frm文件,以及上级目录下的ibdata1文件
  • MYISAM对应的文件
    • *.frm 表结构的定义文件
    • *.MYD 数据文件(data)
    • *.MYI 索引文件 (index)

设置数据库的字符集编码

MySQL默认编码是Latin1,不支持中文

charset=utf8mb4

也可以在my.ini添加下述代码

default-character-set=utf8

2.5 修改删除表

修改

-- 修改表名
alter table `student` rename as student01;
-- 增加表的字段
alter table `student01` add age int(11);
-- 修改表的字段(重命名、修改约束)
alter table `student01` modify age varchar(11);-- 修改约束
alter table `student01` change age age01 int(1);-- 重命名
-- 删除表的字段
alter table `student01` drop age01;

删除

所有的创建和删除操作尽量加上判断,以免报错

-- 删除表
alter table if exists `student01`;

注意点:

  • 反引号`包裹字段名,避免被系统识别为关键字
  • sql关键字大小写不敏感,建议小写

3. MySQL的数据管理

3.1 外键

表与表的约束

数据库只是单纯的表,只用来存数据

不建议使用现在大多不用物理外键,都通过代码逻辑去限制

create table `grade`(
		`id` int(10) not null auto_increment comment '年级id',
		`name` varchar(50) not null comment '年级名称',
		primary key(`id`)
)engine=innodb default charset=utf8;
create table if not exists `student`(
		`id` int(4) not null auto_increment COMMENT '学号',
		`name` varchar(30) not null default '匿名' comment '姓名',
		`gradeid` int(10) not null comment '学生年级',
		`pwd` varchar(20) not null default '123456' comment '密码',
		`sex` varchar(2) not null default '男' comment '性别',
		`birthday` date DEFAULT null comment '出生日期',
		`address` varchar(100) default null comment '家庭地址',
		`email` varchar(100) default null comment '邮箱',
		primary key(`id`),
		key `FK_gradeid`(`gradeid`),
		constraint `FK_gradeid` foreign key (`gradeid`) references `grade`(`id`)
)engine=innodb default charset=utf8
create table `grade`(
		`id` int(10) not null auto_increment comment '年级id',
		`name` varchar(50) not null comment '年级名称',
		primary key(`id`)
)engine=innodb default charset=utf8;
create table if not exists `student`(
		`id` int(4) not null auto_increment COMMENT '学号',
		`name` varchar(30) not null default '匿名' comment '姓名',
		`gradeid` int(10) not null comment '学生年级',
		`pwd` varchar(20) not null default '123456' comment '密码',
		`sex` varchar(2) not null default '男' comment '性别',
		`birthday` date DEFAULT null comment '出生日期',
		`address` varchar(100) default null comment '家庭地址',
		`email` varchar(100) default null comment '邮箱',
		primary key(`id`)
)engine=innodb default charset=utf8
-- 创建表的时候没有外键的约束
alter table `student`
add constraint `FK_gradeid` foreign key(`gradeid`) references `grade`(`id`);

注意点:

  • 要设置外键的字段不能为主键
  • 改建所参考的字段必须为主键
  • 两个字段必须具有相同的数据类型和约束

3.2 DML语言

  • insert
  • update
  • delete

3.3 添加

-- insert into `表名`(`字段1`, `字段2`, `字段3`) values('值1'), ('值2'), ('值3')
-- 数据要一一对应
insert into `grade`(`name`) values('大四'), ('大三');
insert into `student`(`name`, `pwd`,`gradeid`) values('张三', 'aaaaaa','4');

3.4 修改

update `student` set `name`='Jezer' where id = 1; -- 指定条件
update `student` set `name`='Jezer' -- 改动整个库
update `student` set `name`='Jezer', `email` = 'jezer05@qq.com' where id = 1; -- 修改多个字段

条件语句:=,<>或!=,between...and...,and,or


3.5 删除

delete from `student` where  id = 1; -- 删除指定数据
truncate `student`; -- 完全清空一张表的数据,表的结构和索引不变
delete from `student`; -- 完全清空一张表的数据,表的结构和索引不变

delete和truncate的区别

  • truncate重新设置自增列,计数器会归零,不会影响事务

  • delete删除的问题

    • INNODB 自增列会从1开始(存在内存当中,断电即失)

    • MYISAM 继续从上一个自增量开始(存在文件当中,不会丢失)

mysql版本不一样,新版的已经修复内存问题了


4. MySQL的数据查询

image-20210926114951312

4.1 查询字段信息

-- 查询所有的学生信息
select * from `student`
-- 查询指定字段
select `studentno` from `student`
-- 别名,给结果起一个名字 as
select `studentno` as '学号' from `student`
-- 函数 concat(a, b) 拼接
select concat('姓名:', studentname) as '新名字' from `student`
-- 去重
select distinct `studentno` from `result`
-- 查询系统版本
select version()
-- 用来计算
select 100 *3 - 10 as '计算结果'
-- 查询自增的步长
select @@auto_increment_increment as '自增的步长'
-- 对字段的所有数据进行修改,只是修改显示值,原值不会发生变化
select `studentno`, `studentresult` + 1 from `result`

4.2 where 条件子句

逻辑运算符

add 、&&

or 、 ||

not、 !

select `studentno`, `studentresult` from `result` where `studentresult` >= 90 and `studentresult` <= 100
select `studentno`, `studentresult` from `result` where `studentresult` between 90 and 100

模糊查询:比较运算符

is null
is not null
a between ... and ...
a like b
a in(a1, a2, a3, ...)

-- 查询‘高’开头的课程
-- like 结合 %(代表0到任意字符) _(一个字符)
select `subjectName` from `subject` where `subjectName` like '高%'

-- 查询 classhour为110,120, 130的数据, in要求精确匹配
select `subjectName` from `subject` where `classhour` in(110, 120, 130)

4.3 连表查询

①确定需要输出的数据内容,并分析数据来源

②确定交叉点,用于连接两个表

③join on连接查询,where 等值查询

select `s.studentno`, `studentname`, `subjectno`, `studentresult`
from `student` as s -- 左表
inner join `result` as r -- 右表
on s.studentno = r.studentno
select `s.studentno`, `studentname`, `subjectno`, `studentresult`
from `student` as s -- 左表
inner join `result` as r -- 右表
where s.studentno = r.studentno

on条件是在生成临时表时使用的条件,它不管on中的条件是否为真,都会返回左边表中的记录,还会返回on条件为真的记录

假设存在多张表连接查询,先进行两张表连接查询


4.4 自连接

核心:一张表拆为两张表

树形结构

categoryId pId categoryName
2 1 信息技术
3 1 软件开发
4 3 数据库
5 1 美术设计
6 3 web开发
7 5 ps技术
8 2 办公信息

image-20210926114101592

-- 查询父子信息
select a.`categoryName` as '父栏目', b. `categoryName` as '子栏目'
from `catagory` as a, `category` as b
where a.`categoryid` = b.`pid`

4.5 分页和排序

排序

select `s.studentno`, `studentname`, `subjectno`, `studentresult`
from `student` as s 
inner join `result` as r 
where s.studentno = r.studentno
order by  studentresult desc -- 升序ASC 降序DESC

分页

select `s.studentno`, `studentname`, `subjectno`, `studentresult`
from `student` as s 
inner join `result` as r 
where s.studentno = r.studentno
order by  studentresult desc 
limit 0, 5 -- 语法:limit起始数据,页面大小	
-- 查询 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 sub.`subjectNo` = r.`SubjectNo`
where subjectName = 'JAVA第一学年'  and `studentResult` >= 80
order by `studentResult` DESC
limit 0, 10

4.6 子查询

-- 查询 数据库结构-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
-- 方式二:使用子查询(由里及外)
select `studentNo`, r.`subjectNo`, `studentResult`
from `result`
where `subjectNo` = (-- 交集
	select `SubjectNo` from `subject`
    where `subjectName` = '数据库结构-1'
)
-- 查询课程为高等数学-2且分数不小于80的同学的学号和姓名
-- 方式一:
select distinct s.`studentNo`, `StudentName`
from `student` s
inner join result r
on r.`studentNo` = s.`studentNo`
where `studentResult` >= 80 and `subjectNo` = (
	select `subjectNo` from `subject`
    where `subjectName`  = '高等数学-2'
)
-- 方式二:
select distinct s.`studentNo`, `StudentName`
from `student` s
inner join result r
on r.`studentNo` = s.`studentNo`
inner join `subject` sub
on r.`studentNo`= sub.`studentNo`
where `subjectName` = '高等数学-2' and `studentResult` >= 80
-- 方式三
select distinct `studentNo`, `StudentName` from `student` 
where `studentNo` in (
	select `studentNo` from `result` where `studentResult` >= 80 and `subjectNo` =(
        select `subjectNo` from `subject` where `subjectName` = '高等数学-2'
    )
)

4.7 分组与过滤

-- 查询不同课程的平均分,最高分,最低分, 平均分大于等于80
select `subjectName`, avg(`studentresult`) as '平均分',  max(`studentresult`), min(`studentresult`)
from `result` r
inner join `subject` sub
on r.`subjectNo` = sub.`subjectNo`
group by r.`subjectNo`
having 平均分 >= 80

5. MySQL函数

帮助文档

5.1 基础函数

-- 数学运算
select abs(-23) -- 绝对值
select ceiling(9.4) -- 向上取整
select floor(9.4) -- 向下取整
select rand() -- 随机数0~1
select sign(-10) -- 返回一个数的符号 0-0 负数 -1 正数 1
-- 字符串函数
select char_length('学无止境') -- 返回字符串长度
select concat('hello', 'world') -- 拼接字符串
select insert('我爱学习', 1, 2, '超级热爱') -- 替换
select lower('HELLO') -- 转化为小写字母
select upper('hello') -- 转化为大写字母
select instr('hello', 'l') -- 某个字符出现的第一个位置
select replace('坚持就能成功', '坚持', '努力') -- 替换
select substr('坚持就能成功', 2, 2) -- 返回子字符串第二个开始,截取两个长度
select reverse('坚持就能成功') -- 反转
-- 查询姓周的同学,并替换为邹
select replace (`studentName`, '周', '邹') from `student`
where `studentName` like '周%' -- 不会对数据库进行修改
-- 时间和日期函数(记住)
select current_date() -- 当前日期
select now() -- 当前时间
select localtime() -- 本地时间
select sysdate() -- 系统时间
select year(now()) -- 年
--  系统
select system_user() -- 系统用户
select user() -- 系统用户
select version() -- 系统版本 	

5.2 聚合函数

-- 统计个数
select 	count(`studentName`) from `student` -- 统计指定字段的记录个数,会忽略所有的null值
select 	count(*) from `student` -- 本质计算行数,不会忽略null值
select 	count(1) from `student` -- 本质计算行数,不会忽略null值
-- 求和
select sum(`studentResult`) as '总和' from `result`
-- 平均分
select avg(`studentResult`) as '平均分' from `result`
-- 最高分
select max(`studentResult`) as 'max' from `result`
-- 最低分
select min(`studentResult`) as 'min' from `result`

5.3 数据库级别的MD5加密

create table `testmd5` (
    `id` int(4) not null auto_increment comment '学号',
    `name` varchar(30) not null comment '姓名',
    `pwd` varchar(50) not null comment ' 密码', -- 需要长一点,不然无法加密
    primary key(`id`)
)engine = innoDB default charset = utf8mb4
insert into `testmd5` values(1, '张三', '123456'), (2, '李四', '123456'), (3, '王五', '123456')
-- 加密
update `testmd5` set `pwd` = md5(pwd) 
-- 插入的时候加密
insert into `testmd5` values(4, '赵六', md5('123456'))
-- 如何校验:将用户传递进来的密码,进行MD5加密比对
select * from `testmd5` where `pwd` = md5('123456')

6. 事务

6.1 事务的概念

要么都成功,要么都失败

将一组SQL放在一个批次中执行

ACID原则:原子性 一致性 隔离性 持久性

原子性

image-20210927135836046

这个过程包含两个步骤

A: 800 - 200 = 600
B: 200 + 200 = 400

原子性表示,这两个步骤一起成功,或者一起失败,不能只发生其中一个动作

一致性

针对一个事务操作前与操作后的状态一致

操作前A:800,B:200
操作后A:600,B:400

一致性表示事务完成后,符合逻辑运算

持久性

表示事务结束后的数据不随着外界原因导致数据丢失

操作前A:800,B:200
操作后A:600,B:400
如果在操作前(事务还没有提交)服务器宕机或者断电,那么重启数据库以后,数据状态应该为
A:800,B:200
如果在操作后(事务已经提交)服务器宕机或者断电,那么重启数据库以后,数据状态应该为
A:600,B:400

隔离性

针对多个用户同时操作,主要是排除其他事务对本次事务的影响

隔离级别

脏读:指一个事务读取了另外一个事务未提交的数据。

不可重复读:在一个事务内读取表中的某一行数据,多次读取结果不同。(这个不一定是错误,只是某些场合不对)

虚读(幻读):是指在一个事务内读取到了别的事务插入的数据,导致前后读取数量总量不一致。


6.2 执行事务

image-20210927143451414

-- mysql是默认开启事务自动提交的
set autocommit = 1 -- 开启自动提交(默认)
-- 手动处理事务
set autocommit   0 -- 关闭自动提交
-- 事务开启 
start transaction -- 标记一个事务的开启,将之后的sql绑定在一个事务中
/*	
	操作语句
*/
-- 提交:持久化
commit 
-- 回滚:回到原来的样子(if失败)
rollback
-- 事务结束,开启自动提交
set autocommit = 1
-- ==================================拓展=========================
savepoint '保存点名'-- 设置一个事务的保存点
rollback to '保存点名'-- 回滚到保存点
release savepoint '保存点' -- 撤销保存点

模拟场景

-- 转账
create database `shop` character set utf8mb4 collate utf8mb4_bin
use `shop`
create table `account`(
	`id` int(3) not null auto_increment,
    `name` varchar(30) not null,
    `money` decimal(9, 2) not null, -- decimal(a, b) a为定点精度,b为小数位数
    primary key(`id`)
)engine = innoDB default charset = utf8mb4

insert into `account`(`name`, `money`)
values ('A', 2000.00), ('B', 10000.00);

-- 模拟转账
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'; --  B加500
commit;-- 提交事务,一旦提交,就会持久化
rollback; -- 回滚
set autocommit = 1; -- 恢复默认值

7. 索引

索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息。

7.1 索引的分类

  • 主键索引(primary key)
    • 唯一标识,主键不可重复,只能有一个
  • 唯一索引(unique key)
    • 避免重复的列出现,,多个列可以标识为唯一索引
  • 常规索引(key/index)
    • 默认的,index、key关键字来设置
  • 全文索引(fulltext)
    • 在特定的数据库引擎下才有,MYISAX
    • 快速定位数据

7.2 测试索引

-- 显示所有的索引信息
show index from `student`
-- 修改表结构的方式添加索引
alter table `student` add fulltext index `studentName`(`studentName`);
-- explain 分析sql执行的状况
explain select * from `student`; -- 非全文索引

MySQL优化-explain

-- 生成数据
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 default 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=utf8mb4 COMMENT = 'app用户表'

-- 插入1000000条数据  41.181s
SET GLOBAL log_bin_trust_function_creators=1; -- 开启创建函数功能
/*
  第一个语句 delimiter 将 mysql 解释器命令行的结束符由”;” 改成了”$$”,
  让存储过程内的命令遇到”;” 不执行
*/
set autocommit = 0;
start transaction;

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),'19224305@qq.com', concat('', floor(rand() * 9999999999 + 10000000000)),FLOOR(RAND()*2),
              	UUID(), floor(rand() * 100));
    	set i = i + 1;
    end while;
    return i;
end;$$

commit;
rollback;
set autocommit = 1;

select mock_data();
-- 测试
select * from `app_user` where `name` = '用户9999'; -- 0.605s
explain select * from `app_user` where `name` = '用户9999';

image-20210927181718292

-- 创建索引 id_表名_字段名
create [fulltext]index id_app_user_name on `app_user`(`name`); -- 5.252s
select * from `app_user` where `name` = '用户9999'; -- 0.023s
explain select * from `app_user` where `name` = '用户9999';
drop index  id_app_user_name on `app_user`; -- 删除索引

image-20210927182133308


7.3 索引原则

  • 索引不是越多越好
  • 不要对进程变动数据加索引
  • 小数据量的表不需要加索引
  • 索引一般加到常用在查询的字段上

索引的数据结构

[MySQL索引背后的数据结构及算法原理](http://blog.codinglabs.org/articles/theory-of-mysql-index.html)


8. 权限管理和备份

8.1 用户管理

SQL命令操作

用户表:mysql.user

本质:表的增删改查

-- 创建用户
create user Jezer identified by '123456'
-- 修改密码(修改当前用户密码)
set password = password('12345678') -- 新版已经淘汰
alter user '用户名'@'IP地址' identified with mysql_native_password by '123456789';-- 8.0之后
flush privileges;   -- 刷新MySQL的系统权限相关表
-- 修改密码(修改指定用户密码)
set password for Jezer = password('12345678')
-- 重命名 
rename user Jezer to Jezer05
-- 用户授权
grant all privileges on *.* to Jezer05-- [with grant option]
-- 查看权限
show grants for Jezer05
-- 撤销权限
revoke all privileges on *.* from Jezer05
-- 删除用户
drop user Jezer05

8.2 MySQL备份

  • 直接拷贝物理文件

  • 在可视化工具中手动导出

    • image-20210927222649705
  • cmd命令

导出

mysqldump -hlocalhost -uroot -p12345678 school student >D:/a.sql 

导入

mysql -uroot -p12345678
use school;
source d:/a.sql

image-20210927223635451


9. 规范数据库设计

9.1 数据库设计

糟糕的数据库设计

  • 数据库冗余,造成空间浪费
  • 数据库插入和删除麻烦、异常【物理外键】
  • 程序的性能差

良好的数据库设计

  • 节省内存空间
  • 保证数据库的完整性
  • 方便系统开发

数据库设计

  • 分析需求:分析业务需求和需要处理的数据库
  • 概要设计:设计关系图E-R图

个人博客

  • 收集信息,分析需求
    • 用户表(登录注销,个人信息,博客内容,分类)
    • 分类表(文章内容分类,创作者)
    • 文章表
    • 评论表
    • 友链表(友链信息)
    • 自定义表 key:value (标题等)
  • 标识实体(把要求落地到每个字段)
  • 标识实体之间的关系
    • 写博客:user --> blog
    • 创建分类:user --> category
    • 关注:user --> user

9.2 三大范式

三大范式的通俗理解

数据库常见问题

  • 信息重复
  • 更新异常
  • 插入异常
  • 删除异常

第一范式(1NF)

要求数据库表的每一列都是不可分割的原子数据项。

img

在上面的表中,“家庭信息”和“学校信息”列均不满足原子性的要求,故不满足第一范式,调整如下:

img

可见,调整后的每一列都是不可再分的,因此满足第一范式(1NF)

第二范式(2NF)

在1NF的基础上第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)

img

在上图所示的情况中,同一个订单中可能包含不同的产品,因此主键必须是“订单号”和“产品号”联合组成,但可以发现,产品数量、产品折扣、产品价格与“订单号”和“产品号”都相关,但是订单金额和订单时间仅与“订单号”相关,与“产品号”无关,这样就不满足第二范式的要求,调整如下,需分成两个表:

img

image-20210928163010357

第三范式(3NF)

在2NF基础上,第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。

img

上表中,所有属性都完全依赖于学号,所以满足第二范式,但是“班主任性别”和“班主任年龄”直接依赖的是“班主任姓名”,

而不是主键“学号”,所以需做如下调整:

img

image-20210928163233126


9.3 规范性与性能

  1. 关联查询的表不能超过三张

  2. 考虑商业化的需求和目标,数据库的性能更加重要(成本,用户体验)

  3. 有时故意给某些表增加一些冗余的字段(从多表查询变成单表查询)

  4. 故意增加一些计算列(从大数据量降低为小数据量的查询:索引)


10. JDBC

10.1 数据库驱动

image-20210928175037123


10.2 JDBC

sun公司为了简化开发人员的操作(对数据库的统一),提供了一个规范(Java操作数据库),俗称JDBC。这些规范的实现由具体厂商去做

对于开发人员来说,只需要学习JDBC

image-20210928175613222

JDBC数据库驱动的下载、安装与连接


10.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')
  1. 创建一个普通项目

  2. 导入数据库驱动

    image-20210928184116758

  3. 代码编写

import java.sql.*;

public class test {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //1.加载驱动,8.0以上
        //DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver())
        Class.forName("com.mysql.cj.jdbc.Driver");
        //2.用户信息和URL
        String url = "jdbc:mysql://localhost:3306/jdbcStudy?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT%2B8";
        String username = "root";
        String password = "12345678";
        //3.连接成功,返回数据库对象 connection 代表数据库
        Connection connection = DriverManager.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("birthday = " + resultSet.getObject("birthday"));
        }
        //6.释放连接
        connection.close();
        statement.close();
        resultSet.close();
    }
}

DriverManager

//DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver())
Class.forName("com.mysql.cj.jdbc.Driver");//推荐使用这种

URL

String url = "jdbc:mysql://localhost:3306/jdbcStudy?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT%2B8";
//mysql -- 3306
//jdbc:mysql//主机地址:端口号/数据库名?参数1&参数2&......
//oralce -- 1521
//jdbc:oracle:thin:@localhost:

Statement

String sql = "select * from `users`";//SQL语句
statement.executeQuery(sql);//查询操作,返回结果集ResultSet
statement.execute(sql);//执行任何SQL,效率相对较低
statement.executeUpdate(sql);//更新、插入、删除,返回一个受影响的行数
statement.executeBatch(sql);//批量处理sql语句,一般不使用

ResultSet

封装了所有数据查询结果

//获取数据内容
ResultSet resultSet = statement.executeQuery(sql);
resultSet.getObject("id")//在不知道数据类型的情况下使用
resultSet.getInt("id");
resultSet.getString("name");
resultSet.getFloat("id");
resultSet.getDouble("id");
//遍历,指针
resultSet.beforeFirst();//移动到最前面
resultSet.afterLast();//移动到最后
resultSet.next();//下移一条数据
resultSet.previous();//上移
resultSet.absolute(2); //移动到指定行

释放资源

connection.close();
statement.close();
resultSet.close();

10.4 Statement对象

配置文件

#配置文件
driver = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/jdbcStudy?useUnicode = true&characterEncoding =utf8&useSSL= true &serverTimezone=GMT%2B8
username = root
password = 12345678

封装

//函数封装
package utils;

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

/**
 * @author Jay_Soul
 */
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");
             Class.forName(driver);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
    public static Connection getConnection() throws SQLException {
        return  DriverManager.getConnection(url, username, password);
    }
    public static void release(Connection connection, Statement statement, ResultSet resultSet) throws SQLException {
        if  (resultSet!=null){
            resultSet.close();
        }
        if (statement!= null){
            statement.close();
        }
        if (connection != null){
            connection.close();
        }
    }

}

SQL操作

//插入操作
import utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * @author Jay_Soul
 */
public class TestInsert {
    public static void main(String[] args) {
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            //获取数据库连接
            connection = JdbcUtils.getConnection();
            //获得SQL的执行对象
            statement = connection.createStatement();
            String sql  = "insert into `users`(`id`, `name`, `password`, `email`, `birthday`)\n" +
                    "values(4, 'Jezer', '123456', 'jezer05@qq.com', '2021-09-29')";
            int res = statement.executeUpdate(sql);
            if (res > 0) {
                System.out.println("插入成功!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                JdbcUtils.release(connection, statement, resultSet);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

//删除操作
import utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestDelete {
    public static void main(String[] args) {
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            //获取数据库连接
            connection = JdbcUtils.getConnection();
            //获得SQL的执行对象
            statement = connection.createStatement();
            String sql  = "delete from `users` where `id` = 4";
            int res = statement.executeUpdate(sql);
            if (res > 0) {
                System.out.println("删除成功!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                JdbcUtils.release(connection, statement, resultSet);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
//更新操作
import 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.getConnection();
            //获得SQL的执行对象
            statement = connection.createStatement();
            String sql  = "update `users` set `name` = 'Jay' where `name` = 'Jezer'";
            int res = statement.executeUpdate(sql);
            if (res > 0) {
                System.out.println("修改成功!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                JdbcUtils.release(connection, statement, resultSet);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
import 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) throws SQLException {
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;

        try{
           connection = JdbcUtils.getConnection();
           statement = connection.createStatement();
           String sql = "select * from `users` where `id` = 2";
           resultSet = statement.executeQuery(sql);
           while (resultSet.next()){
               System.out.println(resultSet.getString("name"));
           }
        }finally {
            JdbcUtils.release(connection, statement, resultSet);
        }
    }
}

SQL注入问题

sql存在漏洞,会被攻击导致数据泄露

原因:sql语句会被拼接,只要判断结果为true,就可调出sql数据

解决 ---> PreparedStatement


10.5 PreparedStatement 对象

可以防止SQL注入,并且效率最高

插入

import utils.JdbcUtils;

import java.sql.*;

/**
 * @author Jay_Soul
 */
public class TestInsert {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            //获取数据库连接
            connection = JdbcUtils.getConnection();
            //需要预编译SQL
            //使用?占位符代替参数
            String sql  = "insert into `users`(`id`, `name`, `password`, `email`, `birthday`) values(?, ?, ?, ?, ?)";
            preparedStatement = connection.prepareStatement(sql);
            //手动给参数赋值(参数下标, 值)
            preparedStatement.setInt(1, 4);
            preparedStatement.setString(2, "Jezer");
            preparedStatement.setString(3, "123456");
            preparedStatement.setString(4, "jezer05@qq.com");
            //注意点:sql.Date 不是 util.Date
            preparedStatement.setDate(5,new java.sql.Date(System.currentTimeMillis()));

            int i = preparedStatement.executeUpdate();
            if (i > 0) {
                System.out.println("插入成功");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                JdbcUtils.release(connection,preparedStatement , resultSet);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

删除

import utils.JdbcUtils;

import java.sql.*;

public class TestDelete {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            //获取数据库连接
            connection = JdbcUtils.getConnection();
            //需要预编译SQL
            //使用?占位符代替参数
            String sql  = "delete from `users` where `id` = ?";
            preparedStatement = connection.prepareStatement(sql);
            //手动给参数赋值(参数下标, 值)
            preparedStatement.setInt(1, 4);
            int i = preparedStatement.executeUpdate();
            if (i > 0) {
                System.out.println("删除成功");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                JdbcUtils.release(connection,preparedStatement , resultSet);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

更新

import utils.JdbcUtils;

import java.sql.*;

public class TestUpdate {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            //获取数据库连接
            connection = JdbcUtils.getConnection();
            //需要预编译SQL
            //使用?占位符代替参数
            String sql  = "update `users` set `name` = ? where `id` = ?";
            preparedStatement = connection.prepareStatement(sql);
            //手动给参数赋值(参数下标, 值)
            preparedStatement.setString(1, "Jezer");
            preparedStatement.setInt(2, 3);
            int i = preparedStatement.executeUpdate();
            if (i > 0) {
                System.out.println("更新成功");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                JdbcUtils.release(connection,preparedStatement , resultSet);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

查询

import 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.getConnection();
            //需要预编译SQL
            //使用?占位符代替参数
            String sql  = "select * from `users` where `id` = ?";
            preparedStatement = connection.prepareStatement(sql);
            //手动给参数赋值(参数下标, 值)
            preparedStatement.setInt(1, 3);
            resultSet = preparedStatement.executeQuery();
            if (resultSet.next()) {
                System.out.println(resultSet.getString("name"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                JdbcUtils.release(connection,preparedStatement , resultSet);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

PreparedStatement防止注入的本质:将传递的参数当做字符,假设其中存在转义字符,比如说''会被直接忽略


10.6 IDEA连接数据库

视频地址

image-20210929153753338

image-20210929154556490

jdbc:mysql://localhost:3306/ssmbuild?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=true

image-20210929155359479


10.7 JDBC处理事务

import utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class TestTransation01 {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try{
            connection = JdbcUtils.getConnection();
            //关闭数据库自动提交,开启事务
            connection.setAutoCommit(false);
            String sql1 = "update `account` set `money` = `money` - 500 where `name` = 'A'";
            preparedStatement= connection.prepareStatement(sql1);
            preparedStatement.executeUpdate();
            String sql2 = "update `account` set `money` = `money` + 500 where `name` = 'B'";
            preparedStatement= connection.prepareStatement(sql2);
            preparedStatement.executeUpdate();
            //业务完毕,提交事务
            connection.commit();
            System.out.println("操作成功!");
            //恢复自动提交
            connection.setAutoCommit(true);
        } catch (SQLException throwables) {
            //此处没有回滚语句,一旦失败也会默认回滚
            try {
                connection.rollback();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            throwables.printStackTrace();
        }finally {
            try {
                JdbcUtils.release(connection, preparedStatement, resultSet);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

10.8 数据库连接池

著名连接池

DBCP

C3P0

Druid:阿里巴巴

编写连接池,实现一个接口 DataSource

DBCP

Maven安装与配置

Maven安装配置及在idea中配置

需要用到的jar包

  • mysql-connector-java.jar(JDBC驱动包)

  • commons-dbcp-1.4.jar

  • commons-pool-1.6.jar

在pom.xml中下载依赖项

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.26</version>
</dependency>

<dependency>
    <groupId>commons-dbcp</groupId>
    <artifactId>commons-dbcp</artifactId>
    <version>1.4</version>
</dependency>

<dependency>
    <groupId>commons-pool</groupId>
    <artifactId>commons-pool</artifactId>
    <version>1.6</version>
</dependency>

创建dbcpconfig.properties

# dbcpconfig.properties
#连接设置 这里的名字是DBCP数据源中定义好的
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT%2B8
username=root
password=12345678

#!-- 初始化连接 --
initialSize=10

#最大连接数量
maxActive=50

#!-- 最大空闲连接 --
maxIdle=20

#!-- 最小空闲连接 --
minIdle=5

#!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 --
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

在utils下创建JdbcUtils_DBCP配置文件

package utils;

import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;

import javax.sql.DataSource;
import javax.swing.plaf.nimbus.State;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/**
 * @author Jay_Soul
 */
public class JdbcUtils_DBCP {
    private static 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);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //获取连接
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    //释放链接
    public static void release(Connection connection, Statement statement, ResultSet resultSet){
        if (resultSet!=null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (statement != null){
            try {
                statement.close();
            } catch (SQLException e) {
            }
        }
        if (connection != null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

}

实现代码

import utils.JdbcUtils_DBCP;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * @author Jay_Soul
 */
public class TestDBCP {
    public static void main(String[] args) throws SQLException {
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;

        try{
            connection = JdbcUtils_DBCP.getConnection();
            statement = connection.createStatement();
            String sql = "select * from `users` where `id` = 2";
            resultSet = statement.executeQuery(sql);
            while (resultSet.next()){
                System.out.println(resultSet.getString("name"));
            }
        }finally {
            JdbcUtils_DBCP.release(connection, statement, resultSet);
        }
    }
}

C3P0

pom.xml导入外部库

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

<dependency>
    <groupId>commons-dbutils</groupId>
    <artifactId>commons-dbutils</artifactId>
    <version>1.6</version>
</dependency>

<dependency>
    <groupId>com.mchange</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.5.2</version>
</dependency>

 <dependency>
     <groupId>mysql</groupId>
     <artifactId>mysql-connector-java</artifactId>
     <version>8.0.26</version>
</dependency>

创建c3p0-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <!--默认配置。详细配置可查阅在线文档:https://tool.oschina.net/apidocs/apidoc?api=c3p0 -->
    <default-config>
        <property name="initialPoolSize">10</property>
        <property name="maxIdleTime">30</property>
        <property name="maxPoolSize">100</property>
        <property name="minPoolSize">10</property>
        <property name="maxStatements">200</property>
    </default-config>

    <!--配置连接池mysql-->
    <named-config name="MySQL">
        <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcStudy?serverTimezone=GMT%2b8&amp;useUnicode=true&amp;characterEncoding=utf8</property>
        <property name="user">root</property>
        <property name="password">12345678</property>
        <property name="initialPoolSize">10</property>
        <property name="maxIdleTime">30</property>
        <property name="maxPoolSize">100</property>
        <property name="minPoolSize">10</property>
        <property name="maxStatements">200</property>
    </named-config>

</c3p0-config>

在utils下创建JdbcUtils_C3P0.java

package utils;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;

import javax.sql.CommonDataSource;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/**
 * @author Jay_Soul
 */
public class JdbcUtils_C3P0 {
    private static ComboPooledDataSource dataSource = null;
    static {
        try{
            /*代码配置,一般不用
            dataSource = new ComboPooledDataSource("MySQL");
            dataSource.setDriverClass("driverClass");
            dataSource.setJdbcUrl("jdbcUrl");
            dataSource.setUser("user");
            dataSource.setPassword("password");
            dataSource.setMaxPoolSize();
            */
            //配置文件写法
            dataSource = new ComboPooledDataSource("MySQL");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //获取连接
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    //释放链接
    public static void release(Connection connection, Statement statement, ResultSet resultSet){
        if (resultSet!=null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (statement != null){
            try {
                statement.close();
            } catch (SQLException e) {
            }
        }
        if (connection != null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

}

代码实现

import utils.JdbcUtils_C3P0;
import utils.JdbcUtils_DBCP;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * @author Jay_Soul
 */
public class TestC3P0 {
    public static void main(String[] args) throws SQLException {
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;

        try{
            connection = JdbcUtils_C3P0.getConnection();
            statement = connection.createStatement();
            String sql = "select * from `users` where `id` = 2";
            resultSet = statement.executeQuery(sql);
            while (resultSet.next()){
                System.out.println(resultSet.getString("name"));
            }
        }finally {
            JdbcUtils_C3P0.release(connection, statement, resultSet);
        }
    }
}

结论

无论使用什么数据源,本质还是一样,DataSource接口不会变

Apacheyyds

posted @ 2021-10-11 17:23  Jezer  阅读(61)  评论(0)    收藏  举报