数据库
观察现实生活,大大小小的软件应用最基本都会有用户数据的存储。再说的大一点,不都说当今社会是一个数据流量为王的时代。
通过上学期对java面向对象语言的学习,我们来思考两个问题?
1.不使用数据库,我们要如何展开对数据的操作呢?(增删改查)
相信大家肯定马上就想到Java中的序列化
ObjectOutputStream -> Java对象 -> 序列化到文件当中。 (一顿操作猛虎如,结果是真虎。)
1.1序列化的步骤(写入)
第一步:创建FileOutputStream,FileOutputStream把字节写入文件
FileOutputStream fs = new FileOutputStream("foo.ser”);\\如果文件footsore不存在,会自动创建该文件
第二步:创建ObjectOutputStream,ObjectOutputStream把对象转换成可以写入串流的数据
ObjectOutputStream os = new ObjectOutputStream(fs);\\fs是一个FileOutputStream对象
第三步:写入对象,ObjectOutputStream调用writeObject方法把对象打成串流送到FileOutputStream来写入文件
os.writeObject(myBox);\\myBox必须是一个实现了Serializable接口的类,是可以序列化的
第四步:关闭ObjectOutputStream
os.close();\\关闭所关联的输出串流
1.2反序列化的步骤(读出:还原对象)
第一步:创建FileInputStream,读取文件字节,如果文件不存在会抛出异常
FileInputStream fileStream = new FileInputStream("foo.ser”);\\如果文件不存在,会抛出异常
第二步:创建ObjectInputStream,将自己转换成对象的stream
ObjectInputStream os=new ObjectInputStream(fileStream);
第三步:读取对象,会按照os.writeObject(xx)存储的顺序读取,与写入顺序相同
Object one=os.readObject();Object two=os.readObject();
第四步:转换对象类型。默认返回的是Object类型,需要强转换为存储时的类型
GamecCharacter test1=(GameCharacter) one;GamecCharacter test2=(GameCharacter) two;
第五步:关闭ObjectInputStream
os.close();
1.3小结
上述操作对数据的操作当然是可行的,但是回看我们最原始的需求,我们仅仅只是想读取数据,还没涉及到对数据“真正的操作”(需要动脑设计表等等...),对此,如何进行高效的数据管理,提出了数据库技术。
可得好处:
- 方便、高效(最直观的感受)
- 数据应用效率高
这里所提到的数据库技术 ≠ 数据库。
1.4 数据库技术
**数据:1.**描述事物的符号记录_(Eg: 网页上看到卖家秀:图片。)_
2.是数据库存储的基本对象。(这个概念结合上面那波 new java对象 read对象 write对象)
数据库:是长期储存在计算机内、有组织的、可共享的大量数据的集合。(可以理解为对象的集合)
数据库和数据:数据库中的数据是按一定的数据模型组织、描述和储存的,具有较少的冗余度、较高的数据独立性和易拓展性,可为各种用户共享。数据库实际上在硬盘上以文件的形式存在。
数据库管理系统:是用户和操作系统之间的一层数据管理软件。
目的:为了科学地组织和存储数据、高效地获取和维护数据。
主要功能:数据定义、数据组织存储和管理、数据操纵、数据库的事务管理和运行管理、数据库的建立和维护功能...(具体点,它负责去执行sql语句,通过执行sql来操作数据库中的数据)
具体流程:数据库管理系统 -(执行)-> SQL语句 -(操作)-> 数据库
常见的DBMS有:MySQL Oracle DB2 Sybase SqlServer...
**数据库系统:**包含了数据库、数据库管理系统、应用程序和数据库管理者组成的存储、管理、处理和维护数据的系统。一般都简称数据库系统为数据库。
SQL: 结构化查询语言,是一门标准通用的语言。``标准的sql适合于所有的数据库产品。SQL属于高级语言。只要能看懂英语单词的,写出来的sql语句,很简单,可以读懂什么意思。 SQL语句在执行的时候,实际上内部也会先进行编译,然后再执行sql。(sql语句的编译由数据库管理系统完成。)
2.对比数据库系统,文件系统的缺点是什么?
**文件系统:**操作系统自带的数据管理软件,同样以文件存储在硬件设备中。
(window的同学,在编辑文档的时候,另存为的时候是不是要让你选择保存的路径,这就是文件系统的其中一套流程。“由文件名访问,按记录进行存取”)
结合我们实际的案例想一想这套体系下存在的缺点:
(1)数据和数据之间共享性差,冗余度也大。
这里的共享性应该好理解,想象这里有两个word,word中存在有相同的文字,之间无法实现共享性,冗余度大。(在数据库下:文档A有 文档B可以没有 ,冗余度可以理解多余 无意义的东西)
(2)数据独立性差。(难以对文件内的数据进行二次或多次操作)
大家可以借助下面的表格深化理解,文件系统≈大型数据库,不同的地方即上面的缺点的合理解释。
第二节课
回顾数据库概念
1.关系数据库内由什么构成?
表:table = 关系(关系数据库),是数据库的基本组成单元,所有的数据都以表格的形式组织。
表中的每行(即数据库中的每条记录)就是一个元组,每列就是一个属性。
思考:每一列内的数据应该包括哪些? 数据、数据类型、约束条件
2. 开始建表操作
# 用户:root 密码:111 端口:3306 //注意这是我本机的,需要根据你们自己的配置进行修改。
登录:mysql -uroot -p111 //111是我的密码,修改成你们设定的密码。
# 以下是对数据库的操作笔记:
查看数据库:show databases; //默认数据库,四条记录
创建: create database kexie; //新建一个数据库命名为kexie
*删除: drop database kexie; //删除之前新建的kexie库
使用:use kexie; //要对kexie这个数据库展开操作 = use
查看数据库路径:show global variables like "%datadir%"; // 考虑到有些同学会忘记mysql存放的路径,这是关于查找路径的指令,右边是我本机的mysql的路径:D:\mysql80\data\
# 复制上面路径,进入到kexie文件,把kexie.sql复制到kexie文件中去。
# 以下是对数据库中表的操作笔记:
查看表:show tables; //这时候因为没有结果初始化(可以理解成"提醒"数据库系统),因此还是空表。
初始化数据:mysql> source D:\mysql80\data\kexie\kexie.sql //提示数据库系统你"有"了
# 退出重进。再回顾上面的操作:登录+use kexie 数据库切换要记得
查看表结构:show tables; //好使了,可以看到数据库中共有三张表,分别为dept,emp,salgrade
*新建表:create table de; //表示新建了一张表,名为de,注意新建名与其他表名不可相同。
*合并操作:查看创建表的语句:show create table emp;
kexie.sql百度网盘链接如下:_链接:https://pan.baidu.com/s/1E-i5mVIelSJPLD506-2i-Q 提取码:igsi_
第三节课
在上节课我们执行的语句就称为sql语句。那么Sql语句包括增删改查。集合sql语句的文件称为sql脚本。
注意:直接使用source命令可以执行sql脚本,直接拖拽进入也可以。但当sql脚本中的数据量太大的时候,无法打开,需要使用source 文件路径。_(记事本打不开的情况"卡") _
*1.那么SQL语句那么多,如何进行分类呢?
DQL(数据查询语言): 查询语句,凡是select语句都是DQL。
DML(数据操作语言):insert delete update,对表当中的数据进行增删改。
DDL(数据定义语言):create drop alter,对表结构的增删改。
TCL(事务控制语言):commit提交事务,rollback回滚事务。(TCL中的T是Transaction)
DCL(数据控制语言): grant授权、revoke撤销权限等。
数据库系统的三级模式
外模式:又称子模式或用户模式。一个数据库可以有多个外模式(设限 模式的子集)
模式:又称逻辑模式。一个数据库只有一个模式。(DBMS)
内模式:又称存储模式。一个数据库只有一个内模式。(database)
以图书管理系统为例:外模式:借图书的人和采购图书的人的“需求” 模式:DBMS 数据库管理系统内模式:database数据库
2. 对表进行操作
2.1查看表结构
查看数据库中表dept结构:desc dept; #部门表
查看数据库中表emp结构:desc emp; #员工表
查看数据库中表emp结构:desc salgrade; #公司等级表
属性名解释:dept部门表中:DEPTNO 部门编号 DNAME 部门名称 LOC 部门位置 emp员工表中:EMPNO 员工编号 ENAME 员工姓名 JOB 工作岗位 MGR 上级领导编号 HIREDATE 入职日期 SAL 月薪 COMM 补助/津贴 DEPTNO 部门编号salgrade公司等级表中:GRADE 等级 LOSAL 最低薪资 HISAL 最高薪资
2.2 查看表中数据
查看数据库中表dept结构: select * from dept; //注意:实际开发给用户反馈时肯定不能一查就查全表。
查看数据库中表emp结构: select * from emp;
查看数据库中表salgrade结构: select * from salgrade;
# 以emp为例,这里用navicat展示表中数据
2.3 常用命令
查看当前使用的是哪个数据库:select database();
查看mysql的版本号:select version();
结束语句:\c
退出mysql:exit
2.4 数据查询语句(DQL)
单表查询:select 属性1,属性2,属性3,.... from 表名; (若属性为数,可进行数学运算)
问题:查询员工的月薪?
1.员工表是哪个?emp表
2.月薪的属性名是? sal属性
select sal from emp; #为了方便理解,是不是该把员工姓名也加上。员工姓名属性名:ename。
select ename,sal from emp;
3.要是我想查询的是员工的年薪?
select ename,sal*12 from emp;
4.想将月薪列改成年薪列?
select ename,sal * 12 as yearsal from emp;
5.不想要英文命名属性名,就想要年薪?
select ename,sal * 12 as 年薪 from emp; // 错误
select ename,sal * 12 as '年薪' from emp;
6.如果这里我想查找月薪大于等于3000?
这时候就有了条件。不是简单的全返回。也简单。
条件查询: select 属性1,属性2... from 表名 where 条件; (注意是条件,不能是函数)
select ename,sal from emp where sal >= 3000;
7. 找出工资在1100和3000之间的员工,包括1100和3000?
select ename,sal from emp where sal >= 1100 and sal <= 3000;
select ename,sal from emp where sal between 1100 and 3000; // between...and...是闭区间 [1100 ~ 3000]
拓展:between and除了可以使用在数字方面之外,还可以使用在字符串方面。
select ename from emp where ename between 'A' and 'C'; //没有C!注意
8.找出哪些人没有津贴 /实习生/ ?
0和NULL不同,津贴属性名为:comm
select comm from emp where comm is null;
select ename,comm from emp where comm is null;
9.找出名字当中含有O的?
**模糊查询LIKE:**掌握两个特殊的符号
中文模糊查询(注意:’ ‘)
- %(刘% 可以表示为为刘一 刘二 刘一二 刘1234856789 表中所有姓刘的人)
- _ (刘_,这里只能刘一 刘二 刘三 共两个字;刘__ 两个下划线,只能表示为刘一一 刘二二 刘一二 共三个字)
问题:查询表中姓名含有“少"的人?
select ename from emp where ename like '%少%';
问题:查询表中姓名姓“申"的人?
select ename from emp where ename like '申%';
英文模糊查询_(思考为啥这里也要加’ ‘ ) _
select ename from emp where ename like '%O%'; //表示
10.找出名字中第二个字母是A的?
select ename from emp where ename like '_A%';
11.找出名字中最后一个字母是T的?
select ename from emp where ename like '%T';
12.想对员工工资进行排序(升序、降序)?(默认是升序)
select 属性1,属性2... from 表名 order by 属性2 属性3;
select ename , sal from emp order by sal; // 升序 从小到大
select ename , sal from emp order by sal asc; // asc升序 从小到大
select ename , sal from emp order by sal desc; // desc降序 从大到小 一般都是这个 好看嘛
13.若工资相同,按照名字的从小到大排列。
select ename,sal from emp order by sal desc , ename asc;
区别:关键字 函数 方法
关键字 是内置的 具有特殊意义的标识符关键字后面不需要使用括号 函数封装了独立功能,可以直接调用函数名(参数)函数需要死记硬背 方法和函数类似 同样是封装了独立功能方法需要通过对象来调用,表示针对这个对象要做的操作对象.方法名(参数)在变量后面输入. 然后选择针对这个变量要执行的操作,记忆起来比函数要简单很多。
牛客题库
1.给定学生和成绩的数据库表,写一个sql语句求出每门课程的平均分。
A.SELECT SUM(score) FROM course GROUP BY student_id;
B.SELECT score FROM course GROUP BY course_id;
C.SELECT AVG(score) FROM course GROUP BY course_id;
D.SELECT AVG(score) FROM course ;
2.下列关于关系数据库语言 SQL 语言的说法不正确的是()。
A.SQL 支持数据库的三级模式结构
B.SQL 的功能包括查询、操作、定义和控制等四个方面
C.SQL 是作为独立语言由联机终端用户在交互环境下使用的命令语言,它不能嵌入高级语言内
D.SQL 除应用在数据库领域外,还在软件工程、人工智能领域有广泛的应用
3.子模式 DDL 用来描述 ( )。
A.数据库的总体逻辑结构
B.数据库的局部逻辑结构
C.数据库的物理存储结构
D.数据库的概念结构
4.有两个关系 S,P ,已经存有如下数据。S (供应商) P (零件)
其中 S 表的主码为供应商号, P 表的主码为零件号,外码为供应商号,参照 S 表的供应商号,请问下面哪一条语句能插入到 P 表中? ( )
A.('S100',‘红’,‘T20’)
B.(‘TQOT’,‘绿’,NULL)
C.(‘A001’,‘黄’,‘T11’)
D.(NULL,‘红’,‘S20’)
答案1.C 从course选出学生信息,然后通过课程代码进行分组操作,最后使用AVG函数对每个组内的学生成绩求平均值。
2.C sql一种是独立的交互使用数据查询、数据更新等操作,称为自含语言。另一种是嵌入到某种高级语言中,作为高级语言的一种扩充,是程序员编程时既可使用数据库语言又可使用常规的程序设计语言,这时高级语言叫宿主语言。
3.B 外模式也称子模式(Subschema)或用户模式,它是数据库用户(包括应用程序员和最终用户)能看见和使用的局部数据的逻辑结构和特征描述,是数据库用户的数据视图,是与某一应用有关的数据逻辑表示。对应于用户级。它是某个或某几个用户所看到的数据库的数据视图,是与某一应用有关的数据的逻辑表示。DDL(data definition language)是数据定义语言:DDL比DML要多,主要的命令有CREATE、ALTER、DROP等,DDL主要是用在定义或改变表(TABLE)的结构,数据类型,表之间的链接和约束等初始化工作上,他们大多在建立表时使用。
4.B 选项A: P中的主键是零件号,所以零件号不能重复,故A错误。选项C: S中没有 T11 这个主键,故不能成为P中的外键。选项D: 主键不能为空。
练习题
1.查看dept表的结构
DESC dept;
2.查看dept表的所有数据
SELECT * FROM dept;
3.查看dept表中所有部门的MGR
SELECT ename, MGR FROM emp;
4.找出工资在1100和3000之间的员工,包括1100和3000?
SELECT ENAME,SAL FROM emp WHERE SAL >= 1100 and SAL <=3000;
SELECT ENAME,SAL FROM emp WHERE SAL between 1100 and 3000;
5.找出哪些人没有津贴或津贴为0的?
SELECT ENAME,COMM FROM emp WHERE COMM is NULL OR COMM = 0;
6.查询出所有名字中带有A
SELECT ENAME FROM emp where ename like '%A%';
7.查询出所有员工名字中最后一个字母是K的
select ename from emp where ename like '%K';
8.对员工工资进行降序(从大到小),若工资相同,对员工**EMPNO**进行升序(从小到大)。
select ename,sal from emp order by sal desc, empno asc;
9.查询所有员工的平均工资
select avg(sal) from emp;
10.查询员工中JOB为MANAGER,并且对他们的薪资进行排序
select ename,sal from emp WHERE job='MANAGER' order by sal desc;
第四节课
先复习一下上节课对简单sql语句的学习与应用,自查(敲)回顾一下上周的课后题。
这节课我们来学习Java语言连接数据库 JDBC(Java DataBase Connectivity)。
1.回顾思考
下图大家应该比较熟悉,这套是我们目前操作逻辑体系。想一下是不是~
“我们” ->mysql下敲sql语句(eg:查询表的所有数据) ->运行编译 ->本地数据库进行查询操作 -> 返回“目的”数据
这时候如果用户想要查数据/改数据,他“可以”直接到数据库端用数据库产品来对数据进行操作。但这个使用场景的前提是:
- 得拥有数据库端的用户权限。
(对应到具体问题:普通用户登录数据库后select * 某表是可以返回所有数据的) - 数据操作(增删改查)的工作量必须是人类体力/脑力能够承担的。
(对应到具体问题:工作量)
这里有个例子很好理解:店掌柜把账本交给一个可靠的人(帐房先生),帐房先生根据不同人汇总上来的账目,对账本的数据进行各种更改/查询。
2.那么如何利用程序获得数据库中的数据?
答案就是JDBC。观察下列体系的流程图。
试想JDBC体系下是如何解决上面的两个问题。
-
权限:数据库端的权限不开放给普通用户,决定权在root手里。
(具体操作:在JDBC和数据库之间存在“授权操作”,使得root用户可以给普通用户开发权限,使得他们能够获得公司一定的数据)Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/practice?characterEncoding=GBK", "root", "123456"); -
工作量:程序解决(具体展开后续说)
2.1 JDBC本质?
*本质是一套接口
- 面向调用者和实现者。
- 面向接口调用、面向接口写实现类,这都属于面向接口编程。
*为什么要面向接口编程?
解耦合:降低程序的耦合度,提高程序的扩展力。
多态机制就是非常典型的:面向抽象编程。(不要面向具体编程)
建议:
Animal a = new Cat(); Animal a = new Dog();
public void feed(Animal a){ } //面向父类型编程
不建议
Dog d = new Dog(); Cat c = new Cat();
public void feed(Dog d){ }
public void feed(Cat c){ }
这里一个个实现类称作驱动: SqlServer.class -> SqlServer驱动
我们的mysql-版本号.jar 解压可以看到很多.class ,这些都是对JDBC接口进行的实现。
思考?为什么要制定一套JDBC接口呢?
- 适用性更广、跨平台。
- 对应用程序开发者而言更加灵活,
JDBC对数据库厂商而言则更加标准化。
具体:因为每一个数据库的底层实现原理都不一样。 Oracle数据库有自己的原理。 MySQL数据库也有自己的原理。SqlServer数据库也有自己的原理。 .... 每一个数据库产品都有自己独特的实现原理。
3.配置JDBC
1.下载JDBC-MYSQL数据库驱动
这里要注意与不同版本的mysql安装版本是不同的。
eg: 我的mysql8.0 对应的jdbc 版本是mysql-connector-java-8.0.21。
_新版本:dev.mysql.com/downloads/c…](dev.mysql.com/downloads/c…)
_历史版本:downloads.mysql.com/archives/c-…](downloads.mysql.com/archives/c-…)
2.手动配置
- 将下载的压缩包解压,将目录下的
mysql-connector-java-8.0.21.jar文件(驱动)复制到JDK的拓展目录中(即JAVA_HOME环境变量指定的JDK中) - 再将
mysql-connector-java-8.0.21.jar文件(驱动)复制到C:\Program Files\Java\jre1.8.0_241\lib\ext中。保证启动该环境运行程序时,会有驱动的包存在。
JDK是Java的开发工具,它不仅提供了Java程序运行所需的JRE,还提供了一系列的编译,运行等工具,如javac,java,javaw等。JRE只是Java程序的运行环境,它最核心的内容就是JVM(Java虚拟机)及核心类库。
3.验证是否成功,加载驱动,尝试连接
1.在本地新建一个test.java (txt改后缀名暴力转)
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
* 使用JDBC连接MySQL数据库
*
* @author lloyd
*/
public class test {
public static void main(String[] args) {
try {
// 1.加载数据库驱动类
Class.forName("com.mysql.cj.jdbc.Driver");
System.out.println("数据库驱动加载成功");
// 2.创建连接
//格式为jdbc:mysql:
//注意改成自己的账号和密码。 127.0.0.1:3306/数据库名称?useSSL=true&characterEncoding=utf-8&user=账号名&password=密码
Connection connection = DriverManager.getConnection
("jdbc:mysql://127.0.0.1:3306/mysql?useSSL=true&characterEncoding=utf-8&serverTimezone=GMT&user=root&password=111");
System.out.println("创建连接成功");
}
catch (ClassNotFoundException cnfe) {
cnfe.printStackTrace();
} catch (SQLException sqle) {
sqle.printStackTrace();
}
}
}
2.win+r cmd进到dos界面,输入
编译:javac test.java //目的将java源文件编译为class字节码文件
运行:java test //java运行class字节码文件,注意java命令后面不要再加.class。不然会使得java去寻找test.class.class。java指令默认找class文件,找其地址通过CLASSPATH环境变量中指定的目录中寻找。
*4.JDBC编程六步走
- 注册驱动(作用:告诉
Java程序,即将要连接的是哪个品牌的数据库 Mysql) - 获取连接(表示
JVM的进程和数据库进程之间的通道打开了,这属于进程之间的通信,重量级的,使用完之后一定要关闭通道。) - 获取数据库操作对象(专门执行
sql语句的对象) - 执行
SQL语句(DQL数据查询DML数据操纵....) - 处理查询结果集(只有当第四步执行的是
select语句的时候,才有这第五步处理查询结果集。) - 释放资源(使用完资源之后一定要关闭资源。
Java和数据库属于进程间的通信,开启之后一定要关闭。)
牛客题库
1.某学院包含多个专业如计算机科学、信息管理、软件工程、网络工程。每个专业每年都招收一个班级的学生。在招生过程中就已明确规定,一个学生只能就读于该学院的一个班级,但是一个班级可以招收不超过60个学生。那么,学生和班级之间是________的关系。
A.一对多 B.多对多 C.一对一 D.多对一
2.若要“查询选修了3门以上课程的学生的学号”,则正确的SQL语句是( )
A.SELECT S# FROM SC GROUP BY S# WHERE COUNT(*)> 3
B.SELECT S# FROM SC GROUP BY S# HAVING COUNT(*)> 3
C.SELECT S# FROM SC ORDER BY S# WHERE COUNT(*)> 3
D.SELECT S# FROM SC ORDER BY S# HAVING COUNT(*)> 3
3.SQL中,下面对于数据定义语言DDL描述正确的是()
A.DDL关心的是数据库中的数据
B.联盟链
C.控制对数据库的访问
D.定义数据库的结构
4.SQL语言共分为三大类(亦有说法分为四大类),那么不属于数据操纵语言的有()
A.update B.grant C.delete D.insert
5.数据库管理系统(DBMS)是( )
A.数学软件 B.应用软件 C.计算机辅助设计 D.系统软件
6.关系型数据库创建表都有主键。以下对主键描述正确的是:()
A.主键是唯一索引,唯一索引也是主键
B.主键是一种特殊的唯一性索引,只可以是聚集索引
C.主键是唯一、不为空值 的列
D.对于聚集索引来说,创建主键时,不会自动创建主键的聚集索引
7.数据库、数据库系统和数据库管理系统三者之间的关系是()
A.数据库系统包括数据库和数据库管理系统
B.数据库管理系统包括数据库和数据库系统
C.数据库包括数据库系统和数据库管理系统
D.数据库系统就是数据库,也就是数据库管理系统
8. 在关系数据库设计中,设计关系模式是数据库设计中( )阶段的任务
A.逻辑设计 B.物理设计 C.需求分析 D.概念设计
9.在MYSQL数据库中,以下哪条语句用于统计BOOK表中的记录总数?
A.select sum(*) from book;
B.select max(*) from book;
C.select avg(*) from book;
D.select count(*) from book;
答案 1.D 一个学生只能找到一个班级,一个班级有多名学生。学生vs班级是多对一关系。
2.B order by 从英文里理解就是行的排序方式,默认的为升序(从小到大)。order by 后面必须列出要排序的属性,可以是多个属性。group by 从英文里理解就是分组。必须有“聚合函数”来配合才能使用,使用时至少需要一个分组标志字段(即按什么进行分组)。group by的条件语句用having关键字来写。注意:聚合函数对一组值执行计算并返回单一的值。常见的聚合函数有五种,分别是sum()、count()、avg()、max()、min()。
3.D SQL主要分成四部分。
DQL(数据查询语言): 查询语句,凡是select语句都是DQL。
DML(数据操作语言):insert delete update,对表当中的数据进行增删改。
DDL(数据定义语言):create drop alter,对表结构的增删改。
TCL(事务控制语言):commit提交事务,
rollback回滚事务。(TCL中的T是Transaction)
DCL(数据控制语言): grant授权、revoke撤销权限等。
4.B
数据查询语言(DQL):是由SELECT子句,FROM子句,WHERE子句组成的查询块
数据操纵语言(DML): SELECT(查询) INSERT(插入) UPDATE(更新) DELETE(删除)
数据定义语言(DDL):CREATE(创建数据库或表或索引)ALTER(修改表或者数据库)DROP(删除表或索引)
事务控制语言(TCL):SAVEPOINT (设置保存点)ROLLBACK (回滚) COMMIT(提交)
数据控制语言(DCL):GRANT(赋予用户权限) REVOKE(收回权限) DENY(禁止权限)
5.D DBMS数据库管理系统是位于用户与操作系统之间的一层数据管理软件。因此常常也被称为系统软件或软件系统。
6.C 7.A 8.A 9.D 秒选!这里要注意,主键是一种约束(潜在的限制条件),要区分索引!
第五节课
上节课我们学习了Java语言连接数据库JDBC的逻辑体系也自行配置和动手操作了连接,这节课我们将实现JDBC编程的六步走,实现sql注入。
1.JDBC编程六步走
注册驱动 获取连接 获取数据库操作对象 执行SQL语句 处理查询结果集 释放资源
//新建test.java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/*
使用JDBC连接MySQL数据库
*/
public class test {
public static void main(String[] args) {
Connection connection = null;
Statement stmt = null;
try {
// 1.加载数据库驱动类
Class.forName("com.mysql.cj.jdbc.Driver");
System.out.println("数据库驱动Driver.class加载成功");
/* 2.驱动创建连接
格式为jdbc:mysql:
127.0.0.1:3306/数据库名称?useSSL=true&characterEncoding=utf-8&user=账号名&password=密码
useSSL=true 可不加,这块在与服务器建立连接时需使用,为服务器证书验证提供信任存储。
characterEncoding 需要根据自己本地的编码方式是否会有中文?需要进行设置。(utf-8)-> 数据转换为字节码 ->(eg:mysql默认GBK编码)
serverTimezone=GMT jdbc连接服务器的时区设置
*/
connection = DriverManager.getConnection
("jdbc:mysql://127.0.0.1:3306/kexie?useSSL=true&characterEncoding=utf-8&serverTimezone=GMT&user=root&password=111");
System.out.println("创建连接成功");
// 3、获取数据库操作对象
// Statement createStatement() 创建一个 Statement 对象封装Sql语句发送到数据库。
stmt = connection.createStatement();
// 4、执行sql语句
// int executeUpdate(String sql) 专门执行DML语句 insert delete update。
int count = stmt.executeUpdate("update dept set dname = '销售部',loc = '合肥' where deptno = 20;");
System.out.println(count == 1 ? "保存成功":"保存失败"); // 返回值是影响数据库中的记录条数
// 5、处理查询结果集 这里对原表进行的直接操作,因此没有返回结果,不需要处理。eg: 查询
}
catch (ClassNotFoundException cnfe) {
cnfe.printStackTrace();
} catch(SQLException e) {
e.printStackTrace();
} finally {
// 6、释放资源
// 从小到大依次关闭 先开启的connection"小" 之后开启的stmt"大"。
// 注意:不可以一起try
if(stmt != null) {
try {
stmt.close();
}
catch (SQLException e) {
e.printStackTrace();
}
}
if(connection != null) {
try {
connection.close();
}
catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
总结
1.注册驱动 Class.forName(驱动位置)
2.获取连接 connection = DriverManager.getConnection(url)
3. 获取数据库操作对象 stmt = connection.createStatement();
4. 执行SQL语句
stmt.executeUpdate("sql")
5. 处理查询结果集 (针对更新,删除和插入这种只改变原表,而不返回表内容的,不需要执行处理。select要)
6.释放资源(这里最要注意的就是资源释放的顺序问题,connection最先开启,stmt后开启,因此需要先关闭stmt之后再关闭connection。
catch抛出错误,stmt对应一个catch。connection一个catch。观察下面错误示例,思考如果程序中connection没有连接成功为null, 那么作为程序员的我们,要怎么判断错误源自哪里呢?
错误示例:
try{
if(stmt != null){ stmt.close();
}
if(connection != null) {
connection.close();
}
}catch (SQLException e) { e.printStackTrace();
}
2.sql注入
在Navicat中新建一张t_user的表,设计表结构时,属性名分别为userName和userPassword,类型默认varChar即可。之后打开表,填充数据。这步是模拟网页后端数据库的建立过程。
//新建test.java
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
/*
模拟实现用户登录功能
*/
public class test {
public static void main(String[] args) {
// 初始化界面
Map<String,String> userLoginInfo = initUI();
// 验证用户名和密码
boolean loginSuccess = login(userLoginInfo);
// 输出最后结果
System.out.println(loginSuccess ? "登录成功" : "登录失败");
}
/**
* 用户登录
* @param userLoginInfo 用户登录信息
* @return true表示登录成功,false表示登录失败
*/
private static boolean login(Map<String, String> userLoginInfo) {
boolean loginSuccess = false;
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 1、注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 2、获取连接
conn = DriverManager.getConnection
("jdbc:mysql://127.0.0.1:3306/kexie?useSSL=true&characterEncoding=utf-8&serverTimezone=GMT&user=root&password=111");
// 3、获取数据库操作对象
stmt = conn.createStatement();
// 4、执行sql语句
String sql = "select * from t_user where userName = '"+ userLoginInfo.get("userName")+ "' and userPassword = '" + userLoginInfo.get("userPassword")+ "'";
rs = stmt.executeQuery(sql);
// 5、处理结果集
if(rs.next()) {
loginSuccess = true;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
// 6、释放资源
if (rs != null) {
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
return loginSuccess;
}
/**
* 初试化界面
* @return 用户输入的用户名和密码等登录信息
*/
private static Map<String, String> initUI() {
Scanner s = new Scanner(System.in);
System.out.print("请输入用户:");
String userName = s.nextLine();
System.out.print("请输入密码:");
String userPassword = s.nextLine();
Map<String,String> userLoginInfo = new HashMap<>();
userLoginInfo.put("userName",userName);
userLoginInfo.put("userPassword",userPassword);
return userLoginInfo;
}
}
输入:任意用户,任意密码'or' 1'='1可得
运行结果如下图所示:
在封装Sql语句的stmt对象后设置断点,Debug分析其中原因。
可得传入sql语句中的sql语句被封装为一个恒成立条件,因此不需要数据库验证都可以登录成功。
问题就在于userName变量+password变量需要通过拼接组装成字符串(sql语句),而变量通过接受得到的拼接使用的是' '单引号拼接。
黑客在输入时就利用了这个bug,通过自己输入任意密码'or' 1'='1,原代码前后再封装'任意密码'or' 1'='1'形成恒成立语句。
select * from t_user where userName = '任意用户' and userPassword = '任意密码'or' 1'='1';
牛客题库
1.下面哪些字符最可能会导致sql注入?
A. ‘(单引号) B. / C. "(双引号) D. $
2.某IT公司人事管理采用专门的人事管理系统来实现。后台数据库名为LF。新来的人事部张经理新官上任,第一件事是要对公司的员工做全面的了解。可是他在访问员工信息表EMPL里的工资和奖金字段的时被拒绝,只能查看该表其他字段。作为LF的开发者你将如何解决这一问题:( )
A.废除张经理的数据库用户帐户对表EMPL里的工资列和奖金列的SELECT权限
B.添加张经理到r角色
C.添加张经理到db_accessadmin角色
D.授予张经理的数据库用户帐户对表EMPL里的工资列和奖金列的SELECT权限。
(*多选)3.mysql数据库中一张user表中,其中包含字段A,B,C,字段类型如下:A:int,B:int,C:int根据字段A,B,C按照ABC顺序建立复合索引idx_A_B_C,以下查询语句中使用到索引idx_A_B_C的语句有哪些?
A.select *from user where A=1 and B=1
B.select *from user where 1=1 and A=1 and B=1
C.select *from user where B=1 and C=1
D.select *from user where A=1 and C=1
(*多选)4.表结构如下:
以下查询语句结果一定相等的是()
A.SELECT sum(score) / count(*) FROM score WHERE cno = 2;
B.SELECT sum(score) / count(id) FROM score WHERE cno = 2;
C.SELECT sum(score) / count(sno) FROM score WHERE cno = 2;
D.SELECT sum(score) / count(score) FROM score WHERE cno = 2;
E.SELECT sum(score) / count(1) FROM score WHERE cno = 2;
F.SELECT avg(score) FROM score WHERE cno = 2;
答案1.A 控制台输出拼接后的sql为:select * from user_table where username='xxx' and password='xxx' or '1'='1'(达到攻击效果,查询出所有用户信息)所以是单引号导致逻辑发生变化。
public static void main(String[] args) throws Exception {
String name="xxx";
String password="xxx' or '1'='1";
String sql="select * from user_table where username='"+name+"' and
password='"+password+"'";
System.out.println(sql);
}
2. D 具体操作:
1.Grant <权限> on 表名[(列名)] to 用户 With grant option 或 GRANT <权限> ON <数据对象> FROM <数据库用户>
2.权限:select,update,insert,delete
3.回收权限 revoke REVOKE <权限> ON <数据对象> FROM <数据库用户名>
3\. ABD 复合索引可以只使用复合索引中的一部分,但必须是由最左部分开始,且可以存在常量。因复合索引为idx_A_B_C,所以查询条件只能是在a,ab,abc,ac才算,使用到索引idx_A_B_C。
A 复合索引最左前缀规则对于条件A=1 and B=1 显然会用到索引。
B 对于条件 A = 1 and B = 1满足最左前缀 1 = 1 常量表达式这部分不通过索引。
C 不满足最左前缀条件,不能使用索引。
D 通过条件A = 1来使用索引进行查询。因为是最左前缀中一种,对于C=1,就无法使用索引而是全表扫描,这是用于多个and条件连接的条件或单条件应用最左前缀若是or则不行。
4\. 所有的统计函数都会忽略空值(null)。
A :统计所有学生的平均分,就算成绩为空的学生,最后计算count(*)时也作为分母基数,计算得到所有学生的平均分。B :与A一样,因为id主键非空,count(id)所得分母基数是所有学生。 C : 与B一样,非空属性sno。 E: count(1)与count(*)一样。 F:avg(score)会忽略空值,故计算结果为有成绩的学生的平均分。