Day26
数据库
数据库(database)就是一个存储数据的仓库。为了方便数据的存储和管理,它将数据按照特定的规律存储在磁盘上。通过数据库管理系统,可以有效地组织和管理存储在数据库中的数据
数据库的五个基本概念
-
数据库服务器2. 数据库3. 数据表4. 数据字段5. 数据行 **数据库服务器。**是指用来运行数据库服务的一台电脑。小型项目通常为一台,中大型项目通常是多台数据库服务器共同来存储或计算。由于数据安全非常重要,所以我们需 要对数据库服务器里面的数据进经备份管理。 **数据库。**一个数据库服务器里面有可以有多个数据库。主要用来分类使用。我们可以建立学员管理系统数据库、电子商城数据库、CRM数据库、ERP数据库等等,主要用来将各个不同用途的数据,按照业务进行划分。 数据表。例如在学员管理系统数据库中。根据业务的不同又分为了不同的数据表。专门用来存放不同人员的数据。例如:学员数据表(学号、用户名、密码);老师数据表(用户名、密码,工作经验) 数据字段,也叫数据列。就是我们日常所见表格里面的列。在表格中,我们会将一张用户表分成多个列。如下(表一)所示:用户编号、用户名、性别、年龄是字段。在真正的数据库中数据字段需要换成英文需要写成:id、username、sex、age。 **数据行。**真正的数据存在每一个表的行里面。字段(列)划分出来了一个表应该按照什么样的格式存数据。而行,是真正的数据。每一行需要遵循数据字段(列)的规范和要求进行存入数据。(表一)用户编号用户名性别年龄1何翰宇男182波多野结衣女19
MySQL
MySQL是一款完全免费的产品,用户可以直接从网上下载使用,而不必支付任何费用。此外,MySQL数据库的跨平台性也是其一个很大的优势之一。
MySQL是一个真正的多用户、多线程SQL数据库服务器。它是以客户机/服务器结构实现的,由一个服务器守护程序以及很多不同的客户程序和库组成
**官方下载地址:**http://dev.mysql.com/downloads/mysql/
MySQL 5.5融合了MySQL数据库和InnoDB存储引擎的优点,能够提供高性能的数据管理解决方案,包括:InnoDB作为默认的数据库存储引擎。改善性能和可扩展性,全面利用各平台现代、多核构架的计算能力。提高实用性。提高易管理性和效率。提高可用性。
安装MySQL
双击即可,大部分都是一路next
关键节点注意事项:
- 选中“Typical”,典型安装模式
- 选中“Detailed Configuration”(详细配置)单选按钮
- 选中“Developer Machine”(开发者机器)单选按钮
- 选中“Multifunctional Database”(多功能数据库)单选按钮
- 服务端口3306,不建议更改
- 字符集注意要选“Manual Selected Default Character Set/Collation”单选按钮,设置字符集编码为utf8
- 设置密码尽量简单,注意不要忘了,我们只是来做实验用户名:root 密码:root
启动MySQL服务
“我的电脑”→“管理”→“服务”在服务器的列表中找到mysql服务并右键单击,在弹出的快捷菜单中,完成MySQL服务的各种操作(启动、重新启动、停止、 暂停和恢复)
也可以通过命令行的方式来管理Window键+x
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IJRohQTF-1644159414889)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps45D9.tmp.jpg)]
客户端(命令行)连接mySQL服务—登录
-u :username
-p :password
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u36jJJSa-1644159414889)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps45DA.tmp.jpg)]
SQL及分类
一切就绪,开始学SQL
结构化查询语言(Structured Query Language)简称SQL,是一种特殊目的的编程语言,是一种数据库查询和程序设计语言,用于存取数据以及查询、更新和管理关系数据库系统;同时也是数据库脚本文件的扩展名。 hhy.sqlSQL是关系模型的数据库应用语言,由IBM在20世纪70年代为其关系型数据库 System R 所开发。SQL 是1986年10 月由美国国家标准局(ANSI)通过的数据库语言美国标准,接着,国际标准化组织(ISO)颁布了SQL正式国际标准。1989年4月,ISO提出了具有完整性特征的SQL89标准,1992年11月又公布了SQL92标准。虽然各个数据库系统略有不同,但是他们基本均遵循SQL 92标准。或者在SQL 92上做了一些简单的扩展和变化。
- 数据定义语言(DDL ,Data Defintion Language)语句:数据定义语句,用于定义不同的数据对象、数据库、表、列、索引等。常用的语句关键字包括create、drop、alter等。
- 数据操作语言(DML , Data Manipulation Language)语句:数据操纵语句,用于添加、删除、更新和查询数据库记录,并检查数据的完整性。常用的语句关键字主要包括insert、delete、update和select等。(DML:添加,修改,删除,DQL:查询)
- 数据控制语言(DCL, Data Control Language)语句:数据控制语句,用于控制不同数据段直接的许可和访问级别的语句。这些语句定义了数据库、表、字段、用户的访问权限和安全级别。主要的语句关键字包括grant、revoke等。
DDL
我们将分三块来学习1. 数据库操作2. 数据表操作3. 数据字段操作
数据库操作
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x5l5s6h4-1644159414889)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps45EB.tmp.jpg)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PJ5ppMjT-1644159414890)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps45EC.tmp.jpg)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-igSTLoUF-1644159414890)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps45ED.tmp.jpg)]
数据表操作
创建表
基本语法:create table 表名(字段名 字段类型 ,… , 字段名 字段类型);示例:create table user(username varchar(32),password varchar(32));
特别说明:字段类型是建表的关键,目前要掌握关键常用的几个
int — 代表整型
float — 代表浮点
decimal—可以表示小数的字符串
字符串:
char(32):最多只能存储32个字符,如果未满32个,也占32个的空间
varchar(32):最多只能存储32个字符,如果未满32个,占实际字符的个数
注意:以上两种字符串表现形式最多只能存储255个字符
int(3):int类型的三位数
float(8,2):一共八位数,其中两位是小数
text存放长文本信息
datetime,timestamp代表时间 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kvHy7z6Z-1644159414891)(file:///C:\Users\ADMINI1\AppData\Local\Temp\ksohtml\wps45EE.tmp.jpg)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bltJsgnc-1644159414892)(file:///C:\Users\ADMINI1\AppData\Local\Temp\ksohtml\wps45EF.tmp.jpg)]
删除表
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6yoeiDrL-1644159414892)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps45F0.tmp.jpg)]
修改表名
语法:alter table 旧表名 rename 新的表名;[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VKPmUyIp-1644159414893)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps45F1.tmp.jpg)]
数据字段操作
修改字段类型
语法格式:alter table 表名 modify 字段名 varchar(20);
示例:alter table user modify username varchar(64);[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-91i7VVvm-1644159414893)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps4601.tmp.jpg)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f0YGuNWp-1644159414895)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps4602.tmp.jpg)]
增加表字段
语法格式:alter table 表名 add 字段名 类型;[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XBth67NB-1644159414895)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps4603.tmp.jpg)]
删除表字段
语法格式:alter table 表名 drop column 字段名;[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i2p7F412-1644159414895)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps4604.tmp.jpg)]
修改字段名
语法格式:alter table 表名 change 字段原名 字段新名 字段类型;[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sjSMFjL1-1644159414896)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps4605.tmp.jpg)]
DDL
操作数据库
查询所有数据库
SHOW DATABASES;
#创建数据库 CREATE DATABASE 2113javaee;
删除数据库
DROP DATABASE 2113javaee;
使用数据库
USE 2113javaee;
操作数据表
查询该库的所有数据表(前提是 use 数据库)
SHOW TABLES;
添加表
CREATE TABLE s_student( s_name VARCHAR(32), s_sex CHAR(32), age int(3), salary FLOAT(8,2), course VARCHAR(32), hobby VARCHAR(32) );
修改表名
ALTER TABLE s_student RENAME student;
删除表名
DROP TABLE student;
操作数据字段
添加字段
ALTER TABLE student ADD xxx VARCHAR(32);
查询字段信息
DESC student;
查询建表信息
SHOW CREATE TABLE student;
删除字段
ALTER TABLE student DROP xxx;
修改字段类型
ALTER TABLE student MODIFY s_sex VARCHAR(1);
修改字段名 + 类型
ALTER TABLE student CHANGE s_name name VARCHAR(8); ALTER TABLE student CHANGE s_sex sex VARCHAR(1);
DML
增删改查,CRUD ,主键:不允许为空,不允许重复,索引作用
插入记录(增加数据)
语法格式:(建议用第二个)
insert into 表 values(值1,值2,值n);
insert into 表(字段1,字段2,字段n) values(值1,值2,值n);
两种语法的区别:基本语法1的插入语句,表中有多少个字段就必须要插入多少个值。一个不能多,一个也不能少。若有默认值,不想传,可以写上null。基本语法2中,除非有必填字段必须要写入值外。如果有默认值的不想写可以忽略不写。mysql会自动补主默认值[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J0dvVs8u-1644159414897)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps4606.tmp.jpg)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JXfS7cVN-1644159414897)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps4607.tmp.jpg)]
更新记录(修改数据)
语法:update 表名 set 字段1=值1,字段2=值2,字段n=值n where 条件
删除记录
语法:(建议用第二个)
delete from 表名 [where 条件];清空表的数据,并且让自增的id从上次开始自增
truncate table 表名 [where 条件];清空表的数据,并且让自增的id从1开始自增
查询记录
语法:
select * from 表;查询所有字段上的信息
select 字段 from 表; 查询指定字段上的信息
select distinct 字段 from 表; 查询数据 + 去重
select 字段 from 表 where条件 and 条件;查询数据 + 条件
select 字段 from 表 where 字段 like ‘%内容%’;模糊查询
select 字段 from 表 order by 字段 排序关键词;
asc:升序排列,从小到大(默认)
desc:降序排列,从大到小 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4a2z7oNl-1644159414898)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps4618.tmp.jpg)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7KoxqiFM-1644159414900)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps4619.tmp.jpg)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h1HtPH9W-1644159414900)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps461A.tmp.jpg)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YZOATXCx-1644159414900)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps461B.tmp.jpg)]
多字段排序
order by 后面可以跟多个不同的字段排序,并且排序字段的不同结果集的顺序也不同,如果排序字段的值一样,则值相同的字段按照第二个排序字段进行排序。
语法:select 字段 from 表 order by 字段1 desc|asc… 字段n desc|asc;
注意:只有在第一个字段排序后,出现相同值才会比较第二个字段,否则第二个比较字段无效,主排序字段和次排序字段
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NZKtrMPU-1644159414901)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps461C.tmp.jpg)]
分页显示 1-10 11-20语
语法:select 字段 from 表 limit 数量;
取前几条记录
限制结果集并排序
语法:select 字段 from 表 order by 字段 关键词 limit 数量
取这个班年龄最大的前三个人[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oSaCi9sh-1644159414901)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps461D.tmp.jpg)]
结果集区间选择(分页)
语法:select 字段 from 表 limit 偏移量,数量[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bKCv7mea-1644159414902)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps462D.tmp.jpg)]
DML
创建表 – DDL
CREATE TABLE student( id int(3) PRIMARY KEY auto_increment,//PRIMARY KEY–主键, auto_increment–自动增长 name VARCHAR(32), sex VARCHAR(32), age int(3), course VARCHAR(32), salary FLOAT(8,2) )
添加数据
insert into 表 values(值1,值2,值n);
insert into 表(字段1,字段2,字段n) values(值1,值2,值n);
两种语法的区别:基本语法1的插入语句,表中有多少个字段就必须要插入多少个值。一个不能多,一个也不能少。若有默认值,不想传,可以写上null。基本语法2中,除非有必填字段必须要写入值外。如果有默认值的不想写可以忽略不写。mysql会自动补主默认值。(建议用第二个)
INSERT INTO student VALUES(1,‘钟燕’,‘女’,18,‘Java’,12000);
INSERT INTO student(name,sex,age,course,salary) values(‘刘德华’,‘男’,64,‘Java’,18000); INSERT INTO student(name,sex,age,course,salary) values(‘霍建华’,‘男’,35,‘Java’,16000); INSERT INTO student(name,sex,age,course,salary) values(‘欧阳正华’,‘男’,42,‘HTML’,8000); INSERT INTO student(name,sex,age,course,salary) values(‘霍华德’,‘男’,31,‘Python’,12000); INSERT INTO student(name,sex,age,course,salary) values(‘华晨宇’,‘男’,30,‘Python’,6000); INSERT INTO student(name,sex,age,course,salary) values(‘彭于晏’,‘男’,32,‘HTML’,14000); INSERT INTO student(name,sex,age,course,salary) values(‘吴彦祖’,‘男’,39,‘Java’,13000); INSERT INTO student(name,sex,age,course,salary) values(‘刘诗诗’,‘女’,24,‘HTML’,11000); INSERT INTO student(name,sex,age,course,salary) values(‘章若楠’,‘女’,21,‘Python’,10000); INSERT INTO student(name,sex,age,course,salary) values(‘刘亦菲’,‘女’,26,‘Java’,19000);
修改数据
修改数据 + 条件
UPDATE student set salary=20000 WHERE id=1;
修改数据 + 多条件
UPDATE student set salary=20000 WHERE id>3 AND sex=‘女’;#AND 并且 UPDATE student set salary=20000 WHERE id>=9 OR course=‘Java’;# OR 或者
修改多个数据
UPDATE student set age=29,salary=7000 WHERE id=6;
删除数据
删除所有数据
DELETE FROM student;# 删除后,再添加数据id从上次开始累加 TRUNCATE TABLE student;# 删除后,再添加数据id从1开始累加
删除数据 + 条件
DELETE FROM student WHERE id>3 AND sex=‘女’;#AND 并且 DELETE FROM student WHERE id>=9 OR course=‘Java’;# OR 或者
查询信息
查询所有字段上的信息
SELECT * FROM student;
查询指定字段上的信息
SELECT name,age,sex FROM student;
查询指定字段上的信息 + 别名
SELECT name AS ‘姓名’,age AS ‘年龄’,sex AS ‘性别’ FROM student;
查询数据 + 去重
SELECT DISTINCT sex FROM student;
查询数据 + 条件
SELECT * FROM student WHERE id>3 AND sex=‘女’; SELECT * FROM student WHERE id>=9 OR course=‘Java’;
模糊查询 – 了解
%:表示多个字符或者是没有字符
_:表示一个字符
需求:查询名字中带’华’的学生信息
SELECT * FROM student WHERE name LIKE ‘%华%’;
需求:查询名字中最后一个字是带’华’的学生信息
SELECT * FROM student WHERE name LIKE ‘%华’;
需求:查询四个字的名字中最后一个字是带’华’的学生信息
SELECT * FROM student WHERE name LIKE ‘___华’;
排序查询
ORDER BY 排序
ASC-升序 DESC-降序
需求:按照年级排升序
SELECT * FROM student ORDER BY age ASC;
需求:按照工资排降序
SELECT * FROM student ORDER BY salary DESC;
需求:按照年级排升序 并且 都是女生
SELECT * FROM student WHERE sex=‘女’ ORDER BY age ASC ;
多条件排序查询
#需求:按照年龄排升序,年龄相同按照工资排降序 SELECT * FROM student ORDER BY age ASC , salary DESC;
限制查询
查询student表中排名前3工资的学生信息
SELECT * FROM student ORDER BY salary DESC LIMIT 3;
分页
分页算法
SELECT * FROM student LIMIT (页数-1)*每一页的数据条数,每一页的数据条数;
语法:select 字段 from 表 limit 偏移量,数量
SELECT * FROM student LIMIT 0,4;# 第一页 SELECT * FROM student LIMIT 4,4;# 第二页 SELECT * FROM student LIMIT 8,4;# 第三页 SELECT * FROM student LIMIT 12,4;# 第四页
聚合查询 – 统计类函数查询
需求:求学生工资的总和
SELECT SUM(salary) FROM student;
需求:求学生的个数
SELECT COUNT(id) FROM student;
需求:求学生的最高工资
SELECT MAX(salary) FROM student;
需求:求学生的最低工资
SELECT MIN(salary) FROM student;
需求:求学生的平均工资
SELECT AVG(salary) FROM student;
子查询
需求:求最高工资的学生信息
SELECT * FROM student WHERE salary=(SELECT MAX(salary) FROM student);
分组查询
需求:求各学科学员的平均工资
SELECT course,AVG(salary) FROM student GROUP BY course;
分组查询 + 条件
注意:分组里条件用HAVING
需求:求各学科学员的平均工资为10000以上的信息
SELECT course,AVG(salary) FROM student GROUP BY course HAVING AVG(salary)>10000;
多表联合查询
表连接
当需要查询多个表中的字段时,就可以使用表连接来实现。表联接分为内连接和外连接。
内连接:将两个表中存在联结关系的字段符合联结关系的那些记录形成记录集的联结。
外连接:会选出其他不匹配的记录,分为外左联结和外右联结。
内连接
select 表1.字段 [as 别名],表n.字段 from 表1 [别名],表n where 条件;
select 表1.字段 [as 别名],表n.字段 from 表1 INNER JOIN 表n on 条件;
外连接
select 表1.字段 [as 别名],表n.字段 from 表1 LEFT JOIN 表n on 条件;
全链接
(SELECT s.id,s.name,t.name FROM student s LEFT JOIN teacher t ON s.t_id=t.id)
UNION
(SELECT s.id,s.name,t.name FROM student s RIGHT JOIN teacher t ON s.t_id=t.id);
把两个查询结果合并
(SELECT name FROM student WHERE age > 25)
UNION All
(SELECT name FROM student WHERE money > 3000);
– 并集(去重)
(SELECT name FROM student WHERE age > 25)
UNION
(SELECT name FROM student WHERE money > 3000);
左连接:包含所有的左边表中的记录甚至是右边表中没有和它匹配的记录
右连接:包含所有的右边表中的记录甚至是右边表中没有和它匹配的记录
select 表1.字段 [as 别名],表n.字段 from 表1 right JOIN 表n on 条件;
内连接
多表之间有关联的数据才能查询出来
SELECT s.name AS ‘学生姓名’,t.name AS ‘老师姓名’ FROM student s,teacher t WHERE s.t_id = t.id; SELECT s.name AS ‘学生姓名’,t.name AS ‘老师姓名’ FROM student s INNER JOIN teacher t ON s.t_id = t.id;
外连接 - 左连接
SELECT s.name AS ‘学生姓名’,t.name AS ‘老师姓名’ FROM student s LEFT JOIN teacher t ON s.t_id = t.id;
外连接 - 右连接
SELECT s.name AS ‘学生姓名’,t.name AS ‘老师姓名’ FROM student s RIGHT JOIN teacher t ON s.t_id = t.id;
全链接
左连接+右连接,并把重复数据去掉
思路:把两个查询语句的结果合并 并 去重
SELECT s.name AS ‘学生姓名’,t.name AS ‘老师姓名’ FROM student s LEFT JOIN teacher t ON s.t_id = t.id UNION SELECT s.name AS ‘学生姓名’,t.name AS ‘老师姓名’ FROM student s RIGHT JOIN teacher t ON s.t_id = t.id;
把两个查询语句的结果合并
SELECT s.name AS ‘学生姓名’,t.name AS ‘老师姓名’ FROM student s LEFT JOIN teacher t ON s.t_id = t.id UNION ALL SELECT s.name AS ‘学生姓名’,t.name AS ‘老师姓名’ FROM student s RIGHT JOIN teacher t ON s.t_id = t.id;
DCL
开权限
在dos窗口里操作
create user ‘hhy’@‘localhost’ identified by ‘123123’;
删权限
revoke select on 2113javaee.* from ‘hhy’@‘localhost’ identified by ‘123123’;
JDBC
JDBC:java database connectivity SUN公司提供的一套操作数据库的标准规范。
java提供了很多操作数据库的接口:
DriverManager:用于注册驱动
Connection: 表示与数据库创建的连接
Statement: 操作数据库sql语句的对象
ResultSet: sql语句执行后返回的结果集
JDBC与数据库驱动的关系:接口与实现的关系。
java要想操作mysql数据库,就必须要下载mysql的数据驱动(数据驱动里面是mysql实现了java提供的操作数据库的接口的实现类)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9DBxewsy-1644159414902)(D:\2113java_workspace\Day28\Day28上午\JDBC理解图.png)]
使用JDBC去操作数据库
package com.qf.jdbc01;
import org.junit.Test;
import java.sql.*;
public class Test01 {
@Test
public void Test01() throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/2113javaee?useUnicode=true&characterEncoding=utf-8", "root", "root");
Statement statement = connection.createStatement();
String sql = "INSERT INTO student(name,sex,age,course,salary) values('aaa','男',23,'Java',18000);";
int num = statement.executeUpdate(sql);
System.out.println("影响了" + num + "行");
statement.close();
connection.close();
}
@Test
public void Test02() throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/2113javaee?useUnicode=true&characterEncoding=utf-8", "root", "root");
Statement statement = connection.createStatement();
String sql = "UPDATE student set name='abc' WHERE id=12;";
int num = statement.executeUpdate(sql);
System.out.println("影响了" + num + "行");
statement.close();
connection.close();
}
@Test
public void Test03() throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/2113javaee?useUnicode=true&characterEncoding=utf-8", "root", "root");
Statement statement = connection.createStatement();
String sql = "DELETE FROM student WHERE id=12;";
int num = statement.executeUpdate(sql);
System.out.println("影响了" + num + "行");
statement.close();
connection.close();
}
@Test
public void Test04() throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/2113javaee?useUnicode=true&characterEncoding=utf-8", "root", "root");
Statement statement = connection.createStatement();
String sql = "select * from student";
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
String sex = resultSet.getString("sex");
int age = resultSet.getInt("age");
String course = resultSet.getString("course");
float salary = resultSet.getFloat("salary");
System.out.println(id + " -- " + name + " -- " + sex + " -- " + age + " -- " + course + " -- " + salary);
}
resultSet.close();
statement.close();
connection.close();
}
}
使用DBUtils工具类去操作数据库
使用JDBC去操作数据库每次都有导入驱动包、获取连接对象、获取Statement对象、关闭资源这几步,比较麻烦,此时考虑把这几步封装成方法放到一个DBUtils工具类里面,再使用JDBC去操作数据库的时候直接调用DBUtils工具类里面对应的方法即可,这样就会使代码变得更简洁。
driverName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/2113javaee?useUnicode=true&characterEncoding=utf-8
username=root
password=root
DBUtils工具类
package com.qf.util;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;
public class DBUtils {
private static String url;
private static String username;
private static String password;
static{
Properties p = new Properties();
try { p.load(DBUtils.class.getClassLoader().getResourceAsStream("DBConfig.properties"));
} catch (IOException e) {
e.printStackTrace();
}
String driverName = p.getProperty("driverName");
url = p.getProperty("url");
username = p.getProperty("username");
password = p.getProperty("password");
try {
Class.forName(driverName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
Connection connection = DriverManager.getConnection(url,username,password);
return connection;
}
public static void close(Connection connection, Statement statement, ResultSet resultSet){
if(resultSet != null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(statement != null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection != null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
使用DBUtils工具类去操作数据库
package com.qf.jdbc02;
import com.qf.util.DBUtils;
import org.junit.Test;
import java.sql.*;
public class Test01 {
@Test
public void Test01(){
Connection connection = null;
Statement statement = null;
try {
connection = DBUtils.getConnection();
statement = connection.createStatement();
String sql = "INSERT INTO student(name,sex,age,course,salary) values('aaa','男',23,'Java',18000);";
int num = statement.executeUpdate(sql);
System.out.println("影响了" + num + "行");
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtils.close(connection,statement,null);
}
}
@Test
public void Test02() {
Connection connection = null;
Statement statement = null;
try {
connection = DBUtils.getConnection();
statement = connection.createStatement();
String sql = "UPDATE student set name='abc' WHERE id=13;";
int num = statement.executeUpdate(sql);
System.out.println("影响了" + num + "行");
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtils.close(connection,statement,null);
}
}
@Test
public void Test03() throws ClassNotFoundException, SQLException {
Connection connection = null;
Statement statement = null;
try {
connection = DBUtils.getConnection();
statement = connection.createStatement();
String sql = "DELETE FROM student WHERE id=13;";
int num = statement.executeUpdate(sql);
System.out.println("影响了" + num + "行");
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtils.close(connection,statement,null);
}
}
@Test
public void Test04() throws ClassNotFoundException, SQLException {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = DBUtils.getConnection();
statement = connection.createStatement();
String sql = "select * from student";
resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
String sex = resultSet.getString("sex");
int age = resultSet.getInt("age");
String course = resultSet.getString("course");
float salary = resultSet.getFloat("salary");
System.out.println(id + " -- " + name + " -- " + sex + " -- " + age + " -- " + course + " -- " + salary);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtils.close(connection,statement,resultSet);
}
}
}
SQL注入问题
利用jDBC操作数据库时会出现的问题
出现原因:将输入的数据和SQL语句放在一起发送给了数据库,数据库可能会出现把sql语句和数据识别混淆的问题,叫做SQL注入问题
解决方案:使用PreparedStatement,因为PreparedStatement对象是把SQL语句和数据分开发送给数据库的
以利用jDBC操作数据库去查询某一条信息为例说明这个问题
package com.qf.jdbc02;
import com.qf.util.DBUtils;
import java.sql.*;
public class Test04 {
public void Test04() throws ClassNotFoundException, SQLException {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = DBUtils.getConnection();
statement = connection.createStatement();
String sql = "select * from student where username='xxx' and password='123123';";
resultSet = statement.executeQuery(sql);
if (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
String sex = resultSet.getString("sex");
int age = resultSet.getInt("age");
String course = resultSet.getString("course");
float salary = resultSet.getFloat("salary");
System.out.println(id + " -- " + name + " -- " + sex + " -- " + age + " -- " + course + " -- " + salary);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtils.close(connection,statement,resultSet);
}
}
}
解决方案:使用PreparedStatement,因为PreparedStatement对象是把SQL语句和数据分开发送给数据库的
关系:PreparedStatement extends Statement
package com.qf.jdbc03;
import com.qf.util.DBUtils;
import java.sql.*;
public class Test01 {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = DBUtils.getConnection();
String sql = "select * from student where username=? and password=? ;";
statement = connection.prepareStatement(sql);
statement.setString(1,"' or 1=1 #");
statement.setString(2,"111111");
resultSet = statement.executeQuery();
if (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
String sex = resultSet.getString("sex");
int age = resultSet.getInt("age");
String course = resultSet.getString("course");
float salary = resultSet.getFloat("salary");
System.out.println(id + " -- " + name + " -- " + sex + " -- " + age + " -- " + course + " -- " + salary);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtils.close(connection,statement,resultSet);
}
}
}
事务
含义:MySQL:每一条语句都属于独立事务,默认自动管理提交的。
注意:如果需要把多条语句当成一个整体,那么就需要把多条语句放在一个事务里面
两条SQL语句,第一条SQL语句执行完后程序崩掉了,就不会执行第二条SQL语句(从银行转账系统的角度去理解,一个人把钱转出去了,另一个人却没收到)
为了防止这种情况发送,就需要把这两条SQL语句当成一个整体放在一个事务里面,假如第一条SQL语句执行完后程序崩掉了,此时会做一个回滚,把数据回滚到执行第一条SQL语句之前的状态
# 开启事务
START TRANSACTION;
UPDATE bank SET money=money-200 WHERE id=1;
UPDATE bank SET money=money+200 WHERE id=2;
# 回滚事务
ROLLBACK;
# 提交事务
COMMIT;
package com.qf.jdbc04;
import com.qf.util.DBUtils;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
public class Test01 {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
try {
connection = DBUtils.getConnection();
connection.setAutoCommit(false);
statement = connection.createStatement();
String sql1 = "UPDATE bank SET money=money-200 WHERE id=1;";
String sql2 = "UPDATE bank SET money=money+200 WHERE id=2;";
statement.executeUpdate(sql1);
statement.executeUpdate(sql2);
connection.commit();
} catch (Exception e) {
try {
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
} finally {
DBUtils.close(connection,statement,null);
}
}
}
深入事务
package com.qf.jdbc01;
import com.qf.util.DBUtils;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
public class Test01 {
public static void main(String[] args) {
try {
DBUtils.startTransaction();
add();
subtract();
DBUtils.commit();
} catch (Exception e) {
System.out.println("程序发生错误,回滚事务了");
try {
DBUtils.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
}
public static void add() throws SQLException {
Connection connection = null;
Statement statement = null;
try {
connection = DBUtils.getConnection();
System.out.println(connection);
statement = connection.createStatement();
String sql = "UPDATE bank SET money=money+200 WHERE id=2;";
statement.executeUpdate(sql);
} finally {
DBUtils.close(connection,statement,null);
}
}
public static void subtract() throws SQLException {
Connection connection = null;
Statement statement = null;
try {
connection = DBUtils.getConnection();
System.out.println(connection);
statement = connection.createStatement();
String sql = "UPDATE bank SET money=money-200 WHERE id=1;";
statement.executeUpdate(sql);
} finally {
DBUtils.close(connection,statement,null);
}
}
}
数据库工具类
package com.qf.util;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;
public class DBUtils {
private static String url;
private static String username;
private static String password;
static{
Properties p = new Properties();
try { p.load(DBUtils.class.getClassLoader().getResourceAsStream("DBConfig.properties"));
} catch (IOException e) {
e.printStackTrace();
}
String driverName = p.getProperty("driverName");
url = p.getProperty("url");
username = p.getProperty("username");
password = p.getProperty("password");
try {
Class.forName(driverName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private static ThreadLocal<Connection> local = new ThreadLocal<>();
public static void startTransaction() throws SQLException {
Connection connection = getConnection();
connection.setAutoCommit(false);
}
public static void commit() throws SQLException {
Connection connection = local.get();
if(connection != null){
connection.commit();
connection.close();
local.set(null);
}
}
public static void rollback() throws SQLException {
Connection connection = local.get();
if(connection != null){
connection.rollback();
connection.close();
local.set(null);
}
}
public static Connection getConnection() throws SQLException {
Connection connection = local.get();
if(connection == null) {
connection = DriverManager.getConnection(url, username, password);
connection.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
local.set(connection);
}
return connection;
}
public static void close(Connection connection, Statement statement, ResultSet resultSet){
if(resultSet != null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(statement != null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection != null){
try {
if(connection.getAutoCommit()) {
connection.close();
local.set(null);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
事务的特点
事务的特性:ACID
原子性( Atomicity )、一致性( Consistency )、隔离性( Isolation )和持久性( Durability )
原子性:事务是数据库的逻辑工作单位,事务中包含的各操作要么都完成,要么都不完成
一致性:事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。如果数据库系统 运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是 不一致的状态。
隔离性:一个事务的执行不能其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。
持久性:指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。
事务的隔离级别:
属于事务的,都已开启了事务为前提。
不考虑事务的隔离级别,会出现以下的情况:
脏读:一个线程中的事务读到了另外一个线程中未提交的数据。
不可重复读:一个线程中的事务读到了另外一个线程中已经提交的update的数据。
虚读(几乎不会发送):一个线程中的事务读到了另外一个线程中已经提交的insert的数据。
要想避免以上现象,通过更改事务的隔离级别来避免:
READ UNCOMMITTED 脏读、不可重复读、虚读有可能发生。
READ COMMITTED 避免脏读的发生,不可重复读、虚读有可能发生。
REPEATABLE READ 避免脏读、不可重复读的发生,虚读有可能发生。
SERIALIZABLE 避免脏读、不可重复读、虚读的发生(但会造成阻塞,当在更新数据时有其他事务的开启,该事务就会阻塞,只有等到其他事务全部关闭后,才会提交这个事务)
级别依次升高,效率依次降低。
MySQL:默认REPEATABLE READ
ORACLE:默认READ COMMITTED
MySQL:
select @@tx_isolation;//查看当前的隔离级别
set transaction isolation level 级别;// 设置当前的事务隔离级别
批处理
需求:批量执行多条sql语句,sql语句不相同
package com.qf.jdbc02;
import com.qf.util.DBUtils;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
public class Test01 {
public static void main(String[] args) throws SQLException {
Connection connection = DBUtils.getConnection();
Statement statement = connection.createStatement();
String sqlInsert = "INSERT INTO student(name,sex,age,course,salary) values('刘亦菲','女',26,'Java',19000);";
String sqlUpdate = "UPDATE student set salary=20000 WHERE course='Java';";
statement.addBatch(sqlInsert);
statement.addBatch(sqlUpdate);
statement.executeBatch();
DBUtils.close(connection,statement,null);
}
}
需求:批量插入100条记录,sql语句相同,只是参数值不同
package com.qf.jdbc02;
import com.qf.util.DBUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
public class Test02 {
public static void main(String[] args) throws SQLException {
Connection connection = DBUtils.getConnection();
String sql = "INSERT INTO student(name,sex,age,course,salary) values(?,?,?,?,?);";
PreparedStatement statement = connection.prepareStatement(sql);
for (int i = 1; i <= 100; i++) {
statement.setString(1,"maxibin"+i);
statement.setString(2,"男");
statement.setInt(3,25);
statement.setString(4,"Java");
statement.setString(5,"20000");
statement.addBatch();
}
statement.executeBatch();
DBUtils.close(connection,statement,null);
}
}
需求:批量插入10004条记录,每1000条数据就发送一次,sql语句相同,只是参数值不同
package com.qf.jdbc02;
import com.qf.util.DBUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Test03 {
public static void main(String[] args) throws SQLException {
Connection connection = DBUtils.getConnection();
connection.setAutoCommit(false);
String sql = "INSERT INTO student(name,sex,age,course,salary) values(?,?,?,?,?);";
PreparedStatement statement = connection.prepareStatement(sql);
for (int i = 1; i <= 10004; i++) {
statement.setString(1,"maxibin"+i);
statement.setString(2,"男");
statement.setInt(3,25);
statement.setString(4,"Java");
statement.setString(5,"20000");
statement.addBatch();
if(i % 1000 == 0){
statement.executeBatch();
statement.clearBatch();
}
}
statement.executeBatch();
connection.commit();
DBUtils.close(connection,statement,null);
}
}
CBLob
Blob:可以向数据库写入二进制文件,也可以读取 Clob-Text:可以向数据库写入文本文件,也可以读取
package com.qf.jdbc03;
import com.qf.util.DBUtils;
import org.junit.Test;
import java.io.*;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Test01 {
@Test
public void test01() throws SQLException, FileNotFoundException {
Connection connection = DBUtils.getConnection();
String sql = "insert into cblob(b_blob) values(?)";
PreparedStatement statement = connection.prepareStatement(sql);
File file = new File("三上悠亚.jpg");
FileInputStream fis = new FileInputStream(file);
statement.setBinaryStream(1,fis,(int)file.length());
statement.executeUpdate();
DBUtils.close(connection,statement,null);
}
@Test
public void test02() throws SQLException, IOException {
Connection connection = DBUtils.getConnection();
String sql = "select * from cblob where id=1";
PreparedStatement statement = connection.prepareStatement(sql);
ResultSet resultSet = statement.executeQuery();
if(resultSet.next()){
InputStream in = resultSet.getBinaryStream("b_blob");
FileOutputStream out = new FileOutputStream("copyImg.jpg");
byte[] bs = new byte[1024];
int len;
while((len = in.read(bs)) != -1) {
out.write(bs,0,len);
}
in.close();
out.close();
}
DBUtils.close(connection,statement,resultSet);
}
}
package com.qf.jdbc03;
import com.qf.util.DBUtils;
import org.junit.Test;
import java.io.*;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Test02 {
@Test
public void test01() throws SQLException, FileNotFoundException {
Connection connection = DBUtils.getConnection();
String sql = "insert into cblob(c_clob) values(?)";
PreparedStatement statement = connection.prepareStatement(sql);
File file = new File("小说.txt");
FileReader fr = new FileReader(file);
statement.setCharacterStream(1,fr,(int)file.length());
statement.executeUpdate();
DBUtils.close(connection,statement,null);
}
@Test
public void test02() throws SQLException, IOException {
Connection connection = DBUtils.getConnection();
String sql = "select * from cblob where id=2";
PreparedStatement statement = connection.prepareStatement(sql);
ResultSet resultSet = statement.executeQuery();
if(resultSet.next()){
Reader r = resultSet.getCharacterStream("c_clob");
FileWriter w = new FileWriter("copyTxt.txt");
char[] cs = new char[1024];
int len;
while((len = r.read(cs)) != -1) {
w.write(cs,0,len);
}
r.close();
w.close();
}
DBUtils.close(connection,statement,resultSet);
}
}
ection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class Test02 { @Test public void test01() throws SQLException, FileNotFoundException { //向数据库写入文本文件
Connection connection = DBUtils.getConnection();
String sql = "insert into cblob(c_clob) values(?)";
PreparedStatement statement = connection.prepareStatement(sql);
File file = new File("小说.txt");
FileReader fr = new FileReader(file);
statement.setCharacterStream(1,fr,(int)file.length());//写入文本文件
statement.executeUpdate();
DBUtils.close(connection,statement,null);
}
@Test
public void test02() throws SQLException, IOException {
//读取数据库中的文本文件
Connection connection = DBUtils.getConnection();
String sql = "select * from cblob where id=2";
PreparedStatement statement = connection.prepareStatement(sql);
ResultSet resultSet = statement.executeQuery();
if(resultSet.next()){
Reader r = resultSet.getCharacterStream("c_clob");
FileWriter w = new FileWriter("copyTxt.txt");
char[] cs = new char[1024];
int len;
while((len = r.read(cs)) != -1) {
w.write(cs,0,len);
}
r.close();
w.close();
}
DBUtils.close(connection,statement,resultSet);
}
}
|