目录
一、Mysql初级
1、数据库简介
1.1 简介
数据库(DataBase,DB
):指长期保存在计算机的存储设备上,按照一定规则组织起来,可以被各种用户或应用共享的数据集合。
数据库管理系统(DataBase Management System,DBMS
):
- 指一种操作和管理数据库的大型软件,用于建立、使用和维护数据库,对数据库进行统一管理和控制,以保证数据库的安全性和完整性。
- 用户通过数据库管理系统访问数据库中的数据。
- 数据库软件应该为数据库管理系统,数据库是通过数据库管理系统创建和操作的。
数据库:存储、维护和管理数据的集合
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是一个满足第一范式条件的关系模式,X是R的任意属性集,如果X非传递依赖于R的任意一个候选关键字,称R满足第三范式,简记为3NF. 满足
第三范式( 3NF )必须先满足第二范式( 2NF )。 第三范式( 3NF )要求一个数据库表中不包含已在其 它表中已包含的非主关键字信息。注:关系实质上是一张二维表,其中每一行是一个元组,每一列是一个属性第二范式( 2NF )和第三范式( 3NF )的概念很容易混淆,区分它们的关键点在于,2NF :非主键列是 否完全依赖于主键,还是依赖于主键的一部分;3NF :非主键列是直接依赖于主键,还是直接依赖于非 主键列。
1.4 Mysql的卸载和安装
1.4.1
安装
步骤
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# 服务端使用的字符集默认为 UTF8character-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=3306default-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
)采纳为关系数据库语言的国际标准。
- 各数据库厂商都支持ISO的SQL标准,普通话
- 各数据库厂商在标准的基础上做了自己的扩展,方言
SQL 是一种标准化的语言,它允许你在数据库上执行操作,如创建项目,查询内容,更新内容,并删除条目等操作。
Create, Read, Update, and Delete 通常称为
CRUD
操作。
2.2 SQL语句分类
- DDL(Data Defifinition Language):数据定义语言,用来定义数据库对象:库、表、列等。
alter user 'root'@'localhost' identified with mysql_native_password BY '新密码
';
alter user 'root'@'localhost' identified with mysql_native_password BY '123456';
- DML(Data Manipulation Language):数据操作语言,用来定义数据库记录(数据)增删改。
- DCL(Data Control Language):数据控制语言,用来定义访问权限和安全级别。
- DQL(Data 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 intcardnum 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 列名 =''注 : 两个单引号表示空字符串日期类型值的区别 :
- date:yyyy-MM-dd (年月日)
- time:hh: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
数据类型
①数值类型:
②日期类型:
- 表示时间值的日期和时间类型为DATETIME、DATE、TIMESTAMP、TIME和YEAR。
- 每个时间类型有一个有效值范围和一个"零"值,当指定不合法的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 表 1inner join 表 2 on 表 1. 列名 = 表 2. 列名inner join 表 3 on 表 1 或表 2. 列名 = 表 3. 列名 where
等价于
:
select 列名 from 表 1, 表 2, 表 3where 表 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 表 1inner 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 swhere 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、数据库优化
- 对查询进行优化,要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引
- 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:select id from t where num is null 。最好不要给数据库留NULL,尽可能的使用 NOT NULL填充数据库. 备注、描述、评论之类的可以设置为 NULL,其他的,最好不要使用NULL。
- 应尽量避免在 where 子句中使用 != 或 <> 操作符,否则引擎将放弃使用索引而进行全表扫描。
- 应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num=10 or Name = 'admin
可以这样查询:
select id from t where num = 10union allselect 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 事务的语法
- start transaction; begin;
- commit; 使得当前的修改确认
- 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
。
- 连接数据库。
- 创建SQL或MySQL语句。
- 在数据库中执行SQL或MySQL查询。
- 查看和修改生成的记录
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_nameSET column_name = value, column_name = value, ...WHERE conditions;
WHERE
子句可以使用比较运算符,例如
=
,!
=
,
<
,
>
,
<=
和
> =
,以及
BETWEEN
和
LIKE
运算符。
⑧DELETE
语句用于从表中删除数据。
SQL> DELETE FROM table_name WHERE conditions;
WHERE子句可以使用比较运算符,例如=,!=,<,>,<=和> =,以及BETWEEN和LIKE运算符。
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(); 注册驱动程序最常见的方法是使用Java的Class.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()
方法:
- getConnection(String url)
- getConnection(String url,Properties prop)
- getConnection(String url,String user,String 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 execute(String SQL):如果可以检索到ResultSet对象,则返回一个布尔值true; 否则返回false。使用此方法执行SQL DDL语句或需要使用真正的动态SQL时。
- int executeUpdate(String SQL):返回受SQL语句执行影响的行数。使用此方法执行预期会影响多个行的SQL语句,例如INSERT,UPDATE或DELETE语句。
- ResultSet executeQuery(String 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();
}
对比statement和PreparedStatement
(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语句insert、update或delete
- 前一个事务结束后,又输入了另一条DML语句
事务结束于
- 执行commit或rollback语句。
- 执行一条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
对象有两种新的方法来帮助您管理保存点
- setSavepoint(String savepointName):定义新的保存点。它还返回一个Savepoint对象。
- releaseSavepoint(Savepoint 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.Driverurl=jdbc:mysql://localhost:3306/kaikeba?serverTimezone=UTCusername=rootuserPass=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
。