Unit_1 -- Java 应用程序开发
# Part_3
First : 数据库基本概念
01:数据库概念
1.1:概念 和 数据库的种类
数据库(Database) 是存储和管理数据的仓库
种类:
①:关系型数据库(RDBMS):Excel ; Oracle , MySql, SqlServer , sybase;
②:非关系型数据库:mangoDB, redis , Hbase
③:MySql 是最流行的关系型数据库管理系统
1.2:关系型数据库的特点
Ⅰ:关系模型指的就是二维表格模型,而一个关系型数据库就是由二维表及其之间的联系所组成的;
Ⅱ:关系型数据库强调 ACID(原子性、一致性、隔离性、持久性)规则;
Ⅲ:关系型数据库按照结构化的方法存储数据,每个数据表都必须对各个字段定义好,再根据表的结构存入数据;
Ⅳ:多干行和列组成一张表;
Ⅴ:若干表组成database
1.3:数据库里的一些关键词
1.3.1 :创建用户 create user;
---实现 sql 举例:create user test@localhost Identified by '123' : 创建用户test 并指定密码123;
1.3.2:删除用户 drop user;
---实现 sql 举例:drop user test; 删除用户test;
1.3.3:为用户添加权限 grant 权限 on 数据库,数据表 to '用户' @'主机名'
---实现 sql 举例:
grant select, insert , update , delete on dbtest.employee to test@localhost identified by '123';
//给来自 localhost 的用户test 分配可对数据库 dbtest 的employee 表进行select, insert , update , delete 等权限的操作,并设定口令为 123;
1.3.4:创建数据库 create database dbTest;
1.3.5:查看数据库 show database dbTest;
1.3.6:使用数据库 use dbTest;
1.3.7:删除数据库 drop database dbTest;
1.3.8:其他关键字
表(table),模式(schema),而表里又有:列(column),行(row),数据类型(datatype),主键(primary key)
1.4 :表
表 是一种结构,就相当于现实生活中所见的表格,其中一列用来代表一个属性,属性由不同的数据类型来定义;其中关键的一列叫做主键,主键属性的每一个值都需要是独一无二的不能重复,而每一行就是各个列属性的实例,好比Java中的类属性
学号 | 姓名 | 性别 | 籍贯 | 专业 |
---|---|---|---|---|
20241001 | 张三 | 男 | 北京 | 语文 |
20241002 | 李四 | 女 | 上海 | 英语 |
20241003 | 王五 | 男 | 广州 | 物理 |
那么在这张表中,学号是独一无二不能重复的,因此设为主键;
其余列属性分别为姓名,性别,籍贯,专业,这些是可以重复的
主键的值不能为空,不能重复
02:数据库三大范式
2.1:范式
范式:构建数据库,必须满足已定的规则,在关系型数据库中,这种规则称之为范式;目前关系型数据库有 六种范式,比较常见的是前三个范式!
2.2:第一范式
第一范式(1NF):是指数据库表中的每一列都是不可分割的基本数据项,同一列不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性;
简而言之:第一范式就是没有重复的列,比如一张表中有进货、销售两个列,这两个列都可以拆分为有数量、单价的列,这样的话,表中就存在重复字段,第一范式的规则是不允许的;
2.3:第二范式
第二范式(2NF):要求实体的属性完全依赖于主键。所谓完全依赖是指:不能存在仅依赖主键一部分的属性,如果存在,那么这个属性和关键字的这一部分应该分离出来形成一个新的实体,新实体和原实体之间是一对多的关系;
为实现区分通常需要为表加上一个列,以存储各个实例的唯一标识;例如:员工信息表中加上了员工编号(emp_id) 列,因为每个员工的员工编号都是唯一的,因此每个员工可以被唯一区分,这个唯一属性列被称之为主键关键字或者主键、主码;
简而言之:第二范式就是属性完全依赖于主键
注意事项:
第二范式(2NF) 是在第一范式(1NF)的基础之上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)
2.4:第三范式
第三范式(3NF):要求一个数据库表中不包含已在其他表中已包含的非主关键字的信息:
例如:存一个部分信息表中,其中每个部分有部门编号(dept_id)、部门名称,部门简介等信息,那么员工信息表中列出部分编号后就不能再将部门名称,部门简介等与部门相关的信息存入员工信息表中
注意事项:
第三范式(3NF)是在第二范式(2NF)的基础上建立起来的,即满足第三范式(3NF)必须先满足第二范式(2NF)
03:E-R 图
3.1:E-R图
ER图:概念模型是对信息世界的建模,所以概念模型能够方便、准确的表示信息世界中的常用概念,称之为“实体-联系模型”;
3.2:E-R模型
E-R模型是软件工程设计中的一个重要方法,在数据库设计中,常用 E-R 模型来描述现实世界 到 信息世界的问题
①:实体(Entity):在 E-R 图中实体用矩形表示,通常在矩形框内写明实体名;
②:联系(Relationship):在 E-R 模型中,联系用菱形表示;
③:属性:在 E-R 模型中,使用椭圆形表示。
Second:数据库 SQL 语句开发
01:单表增删改查
1.1:SQL 语句有称为结构化查询语句,SQL 语言分为四大类
①:数据定义语言:简称 DDL(Data Definition Language)
②:数据操作语言:简称 DML(Data Manipulation Language)-->主要针对表
③:数据控制语言:简称 DCL(Data Control Language)
④:数据查询语言:简称 DQL(Data Query Language)
1.2:DDL 语言命令
CREATE 创建; 比如:创建数据库、创建表、创建索引;
create database 数据库名称;
create table 表名称;
create index 索引名称;
ALTER 修改; 比如修改表、修改表里面的字段等等;
alter table ...
alter database 数据库名称 character set gbk; 修改字符编码
DROP 删除; 比如:删除表、drop table 表名
删除数据库 drop database 数据库名称
// DDL 语言创建 Department Emploree 表结构
CREATE TABLE 'department' ( //---> department 部门表
'sn' char(5) NOT NULL,
'name' varchar(20) DEFAULT NULL,
'address' varchar(100) DEFAULT NULL,
PRIMARY KEY('sn')
)
//---> 创建 employee 员工表
CREATE TABLE 'employee' (
'sn' char(5) NOT NULL,
'password' varchar(20) DEFAULT NULL,
'name' varchar(20) DEFAULT NULL,
'department_sn' char(5) DEFAULT NULL,
'post' varchar(20) DEFAULT NULL,
'salary' double(15,2) DEFAULT NULL,
PRIMARY KEY('sn'), //主键
KEY 'FK_Reference_1'('department_sn'),
CONSTRAINT 'FK_Reference_1' FOREIGN KEY ('department_sn') REFERENCES 'department' ('sn') //外键约束
)
1.3:单表的增删改查
DML 语言命令(增/删/改):
INSERT:插入; insert table user values (数据1 , 数据2);
insert into 'department' calues ('001' , '开发' , ‘中关村’);
UPDATE:更新/修改; update 表名 set name = 'zhangsan';
DELETE:删除; delete from 表名;
DCL 语言命令:
GRANT :赋权限;
COMMIT:提交;
ROLLBACK:回滚;
DQL 语言语法(查):
SELECT 查询
select * from 表名 where 条件;
02:order by 和 group by
2.1:排序
在 SQL 语句中,对表数据进行按照某一个字段或者一些字段进行正序和倒序排序时使用 order by ;
//人事查询员工按照薪资正/倒序排列
//asc 是正(升)序排列 -- 关键字默认可以不写
select * from employee e order by e.salary asc;
//desc 是倒叙排列,关键字必须写
select * from employee e order by e.salary desc;
//** 注意的是:如果是按照多个字段排序,中间使用逗号作为分隔,按照字段顺序先后排序;
2.2:分组
在 SQL 语句中,对表数据进行按照某一个字段或者一些字段进行归类分组,使用 group by;
//人事想要查看 employee 表中部门编号信息,使用 group by 进行分组
select e.department_sn from employee e group by e.department_sn;
需要注意的是:
查询的信息内容必须是与部门 sn 相关的信息内容,不能查询员工信息的内容,不然会出错,比如:select e.department_sn , name 这个 name 是员工名称,不能按照部门分组再查询
错误信息:查询的列不是再分组子句子句中,并且包含非聚合的列(project.e.name),这与sql_mode = only_full_group_by 不符合;
解决方案:修改 my.ini(win10 mysql7的配置文件),将 only_full_group_by 策略去掉
//分组查询案例语句
select e.department_sn , sum(e.salary) from employee e GROUP BY e.department_sn;
2.3:order by 和 group by
employee 表中按照部门编号分组,查询出只有部门编号为 3 的;
在分组后加 having 代表对分组后的数据进行条件筛选;
select e.department_sn from employee e group by e.department_sn having e.department_sn=3;
注意:如果一条 sql 语句中 有 where 、order by、group by having 同时存在,按照where 、group by having 、order by 这样的顺序来
03:聚合函数和分页
3.1:常用的聚合函数
AVG(字段名) : 返回指定列的平均值;【例如:select avg (SAL) from t_student;】
COUNT(col):返回指定列中非 NULL 值的个数;【例如:select count(*) from t_student;】
MIN(col):返回指定列中的最小值;【例如:select min(SAL) from t_student;】
MAX(col):返回指定列中的最大值;【例如:select max(SAL) from t_student;】
SUM(col):返回指定列的所有值之和;【例如:select sum(SAL) from t_student;】
*
CHAR_LENGTH(字段名):来计算字符串中字符的个数;
length(字段名) : 根据字段名的长度计算
*
注意事项:
聚合函数经常和 group by 联用,获取分组后的最大、最小、总数、数据量、平均数等信息;
//聚合函数 sum() ,人事统计各个部门薪资总和
select e.department_sn, sum(e.salary) from employee e group by e.department_sn;
//聚合函数 count(),统计员工总数 (注意:使用count(1)或者count(*)皆可)
select count(1) from employee;
//聚合函数 max() , 统计各部门薪资最高的薪资
select e.department_sn, max(e.salary) from employee e group by e.department_sn;
3.2:MySQL 的分页关键字 limit
select * from employee limit 0,2
0:代表起始索引值(第几条数据开始取);
2:代表每页显示的条数
*
*
select * from employee limit 3,2
3:代表起始索引值
2:代表每页展示条数
04:连接查询
连接查询是建立在夺标关联查询的情况下使用,MySQL 中的连接查询包含 左连接(left join)、右连接(right join)、内连接(inner join)、全外连接
//inner join..on 内连接,查询员工和部门连接信息
select * from enoloyee e inner join department d on e.department_sn=d.sn;
4.1:内连接
inner join (内连接/等值连接):获取两个表中字段匹配关系的记录,on 代表通过关联字段建立连接关系
4.2:外连接
4.2.1:左连接
LEFT JOIN (左连接) :left join...on
获取左表所有记录,即使右表没有对应匹配的记录。
注意:where 条件写在连接 on 后
//
select * from employee e left join department d on e.department_sn=d.sn;
4.2.2:右连接
右连接 right join...on
right join (右连接):与 left join 相反,用于获取右表所有记录,即使左表没有对应匹配的记录。
//
select * from employee e right join department d on e.department_sn=d.sn;
4.3: union 和 union all
MySQL UNION 操作符用于连接两个以上的 SELECT 语句的结果组合到一个结果集合中,多个 select 语句会删除重复的数据
Union 会删除重复的数据;Union all 会展示全部的数据,没有排序
Third:数据库索引开发
01:索引的分类
1.1:索引的概念
在关系数据库中,索引是一种与表有关的数据库结构,它可以使对应的表的 SQL 语句执行的更快
索引的作用:
①:索引相当于图书的目录,可以根据目录中的页码快速找到所需的内容;
②:对于数据来说,索引不是一个必选项,但是对于现在的各种大型数据库来说,索引可以大大提高数据库的性能,以至于它编程了数据库中不可缺少的一部分
索引的分类:
根据数据与索引的存储关联性,可以分为聚簇索引 和 非聚簇索引(也叫做聚集索引 和 非聚集索引)
1.2:聚簇索引
表数据是按照索引的顺序来存储的,也就是说索引项的顺序与表中记录的物理顺序一致。聚簇索引就是按照每一张表的主键构造一棵 B+ 树,同时:叶子节点中存放的是整张表的行记录数据,所以,也就将聚簇索引的叶子节点称之为数据页;
注意事项:在一张表上最多只能创建一个聚簇索引;
1.3:非聚簇索引
表数据存储顺序与索引顺序无关。对于非聚簇索引,叶子节点包含索引字段值及指向数据页数据行的逻辑指针,其行数量与表行数据量一致
1.4:聚簇索引 和 非聚簇索引的区别
动作描述 | 使用聚簇索引 | 使用非聚簇索引 |
---|---|---|
列经常被分组排序 | 使用 | 使用 |
返回某范围内的数据 | 使用 | 不使用 |
一个或极少不同值 | 不使用 | 不使用 |
小数目的不同值 | 使用 | 不使用 |
大数目的不同值 | 不使用 | 使用 |
频繁更新的列 | 不使用 | 使用 |
外键列 | 使用 | 使用 |
主键列 | 使用 | 使用 |
频繁修改的索引列 | 不使用 | 使用 |
小结:聚簇索引不适用于频繁更新的列,频繁修改的索引列和小数目的不同值;
02:索引的作用
举例说明:
1:若没有索引,(例如:查找 name=‘张三’)需要全表逐一查找,如果符合 就输出该记录;如果不符合就看下一个;
2:在 name 上建立索引,MySQL 会使用简单的平衡二叉树结构通过进行比对能够快速定位查询 name 为‘张三’ 的数据;
3:表中数据很少时使用全表扫描速度已经很快了,没有必要使用索引。
注意事项:
①:不是创建了索引就是好的,因为创建索引需要占用物理空间;
②:当对表中的数据进行增加、删除和修改的时候,索引也需要动态的维护,降低维护效率;
③:维护索引会随着数据的增加,消耗的时间也会越高;
2.1:创建索引 --- 索引的使用
2.1.1:单一索引
单一索引是指:索引列为一列的情况,即 新建索引的语句指实施在一列上。
//单一索引
create index cs_index1 on cstable(id);
2.1.2:复合索引
用户可以在多个列上建立索引,这种索引也叫做复合索引(组合索引)
// 复合索引
create index cs_index2 on cstable(id, sex);
2.1.3:函数索引
//函数索引
create index upper_index3 on cstable(upper(name));
2.1.4:删除和修改索引
//a: 重建索引:如果经常在索引列上执行 DML 操作,需要定期重建索引
alter index cs_index1 rebuild;
//b:删除索引
drop index cs_index2;
2.2:索引的使用
2.2.1:什么字段可以使用索引
①:大表,返回的行数 <5%;
②:经常使用 where 子句查询的列;
③:离散度高的列;
④:更新键值代价低。
2.2.2:注意事项:什么时候创建索引
Ⅰ:where 从句频繁使用的关键字;
Ⅱ:SQL 语句中频繁由于进行表连接的关键字;
Ⅲ:可选择性高(重复性少)关键字;
Ⅳ:对于取值较少的关键字或表达式,不要采取标准的 B 树索引,可以考虑建立位图索引;
Ⅴ:不要将那些频繁修改的列作为索引列;
Ⅵ:不要使用包含操作符 或 函数的 where 从句中的关键字作为索引列,如果需要的话,可以考虑建立函数索引;
Ⅶ:如果大量并发的 insert 、update、delete 语句访问了父表或子表,则考虑使用完整性约束的外部键作为索引;
Ⅷ:在选择索引列时,还要考虑索引引起的 insert 、update、delete 操作是否值得。
03:索引失效
Fourth:JDBC 连接数据库开发
01:JDBC连接数据库
1.1:JDBC 的概念
JDBC 全称为:Java 数据库连接(Java DataBase Connectivity),可以为不同数据库提供统一的访问;
JDBC 的作用:JDBC 是一组用 Java 编程语言编写的类及接口的组成;利用 JDBC 可以将 Java 代码连接到 Oracle、SQLServer、MySQL 等数据库,从而实现对数据库中的数据操作的目的。
JDBC 的主要功能:①:建立与数据库或其他数据源的连接;②:想数据库发送 SQL 命令;③:处理数据库的返回结果;
1.2:JDBC 中常用的类和接口
名称 | 功能说明 |
---|---|
驱动程序管理类 (DriverManager) | DriverManager 类是 JDBC 的管理类,作用域用户和驱动程序之间,通过 getConnection() 方法可以建立连接; |
Connection 接口 | Connection 接口代表与数据库的连接,一个应用程序可以与单个数据库右一个或多个连接,或者可以与多个数据库有连接 |
Statement 接口 | Statement 接口用于u已经建立数据库连接的基础上向数据库发送 SQL 语句 |
PreparedStatement 接口 | PreparedStatement 接口用来动态执行 SQL 语句,通过 PreparedStatement实例执行的动态 SQL 语句,将被编译并保存到 PreparedStatement 实例中。 |
ResultSet 接口 | ResultSet 接口类似于一个临时表,用来临时存放数据库查询操作所获得的结果集 |
注意事项:
①:Statement 每次执行 SQL 语句,相关数据库都要执行 SQL 语句的编译!
②:PreparedStatement 预编译,PreparedStatement 支持批处理,执行多条 SQL语句时,PreparedStatement效率会更高;
1.2.1:驱动程序管理类(DriverManager) 常用方法
NO. | 方法 | 功能描述 |
---|---|---|
1 | getConnection(String url,String user,String password) | 指定三个入口参数(数据库的 URL、用户名、密码)来获取与数据库的连接; |
2 | setLoginTimeout() | 获取驱动程序试图登录到某一数据库时可以等待的最长时间,单位为秒 |
1.2.2:Connection 常用方法
NO. | 方法 | 功能描述 |
---|---|---|
1 | createStatement() | 创建 Statement 对象 |
2 | preparedStatement(String sql) | 创建预处理对象 PreparedStatement t,可以将 SQL 当作参数 |
3 | commit() | 使所有上一次提交/回滚后进行的更改称为持久更改,并释放 Connection 对象当前持有的所有数据库锁 |
4 | rollback() | 取消在当前事务中进行的所有更改,并释放此 Connection 对象当前持有的所有数据库锁 |
5 | close() | 立即释放此 Connection 对象的数据库和 JDBC 资源,而不是等待它们被自动释放 |
注意事项:
commit() 方法保存自上次提交以来所做的所有修改,在提交之后发生任何问题,使用rollback() 回滚事务;
close() 方法的调用用于进行资源的释放,否则连接会一直存在,这样会占用 JDBC 的资源
1.2.3:Statement 接口常用方法
NO. | 方法 | 功能描述 |
---|---|---|
1 | execute(String sql) | 执行静态的 select 语句,该语句可能返回多个结果集 |
2 | executeQuery(String sql) | 指定给定的 SQL 语句,该语句返回多个 ResultSet 对象 |
3 | executeUpdate(String sql) | 执行给定的 SQL 语句,这可能是一个 insert、update、delete语句或SQL语句不反悔值 |
4 | close() | 立即释放 Connecton 对象的数据库和 JDBC资源,而不是等待它们被自动释放 |
注意事项:
execute() 方法可执行增删改任何操作,但是返回的结果是 Boolean 值,使用的不多
1.2.4:PreparedStatement 接口常用方法
NO. | 方法 | 功能描述 |
---|---|---|
1 | setInt(int index,int k) | 将指定位置的参数设置为 int 值 |
2 | setString(int index,String s) | 将指定位置的参数设置为对应的 String 值 |
3 | setDouble(int index,double k) | 将指定位置的参数设置为 double 值 |
4 | executeQuery() | 在此 PreparedStatement 对象中执行 SQL 查询,并返回该查询生成的 ResultSet 对象 |
5 | executeUpdate() | 执行前面包含的参数的动态 insert、update、delete 语句 |
6 | close() | 立即释放 Connecton 对象的数据库和 JDBC资源,而不是等待它们被自动释放 |
1.2.5:ResultSet 接口常用方法
NO. | 方法 | 功能描述 |
---|---|---|
1 | getInt() | 以 int 形式获取此 ResultSet 对象的当前行的 指定列值;如果列值是 null 则返回值是 0; |
2 | getString() | 以 String 形式获取此 ResultSet 对象的当前行的指定列值;如果是 null ,则返回值是 null |
3 | getDouble() | 以 double 形式获取此 ResultSet 对象的当前行的指定列值 |
4 | next() | 将指针向下移一行 |
1.3:JDBC 编程步骤
1.3.1:加载驱动程序
Class.forName(driverClass)
//加载 MySQL 驱动
Class.forName("com.mysql.jdbc.Driver");
1.3.2:获得数据库连接
//获得数据库连接
DriverManager.getConnection(URL, user, password);
DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/student", user, password);
参数1 | 要连接数据库的 URL | String url = "jdbc:mysql://localhost:3306/student?"+"useUnicode=true&characterEncoding=UTF8"; //防止乱码 |
---|---|---|
参数2 | 要连接数据库的用户名 | String user = "root"; |
参数3 | 要连接数据库的密码 | String pass = "123456"; |
参数 1 中的解释 | |
---|---|
jdbc | 这是协议以 jdbc 开头 |
Mysql | 这是子协议,数据库管理系统名称 |
//localhost | 数据库来源地址 |
:3306 | 目标端口 |
/student | 要查询的数据库 |
useUnicode=true&characterEncoding=UTF8 | 添加这个是为了防止乱码,指定使用 Unicode 字符集,且使用 UTF-8 来编辑 |
1.3.3:创建 Statement 对象:conn.createStatement()
// 创建 Statement 对象
// Statement 和 PreparedStatement 对象的区别:后者可以动态设置查询参数
Statement stmt = conn.createStatement();
PreparedStatement pstmt = conn.PreparedStatement()
1.3.4:向数据库发送 SQL 命令
//向数据库发送 SQL 命令
ResultSet rs = stmt.executeQuery(sql);
1.3.5:处理数据库返回的结果(ResultSet类)
// 处理返回结果
while(rs.next()){
rs.getInt(columnIndex); //通过列的序号来获取字段的值
rs.getString(columnName); //通过列的名字来获取字段的值
}
1.3.6:关闭资源
操作完成后要关闭 jdbc 来释放 JDBC 的资源
rs.close();
pstmt.close();
conn.close();
依次关闭
/*
* JDBC 代码实现
*/
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class DBUtil {
private static final String URL = "jdbc:mysql://127.0.0.1:3306/"
+ "jspdb?useUnicode=true&characterEncoding=utf8&useSSL=false";
private static final String NAME = "root";
private static final String PASSWORD="root";
public static void main(String[] args) throws Exception {
//1.加载驱动程序(mysql 8.0以上版本)
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获得数据库连接
Connection conn = DriverManager.getConnection(URL,NAME,PASSWORD);
//3.通过数据库连接操作数据库,实现增删改查
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select goods_name,goods_price from goods");
//如果对象中有数据,就会循环打印出来
while(rs.next()) {
System.out.println(rs.getString("goods_name")+","+rs.getInt("goods_price"));
}
}
}
1.4:JDBC 事务提交
①:setAutoCommit(boolean b)
// 设置是否自动提交事务,true 为自动提交,false 为不自动提交;
conn.setAutoCommit(true);
②:commit() 提交事务
conn.commit();
③:rollback() 回滚事务
conn.rollback();