数据库总结

目录

一、Mysql初级

1、数据库简介

1.1 简介

1.2 常见的数据库管理系统

1.3 三大范式

1.4 Mysql的卸载和安装

2、SQL语言

2.1 概述

2.2 SQL语句分类

2.3 DDL操作数据库

2.4 DDL操作表

2.5 DML操作

2.6 DCL

3、DQL数据查询

 3.1  简单查询

 3.2 条件查询

 3.3 模糊查询

 3.4 字段控制查询

 3.5 排序

 3.6 聚合函数

 3.7 分组查询

 3.8 LIMIT

二、数据库高级

1、数据库的完整性

1.1 实体完整性

1.2 域完整性

1.3 引用完整性(参照完整性)

2、多表查询

2.1 多表的关系

2.2 多表查询

 3、扩展

3.1 多行新增

3.2 多表更新

3.3 多表删除

4.4 日期运算函数

 4、数据库优化

三、数据库进阶

1、事务

1.1 事务的语法

1.2 事务的ACID特性

1.3 事务的并发问题

1.4 事务的隔离级别

1.5 不同隔离级别的锁的情况

1.6 隐式提交

四、JDBC

1、简介

2、JDBC体系结构

3、JDBC核心组件

4、CRUD语法介绍

5、使用步骤

6、JDBC连接步骤

6.1 JDBC执行SQL语句

6.2 Statement

6.3 SQL注入

7、PreparedStatement(预状态通道)

8、 ResultSet

9、Java操作两表关系

10、数据库事务

10.1 事务概述

10.2 事务的四大特点 (ACID)

10.3 JDBC中事务应用

10.4 事务的提交和回滚

10.5 Savepoints

11 、JDBC批处理

11.1 Statement批处理

11.2 PreparedStatement批处理

12、反射处理结果集

13、工具类的定义

14、连接池

14.1 自定义连接池

14.2 DBCP连接池

14.3 C3P0连接池

14.3 Druid连接池


一、Mysql初级

1、数据库简介

1.1 简介

数据库(DataBaseDB :指长期保存在计算机的存储设备上,按照一定规则组织起来,可以被各种用户或应用共享的数据集合。
数据库管理系统(DataBase Management SystemDBMS
  • 指一种操作和管理数据库的大型软件,用于建立、使用和维护数据库,对数据库进行统一管理和控制,以保证数据库的安全性和完整性。
  • 用户通过数据库管理系统访问数据库中的数据。
  • 数据库软件应该为数据库管理系统,数据库是通过数据库管理系统创建和操作的。
数据库:存储、维护和管理数据的集合

1.2 常见的数据库管理系统

- Oracle Oracle 数据库被认为是业界目前比较成功的关系型数据库管理系统。 Oracle 数据库可以运行在UNIX Windows 等主流操作系统平台,完全支持所有的工业标准,并获得最高级别的 ISO 标准安全性认证。

- MySQL MySQL 是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,目前属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面, MySQL 是最好的 RDBMS (Relational Database Management System,关系数据库管理系统 ) 应用软件。

- DB2 DB2 IBM 公司的产品, DB2 数据库系统采用多进程多线索体系结构,其功能足以满足大中公司的需要,并可灵活地服务于中小型电子商务解决方案。
- Microsoft SQL Server SQL Server Microsoft 公司推出的关系型数据库管理系统。具有使用方便、可伸缩性好、相关软件集成程度高等优点。

1.3 三大范式

什么是三大范式:
  • 第一范式:无重复的列。当关系模式R的所有属性都不能在分解为更基本的数据单位时,称R是满足第一范式的,简记为1NF。满足第一范式是关系模式规范化的最低要求,否则,将有很多基本操作在这样的关系模式中实现不了。
  • 第二范式:属性完全依赖于主键 [ 消除部分子函数依赖 ]如果关系模式R满足第一范式,并且R得所有非主属性都完全依赖于R的每一个候选关键属性,称R满足第二范式,简记为2NF。第二范式(2NF)是
在第一范式( 1NF )的基础上建立起来的,即满足第二范式( 2NF )必须先满足第一范式( 1NF )。 二范式( 2NF )要求数据库表中的每个实例或行必须可以被唯一地区分 。为实现区分通常需要为表加上一个列,以存储各个实例的唯一标识。这个唯一属性列被称为主关键字或主键、主码。
  • 第三范式:属性不依赖于其它非主属性 [ 消除传递依赖 ]R是一个满足第一范式条件的关系模式,XR的任意属性集,如果X非传递依赖于R的任意一个候选关键字,称R满足第三范式,简记为3NF. 满足
第三范式( 3NF )必须先满足第二范式( 2NF )。 第三范式( 3NF )要求一个数据库表中不包含已在其 它表中已包含的非主关键字信息。
注:关系实质上是一张二维表,其中每一行是一个元组,每一列是一个属性
第二范式( 2NF )和第三范式( 3NF )的概念很容易混淆,区分它们的关键点在于,
2NF :非主键列是 否完全依赖于主键,还是依赖于主键的一部分;
3NF :非主键列是直接依赖于主键,还是直接依赖于非 主键列。

 1.4 Mysql的卸载和安装

1.4.1 安装
步骤 1: 访问地址 :https://dev.mysql.com/downloads/mysql/
步骤 2: 下载压缩包
for window

for mac

没有账户的点击左下方 :No thanks

下载后解压,放在非 C 盘下,文件夹改名 mysql
将解压文件夹下的 bin 路径添加到变量值中,前后以 ; 开头结尾

步骤 3: mysql 文件夹下找到 my.ini my-default.ini ,如果没有 .ini 结尾的文件 , 直接创建该文件。新增加内容为如下,注意basedir datadir 是我自己的路径位置,自定义。记得新增一个文件 Data 文件夹。

[mysqld]

# 设置 3306 端口
port=3306
# 设置 mysql 的安装目录
basedir=D:\Program Files\mysql # 设置 mysql 数据库的数据的存放目录
datadir=D:\Program Files\mysql\data
# 允许最大连接数
max_connections=200
# 允许连接失败的次数。这是为了防止有人从该主机试图攻击数据库系统
max_connect_errors=10
# 服务端使用的字符集默认为 UTF8
character-set-server=utf8
# 创建新表时将使用的默认存储引擎
default-storage-engine=INNODB
# 默认使用 “mysql_native_password” 插件认证
default_authentication_plugin=mysql_native_password
[mysql]
# 设置 mysql 客户端默认字符集
default-character-set=utf8
[client]
# 设置 mysql 客户端连接服务端时默认使用的端口
port=3306
default-character-set=utf8

步骤 4: 安装 mysql
mysql 的安装目录中,打开 bin 文件夹,运行 cmd. 执行初始化数据库的指令:
mysqld --initialize --console

root 用户的初始化密码 :

要是你不小心关掉 cmd ,或者没记住,那也没事,删掉初始化的 datadir 目录,再执行一遍初始化命令,又会重新生成的。
步骤 5: 安装服务
MySQL 安装目录的 bin 目录下执行命令:
mysqld --install [ 服务名 ] 这里的服务名默认是 mysql ,可以自定义

如果提示上述错误,需要关闭 cmd, 重新打开,使用管理员身份执行

安装完成之后
通过命令 net start mysql8 启动 MySQL 的服务了。
通过命令 net stop mysql8 停止服务。

注意 : 安装时,卸载其他版本的 mysql 数据库
步骤 6: 链接数据库

修改账户密码 :
alter user 'root'@'localhost' identified with mysql_native_password BY ' 新密码 ';

 修改密码,注意命令尾的分号一定要有,这是mysql的语法

退出数据库:

1.4.2 卸载
步骤 1: 使用管理员身份运行 cmd, 关闭 mysql 服务

步骤 2: 删除 mysql 服务
命令 :sc delete mysql8 或者 mysqld remove mysql8

步骤 3: 刪除 mysqlDB 目录文件( 安裝 mysql my.ini 指定的目录)

2、SQL语言

2.1 概述

        SQL: Structure Query Language (结构化查询语言), SQL 被美国国家标准局( ANSI )确定为关系型数据库语言的美国标准,后来被国际化标准组织(ISO )采纳为关系数据库语言的国际标准。
  • 各数据库厂商都支持ISOSQL标准,普通话
  • 各数据库厂商在标准的基础上做了自己的扩展,方言
        SQL 是一种标准化的语言,它允许你在数据库上执行操作,如创建项目,查询内容,更新内容,并删除条目等操作。
        Create, Read, Update, and Delete 通常称为 CRUD 操作。

 2.2 SQL语句分类

  • DDLData Defifinition Language):数据定义语言,用来定义数据库对象:库、表、列等。
        alter user 'root'@'localhost' identified with mysql_native_password BY '新密码 ';
        alter user 'root'@'localhost' identified with mysql_native_password BY '123456';
  • DMLData Manipulation Language):数据操作语言,用来定义数据库记录(数据)增删改。
  • DCLData Control Language):数据控制语言,用来定义访问权限和安全级别。
  • DQLData Query Language):数据查询语言,用来查询记录(数据)查询。 
注意: sql 语句以 ; 结尾
mysql 中的关键字不区分大小写

2.3 DDL操作数据库

1 创建
CREATE DATABASE 语句用于创建新的数据库:
编码方式 :gb2312,utf-8,gbk,iso-8859-1
//create database 数据库名 
CREATE DATABASE mydb1; 
//create database 数据库名 character set 编码方式 
CREATE DATABASE mydb2 character SET GBK; 
//create database 数据库名 character set 编码方式 collate 排序规则 
CREATE DATABASE mydb3 character SET GBK COLLATE gbk_chinese_ci;
2 查看数据库
查看当前数据库服务器中的所有数据库
show databases;
查看前面创建的 mydb2 数据库的定义信息
//show create database 数据库名; 
Show CREATE DATABASE mydb2;
3 修改数据库
alter database 数据库名 character set 编码方式
查看服务器中的数据库,并把 mydb2 的字符集修改为 utf8;
ALTER DATABASE mydb2 character SET utf8;
4 删除数据库
drop database 数据库名
DROP DATABASE mydb3;
5 其他语句
查看当前使用的数据库
Select database();
切换数据库 : use 数据库名
USE mydb2;

2.4 DDL操作表

CREATE TABLE 语句用于创建新表。
语法:
CREATE TABLE 表名( 
列名1 数据类型 [约束], 
列名2 数据类型 [约束], 
列名n 数据类型 [约束] 
);
说明 : 表名,列名是自定义,多列之间使用逗号间隔,最后一列的逗号不能写
[ 约束 ] 表示可有可无
示例:
CREATE TABLE Employees( 
    id INT , 
    age INT , 
    first VARCHAR(255), 
    last VARCHAR(255) 
);
常用数据类型:
        int:整型
        double:浮点型,例如 double(5,2) 表示最多 5 位,其中必须有 2 位小数,即最大值为999.99;默认支持四舍五入
        char:固定长度字符串类型; char(10) 'aaa ' 10
        varchar:可变长度字符串类型; varchar(10) 'aaa' 3
        text:字符串类型,比如小说信息;
        blob:字节类型,保存文件信息 ( 视频,音频,图片 )
        date:日期类型,格式为: yyyy-MM-dd
        time:时间类型,格式为: hh:mm:ss
        timestamp:时间戳类型 yyyy-MM-dd hh:mm:ss 会自动赋值
        datetime:日期时间类型 yyyy-MM-dd hh:mm:ss
2.4.1 其他表操作
drop table 表名 ;
DROP TABLE table_name;
当前数据库中的所有表
show tables;
SHOW TABLES;
查看表的字段信息
desc 表名;
DESC employee;
增加列 : 在上面员工表的基本上增加一个 image 列。
alter table 表名 add 新列名 新的数据类型
ALTER TABLE employee ADD image blob;
修改 job 列,使其长度为 60
alter table 表名 change 旧列名 新列名 新的数据类型
ALTER TABLE employee MODIFY job varchar(60); 
ALTER TABLE employee change job job varchar(60);
列名 name 修改为 username
ALTER TABLE user CHANGE name username varchar(100);
删除 image , 一次只能删一列。
alter table 表名 drop 列名
ALTER TABLE employee DROP image;
修改表名 , 表名改为 user
alter table 旧表名 rename 新表名 ;
alter table user rename users;
查看表格的创建细节
show create table 表名 ;
SHOW CREATE TABLE user;
修改表的字符集为 gbk
alter table 表名 character set 编码方式
ALTER TABLE user CHARACTER SET gbk;
练习:
表名 card( 会员卡表 )
列名 数据类型
cardid int
cardnum varchar(20)
regDate date
需求:
(1) 创建该表
(2) card 表名修改为 CardInfo
(3) 添加 delDate( 注销时间 ) 列到表中
(4) cardnum 改为 varchar(30)
(5) 删除 regDate
(6) 删除 cardInfo

 2.5 DML操作

DML 是对表中的数据进行增、删、改的操作。不要与 DDL 混淆了。
主要包括: INSERT UPDATE DELETE
小知识:
mysql 中,字符串类型和日期类型都要用单引号括起来。
空值: null
1)插入操作:INSERT:
insert into 表名 ( 列名 ) values( 数据值 );
insert into student(stuname,stuage,stusex,birthday) values('张三1',18,'a','2000- 1-1');
  • 注意:
        1.多列和多个列值之间使用逗号隔开
        2.列名要和列值一一对应
  • 非数值的列值两侧需要加单引号
        常见错误: Data too long for column 'stusex' at row 1

  • 添加数据的时候可以将列名省略->当给所有列添加数据的时候
  • 此时列值的顺序按照数据表中列的顺序执行
        insert into student values('李四 ',12,'1111',189.98,'2000-1-1',' ','2007-1-1');
  • 同时添加多行
        insert into 表名 ( 列名 ) values( 第一行数据 ),( 第二行数据 ),(),();
insert into student(stuname,stuage,stusex,birthday)
values('张三3',18,'a','2000-1-1'), 
('张三4',18,'a','2000-1-1'), 
('张三5',18,'a','2000-1-1'), 
('张三6',18,'a','2000-1-1'), 
('张三7',18,'a','2000-1-1'), 
('张三8',18,'a','2000-1-1');
注意:
  • 列名与列值的类型、个数、顺序要一一对应。
  • 参数值不要超出列定义的长度。
  • 如果插入空值,请使用null
  • 插入的日期和字符一样,都使用引号括起来。
练习准备 :
create table emp(
    id int primary key, 
    name varchar(100) not null, 
    gender varchar(10) not null, 
    birthday date, 
    salary float(10,2), 
    entry_date date, 
    resume text 
);
INSERT INTO emp(id,name,gender,birthday,salary,entry_date,resume) 
VALUES(1,'zhangsan','female','1990-5-10',10000,'2015-5-5-','goodgirl'); 

INSERT INTO emp(id,name,gender,birthday,salary,entry_date,resume) 
VALUES(2,'lisi','male','1995-5-10',10000,'2015-5-5','good boy'); 

INSERT INTO emp(id,name,gender,birthday,salary,entry_date,resume) 
VALUES(3,'你好','male','1995-5-10',10000,'2015-5-5','good boy');
sql 中的运算符 :
  • 算术运算符: +-*/(除法),求余(%)
  • 赋值运算符:=
  • 逻辑运算符:
         and(并且),or( 或者 ),not (取非)
        作用: 用于连接多个条件时使用
  • 关系运算符:  
        >,<,>=,<=,!=(不等于),=( 等于 ),<>( 不等于 )
        补充: 查询所有数据 :select * from 表名
2)修改(更新)操作:UPDATE:
        语法:UPDATE 表名 SET 列名 1= 列值 1, 列名 2= 列值 2 ... WHERE 列名 =
3)删除操作:DELETE:
        语法 : DELETE from 表名 【 WHERE 列名 = 值】
  • DELETE 删除表中的数据,表结构还在;删除后的数据可以找回
  • TRUNCATE 删除是把表直接DROP掉,然后再创建一个同样的新表。
  • 删除的数据不能找回。执行速度比DELETE快。
小结:
为空的条件:列名 is null or 列名 =''
: 两个单引号表示空字符串
日期类型值的区别 :
  • dateyyyy-MM-dd (年月日)
  • timehh:mm:ss (时分秒)
  • datetime:yyyy-MM-dd hh:mm:ss (年月日时分秒)
获取当前系统时间 :now()
select now();

2.6 DCL

1、创建用户:
create user 用户名 @ 指定 ip identifified by 密码 ;
create user test123@localhost IDENTIFIED by 'test123'
create user 用户名 @ 客户端 ip identifified by 密码 ; 指定 IP 才能登陆
create user test456@10.4.10.18 IDENTIFIED by 'test456'
create user 用户名 @‘% ’ identifified by 密码 任意 IP 均可登陆
create user test7@'%' IDENTIFIED by 'test7'
2、用户授权:
grant 权限 1, 权限 2,........, 权限 n on 数据库名.* to 用户名 @IP; 给指定用户授予指定指定数据库指定权限
grant select,insert,update,delete,create on chaoshi.* to 'test456'@'127.0.0.1';
grant all on . to 用户名 @IP 给指定用户授予所有数据库所有权限
grant all on *.* to 'test456'@'127.0.0.1'
3、用户权限查询:
show grants for 用户名 @IP;
show grants for 'root'@'%';
4、撤销用户权限:
revoke 权限 1, 权限 2,........, 权限 n on 数据库名 .* from 用户名 @IP;
REVOKE SELECT ON *.* FROM 'root'@'%' ;
5、删除用户:
drop user 用户名 @IP;
drop user test123@localhost;

3、DQL数据查询

DQL 数据查询语言(重要)
数据库执行 DQL 语句不会对数据进行改变,而是让数据库发送结果集给客户端。
查询返回的结果集是一张虚拟表。
查询关键字: SELECT
语法: SELECT 列名 FROM 表名 【 WHERE --> BROUP BY-->HAVING--> ORDER BY
* 表示所有列

SELECT 要查询的列名称
FROM 表名称
WHERE 限定条件 /* 行条件 */
GROUP BY grouping_columns /* 对结果分组 */
HAVING condition /* 分组后的行条件 */
ORDER BY sorting_columns /* 对结果分组 */
LIMIT offset_start, row_count /* 结果限定 */

 3.1  简单查询

查询所有列

SELECT * FROM stu;
查询指定列
SELECT sid, sname, age FROM stu;

 3.2 条件查询

条件查询就是在查询时给出 WHERE 子句,在 WHERE 子句中可以使用如下运算符及关键字:
= != <> < <= > >=; BETWEEN…AND IN(set) IS NULL AND OR NOT

 3.3 模糊查询

当想查询姓名中包含 a 字母的学生时就需要使用模糊查询了。模糊查询需要使用关键字 LIKE
语法 : 列名 like ' 表达式 ' // 表达式必须是字符串
通配符 :
_( 下划线 ): 任意一个字符
% :任意 0~n 个字符 ,' %'

3.4 字段控制查询

 3.5 排序

语法: order by 列名 asc/desc
//asc 升序 desc 降序

 3.6 聚合函数

聚合函数是用来做纵向运算的函数:
  • COUNT(列名):统计指定列不为NULL的记录行数;
  • MAX(列名):计算指定列的最大值,如果指定列是字符串类型,那么使用字符串排序运算;
  • MIN(列名):计算指定列的最小值,如果指定列是字符串类型,那么使用字符串排序运算;
  • SUM(列名):计算指定列的数值和,如果指定列类型不是数值类型,那么计算结果为0
  • AVG(列名):计算指定列的平均值,如果指定列类型不是数值类型,那么计算结果为0

 

 3.7 分组查询

当需要分组查询时需要使用 GROUP BY 子句,例如查询每个部门的工资和,这说明要使用部分来分组。
注意 : 如果查询语句中有分组操作,则 select 后面能添加的只能是聚合函数和被分组的列名
3.7.1 分组查询

 

 3.7.2 HAVING子句

3.8 LIMIT

LIMIT 用来限定查询结果的起始行,以及总行数。
limit 开始下标 , 显示条数; // 开始下标从 0 开始
limit 显示条数; // 表示默认从 0 开始获取数据

 3.8.1 分页查询

 

二、数据库高级

1.1 数据库的完整性

①用来保证存放到数据库中的数据是有效的,即数据的有效性和准确性
确保数据的完整性 = 在创建表时给表中添加约束
完整性的分类
  • 实体完整性(行完整性)
  • 域完整性(列完整性)
  • 引用完整性(关联表完整性、参照完整性)
主键约束: primary key
唯一约束: unique [key]
非空约束: not null
默认约束: default
自动增长: auto_increment
外键约束 : foreign key
建议这些约束应该在创建表的时候设置,多个约束条件之间使用空格间隔。
create table student( 
    studentno int primary key auto_increment, 
    loginPwd varchar(20) not null default '123456', 
    studentname varchar(50) not null, 
    sex char(2) not null, 
    gradeid int not null, 
    phone varchar(255) not null, 
    address varchar(255) default '学生宿舍', 
    borndate datetime, 
    email varchar(50) );

1.2 实体完整性

实体:即表中的一行 ( 一条记录 ) 代表一个实体( entity
实体完整性的作用:标识每一行数据不重复。

约束类型:

  • 主键约束(primary key) *
  • 唯一约束unique)*
  • 自动增长列auto_ increment)*
1.2.1 主键约束( primary key
注:每个表中要有一个主键。
特点:数据唯一,且不能为 null

1.2.2 唯一约束 (unique)
特点:数据不能重复。
1.2.3 自动增长列 (auto_increment)
  • sqlserver数据库 (identity-标识列)
  • oracle数据库(sequence-序列)
给主键添加自动增长的数值,列只能是整数类型

1.2 域完整性

  • 域完整性的作用:限制此单元格的数据正确,不对照此列的其它单元格比较
  • 域代表当前单元格
域完整性约束:
  • 数据类型
  • 非空约束(not null
  • 默认值约束(default)
  • check约束(mysql不支持)
  • check(sex='' or sex='')
1.3.1 数据类型

①数值类型: 

②日期类型:
  • 表示时间值的日期和时间类型为DATETIMEDATETIMESTAMPTIMEYEAR
  • 每个时间类型有一个有效值范围和一个""值,当指定不合法的MySQL不能表示的值时使用""值。
  • TIMESTAMP类型有专有的自动更新特性

③字符串类型:
字符串类型指 CHAR VARCHAR BINARY VARBINARY BLOB TEXT ENUM SET

  

1.3.2 非空约束
not null
CREATE TABLE student( 
    Id int primary key, 
    Name varchar(50) not null, 
    Sex varchar(10) ); 

INSERT INTO student values(1,’tom’,null);
1.3.3 默认值约束
default

 1.4 引用完整性(参照完整性)

外键约束: FOREIGN KEY
示例:
CREATE TABLE student(
    id int primary key, 
    name varchar(50) not null, 
    sex varchar(10) default '男' ); 

create table score( 
    id int primary key, 
    score int, 
    sid int , 
    constraint fk_score_sid foreign key(sid) references student(id) );
constraint 自定义约束名称 foreign key(外键列名) references 主键表名(主键列名)
外键列的数据类型一定要与主键的类型一致
第二种添加外键方式。
ALTER TABLE score ADD CONSTRAINT fk_stu_score FOREIGN KEY(sid) REFERENCES student(id);

2、多表查询

多个表之间是有关系的,那么关系靠谁来维护 ?
多表约束:外键列

 2.1 多表的关系

2.1.1 一对多 / 多对一关系
客户和订单,分类和商品,部门和员工 .
一对多建表原则:在多的一方创建一个字段,字段作为外键指向一的一方的主键。
2.1.2 多对多关系
学生和课程
多对多关系建表原则:需要创建第三张表 , 中间表中至少两个字段,这两个字段分别作为外键指向各自一 方的主键。
2.1.3 一对一关系
在实际的开发中应用不多 . 因为一对一可以创建成一张表 .
两种建表原则:
唯一外键对应:假设一对一是一个一对多的关系,在多的一方创建一个外键指向一的一方的主键,将外 键设置为 unique。
主键对应:让一对一的双方的主键进行建立关系

2.2 多表查询

多表查询有如下几种:
1. 合并结果集 :UNION UNION ALL
2. 连接查询
        2.1内连接 [INNER] JOIN ON
        2.2外连接 OUTER JOIN ON
                -左外连接 LEFT [OUTER] JOIN
                - 右外连接 RIGHT [OUTER] JOIN
                - 全外连接(MySQL 不支持) FULL JOIN
        2.3 自然连接 NATURAL JOIN
3. 子查询
2.2.1 合并结果集
作用:合并结果集就是把两个 select 语句的查询结果合并到一起!
合并结果集有两种方式:
l UNION :去除重复记录,例如: SELECT* FROM t1 UNION SELECT * FROM t2
l UNION ALL :不去除重复记录,例如: SELECT * FROM t1 UNION ALL SELECT * FROM t2

 注意:被合并的两个结果:列数、列类型必须相同。

2.2.2 连接查询
连接查询就是求出多个表的乘积,例如 t1 连接 t2 ,那么查询出的结果就是 t1*t2

连接查询会产生 笛卡尔积 ,假设集合 A={a,b} ,集合 B={0,1,2} ,则两个集合的笛卡尔积为 {(a,0),(a,1), (a,2),(b,0),(b,1),(b,2)}。可以扩展到多个集合的情况。
那么多表查询产生这样的结果并不是我们想要的,那么怎么去除重复的,不想要的记录呢,当然是通过条件过滤。通常要查询的多个表之间都存在关联关系,那么就通过关联关系去除笛卡尔积。

 使用主外键关系做为条件来去除无用信息

一:内连接
上面的连接语句就是内连接,但它不是 SQL 标准中的查询方式,可以理解为方言!

:
<1> 1 和表 2 的顺序可以互换
<2> 找两张表的等值关系时, 找表示相同含义的列作为等值关系。
<3> 点操作符表示 ”, 格式: 表名 . 列名
<4> 可以使用 as 给表名起别名, 注意定义别名之后, 统一使用别名

三表联查:
语法:
select 列名 from 1
inner join 2 on 1. 列名 = 2. 列名
inner join 3 on 1 或表 2. 列名 = 3. 列名 where
等价于 :
select 列名 from 1, 2, 3
where 1. 列名 = 2. 列名 and 1/ 2. 列名 = 3. 列名
SQL 标准的内连接为

 内连接的特点:查询结果必须满足条件。

二:外连接
  • 包括左外连接和右外连接,
  • 外连接的特点:查询出的结果存在不满足条件的可能。
-- 显示还没有员工的部门名称 ?
-- 外联查询
        -- 左外联 :
                select 列名 from 主表 left join 次表 on 主表.列名=次表.列名
                1.主表数据全部显示,次表数据匹配显示,能匹配到的显示数据,匹配不成功的显示null
                2.主表和次表不能随意调换位置
使用场景 : 一般会作为子查询的语句使用

        -- 右外联 :select 列名 from 次表 right join 主表 on 主表 . 列名 = 次表 . 列名

连接查询心得
  • 连接不限于两张表,连接查询也可以是三张、四张,甚至N张表的连接查询。
  • 通常连接查询不可能需要整个笛卡尔积,而只是需要其中一部分,那么这时就需要使用条件来去除不需要的记录。这个条件大多数情况下都是使用主外键关系去除。
  • 两张表的连接查询一定有一个主外键关系,三张表的连接查询就一定有两个主外键关系,所以在大家不是很熟悉连接查询时,首先要学会去除无用笛卡尔积,那么就是用主外键关系作为条件来处理。如果两张表的查询,那么至少有一个主外键条件,三张表连接至少有两个主外键条件。
. 自然连接
自然连接( NATURAL INNER JOIN ):自然连接是一种特殊的等值连接 ,他要求两个关系表中进行连 接的必须是相同的属性列(名字相同),无须添加连接条件,并且在结果中消除重复的属性列。
2.2.3 子查询
  • 一个select语句中包含另一个完整的select语句。
  • 子查询就是嵌套查询,即SELECT中包含SELECT,如果一条语句中存在两个,或两个以上SELECT,那么就是子查询语句了。
①子查询出现的位置:
  • where后,作为条为被查询的一条件的一部分;
  • from后,作表;
当子查询出现在 where 后作为条件时,还可以使用如下关键字:
  • any
  •  all
③  子查询结果集的形式:  
  • 单行单列(用于条件)
  • 单行多列(用于条件)
  • 多行单列(用于条件)
  • 多行多列(用于表)

 

 3、扩展

3.1 多行新增

insert into 表名 ( 列名 ) values ( 列值 ),( 列值 ),( 列值);

 3.2 多表更新

(1)
update 表 1, 2 set 列名 = 列值 where 1. 列名 = 2. 列名 and 其他限定条件
(2)
update 1
inner join 2 on 1. 列名 = 2. 列名
set 列名 = 列值
where 限定条件
示例:
update employee e,salary s

set title='助工',salary=1000

where e.empid=s.empid and name=' 李四 '

3.3 多表删除

语法:
delete 被删除数据的表 from 删除操作中使用的表
where 限定条件
: 多张表之间使用逗号间隔
示例:
// 删除人事部的信息
delete d,e,s from department d,employee e,salary s
where d.depid=e.depid and s.empid=e.empid and depname='人事部 '

 4.4 日期运算函数

  • now() 获得当前系统时间
  • year(日期值) 获得日期值中的年份
  • date_add(日期,interval 计算值 计算的字段);
注:计算值大于 0 表示往后推日期,小于 0 表示往前推日期
示例:
date_add(now(),interval -40 year);//40 年前的日期

 3、数据库优化

  1. 对查询进行优化,要尽量避免全表扫描,首先应考虑 where order by 涉及的列上建立索引
  2. 尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:select id from t where num is null 最好不要给数据库留NULL,尽可能的使用 NOT NULL填充数据库. 备注、描述、评论之类的可以设置为 NULL,其他的,最好不要使用NULL
  3. 应尽量避免在 where 子句中使用 != <> 操作符,否则引擎将放弃使用索引而进行全表扫描。
  4. 应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num=10 or Name = 'admin
可以这样查询:
select id from t where num = 10
union all
select id from t where Name = 'admin'

      5. in 和 not in 也要慎用,否则会导致全表扫描,如:

 select id from t where num in(1 , 2 , 3 )
对于连续的数值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
很多时候用 exists 代替 in 是一个好的选择

三、数据库进阶

1、事务

事务(Transaction)是由一系列对系统中数据进⾏访问与更新的操作所组成的⼀个程序执行逻辑单元。
(1) 事务的语法
(2) 事务的特性
(3) 事务并发问题
(4) 事务隔离级别
(5) 不同隔离级别的锁的情况 ( 了解 )
(6) 隐式提交 ( 了解 )

 1.1 事务的语法

  1.  start transaction; begin;
  2.  commit; 使得当前的修改确认
  3.  rollback; 使得当前的修改被放弃

1.2 事务的ACID特性

1. 原⼦性(Atomicity
事务的原⼦性是指事务必须是⼀个原子的操作序列单元。事务中包含的各项操作在⼀次执⾏过程中,只允许出现两种状态之一:
  • 全部执行成功
  • 全部执行失败
事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执⾏过程中出错, 会回滚到事务开始前的状态,所有的操作就像没有发⽣一样。也就是说事务是⼀个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。
2. ⼀致性(Consistency
事务的一致性是指事务的执⾏不能破坏数据库数据的完整性和一致性,一个事务在执⾏之前和执行之 后,数据库都必须处以⼀致性状态。
比如:如果从 A 账户转账到 B 账户,不可能因为 A 账户扣了钱,⽽ B 账户没有加钱。
3. 隔离性(Isolation
事务的隔离性是指在并发环境中,并发的事务是互相隔离的。也就是说,不同的事务并发操作相同的数据时,每个事务都有各自完整的数据空间。
⼀个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务是不能互相干扰的。
隔离性分 4 个级别,下面会介绍。
4. 持久性(Duration
事务的持久性是指事务⼀旦提交后,数据库中的数据必须被永久的保存下来。即使服务器系统崩溃或服务器宕机等故障。只要数据库重新启动,那么一定能够将其恢复到事务成功结束后的状态。

1.3 事务的并发问题

脏读:读取到了没有提交的数据 , 事务 A 读取了事务 B 更新的数据,然后 B 回滚操作,那么 A 读取到的数据是脏数据。
不可重复读:同⼀条命令返回不同的结果集(更新), 事务 A 多次读取同一数据,事务 B 在事务 A 多次读取的过程中,对数据做了更新并提交,导致事务A 多次读取同一数据时,结果不一致。
幻读:重复查询的过程中,数据就发⽣了量的变化(insert delete )。

1.4 事务的隔离级别

4 种事务隔离级别从上往下,级别越高,并发性越差,安全性就越来越高。 ⼀般数据默认级别是读以提交或可重复读。
查看当前会话中事务的隔离级别
mysql> select @@tx_isolation; 
+-----------------+ 
| @@tx_isolation | 
+-----------------+ 
| REPEATABLE-READ | 
+-----------------+ 
1 row in set, 1 warning (0.93 sec)
设置当前会话中的事务隔离级别
mysql> set session transaction isolation level read uncommitted;
Query OK, 0 rows affffected (0.00 sec)
1. 读未提交(READ_UNCOMMITTED
读未提交,该隔离级别允许脏读取,其隔离级别是最低的。换句话说,如果一个事务正在处理理某一数据,并对其进⾏了更新,但同时尚未完成事务,因此还没有提交事务;而以此同时,允许另一个事务也能够访问该数据。
脏读示例:
在事务 A 和事务 B 同时执行时可能会出现如下场景:

余额应该为 1500 元才对。请看 T5 时间点,事务 A 此时查询的余额为 0 ,这个数据就是脏数据,他是事务 B 造成的,很明显是事务没有进行隔离造成的。

2. 读已提交(READ_COMMITTED
读已提交是不同的事务执行的时候只能获取到已经提交的数据。 这样就不会出现上面的脏读的情况了。但是在同一个事务中执行同一个读取, 结果不一致
不可重复读示例
可是解决了脏读问题,但是还是解决不了可重复读问题。

事务A其实除了了查询两次以外,其它什什么事情都没做,结果钱就从1000变成0了了,这就是不不可重复读的问题。

3. 可重复读(REPEATABLE_READ
可重复读就是保证在事务处理理过程中,多次读取同一个数据时,该数据的值和事务开始时刻是一致的。因此该事务级别限制了不可重复读和脏读,但是有可能出现幻读的数据。
幻读
幻读就是指同样的事务操作,在前后两个时间段内执行对同一个数据项的读取,可能出现不一致的结果。
诡异的更新事件

4. 顺序读(SERIALIZABLE
顺序读是最严格的事务隔离级别。它要求所有的事务排队顺序执行,即事务只能一个接一个地处理,不能并发。

1.5 不同隔离级别的锁的情况

1. 读未提交( RU :   有行级的锁,没有间隙锁。它与 RC 的区别是能够查询到未提交的数据。
2. 读已提交( RC ):有行级的锁,没有间隙锁,读不到没有提交的数据。
3. 可重复读( RR ):有行级的锁,也有间隙锁,每次读取的数据都是一样的,并且没有幻读的情况。
4. 序列化( S ):有行级锁,也有间隙锁,读表的时候,就已经上锁了。

1.6 隐式提交

DQL: 查询语句
DML: 写操作 ( 添加 , 删除 , 修改 )
DDL: 定义语句 ( 建库 , 建表 , 修改表 , 索引操作 , 存储过程 , 视图 )
DCL: 控制语言( 给⽤用户授权 , 或删除授权 )
DDL Data Defifine Language ):都是隐式提交。
隐式提交:执行这种语句相当于执行commit; DDL

四、JDBC

1、简介

        JDBC( Java DataBase Connectivity,java 数据库连接)是一种用于执行 SQL 语句的 Java API ,可以为多种关系数据库提供统一访问,它由一组用Java 语言编写的类和接口组成。 JDBC 提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。
        Java 具有坚固、安全、易于使用、易于理解和可从网络上自动下载等特性,是编写数据库应用程序的杰出语言。所需要的只是 Java 应用程序与各种不同数据库之间进行对话的方法。
        JDBC可以在各种平台上使用 Java ,如 Windows Mac OS 和各种版本的 UNIX
        JDBC库包括通常与数据库使用相关的下面提到的每个任务的 API
  • 连接数据库。
  • 创建SQLMySQL语句。
  • 在数据库中执行SQLMySQL查询。
  • 查看和修改生成的记录

2、JDBC体系结构

JDBC API 支持用于数据库访问的两层和三层处理模型,但通常, JDBC 体系结构由两层组成:
  • JDBC API这提供了应用程序到JDBC管理器连接。
  • JDBC驱动程序API这支持JDBC管理器到驱动程序连接。
JDBC API 使用驱动程序管理器和特定于数据库的驱动程序来提供与异构数据库的透明连接。

 3、JDBC核心组件

  • DriverManager此类管理数据库驱动程序列表。使用通信子协议将来自java应用程序的连接请求与适当的数据库驱动程序匹配。
  • Driver:此接口处理与数据库服务器的通信,我们很少会直接与Driver对象进行交互。而是使用 DriverManager对象来管理这种类型的对象。
  • Connection该界面具有用于联系数据库的所有方法。连接对象表示通信上下文,即,与数据库的所有通信仅通过连接对象。
  • Statement:使用从此接口创建的对象将SQL语句提交到数据库。除了执行存储过程之外,一些派生接口还接受参数。
  • ResultSet在使用Statement对象执行SQL查询后,这些对象保存从数据库检索的数据。它作为一个迭代器,允许我们移动其数据。
  • SQLException此类处理数据库应用程序中发生的任何错误

 4、CRUD语法介绍

SQL 是一种标准化的语言,它允许你在数据库上执行操作,如创建项目,查询内容,更新内容,并删除条目等操作。
Create, Read, Update, and Delete 通常称为 CRUD 操作。
①CREATE DATABASE 语句用于创建新的数据库:
SQL> CREATE DATABASE DATABASE_NAME;
②DROP DATABASE 语句用于删除现有数据库:
SQL> DROP DATABASE DATABASE_NAME;
③CREATE TABLE 语句用于创建新表。语法是
SQL> CREATE TABLE Employees (
id INT NOT NULL,
age INT NOT NULL,
first VARCHAR(255),
last VARCHAR(255),
PRIMARY KEY ( id )
);

④DROP TABLE语句用于删除现有表。

SQL> DROP TABLE table_name; 

⑤INSERT 的语法类似于以下内容,其中 column1 column2 等表示要显示在相应列中的新数据
SQL> INSERT INTO table_name VALUES (column1, column2, ...);
⑥SELECT 语句用于从数据库中检索数据。 SELECT 的语法是
SQL> SELECT column_name, column_name, ... FROM table_name WHERE conditions;
WHERE 子句可以使用比较运算符,例如 = ,! = < > <= > = ,以及 BETWEEN LIKE 运算符。
⑦UPDATE 语句用于更新数据。
SQL> UPDATE table_name
SET column_name = value, column_name = value, ...
WHERE conditions;
WHERE 子句可以使用比较运算符,例如 = ,! = < > <= > = ,以及 BETWEEN LIKE 运算符。
⑧DELETE 语句用于从表中删除数据。
SQL> DELETE FROM table_name WHERE conditions;

WHERE子句可以使用比较运算符,例如=,!=<><=> =,以及BETWEENLIKE运算符。

5、使用步骤

构建 JDBC 应用程序涉及以下六个步骤:
  • 导入包:需要包含数据库编程所需的JDBC类的包。大多数情况下,使用import java.sql.*就足够了。
  • 注册JDBC驱动程序:要求您初始化驱动程序,以便您可以打开与数据库的通信通道。
  • 打开连接:需要使用DriverManager.getConnection()方法创建一个Connection对象,该对象表示与数据库的物理连接。
  • 执行查询:需要使用类型为Statement的对象来构建和提交SQL语句到数据库。
  • 从结果集中提取数据:需要使用相应的ResultSet.getXXX()方法从结果集中检索数据。
  • 释放资源:需要明确地关闭所有数据库资源,而不依赖于JVM的垃圾收集。

 6、JDBC连接步骤

建立 JDBC 连接所涉及的编程相当简单。这是简单的四个步骤
  • 导入JDBC包:Java语言的*import*语句添加到Java代码中导入所需的类。
  • 注册JDBC驱动程序:此步骤将使JVM将所需的驱动程序实现加载到内存中,以便它可以满足您的JDBC请求。
  • 数据库URL配置:这是为了创建一个格式正确的地址,指向要连接到的数据库。
  • 创建连接对象:最后,调用DriverManager对象的getConnection()方法来建立实际的数据库连接。 

①注册JDBC驱动程序

Class.forName(); 注册驱动程序最常见的方法是使用JavaClass.forName()方法,将驱动程序的类文件动态加载到内存中,并将其自动注册

try {
    Class.forName("com.mysql.cj.jdbc.Driver"); 
}catch(ClassNotFoundException ex) { 
    System.out.println("Error: unable to load driver class!"); 
    System.exit(1); 
}
DriverManager.registerDriver()
第二种方法是使用静态 DriverManager.registerDriver () 方法。
try {
    Driver myDriver = new com.mysql.cj.jdbc.Driver(); 
    DriverManager.registerDriver( myDriver ); 
}catch(ClassNotFoundException ex) { 
    System.out.println("Error: unable to load driver class!"); 
    System.exit(1); 
}
②数据库 URL 配置
加载驱动程序后,可以使用 DriverManager.getConnection () 方法建立连接。为了方便参考,让我列出三个重载的DriverManager.getConnection() 方法:
  • getConnectionString url
  • getConnectionString urlProperties prop
  • getConnectionString urlString userString password

 ③建数据库连接对象

String URL = "jdbc:mysql://localhost:3306/数据库名?serverTimezone=UTC"; 
String USER = "username"; 
String PASS = "password";
Connection conn = DriverManager.getConnection(URL, USER, PASS);
完整的连接地址 :
版本 1:
jdbc:mysql://localhost:3306/数据库名? 
useSSL=false&useUnicode=true&characterEncoding=UTF-8

版本2:

jdbc:mysql://localhost:3306/数据库名?serverTimezone=UTC
④使用数据库 URL 和属性对象
DriverManager.getConnection ()方法的第三种形式需要一个数据库 URL 和一个 Properties 对象
DriverManager.getConnection(String url, Properties info);
import java.util.*; String URL = "jdbc:mysql://localhost:3306/yhp2?serverTimezone=UTC"; 
Properties info = new Properties( ); 
info.put( "user", "username" ); 
info.put( "password", "password" ); 
Connection conn = DriverManager.getConnection(URL, info);
⑥关闭数据库连接
为确保连接关闭,您可以在代码中提供一个 “fifinally” 块。一个 fifinally 块总是执行,不管是否发生异常。
要关闭上面打开的连接,你应该调用 close ()方法如下
com.close();

6.1 JDBC执行SQL语句

一旦获得了连接,我们可以与数据库进行交互。 JDBC Statement PreparedStatement 接口定义了使您能够发送SQL 命令并从数据库接收数据的方法和属性。

接口推荐使用
声明
用于对数据库进行通用访问。在运行时使用静态 SQL 语句时很有用。 Statement 接口不能接受参数。
PreparedStatement当您计划多次使用SQL语句时使用。PreparedStatement接口在运行时接受输入参数。

6.2 Statement

创建语句对象
在使用 Statement 对象执行 SQL 语句之前,需要使用 Connection 对象的 createStatement ()方法创建一个,如下例所示:
Statement stmt = null; 
try {
    stmt = conn.createStatement( );
     . . . 
}catch (SQLException e) {
     . . . 
}finally {
     . . . 
}
创建 Statement 对象后,您可以使用它来执行一个 SQL 语句,其中有三个执行方法之一。
  • boolean executeString SQL:如果可以检索到ResultSet对象,则返回一个布尔值true; 否则返回false。使用此方法执行SQL DDL语句或需要使用真正的动态SQL时。
  • int executeUpdateString SQL:返回受SQL语句执行影响的行数。使用此方法执行预期会影响多个行的SQL语句,例如INSERTUPDATEDELETE语句。
  • ResultSet executeQueryString SQL:返回一个ResultSet对象。当您希望获得结果集时,请使用此方法,就像使用SELECT语句一样。
关闭 Statement 对象
就像我们关闭一个 Connection 对象以保存数据库资源一样,由于同样的原因,还应该关闭 Statement 对象。
一个简单的调用 close ()方法将执行该作业。如果先关闭 Connection 对象,它也会关闭 Statement 对象。但是,应始终显式关闭Statement 对象,以确保正确清理。
Statement stmt = null; 
try {
    stmt = conn.createStatement( ); 
    . . . 
}catch (SQLException e) { 
    . . . 
}finally { 
    stmt.close(); 
}

6.3 SQL注入

        就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL 命令
        具体来说,它是利用现有应用程序,将(恶意的)SQL 命令注入到后台数据库引擎执行的能力,它可以通过在Web 表单中输入(恶意) SQL 语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL 语句。比如先前的很多影视网站泄露 VIP 会员密码大多就是通过WEB表单递交查询字符暴出的,这类表单特别容易受到 SQL 注入式攻击。
String username ="admin"; 
String password=" 'abc' or 1=1 "; 
String sql="select * from users where username= '"+username+"' and password= "+password;

7、PreparedStatement(预状态通道)

PreparedStatement 接口扩展了 Statement 接口,它为您提供了一个通用的 Statement 对象有两个优点附加功能。
此语句使您可以动态地提供参数。
PreparedStatement pstmt = null; 
try {
    String SQL = "Update Employees SET age = ? WHERE id = ?"; 
    pstmt = conn.prepareStatement(SQL); 
    . . . 
}catch (SQLException e) { 
    . . . 
}finally { 
    . . . 
}
JDBC 中的所有参数都由?符号,这被称为参数标记。在执行 SQL 语句之前,必须为每个参数提供值。
所述的 setXXX() 方法将值绑定到所述参数,其中 XXX 代表要绑定到输入参数的值的 Java 数据类型。如果 忘记提供值,将收到一个 SQLException
每个参数标记由其顺序位置引用。第一个标记表示位置 1 ,下一个位置 2 等等。该方法与 Java 数组索引不 同,从 0 开始。
关闭PreparedStatement对象
就像关闭 Statement 对象一样,由于同样的原因,还应该关闭 PreparedStatement 对象。
一个简单的调用 close ()方法将执行该作业。如果先关闭 Connection 对象,它也会关闭
PreparedStatement 对象。但是,应始终显式关闭 PreparedStatement 对象,以确保正确清理。
PreparedStatement pstmt = null; 
try {
    String SQL = "Update Employees SET age = ? WHERE id = ?"; 
    pstmt = conn.preparedStatement(SQL); 
    . . . 
}catch (SQLException e) { 
    . . . 
}finally { 
    pstmt.close(); 
}
对比statementPreparedStatement
(1)statement 属于状态通道, PreparedStatement 属于预状态通道
(2) 预状态通道会先编译 sql 语句 , 再去执行,比 statement 执行效率高
(3) 预状态通道支持占位符 ? 给占位符赋值的时候,位置从 1 开始
(4) 预状态通道可以防止 sql 注入,原因 : 预状态通道在处理值的时候以字符串的方式处理

实例:

public class JDBCTest {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement pps = null;
        ResultSet resultset = null;
        int result = 0;
        try {
            //1.加载驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //2.获得连接
            String username = "root";
            String password = "123456";
            String url = "jdbc:mysql://localhost:3306/kaikeba?serverTimezone=UTC";
            connection = DriverManager.getConnection(url,username,password);
            //3.定义sql创建预状态通道(进行sql的发送)
            String sql = "select * from employee where name=? and title=?";
            pps = connection.prepareStatement(sql);
            pps.setString(1,"李四");
            pps.setString(2,"工程师");
            resultset = pps.executeQuery();
            //4.取出结果集信息
            while(resultset.next()){
                //取出数据
                String name = resultset.getString("name");
                String sex = resultset.getString("sex");
                System.out.println("姓名:"+name+",性别:"+sex);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            try {
                if(resultset != null) {
                    //关闭数据库连接
                    resultset.close();
                }
                if(pps != null){
                    pps.close();
                }
                if(connection != null){
                    connection.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }

    }

8、 ResultSet

SELECT 语句是从数据库中选择行并在结果集中查看行的标准方法。该 java.sql.ResultSet 中的 接口表示结果集数据库查询。
ResultSet 对象维护指向结果集中当前行的游标。术语 结果集 是指包含在 ResultSet 对象中的行和列数据。
如果没有指定任何 ResultSet 类型,您将自动获得一个 TYPE_FORWARD_ONLY

try {
    Statement stmt = conn.createStatement( ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); 
}catch(Exception ex) { 
    .... 
}finally { 
    .... 
}

实例: 

import java.sql.*;

/**
 * @Author: xuliushen
 * @Description:
 * @Date Created in 2021-08-16 10:02
 * @Modified by :
 */
public class JDBCTest {
    public static void main(String[] args) {
        Connection connection = null;
        Statement statement = null;
        ResultSet resultset = null;
        try {
            //1.加载驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //2.获得连接
            String username = "root";
            String password = "123456";
            String url = "jdbc:mysql://localhost:3306/kaikeba?serverTimezone=UTC";
            connection = DriverManager.getConnection(url,username,password);
            //3.定义sql创建状态通道(进行sql的发送)
            statement = connection.createStatement();
            resultset = statement.executeQuery("select * from employee");
            //4.取出结果集信息
            while(resultset.next()){
                //取出数据
                String name = resultset.getString("name");
                System.out.println(name);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            try {
                if(resultset != null) {
                    //关闭数据库连接
                    resultset.close();
                }
                if(statement != null){
                    statement.close();
                }
                if(connection != null){
                    connection.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }

    }
}

 

 9、Java操作两表关系

10、数据库事务

一组要么同时执行成功,要么同时执行失败的 SQL 语句。是数据库操作的一个执行单元。

10.1 事务概述

        数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。
        事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。
        一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性。事务是数据库运行中的逻辑工作单位,由DBMS中的事务管理子系统负责事务的处理。
事务开始于
  • 连接到数据库上,并执行一条DML语句insertupdatedelete
  • 前一个事务结束后,又输入了另一条DML语句
事务结束于
  • 执行commitrollback语句。
  • 执行一条DDL语句,例如create table语句,在这种情况下,会自动执行commit语句。
  • 执行一条DCL语句,例如grant语句,在这种情况下,会自动执行commit
  • 断开与数据库的连接。
  • 执行了一条DML语句,该语句却失败了,在这种情况中,会为这个无效的DML语句执行rollback句。

10.2 事务的四大特点 (ACID)

- actomicity( 原子性 )
表示一个事务内的所有操作是一个整体,要么全部成功,要么全部失败
- consistency( 一致性 )
表示一个事务内有一个操作失败时,所有的更改过的数据都必须回滚到修改前状态
- isolation( 隔离性 )
事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修
改它之后的状态,事务不会查看中间状态的数据。
- durability( 持久性 )
持久性事务完成之后,它对于系统的影响是永久性的。

10.3 JDBC中事务应用

如果 JDBC 连接处于 自动提交 模式,默认情况下,则每个 SQL 语句在完成后都会提交到数据库。
事务使您能够控制是否和何时更改应用于数据库。它将单个 SQL 语句或一组 SQL 语句视为一个逻辑单元,如果任何语句失败,则整个事务将失败。
要启用手动事务支持,而不是 JDBC 驱动程序默认使用的 自动提交 模式,请使用 Connection 对象的
setAutoCommit () 方法。如果将 boolean false 传递给 setAutoCommit (),则关闭自动提交。我们可以传递一个布尔值true 来重新打开它。

10.4 事务的提交和回滚

完成更改后,我们要提交更改,然后在连接对象上调用 commit () 方法,如下所示:
conn.commit( );
否则,要使用连接名为 conn 的数据库回滚更新,请使用以下代码  
conn.rollback( );
try{
        //Assume a valid connection object conn
        conn.setAutoCommit(false);
        Statement stmt = conn.createStatement();
        String SQL = "INSERT INTO Employees values (106, 20, 'Rita', 'Tez')";
        stmt.executeUpdate(SQL);
        //Submit a malformed SQL statement that breaks
        String SQL = "INSERTED IN Employees VALUES (107, 22, 'Sita', 'Singh')";
        stmt.executeUpdate(SQL);
        // If there is no error.
        conn.commit();

}catch(SQLException se){
        // If there is any error.
        conn.rollback();
}

10.5 Savepoints

新的 JDBC 3.0 Savepoint 接口为您提供了额外的事务控制。
设置保存点时,可以在事务中定义逻辑回滚点。如果通过保存点发生错误,则可以使用回滚方法来撤消所有更改或仅保存在保存点之后所做的更改。
Connection 对象有两种新的方法来帮助您管理保存点  
  • setSavepointString savepointName):定义新的保存点。它还返回一个Savepoint对象。
  • releaseSavepointSavepoint savepointName):删除保存点。请注意,它需要一个Savepoint对象作为参数。此对象通常是由setSavepoint()方法生成的保存点。
try{
    //Assume a valid connection object conn
    conn.setAutoCommit(false);
    Statement stmt = conn.createStatement();
    Savepoint savepoint1 = conn.setSavepoint("Savepoint1");
    String SQL = "INSERT INTO Employees VALUES (106, 20, 'Rita', 'Tez')";
    stmt.executeUpdate(SQL);
    String SQL = "INSERTED IN Employees VALUES (107, 22, 'Sita', 'Tez')";
    stmt.executeUpdate(SQL);
    conn.commit();
}catch(SQLException se){
    conn.rollback(savepoint1);
}
1 、要取消掉 JDBC 的自动提交: void setAutoCommit(boolean autoCommit)
2 、执行各个 SQL 语句,加入到批处理之中
3 、如果所有语句执行成功,则提交事务 commit() ;如果出现了错误,则回滚: rollback()
try {
    connection.setAutoCommit(false);
    add(connection);
    // int i = 1/0;
    sub(connection);
    System.out.println("===============");
    connection.commit();
} catch (Exception e) {
    // TODO Auto-generated catch block
    System.out.println("---------------");
    try {
        connection.rollback();
    } catch (SQLException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
}
以上就是 java 代码利用 jdbc 操作数据库的最简单版本, 数据库事务通常要借助补捉异常语句

11 、JDBC批处理

批量处理允许您将相关的 SQL 语句分组到批处理中,并通过对数据库的一次调用提交它们。
当您一次向数据库发送多个 SQL 语句时,可以减少连接数据库的开销,从而提高性能。

11.1 Statement批处理

以下是使用语句对象的批处理的典型步骤序列
  • - 使用createStatement()方法创建Statement对象。
  • - 使用setAutoCommit()auto-commit设置为false
  • - 使用addBatch()方法在创建的语句对象上添加您喜欢的SQL语句到批处理中。
  • - 在创建的语句对象上使用executeBatch()方法执行所有SQL语句。
  • - 最后,使用commit()方法提交所有更改。
Statement stmt = conn.createStatement();
conn.setAutoCommit(false);
//sql1
String SQL = "INSERT INTO Employees (id, first, last, age) VALUES(200,'Zia',
'Ali', 30)";
stmt.addBatch(SQL);
//sql2
String SQL = "INSERT INTO Employees (id, first, last, age) VALUES(201,'Raj',
'Kumar', 35)";
stmt.addBatch(SQL);
//sql3
String SQL = "UPDATE Employees SET age = 35 WHERE id = 100";
stmt.addBatch(SQL);
int[] count = stmt.executeBatch();
conn.commit();

11.2 PreparedStatement批处理

1. 使用占位符创建 SQL 语句。
2. 使用 prepareStatement () 方法创建 PrepareStatement 对象。
3. 使用 setAutoCommit () auto-commit 设置为 false
4. 使用 addBatch () 方法在创建的语句对象上添加您喜欢的 SQL 语句到批处理中。
5. 在创建的语句对象上使用 executeBatch () 方法执行所有 SQL 语句。
6. 最后,使用 commit () 方法提交所有更改。
String SQL = "INSERT INTO Employees (id, first, last, age) VALUES(?, ?, ?, ?)";
PreparedStatement pstmt = conn.prepareStatement(SQL);
conn.setAutoCommit(false);
// Set the variables
pstmt.setInt( 1, 400 );
pstmt.setString( 2, "Pappu" );
pstmt.setString( 3, "Singh" );
pstmt.setInt( 4, 33 );
// Add it to the batch
pstmt.addBatch();
// Set the variables
pstmt.setInt( 1, 401 );
pstmt.setString( 2, "Pawan" );
pstmt.setString( 3, "Singh" );
pstmt.setInt( 4, 31 );
// Add it to the batch
pstmt.addBatch();
//add more batches
//Create an int[] to hold returned values
int[] count = stmt.executeBatch();
//Explicitly commit statements to apply changes
conn.commit();

12、反射处理结果集

之前我们从数据库获取对象的的写法:

  • 获取固定的表的数据,从结果集中依次拿出每一列的数据对对象进行赋值
  • 当列数很多的时候,这种方法并不方便

 使用反射处理结果集:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author: xuliushen
 * @Description:
 * @Date Created in 2021-08-20 8:30
 * @Modified by :
 */
public class StudentDaoImpl2 implements StudentDao{
    @Override
    public List<Student> getAllStudent(Class c ) {
        Connection connection = null;
        PreparedStatement pps = null;
        ResultSet result = null;
        try {
            //1.加载驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //2.获得连接
            String username = "root";
            String password = "123456";
            String url = "jdbc:mysql://localhost:3306/kaikeba?serverTimezone=UTC";
            connection = DriverManager.getConnection(url,username,password);
            //3.定义sql,创建预状态通道
            String sql = "select * from student";
            pps = connection.prepareStatement(sql);
            //4.执行sql
            result = pps.executeQuery();
            List students = new ArrayList();
            //1.得到数据库查询结果信息
            ResultSetMetaData metaData = result.getMetaData();//存储结果集信息
            int columnCount = metaData.getColumnCount();//得到列数
            String[] columnNames = new String[columnCount];
            for (int i=0;i<columnCount;i++){
                columnNames[i] = metaData.getColumnName(i+1);//列数从1开始
                System.out.println("columnName="+columnNames[i]);
            }
            //得到类中所有方法
            Method []declaredMethods = c.getDeclaredMethods();

            while(result.next()){
                Object student = c.newInstance();
                for (String columnName:columnNames) {
                    String methodName = "set"+columnName;
                    for (Method declaredmethod:declaredMethods) {
                        if(declaredmethod.getName().equalsIgnoreCase(methodName)){
                            declaredmethod.invoke(student,result.getObject(columnName));
                            break;
                        }
                    }
                }
                students.add(student);
            }
            return students;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } finally {
            try {
                if(result != null) {
                    result.close();
                }
                if(pps != null){
                    pps.close();
                }
                if(connection != null){
                    connection.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        return null;
    }
}

13、工具类的定义

把操作数据库过程中重复使用到的代码封装起来(其中方法的权限修饰符都是protected,因此Dao类可以通过继承该工具类而直接调用其中的方法)

import java.sql.*;
import java.util.List;

/**
 * @Author: xuliushen
 * @Description:
 * @Date Created in 2021-08-20 9:24
 * @Modified by :
 */
public class DBUtils {
    //1.定义变量
    private Connection connection = null;
    private PreparedStatement pps = null;
    private ResultSet resultSet = null;
    private int count;//存储受影响的行数

    private String username = "root";
    private String userPass = "123456";
    private String url = "jdbc:mysql://localhost:3306/kaikeba?serverTimezone=UTC";

    //2.加载驱动
    static {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }

    //3.获得链接
    protected Connection getConnection(){
        try {
            connection = DriverManager.getConnection(url,username,userPass);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return connection;
    }

    //4.获得预状态通道
    protected PreparedStatement getPps(String sql){
        try {
            pps = getConnection().prepareStatement(sql);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return pps;
    }

    //5.绑定参数 list保存的十给占位符所赋的值
    protected void param(List list){
        try {
            if(list!=null && list.size()>0){
                for (int i = 0; i < list.size(); i++) {
                    pps.setObject(i+1,list.get(i));
                }
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }

    //6.执行操作(增删改、查询)
    protected int update(String sql,List list){
        try {
            getPps(sql);
            param(list);
            count = pps.executeUpdate();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return count;
    }

    //7.查询
    protected ResultSet query(String sql,List list){
        try {
            getPps(sql);
            param(list);
            resultSet = pps.executeQuery();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return resultSet;
    }

    //8.关闭资源
    protected void closeAll(){
        try {
            if(connection != null){
                connection.close();
            }
            if(pps != null){
                pps.close();
            }
            if(resultSet != null){
                resultSet.close();
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }

}

 StudentDao:

import JDBC.util.DBUtils;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author: xuliushen
 * @Description:
 * @Date Created in 2021-08-20 8:30
 * @Modified by :
 */
public class StudentDaoImpl2 extends DBUtils implements StudentDao{
   
    @Override
    public Student getByStuid(int id) {
        Student student = new Student();
        try {
            String sql =  "select * from student where stuid=?";
            List list = new ArrayList();
            list.add(id);
            ResultSet rs = query(sql,list);
            while(rs.next()){
                student.setStuid(rs.getInt("stuid"));
                student.setStuname(rs.getString("stuname"));
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            closeAll();
        }
        return student;
    }
}

属性文件:properties 

方式一: 

 方式二:

14、连接池

14.1 自定义连接池

数据连接池原理
  • 在系统初始化的时候,将数据库连接作为对象存储在内存中。
  • 当用户需要访问数据库时,并非建立一个新的连接,而是从连接池中取出一个已建立的空闲连接对象。
  • 使用完毕后,用户也并非将连接关闭,而是将连接放回连接池中,以供下一个请求访问使用。
  • 连接的建立、断开都由连接池自身来管理。
  • 可以通过设置连接池的参数来控制连接池中的初始连接数、连接的上下限数以及每个连接的最大使用次数、最大空闲时间等等。
  • 可以通过其自身的管理机制来监视数据库连接的数量、使用情况等。
1.1 自定义连接池
我们可以通过自定义的方式实现连接池! 分析连接池类应该包含特定的属性和方法!
属性 : 集合 放置 Connection
方法 :
  • 获取连接方法
  • 回收连接方法
具体实现代码:
public class Pool{
    static LinkedList<Connection> list = new LinkedList<Connection>(); 
    static{ 
        for (int i = 0; i < 10; i++) { 
            Connection connection = JDBCUtils.newInstance().getConnection();               
            list.add(connection); } }/*** 从连接池子中获取连接的方式 * @return */ 
            public static Connection getConnection(){ 
                if (list.isEmpty()) { 
                    //JDBCUtils类是自定义类,封装了连接数据库的信息代码 
                    Connection connection = JDBCUtils.newInstance().getConnection(); 
                    list.addLast(connection); 
                }
                Connection conn = list.removeFirst(); 
                return conn; }

        
        /*** 返回到连接池子中 */ 
        public static void addBack(Connection conn){ 
                if (list.size() >= 10) { 
                    try {
                        conn.close(); 
                    } catch (SQLException e) { 
                        // TODO Auto-generated catch block 
                        e.printStackTrace(); 
                    } 
                }else{
                    list.addLast(conn); //10 } 
        }
    

        /*** 获取连接池子中连接数量的方法 */ 
        public static int getSize(){ 
            return list.size(); 
        } 
}
1.2 java 规范实现连接池
Java 为连接池实现提供了一个规范 ( 接口 ), 规范的写法 , 我们需要实现DataSource接口 !
但是实现 DataSource 接口有一个弊端 , 没有提供回收链接方法 ! 这里我们将使用装饰者模式 !
public class MyConnection implements Connection{
    //将被装饰者导入
    private Connection conn;
    private LinkedList<Connection> list;
    public MyConnection(Connection conn, LinkedList<Connection> list) {
        super();
        this.conn = conn;
        this.list = list;
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return conn.unwrap(iface);
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return conn.isWrapperFor(iface);
    }

    @Override
    public Statement createStatement() throws SQLException {
        return conn.createStatement();
    }

    @Override
    public PreparedStatement prepareStatement(String sql) throws SQLException {
        return conn.prepareStatement(sql);
    }

    @Override
    public CallableStatement prepareCall(String sql) throws SQLException {
        return null;
    }

    @Override
    public String nativeSQL(String sql) throws SQLException {
        return null;
    }

    @Override
    public void setAutoCommit(boolean autoCommit) throws SQLException {
    }

    @Override
    public boolean getAutoCommit() throws SQLException {
        return false;
    }

    @Override
    public void commit() throws SQLException {
        conn.commit();
    }

    @Override
    public void rollback() throws SQLException {
        conn.rollback();
    }

    @Override
    public void close() throws SQLException {
        list.addLast(conn);
    }
    ...
}
基于规范的连接池:
/**
 * 创建一个规范的连接池子
 */
public class DataSourcePool implements DataSource{
    static LinkedList<Connection> list = new LinkedList<Connection>();
    
    static{
        for (int i = 0; i < 10; i++) {
            Connection connection = JDBCUtils.newInstance().getConnection();
            list.add(connection);
        }
    }
   
    public static int getSize(){
        return list.size();
    }
  
    @Override
    public Connection getConnection() throws SQLException {
        Connection conn = list.removeFirst();
        MyConnection conn1 = new MyConnection(conn, list);
        return conn1;
    }
   
    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }
  
    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {
    }
    
    @Override
    public void setLoginTimeout(int seconds) throws SQLException {
    }
    
    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }
    
    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }
    
    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }
    
    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }
   
    @Override
    public Connection getConnection(String username, String password) throws
            SQLException {
        return null;
    }
}
最小连接数 :
是数据库一直保持的数据库连接数,所以如果应用程序对数据库连接的使用量不大,将有大量的数据库资源被浪费。
初始化连接数:
连接池启动时创建的初始化数据库连接数量。
最大连接数
是连接池能申请的最大连接数,如果数据库连接请求超过此数,后面的数据库连接请求被加入到等待队列中。
最大等待时间:
当没有可用连接时,连接池等待连接被归还的最大时间,超过时间则抛出异常,可设置参数为 0 或者负数使得无限等待( 根据不同连接池配置 )

1 : DBCP 连接池的配置中,还有一个 maxIdle 的属性,表示最大空闲连接数,超过的空闲连接将被释放,默认值为8 。对应的该属性在 Druid 连接池已不再使用,配置了也没有效果, c3p0 连接池则没有对应的属性。
2 :数据库连接池在初始化的时候会创建 initialSize 个连接,当有数据库操作时,会从池中取出一个连接。如果当前池中正在使用的连接数等于maxActive ,则会等待一段时间,等待其他操作释放某一个连接,如果这个等待时间超过了maxWait ,则会报错;如果当前正在使用的连接数没有达到
maxActive ,则判断当前是否空闲连接,如果有则直接使用空闲连接,如果没有则新建立一个连接。在连接使用完毕后,不是将其物理连接关闭,而是将其放入池中等待其他操作复用。

14.2 DBCP连接池

DBCP 是一个依赖 Jakarta commons-pool 对象池机制的数据库连接池。 DBCP 可以直接的在应用程序中使用,Tomcat 的数据源使用的就是 DBCP
2.1 DBCP 连接池的使用
2.1.1 导入相应 jar
  • mysql-jdbc.jar
  • commons-dbcp.jar
  • commons-pool.jar
2.1.2 硬编码使用 DBCP
  • 所谓的硬编码方式就是在代码中添加配置
    @Test
    public void testHard() throws SQLException{
        // 硬编码 使用DBCP连接池子
        BasicDataSource source = new BasicDataSource();
        //设置连接的信息
        source.setDriverClassName("com.mysql.jdbc.Driver");
        source.setUrl("jdbc:mysql://localhost:3306/kaikeba?serverTimezone=UTC");
        source.setUsername("root");
        source.setPassword("123456");
        Connection connection = source.getConnection();
        String sql = "select * from student";
        Statement createStatement = connection.createStatement();
        ResultSet executeQuery = createStatement.executeQuery(sql);
        while (executeQuery.next()) {
            System.out.println(executeQuery.getString(2));
        }
        connection.close(); //回收
    }
2.1.3 软编码使用DBCP
  • 所谓的软编码,就是在项目中添加配置文件,这样就不需要每次代码中添加配合!
①项目中添加配置
文件名称 : db.properties
文件位置 : src
#连接设置
driverclass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/kaikeba?serverTimezone=UTC
username=root
userPass=123456
#<!-- 初始化连接 -->
initialSize=20
# 最大连接数量
maxActive=50
#<!-- 最大空闲连接 -->
maxIdle=20
#<!-- 最小空闲连接 -->
minIdle=5
#<!-- 超时等待时间以毫秒为单位 6000 毫秒 /1000 等于 60 -->
maxWait=6000

②代码中读取配置文件 

    static {
        //DBCP
        ResourceBundle bundle = ResourceBundle.getBundle("db");
        driverName = bundle.getString("driverclass");
        username = bundle.getString("username");
        userPass = bundle.getString("userPass");
        url = bundle.getString("url");
        basicDataSource = new BasicDataSource();
        basicDataSource.setUsername(username);
        basicDataSource.setPassword(userPass);
        basicDataSource.setUrl(url);
        basicDataSource.setDriverClassName(driverName);
        basicDataSource.setInitialSize(20);
    }

    //3.获得链接
    protected Connection getConnection(){
        try {
            //DBCP
            connection =  basicDataSource.getConnection();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return connection;
    }

14.3 C3P0连接池

 c3p0 是一个开放源代码的 JDBC 连接池,它在 lib 目录中与 Hibernate 一起发布 , 包括了实现 jdbc3
jdbc2 扩展规范说明的 Connection Statement 池的 DataSources 对象。
c3p0 dbcp 区别:
  • dbcp没有自动回收空闲连接的功能
  • c3p0有自动回收空闲连接功能
  • dbcp需要手动设置配置文件
  • c3p0不需要手动设置
3.1 实现方式
1 . 手动设置 ComboPooledDataSource
2 加载配置文件方式
src/c3p0-config.xml (文件名固定)
ComboPooledDataSource cpds = new ComboPooledDataSource();
加载 文件中 <default-config> 中的配置
ComboPooledDataSource cpds = new ComboPooledDataSource("aaa");
加载 <named-config name="aaa"> 中的配置
3.2 实现步骤
3.1.1 导入 jar
c3p0-0.9.1.2.jar
mysql-connector-java-5.0.8.jar
3.1.2. 添加配置文件
c3p0 是在外部添加配置文件 , 工具直接进行应用 , 因为直接引用 , 所以要求固定的命名和文件位置
文件位置 : src
文件命名 :c3p0-config.xml/c3p0-config.properties
<?xml version="1.0" encoding="utf-8"?>
<c3p0-config>
    <!-- 默认配置,如果没有指定则使用这个配置 -->
    <default-config>
        <!-- 基本配置 -->
        <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/kaikeba?serverTimezone=UTC</property>
        <property name="user">root</property>
        <property name="password">123456</property>
        <!--扩展配置-->
        <!-- 连接超过30秒报错-->
        <property name="checkoutTimeout">30000</property>
        <!--30秒检查空闲连接 -->
        <property name="idleConnectionTestPeriod">30</property>
        <property name="initialPoolSize">10</property>
        <!-- 30秒不适用丢弃-->
        <property name="maxIdleTime">30</property>
        <property name="maxPoolSize">100</property>
        <property name="minPoolSize">10</property>
        <property name="maxStatements">200</property>
    </default-config>
</c3p0-config>

代码:

    static {
        //C3P0
        comboPooledDataSource =  new ComboPooledDataSource();
    }

    //3.获得链接
    protected Connection getConnection(){
        try {
            //C3P0
            connection = comboPooledDataSource.getConnection();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return connection;
    }

14.3 Druid连接池

阿里出品,淘宝和支付宝专用数据库连接池,但它不仅仅是一个数据库连接池,它还包含一个
ProxyDriver (代理驱动),一系列内置的 JDBC 组件库,一个 SQL Parser(sql 解析器 ) 。支持所有 JDBC 兼容的数据库,包括Oracle MySql Derby Postgresql SQL Server H2 等等。
Druid 针对 Oracle MySql 做了特别优化,比如 Oracle PS Cache 内存占用优化, MySql ping 检测优化。
Druid 提供了 MySql Oracle Postgresql SQL-92 SQL 的完整支持,这是一个手写的高性能 SQL Parser,支持 Visitor 模式,使得分析 SQL 的抽象语法树很方便。
简单 SQL 语句用时 10 微秒以内,复杂 SQL 用时 30 微秒。
通过 Druid 提供的 SQL Parser 可以在 JDBC 层拦截 SQL 做相应处理,比如说分库分表、审计等。 Druid 防御SQL 注入攻击的 WallFilter 就是通过 Druid SQL Parser 分析语义实现的。
Druid 是目前比较流行的高性能的,分布式列存储的 OLAP 框架 ( 具体来说是 MOLAP) 。它有如下几个特点:
. 亚秒级查询
druid 提供了快速的聚合能力以及亚秒级的 OLAP 查询能力,多租户的设计,是面向用户分析应用的理想方式。
. 实时数据注入
druid 支持流数据的注入,并提供了数据的事件驱动,保证在实时和离线环境下事件的实效性和统一性
. 可扩展的 PB 级存储
druid 集群可以很方便的扩容到 PB 的数据量,每秒百 万级别的数据注入。即便在加大数据规模的情况下,也能保证时其效性
. 多环境部署
druid 既可以运行在商业的硬件上,也可以运行在云上。它可以从多种数据系统中注入数据,包括
hadoop spark kafka storm samzaji
4.1 使用步骤
4.1.1 导入 jar
4.1.2 编写工具类
static {
    //德鲁伊
    ResourceBundle bundle = ResourceBundle.getBundle("db");
    driverName = bundle.getString("driverclass");
    username = bundle.getString("username");
    userPass = bundle.getString("userPass");
    url = bundle.getString("url");
    druidDataSource = new DruidDataSource();
    druidDataSource.setUsername(username);
    druidDataSource.setPassword(userPass);
    druidDataSource.setUrl(url);
    druidDataSource.setDriverClassName(driverName);
}

//3.获得链接
protected Connection getConnection(){
    try {
        //德鲁伊
        connection = druidDataSource.getConnection();
    } catch (SQLException throwables) {
        throwables.printStackTrace();
    }
    return connection;
}
: Druid 连接池的配置中, driverClassName 可配可不配,如果不配置会根据 url 自动识别 dbType( 数据库类型) ,然后选择相应的 driverClassName
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hnu哈哈

请接受直女的么么哒????

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值