本文最后编辑于   前,其中的内容可能需要更新。
            
            
             
            初始Mysql https://www.kuangstudy.com/bbs/1467760102697095170#header2 
什么是数据库 概念:     数据仓库(软件),安装在操作系统(window,Linux,mac…)之上。可以存储大量数据。500万
作用:     数据库是存储数据,管理数据,
为什么学习数据库 
趋势,岗位需求 
大数据时代,得数据者得天下 
被迫需求:存数据 
数据库是所有软件体系中最核心得存在 
 
数据库分类 关系型数据库:(SQL)
MySQL、Oracle、SQL server、DB2、SQLlite… 
通过表与表之间、行与行之间的关系进行数据的存储。 
 
非关系型数据库:(NoSQL)Not Only SQL
redis、MongDB 
对象存储,通过对象自身的属性来决定。 
 
连接数据库 命令行连接:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 mysql  update mysql.user set  authentication_string= password('123456' ) where  user = 'root'  and  Host =  'localhost' ;  flush privileges;  show  databases;    mysql>  use school     Database changed show  tables;    describe  student;    create  database westos;    exit;     
 
数据库XXX语言 DDL    定义
DML    操作
DQL    查询
DCL    控制
MySQL属性和操作 1.常用密令 1 2 3 show create database user; --查看创建数据库user的语句 show create table user; --查看创建数据表user的语句 desc user; --查看数据表user的结构 
 
mysql的关键字不区分字母的大小写
 
2.操作数据库。数据库名:demo 
创建数据库
1 create database [if not exists] demo; 
 
删除数据库
1 drop database [if exists] demo; 
 
使用数据库
1 use `demo`; --tab键上面,如果表名或者字段名是一个特殊字符,就需要使用`` 
 
查看数据库
1 show databases; --查看所有数据库 
 
 
3.数据库列的类型 
mysql数据类型长度问题总结:https://blog.csdn.net/yaruli/article/details/79187814 
 
数值
tinyint:十分小的数据,1个字节。 
smallint:较小的数据,2个字节。 
mediumint:中等大小的数据,3个字节。 
int:标准的证书,4个字节。(常用的变量)  
bigint:较大的数据,8个字节。 
float:浮点数,4个字节。 
double:浮点数,8个字节。 
decimal:字符串形式的浮点数。涉及到金钱计算时,一般使用decimal 
 
 
字符串
char:字符串固定大小的,0~255字节。 
varchar:可变字符串,0~65535字节。(常用的变量)  
tinytext:微型文本,2^8-1字节。 
text:文本串,2^16-1字节。  
 
 
时间
date:YYYY-MM-DD,日期格式。 
time:HH:mm:ss,时间格式。 
datatime:YYYY-MM-DD HH:mm:ss,最常用的时间格式。  
timestamp:时间戳,1970.1.1道现在的毫秒数。  
year:年份表示。 
 
 
null
没有值,未知。 
注意:不要使用NULL进行运算,没有意义,计算结果为NULL 
 
 
 
4.数据库的字段属性 
Unsigned
 
zerofill
0填充 
不足的位数使用0填充。int(5)类型存储数字9会变成00009 
 
 
自增
通常理解为自增,自动在上一条记录的基础上+1(默认)。 
通常用来设计唯一的主键,必须是整数类型。 
可以自定义设计主键自增的起始值和步长。 
 
 
非空
勾选上not null,如果不给字段赋值,则会报错。 
 
 
默认
设置默认的值。 
sex,默认值为男,如果不指定该列的值,则会有默认的值。 
 
 
 
拓展:
 
5.创建数据库 
6.数据表类型 
关于数据库引擎
InnoDB:5.5版本以后默认使用。 
MyISam:早些年使用的默认。 
 
 
 
 
MyISam 
InnoDB 
 
 
事务支持 
不支持 
支持 
 
数据行锁定 
不支持 
支持 
 
外键约束 
不支持 
支持 
 
全文索引 
支持 
不支持 
 
表空间大小 
较小 
较大,约为myisam两倍 
 
1 2 3 常规使用操作: - MYISAM节约空间,速度较快。  - INNODB安全性高,事务的处理,多表多用户操作。 
 
在物理空间存在的位置 所有的数据库文件都存在data目录下,一个文件夹就对应一个数据库,本质还是文件的存储。 
MySQL引擎在物理文件上的区别。
InnoDB在数据库表中只有一个*.frm文件,以及上级目录下的ibdata1文件。 
MYISAM对应文件:
*.frm:表结构的定义文件 
*.MYD:数据文件(data) 
*.MYI:索引文件(index) 
 
 
 
 
 
7.设置数据库表的字符集编码 
MySQL默认字符编码的设置:https://www.jianshu.com/p/ec0c86ee3e04 
 
 
不设置的话,会是mysql默认的字符集编码(不支持中文) 
MySQL的默认编码是Latin1,不支持中文。 
在my.ini中配置默认的编码 
 
1 character-set-server=utf8 
 
8.修改数据表字段 1 2 3 4 5 6 7 8 9 10 11 12 13 -- 修改表名:ALTER TABLE 旧表名 RENAME AS 新表名 ALTER TABLE teacher RENAME AS teacher1 -- 增加表的字段:ALTER TABLE 表名 ADD 字段名 列属性 ALTER TABLE teacher1 ADD age INT(11) -- 修改表的字段(重命名,修改约束) -- ALTER TABLE 表名 MODIFY 字段名 列属性[] ALTER TABLE teacher1 MODIFY age VARCHAR(11)    -- 修改约束 -- ALTER TABLE 表名 CHANGE 旧名字 新名字 列属性[] ALTER TABLE teacher1 CHANGE age age1 INT(1)    -- 字段重命名 -- 删除表的字段:ALTER TABLE 表名 DROP 字段名 ALTER TABLE teacher1 DROP age1 
 
*change一般用来字段重命名,modify不用来字段重命名,只能修改字段类型和约束* 
9.删除数据表字段 1 2 -- 删除表(如果表存在再删除) drop table if exists `teacher1` 
 
MySQL数据管理 外键(了解即可) 方式一:在创建表的时候,增加约束(麻烦,比较复杂)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 -- 学生表的gradeid字段,要去引用年级表的gradeid -- 定义外键key -- 给这个外键添加约束(执行引用) references 引用 CREATE TABLE `grade`(     `gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT '年级id',     `gradename` VARCHAR(50) NOT NULL COMMENT '年级名称',     PRIMARY KEY(`gradeid`) )ENGINE=INNODB DEFAULT CHARSET=utf8 CREATE TABLE IF NOT EXISTS `student`(     `id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号',     `name` VARCHAR(20) NOT NULL DEFAULT '匿名' COMMENT '姓名',     `pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密码',     `sex` VARCHAR(2) NOT NULL DEFAULT '男' COMMENT '性别',     `gradeid` INT(10) NOT NULL COMMENT '年级',     `birthday` DATETIME DEFAULT NULL COMMENT '生日',     `address` VARCHAR(20) DEFAULT NULL COMMENT '地址',     `email` VARCHAR(20) DEFAULT NULL COMMENT '邮箱',     PRIMARY KEY(`id`),     KEY `FK_gradeid`(`gradeid`),     CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade`(`gradeid`)      )ENGINE=INNODB DEFAULT CHARSET=utf8 
 
删除有外键关系的表的时候,必须要先删除引用别人的表(从表),再删除被引用的表(主表)
方式二:创建表成功后,添加外键约束
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 -- 学生表的gradeid字段,要去引用年级表的gradeid -- 定义外键key -- 给这个外键添加约束(执行引用) references 引用 CREATE TABLE `grade`(     `gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT '年级id',     `gradename` VARCHAR(50) NOT NULL COMMENT '年级名称',     PRIMARY KEY(`gradeid`) )ENGINE=INNODB DEFAULT CHARSET=utf8 CREATE TABLE IF NOT EXISTS `student`(     `id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号',     `name` VARCHAR(20) NOT NULL DEFAULT '匿名' COMMENT '姓名',     `pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密码',     `sex` VARCHAR(2) NOT NULL DEFAULT '男' COMMENT '性别',     `gradeid` INT(10) NOT NULL COMMENT '年级',     `birthday` DATETIME DEFAULT NULL COMMENT '生日',     `address` VARCHAR(20) DEFAULT NULL COMMENT '地址',     `email` VARCHAR(20) DEFAULT NULL COMMENT '邮箱',     PRIMARY KEY(`id`) )ENGINE=INNODB DEFAULT CHARSET=utf8 -- 创建表的时候没有外键关系 ALTER TABLE `student` ADD CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade`(`gradeid`); -- ALTER TABLE 表 ADD CONSTRAINT 约束名 FOREIGN KEY(作为外键的列) REFERENCES 那个表(那个字段) 
 
以上操作都是物理外键,数据库级别的外键,不建议使用!(避免数据库过多造成困扰)
==最佳实践==
数据库就是单纯的表,只用来存数据,只有行(数据)和列(字段) 
我们想使用多张表的数据,想使用外键(程序去实现) 
 
DML语言(全部记住) 数据库意义:数据存储,数据管理
DML语言:数据操作语言
添加 1 2 3 4 5 6 insert  into  `student`(id,name,age)values (1 ,'zhangsan' ,12 );INSERT  INTO  `grade`(`gradename`)VALUES ('大一' ),('大二' )
 
注意事项:
字段和字段之间使用 英文逗号 隔开 
字段可以省略,但是后面的值必须要一一对应,不能少 
可以同时插入多条数据,VALUES后面的值,需要使用,隔开即可 (),() 
 
修改 1 2 3 4 -- 不指定条件的情况下,会修改所有的记录:update 表名 set column_name=value,[column_name=value,...] where [条件] update `student` set name='张三' where id=1 UPDATE student SET NAME = '行初雾',email = '1092315259@qq.com' WHERE id = 1 
 
条件:where子句
操作符:
 =、<>或!=、<、>、<=、>=、BETWEEN…and… 、AND、OR 
 
1 UPDATE `student` set `name` = 'hello' WHERE `name` = '1' AND sex = '女' 
 
语法:update 表名 set column_name=value,[column_name=value,…] where [条件]
注意:
colnum_name 是数据库的列,尽量带上`` 
条件,筛选的条件,如果没有指定,则会修改所有的列 
value,是一个具体的值,也可以是一个变量 
多个设置的属性之间,使用英文逗号隔开 
 
删除 delete命令:
INSERT INTO test(coll) VALUES(‘1’),(‘2’),(‘3’)
DELETE FROM test    – 不会影响自增
TRUNCATE TABLE test    – 自增会归零
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 delete删除问题(了解即可):重启数据库,现象 - InnoDB    自增列会重1开始,(存在内存当中,断电即失) - MyISAM    继续从上一个自增量开始(存在文件中,不会丢失) ## DQL查询数据(最重点) ### DQL (Data Query LANGUAGE:数据查询语言) - 所以的查询操作都用:Select - ==数据库中最核心的语言,最重要的语句== - 使用频率最高的语句 select 语法 
 
SELECT [ALL | DISTINCT] {* | table.* | [table.field1[as alias1][,table.field2[as alias2]][,…]]} FROM table_name [as table_alias]     [left | right | inner join table_name2]  – 联合查询     [WHERE …]  – 指定结果需满足的条件     [GROUP BY …]  – 指定结果按照哪几个字段来分组     [HAVING]  – 过滤分组的记录必须满足的次要条件     [ORDER BY …]  – 指定查询记录按一个或多个条件排序     [LIMIT {[offset,]row_count | row_countOFFSET offset}];     –  指定查询的记录从哪条至哪条
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 注意:[]括号代表可选的,{}括号代表必选的 ### 指定查询字段 ```sql -- 查询全部的学生 SELECT 字段 FROM 表 select * from student; -- 查询指定字段 select `StudentId`,`StudentName` from student; -- 别名,给结果起一个名字 AS    可以给字段起别名,也可以给表起别名 select `StudentId` as 学号 , `StudentName` AS 学生姓名 from student as s; -- 函数 Concat(a,b)  拼接 select concat('姓名:',StudentName) as 新名字 from student; 
 
语法:==SELECT 字段,… FROM 表==
有时,列表名不是那么见名知意,可以起别名:AS
去重及数据库的表达式 去重:distinct
1 2 3 4 5 6 7 8 9 10 -- 查询全部考试成绩 SELECT * FROM result; -- 查询有哪些同学参加了考试 SELECT `StudentID` FROM result; -- 发现数据重复,去重 SELECT DISTINCT `StudentID` FROM result; 
 
数据库的列(表达式)
1 2 3 4 5 6 7 8 9 10 11 12 SELECT  VERSION();SELECT  100 * 3 -1  AS  计算结果;SELECT  @@auto _increment_increment;SELECT  `StudentID`,`StudentResult`+ 1  AS  '+1后'  FROM  result ;
 
==数据库中的表达式:文本值、列、Null、函数、计算表达式、系统变量…==
select ==表达式== from 表
where子句之逻辑运算符 作用:检索数据中符合条件的值
搜索的条件由一个或者多个表达式组成,结果布尔值
逻辑运算符
 
运算符 
语法 
描述 
 
 
and && 
a and b a&&b 
逻辑与 
 
or || 
a orb a||b 
逻辑或 
 
not ! 
not a !a 
逻辑非 
 
==尽量使用英文字母==
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 -- 查询考试成绩在 95 ~ 100分之间 SELECT studentid,studentresult FROM result; -- and SELECT studentid,studentresult FROM result WHERE studentresult >= 95 AND studentresult <= 100; -- &&  SELECT studentid,studentresult FROM result WHERE studentresult >= 95 && studentresult <= 100; -- 模糊查询(区间) SELECT studentid,studentresult FROM result WHERE studentresult BETWEEN 95 AND 100; -- 除了1000号学生之外的学生的成绩 -- != SELECT studentid,studentresult FROM result WHERE studentid != 1000; -- not SELECT studentid,studentresult FROM result WHERE NOT studentid = 1000; 
 
模糊查询:比较运算符 
模糊查询:比较运算符
 
运算符 
语法 
描述 
 
 
IS NULL 
a is null 
如果操作符为null,结果为真 
 
IS NOT NULL 
a is not null 
如果操作符不为null,结果为真 
 
BWTWEEN…AND… 
a between b and c 
若a在b和c之间,则结果为真 
 
LIKE 
a like b 
SQL匹配,如果a匹配b,则结果为真 
 
IN 
a in (a1,a2,a3,…) 
假设a在a1或者a2或者a3,…其中的某一个,则结果为真 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 -- 查询姓王的同学 -- like 结合  --   %(代表0到任意个字符) --   _(代表1) -- 查询姓王的同学 SELECT `studentId`,`studentName` FROM `student` WHERE studentName LIKE '王%'; -- 查询姓王的同学,名字后面只有一个字的 SELECT `studentId`,`studentName` FROM `student` WHERE studentName LIKE '王_'; -- 查询姓王的同学,名字后面有两个字的 SELECT `studentId`,`studentName` FROM `student` WHERE studentName LIKE '王__'; -- 查询名字中间有嘉字的同学 SELECT `studentId`,`studentName` FROM `student` WHERE studentName LIKE '%嘉%'; -- in (具体的一个或者多个值) -- 查询学号1001,1002,1003号学号 SELECT `studentId`,`studentName` FROM `student` WHERE studentId IN ('1001','1002','1003'); -- 查询在北京的学生 SELECT `studentId`,`studentName` FROM `student` WHERE address IN ('北京'); -- null -- 查询地址为空的学生 SELECT `studentId`,`studentName` FROM `student` WHERE address = '' OR address IS NULL; -- not null -- 查询有出生日期的同学 不为空 SELECT `studentId`,`studentName` FROM `student` WHERE borndate IS NOT NULL; -- 查询没有出生日期的同学 为空 SELECT `studentId`,`studentName` FROM `student` WHERE borndate IS NULL; 
 
连表查询join on 
join 对比
 
七种join理论
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 --   =========连表查询================== -- 查询参加了考试的同学(学号,姓名,科目编号,分数) SELECT * FROM student; SELECT * FROM result; -- join on 连接查询 -- where 等值查询 -- inner join SELECT s.`StudentId`,`StudentName`,`SubjectID`,`StudentResult` FROM student AS s INNER JOIN result AS r ON s.`StudentId` = r.`StudentID` -- right join SELECT s.`StudentId`,`StudentName`,`SubjectID`,`StudentResult` FROM student AS s RIGHT JOIN result AS r ON s.`StudentId` = r.`StudentID` -- left join SELECT s.`StudentId`,`StudentName`,`SubjectID`,`StudentResult` FROM student AS s LEFT JOIN result AS r ON s.`StudentId` = r.`StudentID` -- 查询缺考的同学 SELECT s.`StudentId`,`StudentName`,`SubjectID`,`StudentResult` FROM student AS s LEFT JOIN result AS r ON s.`StudentId` = r.`StudentID` WHERE r.`StudentID` IS NULL -- 查询了参加考试的同学信息(学号,学生姓名,科目名称,分数) SELECT s.`StudentId`,`StudentName`,`Subjectname`,`StudentResult` FROM student AS s INNER JOIN result AS r ON s.`StudentId` = r.`StudentID` INNER JOIN SUBJECT AS sub ON r.`SubjectID` = sub.`subjectno` -- 查询了参加高等数学-1考试的同学信息(学号,学生姓名,科目名称,分数) SELECT s.`StudentId`,`StudentName`,`Subjectname`,`StudentResult` FROM student AS s INNER JOIN result AS r ON s.`StudentId` = r.`StudentID` INNER JOIN SUBJECT AS sub ON r.`SubjectID` = sub.`subjectno` WHERE sub.`subjectname` = '高等数学-1' -- 我要查询哪些数据 select ... -- 从哪几个表中查 from 表 XXX join 连接的表 on 交叉条件 -- 假设存在一种多张表查询,慢慢来,先查询两张表然后再慢慢增加 
 
操作 
描述 
 
 
inner join 
如果表中至少有一个匹配,就返回行 
 
left join 
会从左边中返回所有的值,即使右表中没有匹配 
 
right join 
会从右边中返回所有的值,即使左表中没有匹配 
 
自连接 自己的表和自己的表连接,核心:==一张表拆为两张一样的表即可==
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 -- 创建表 -- unsigned 无符号 -- auto_increment=9 自增的起始值 DROP TABLE IF EXISTS `category` ; CREATE TABLE `category` (   `category_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主题id',   `pid` INT(10) NOT NULL COMMENT '父id',   `category_name` VARCHAR(50) NOT NULL COMMENT '主题名字',   PRIMARY KEY (`category_id`) ) ENGINE=INNODB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8; -- 插入值 INSERT INTO `category`(`category_id`,`pid`,`category_name`) VALUES('2','1','信息技术'), ('3','1','软件开发'), ('4','3','数据库'), ('5','1','美术设计'), ('6','3','web开发'), ('7','5','ps技术'), ('8','2','办公信息'); SELECT * FROM `category`; 
 
父类
pid 
category_id 
category_name 
 
 
1 
2 
信息技术 
 
1 
3 
软件开发 
 
1 
5 
美术设计 
 
子类
pid 
category_id 
category_name 
 
 
3 
4 
数据库 
 
2 
8 
办公信息 
 
3 
6 
web开发 
 
5 
7 
ps技术 
 
操作:查询父类对应的子类关系
父类 
子类 
 
 
信息技术 
办公信息 
 
软件开发 
数据库 
 
软件开发 
web开发 
 
美术设计 
ps技术 
 
1 2 3 4 -- 查询父子信息,把一张表看为两个一模一样的表 SELECT a.`category_name` AS '父栏目',b.`category_name` AS '子栏目' FROM `category` AS a, `category` AS b WHERE a.`category_id`=b.`pid`; 
 
分页和排序 
排序
 
1 2 3 4 5 6 7 8 9 10 SELECT  s.`StudentId`,`StudentName`,`Subjectname`,`StudentResult`FROM  student AS  sINNER  JOIN  result  AS  rON  s.`StudentId` =  r.`StudentID`INNER  JOIN  SUBJECT AS  subON  r.`SubjectID` =  sub.`subjectno`ORDER  BY  `studentResult` ASC 
 
分页
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 -- 100w -- 为什么要分页 -- 缓解数据库压力,给人更好的体验   瀑布流 -- 分页,每页只显示五条数据 -- 语法 : limit 起始值,页面的大小 -- 网页应用:当前,总的页数,每页大小 -- LIMIT 0,5    1~5 -- LIMIT 1,5    2~6 -- LIMIT 6,5 SELECT s.`StudentId`,`StudentName`,`Subjectname`,`StudentResult` FROM student AS s INNER JOIN result AS r ON s.`StudentId` = r.`StudentID` INNER JOIN SUBJECT AS sub ON r.`SubjectID` = sub.`subjectno` ORDER BY `studentResult` ASC LIMIT 0,3 -- 第一页 limit 0,5    (1-1)*5 -- 第二页 limit 5,5    (2-1)*5 -- 第三页 limit 10,5   (3-1)*5 -- 第N页 limit 10,5    (n-1)*pageSize,pageSize -- pageSize,页面大小 -- (n-1)*pageSize,起始值 -- n,当前页 -- 总页数 = (数据总数%页面大小==0)? (数据总数/页面大小) : (数据总数/页面大小 + 1) 
 
语法: limit (查询起始下标,页面大小)
子查询和嵌套查询 where(这个值是计算出来的)
本质:在where语句中嵌套一个子查询语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 -- 1.查询数据库结构-1的所有考试结果(学号,科目名,成绩),降序排列 -- 方式1:使用连接查询 SELECT r.`StudentId`,`Subjectid`,`StudentResult` FROM result AS r INNER JOIN `subject` AS sub ON r.`SubjectID` = sub.`subjectno` WHERE sub.`subjectname` = '高等数学-1' ORDER BY res.`StudentResult` DESC; -- 使用子查询(由里及外) select r.`StudentId`,subjectId,studentResult from result as r where SubjectID = (     select Subjectno from `subject` where SubjectName = '高等数学-1' ) ORDER BY res.`StudentResult` DESC; -- 分数不小于80分的学生的学号和姓名 SELECT DISTINCT s.`StudentId`,s.`StudentName` FROM student s INNER JOIN result r ON s.`StudentId` = r.`StudentID` WHERE r.`StudentResult` > 80 -- 在这个基础上增加一个科目,查询课程为高等数学-1,且分数不小于80分的学生的学号和姓名 SELECT DISTINCT s.`StudentId`,s.`StudentName` FROM student s INNER JOIN result r ON s.`StudentId` = r.`StudentID` WHERE r.`StudentResult` > 80  AND r.`SubjectID` = (     SELECT subjectno FROM `subject` WHERE subject.`subjectname` = '高等数学-1' )  SELECT DISTINCT s.`StudentId`,s.`StudentName` FROM student s INNER JOIN result r ON s.`StudentId` = r.`StudentID` INNER JOIN `subject` sub ON r.`SubjectID` = sub.`subjectno` WHERE sub.`subjectname` = '高等数学-1' AND r.`StudentResult` > 80 --  再次改造(由里及外) SELECT DISTINCT s.`StudentId`,s.`StudentName` FROM student s WHERE studentId IN (     SELECT studentId FROM result WHERE StudentResult > 80     AND subjectid = ( 	SELECT subjectno FROM `subject` WHERE subjectname = '高等数学-1'     ) ) 
 
常用函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 SELECT  ABS (-8 ); SELECT  CEILING (9.4 ) ;SELECT  FLOOR (9.4 );SELECT  RAND(); SELECT  SIGN(-10 ); SELECT  CHAR_LENGTH ('哈哈' ); SELECT  CONCAT('我' ,'爱' ,'你' ); SELECT  INSERT ('我爱编程helloworld' ,1 ,2 ,'超级热爱' ); SELECT  LOWER ('ZYY' ); SELECT  UPPER ('zyy' ); SELECT  INSTR('zyy' ,'y' ); SELECT  REPLACE('坚持就能成功' ,'坚持' ,'努力' ); SELECT  SUBSTR('坚持就能成功' , 5 , 2 ); SELECT  REVERSE('清晨我上马' ); SELECT  CURRENT_DATE (); SELECT  CURDATE(); SELECT  NOW(); SELECT  LOCALTIME (); SELECT  SYSDATE(); SELECT  YEAR (NOW()); SELECT  MONTH (NOW()); SELECT  DAY (NOW()); SELECT  HOUR (NOW()); SELECT  MINUTE (NOW()); SELECT  SECOND (NOW()); SELECT  SYSTEM_USER ();SELECT  USER ();SELECT  VERSION();
 
聚合函数及分组过滤 
函数名称 
描述 
 
 
count() 
计数 
 
sum() 
求和 
 
avg() 
平均值 
 
max() 
最大值 
 
min() 
最小值 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 -- 聚合函数 -- 都能统计 表中数据 -- count(字段) 会忽略所有的null值(想查询一个表中有多少个记录,就使用这个count()) SELECT COUNT(studentname) FROM student; -- COUNT(*) 不会忽略所有的null值 本质计算行数 SELECT COUNT(*) FROM student; -- COUNT(1) 不会忽略所有的null值 本质计算行数 SELECT COUNT(1) FROM student; SELECT SUM(studentResult) AS '总和'  FROM result; SELECT AVG(studentResult) AS '平均值'  FROM result; SELECT MAX(studentResult) AS '最大值'  FROM result; SELECT MIN(studentResult) AS '最小值'  FROM result; -- 查询不同课程的平均分,最高分,最低分 SELECT sub.subjectName,AVG(r.studentResult),MAX(r.studentResult),MIN(r.studentResult) FROM result r INNER JOIN `subject` sub ON r.`SubjectID` = sub.`subjectno` GROUP BY r.`SubjectID` HAVING AVG(r.`StudentResult`) > 80 
 
数据库级别的md5加密(扩展) 什么是MD5?
主要增加算法复杂度和不可逆性。
MD5不可逆,具体的值的md5是一样的
MD5破解网站的原理,背后有一个字典,MD5加密后的值,加密前的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 CREATE TABLE `testmd5`(   `id` INT(4) NOT NULL,   `name` VARCHAR(20) NOT NULL,   `pwd` VARCHAR(50) NOT NULL,   PRIMARY KEY (`id`) )ENGINE=INNODB DEFAULT CHARSET=utf8; -- 明文密码 INSERT INTO `testmd5`(`id`,`name`,`pwd`) VALUES (1,'张三','123456'), (2,'李四','123456'), (3,'王五','123456'); SELECT * FROM `testmd5`; -- 加密 UPDATE testmd5 SET pwd=MD5(pwd) WHERE id=2; -- 插入的时候加密 INSERT INTO `testmd5`(`id`,`name`,`pwd`) VALUES (4,'小明',MD5('123456')); -- 如何校验,将用户传递进来的密码,进行MD5加密,然后比对加密后的值 SELECT * FROM `testmd5` WHERE `name`='小明' AND pwd = MD5('123456'); 
 
事务 什么是事务 ==要么都成功,要么都失败==
将一组sql放到一个批次中去执行
事务原则:ACID原则 原子性 、一致性、隔离性、持久性 (脏读,幻读。。。)
 
参考博客链接:事务ACID理解 
原子性(Atomicity) 
要么都成功,要么都失败
一致性(Consistency) 
事务前后的数据完整性要保持一致
下图操作前和操作后的总和都是1000
隔离性(Isolation) 
事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
持久性(Durability) 
事务一旦移交不可逆,被持久化到数据库中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 SET  autocommit =  0   SET  autocommit =  1   SET  autocommit =  0  START  TRANSACTION    INSERT  xxINSERT  xxCOMMIT  ROLLBACK  SET  autocommit =  1   SAVEPOINT  保存点名  ROLLBACK  TO  SAVEPOINT  保存点名 RELEASE  SAVEPOINT  保存点名 CREATE  DATABASE shop CHARACTER  SET  utf8mb4 COLLATE  utf8mb4_general_ci	USER  shopCREATE  TABLE  `account`(    `id` INT (3 ) NOT  NULL  AUTO_INCREMENT,     `name` VARCHAR (30 ) NOT  NULL ,     `money` DECIMAL (9 ,2 ) NOT  NULL ,     PRIMARY  KEY (`id`) )ENGINE= INNODB DEFAULT  CHARSET= utf8mb4 INSERT  INTO  account(`name`,`money`)VALUE  ('A' ,2000.00 ),('B' ,10000.00 )SET  autocommit =  0 ;    START  TRANSACTION UPDATE account SET  money= money-500  WHERE  `name` =  'A'   UPDATE account SET  money= money+ 500  WHERE  `name` =  'B'   COMMIT ;    ROLLBACK ; SET  autocommit =  1 ; 
 
隔离所导致的一些问题 脏读: 1、在事务A执行过程中,事务A对数据资源进行了修改,事务B读取了事务A修改后的数据。
2、由于某些原因,事务A并没有完成提交,发生了RollBack操作,则事务B读取的数据就是脏数据。
这种读取到另一个事务未提交的数据的现象就是脏读(Dirty Read)。 
不可重复读: 事务B读取了两次数据资源,在这两次读取的过程中事务A修改了数据,导致事务B在这两次读取出来的数据不一致。
这种**==在同一个事务中==,前后两次读取的数据不一致的现象就是不可重复读(Nonrepeatable Read)。**
虚读(幻读) 事务B前后两次读取同一个范围的数据,在事务B两次读取的过程中事务A新增了数据,导致事务B后一次读取到前一次查询没有看到的行。
幻读和不可重复读有些类似,但是幻读强调的是集合的增减,而不是单条数据的更新。 
第一类更新丢失 事务A和事务B都对数据进行更新,但是事务A由于某种原因事务回滚了,把已经提交的事务B的更新数据给覆盖了。这种现象就是第一类更新丢失。
第二类更新丢失 其实跟第一类更新丢失有点类似,也是两个事务同时对数据进行更新,但是事务A的更新把已提交的事务B的更新数据给覆盖了。这种现象就是第二类更新丢失。
事务隔离级别 为了解决以上的问题,主流的关系型数据库都会提供四种事务的隔离级别。事务隔离级别从低到高分别是:读未提交,读已提交,可重复读,串行化。事务隔离级别越高,越能保证数据的一致性和完整性,但是执行效率也越低,所以在设置数据库的事务隔离级别时需要做一下权衡,mysql默认是可重复读
读未提交 读未提交(Read Uncommitted),是最低的隔离级别,所有的事务都可以看到其他未提交的事务的执行结果。 只能防止第一类更新丢失,不能解决脏读,可重复读,幻读,所以很少应用于实际项目。
读已提交 读已提交(Read Committed),在该隔离级别下,一个事务的更新操作只有在该事务提交之后,另外一个事务才可能读取到同一笔数据更新后的结果。 可以防止脏读和第一类更新丢失,但是不能解决可重复和幻读的问题。
可重复读(重要) 可重复读(Repeatable Read),mysql默认的隔离级别。在该隔离级别下,一个事务多次读同一个数据,在这个事务还没有结束时,其他事务不能访问该数据(包括了读写) ,这样就可以在同一个事务内两次读到的数据是一样的。可以防止脏读、不可重复读、第一类更新丢失,第二类更新丢失的问题,不过还是会出现幻读。
串行化 串行化(Serializable),这是最高的隔离级别。它要求事务序列化执行,事务只能一个接着一个的执行,不能并发执行。在这个级别,可以解决上面提到的所有并发问题,但是可能导致大量的超时现象和锁竞争,通常不会用这个隔离级别。
总结 
扩展:回滚机制 在mysql中,恢复机制是通过回滚日志(undo log)实现的,所有的事务进行的修改都会先记录到这个回滚日志中,然后在堆数据库中的对应进行写入。
mysql的事务是由redo和undo的,redo操作的所有信息都是记录到重做日志(redo_log)中,也就是说当一个事务做commit操作时,需要先把这个事务的操作写到redo_log中,然后在把这些操作flush到磁盘上,当出现故障时,只需要读取redo_log,然后在重新flush到磁盘就行了。
而对于undo就比较麻烦,mysql在处理事务时,会在数据共享表空间里申请一个段就做segment段,用保存undo信息,当在处理rollback,不是完完全全的物理undo,而是逻辑undo,也就是说会之前的操作进行反操作(对于每个insert,回滚时会执行delete;对于每个delete,回滚时会执行insert;对于每个update,回滚时会执行一个相反的update,把数据改回去。),但是这些共享表空间是不进行回收的。这些表空间的回收需要由mysql的master thread进程进行回收。
索引 
Msql官方对索引的定义为:索引(index)是帮助MySQL高效获取数据的数据结构 。
提取句子主干,就可以得到索引的本质:索引是数据结构。
 
索引的分类 
在一个表中,主键索引只能有一个,唯一索引可以有多个
 
主键索引(primary key)
 
唯一索引 (unique key)
避免重复的列出现,可以重复,多个列都可以标示为唯一索引 
 
 
常规索引(key/index)
 
全文索引(FullText)
在特定的数据库引擎下才有,myisam 
快速定位数据 
 
 
 
基础语法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 -- 索引的使用 -- 1.在创建表的时候给字段增加索引 -- 2.创建完毕后,增加索引 -- 显示所有的索引信息 SHOW INDEX FROM student; -- 新增一个索引 (索引名) 列名 ALTER TABLE `student` ADD UNIQUE KEY `UK_IDENTITY_CARD` (`identity_card`); ALTER TABLE `student` ADD KEY `K_STUDENT_NAME`(`student_name`); ALTER TABLE `student`  ADD FULLTEXT INDEX `FI_PHONE` (`phone`); -- explain 分析sql执行的状况 EXPLAIN SELECT * FROM student; -- 非全文索引 EXPLAIN SELECT * FROM student WHERE MATCH(`phone`) AGAINST('138'); -- 全文索引 
 
【MySQL优化】——看懂explain_漫漫长途,终有回转;余味苦涩,终有回甘-CSDN博客_explain 
测试索引 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 CREATE TABLE app_user (   `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID',   `name` VARCHAR(50)  DEFAULT '' COMMENT '用户昵称',   `email` VARCHAR(50)  NOT NULL COMMENT '用户邮箱',   `phone` VARCHAR(20)  DEFAULT '' COMMENT '手机号',   `gender` TINYINT(4)  UNSIGNED DEFAULT '0' COMMENT '性别(0:男  1:女)',   `password` VARCHAR(100)  NOT NULL COMMENT '密码',   `age` TINYINT(4)  DEFAULT '0' COMMENT '年龄',   `create_time` DATETIME  DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',   `update_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',   PRIMARY KEY (`id`) ) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COMMENT='app用户表' -- 创建函数时报错信息:This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled -- 错误分析:我们创建函数时必须指定我们的函数是否是 /*  1. DETERMINISTIC 不确定的  2. NO SQL 没有SQl语句,当然也不会修改数据  3. READS SQL DATA 只是读取数据,当然也不会修改数据  4. MODIFIES SQL DATA 要修改数据  5. CONTAINS SQL 包含了SQL语句*/ -- 解决办法:set global log_bin_trust_function_creators=TRUE; -- 插入100万数据b (函数)      DELIMITER $$ -- 写函数之前必须要写,标志 CREATE FUNCTION mock_data() RETURNS INT BEGIN   DECLARE num INT DEFAULT 1000000;   DECLARE i INT DEFAULT 0;   WHILE i<num DO     INSERT INTO app_user(`name`,`email`,`phone`,`gender`,`password`,`age`)     VALUES(CONCAT('用户',i),'123345@qq.com',CONCAT('18',FLOOR(RAND()*((999999999-100000000)+100000000))),FLOOR(RAND()*2),UUID(),FLOOR(RAND()*100));     SET i = i+1;   END WHILE;   RETURN i; END; -- 执行函数 SELECT mock_data(); SELECT * FROM app_user; -- 函数中间的插入语句 INSERT INTO app_user(`name`,`email`,`phone`,`gender`,`password`,`age`) VALUES(CONCAT('用户X'), '123345@qq.com', CONCAT('18',FLOOR(RAND()*((999999999-100000000)+100000000))), FLOOR(RAND()*2), UUID(), FLOOR(RAND()*100)); 
 
测试:
1 2 3 4 5 6 7 8 9 10 11 -- 加索引前 SELECT * FROM app_user WHERE `name` = '用户9999'; -- 0.440 sec EXPLAIN SELECT * FROM app_user WHERE `name` = '用户9999'; -- 创建索引 -- id_表名_字段名  索引名 -- CREATE INDEX 索引名 ON 表名(`字段名`); CREATE INDEX id_app_user_name ON app_user(`name`);  -- 加索引后 SELECT * FROM app_user WHERE `name` = '用户9999'; -- 0.002 sec EXPLAIN SELECT * FROM app_user WHERE `name` = '用户9999'; 
 
索引在小数据量的时候,用处不大,但是再大数据的时候,区分十分明显 
索引原则 
索引不是越多越好 
不要对经常变动的数据加索引 
小数据量的表不需要加索引 
索引一般加载常用来查询的字段上 
 
索引的数据结构
 
Hash类型的索引
Btree :innodb的默认数据结构
CodingLabs - MySQL索引背后的数据结构及算法原理 
权限管理和备份 用户管理 
sql 命令操作
 
用户表:mysql.user
本质:读这张表进行增删改查
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 -- 创建用户 CREATE USER zyy IDENTIFIED BY '123456'; -- 修改密码(修改当前用户密码) SET PASSWORD = PASSWORD('123456'); -- 修改密码(修改指定用户密码) SET PASSWORD FOR zyy = PASSWORD('123456'); -- 重命名  RENAME 原名子 zyy TO 新名字; RENAME USER zyy TO newzyy; -- 用户授权  ALL PRIVILEGES 全部的权限,库,表 -- ALL PRIVILEGES 除了给别人授权不行,其他都能干 GRANT ALL PRIVILEGES ON *.* TO newzyy; -- 查询权限 SHOW GRANTS FOR newzyy; -- 查看指定用户的权限 SHOW GRANTS FOR root@localhost; -- 查看root用户的权限 -- 撤销权限   REVOKE哪些权限,在哪个库,给谁撤销 REVOKE ALL PRIVILEGES ON *.* FROM newzyy; -- 删除用户 DROP USER newzyy; 
 
MySQL备份 为什么要备份?
mysql数据库备份的方式
直接拷贝物理文件
 
在sqlyog这种可视化工具中手动导出
 
使用命令行导出 mysqldump 命令行使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 # 一张表 mysqldump -h主机 -u用户名 -p密码 数据库 表名 >物理磁盘位置/文件名 mysqldump -hlocalhost -uroot -p123456 school student >D:/a.sql # 多张表 mysqldump -h主机 -u用户名 -p密码 数据库 表名1 表名2 >物理磁盘位置/文件名 mysqldump -hlocalhost -uroot -p123456 school student result >D:/a.sql # 数据库 mysqldump -h主机 -u用户名 -p密码 数据库 >物理磁盘位置/文件名 mysqldump -hlocalhost -uroot -p123456 school >D:/a.sql # 导入 # 登录的情况下,切换到指定的数据库 # source 备份文件 # 也可以这样 mysql -u用户名 -p密码 库名<备份文件 
 
 
 
假设你要备份数据库,防止数据丢失。
把数据库给别人,直接给sql即可。
如何设计一个项目的数据库 为什么需要设计 
==当数据库比较复杂的时候,我们就需要设计了==
糟糕的数据库设计 
数据冗余,浪费空间 
数据库插入和删除都会麻烦、异常(屏蔽使用物理外键) 
程序的性能差 
 
良好的数据库设计 
节省内存空间 
保证数据库的完整性 
方便我们开发系统 
 
软件开发中,关于数据库的设计 
分析需求,分析业务和需要处理的数据库的需求 
概要设计:设计关系图E-R图 
 
设计数据库的步骤(个人博客) 
收集信息,分析需求
用户表(用户登录注销,用户的个人信息,写博客,创建分类) 
分类表(文章分类,谁创建的) 
文章表(文章信息) 
评论表 
友链表(友情链接信息) 
自定义表(系统信息,某个关键的字,或者一些主字段) key:value 
关注表(粉丝数) 
说说表(发表心情, id…content…create_time) 
 
 
标识实体(把需求落到每个字段) 
标识实体之间的关系
写博客:user –> blog 
创建分类:user –> category 
关注:user –> user 
友链:links 
评论:user –> user –> blog 
 
 
 
(bbs / crm)
三大范式 第一范式(1NF) 
原子性:保证每一列不可再分
第二范式(2NF) 
前提:满足第一范式
第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)。
每张表只描述一件事情
第三范式(3NF) 
前提:满足第一范式和第二范式
第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。
规范数据库的设计
规范性和性能的问题 
关联查询的表不得超过三张表
考虑商业化的需求和目标(成本,用户体验)数据库的性能更加重要 
在规范性能的问题的时候,需要适当的考虑一下规范性 
故意给某些表增加一些冗余的字段。(从多表查询中变为单表查询) 
故意增加一些计算列(从大数据库降低为小数据量的查询:索引) 
 
JDBC 数据库驱动 驱动:声卡,显卡,数据库
我们的程序会通过数据库驱动,和数据库打交道!
JDBC SUN公司为了简化开发人员的(对数据库的统一)操作,提供了一个(java操作数据库的)规范,俗称JDBC
这些规范的实现由具体的厂商去做~
对于开发人员来说,我们只需要掌握JDBC接口的操作即可!
java.sql
javax.sql
还需要导入一个数据库驱动包 mysql-connector-java-5.1.47.jar
第一个JDBC程序 
创建测试数据库
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 CREATE DATABASE jdbcstudy CHARACTER SET utf8 COLLATE utf8_general_ci; USE jdbcstudy; CREATE TABLE users(   `id` INT PRIMARY KEY,   `name` VARCHAR(40),   `password` VARCHAR(40),   `email` VARCHAR(60),   `birthday` DATE ); INSERT INTO users(`id`,`name`,`password`,`email`,`birthday`) VALUES(1,'张三','123456','zs@sina.com','1980-12-04'), (2,'李四','123456','lisi@sina.com','1981-12-04'), (3,'王五','123456','wangwu@sina.com','1982-12-04'); 
 
创建一个普通项目
 
导入数据库驱动(jar包)
 
编写测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 public class jdbcDemo1 {     public static void main(String[] args) throws ClassNotFoundException, SQLException {         //1.加载驱动         Class.forName("com.mysql.jdbc.Driver");    //固定写法,加载驱动         //2.用户信息和url         //useUnicode=true    支持中文         //characterEncoding=utf8         //useSSL=false    使用安全的连接         String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false";         String username = "root";         String password = "cjy521213";         //3.连接成功,数据库对象  Connection 代表数据库         Connection connection = DriverManager.getConnection(url, username, password);         //4.执行SQL的对象    Statement 执行SQL的对象         Statement statement = connection.createStatement();         //5.执行SQL的对象 去 执行SQL,可能存在结果,查看返回结果         String sql = "SELECT * FROM users";         ResultSet resultSet = statement.executeQuery(sql);         while (resultSet.next()){             System.out.println("id = " + resultSet.getObject("id"));             System.out.println("name = " + resultSet.getObject("name"));             System.out.println("password = " + resultSet.getObject("password"));             System.out.println("email = " + resultSet.getObject("email"));             System.out.println("birthday = " + resultSet.getObject("birthday"));             System.out.println("=======================");         }         //6.释放连接         resultSet.close();         statement.close();         connection.close();     } } 
 
 
步骤总结:
加载驱动 
连接数据库DriverManager 
获取执行SQL的对象 Statement 
获得返回的结果集 
释放连接 
 
JDBC对象解释 
DriverManager
 
1 2 3 4 5 6 7 8 9 10 11 12 13 //1.加载驱动 //DriverManager.registerDriver(new com.mysql.jdbc.Driver()); //推荐这种写法加载驱动 Class.forName("com.mysql.jdbc.Driver"); Connection connection = DriverManager.getConnection(url, userName, passWord); // connection代表数据库 // 数据库设置自动提交 // 事务提交 // 事务回滚 connection.setAutoCommit(true); connection.commit(); connection.rollback(); 
 
URL
 
1 2 3 4 5 6 String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false"; // mysql默认端口3306 // 协议://主机地址:端口号/数据库名?参数1&参数2&参数3 // oracle默认端口1521 // jdbc:oracle:thin:@localhost:1521:sid 
 
Statement 执行sql对象 、 PreparedStatement 执行sql对象
 
1 2 3 4 5 String sql = "SELECT * FROM users";//编写SQL statement.executeQuery();//执行查询 返回ResultSet statement.executeUpdate();//新增,删除,修改,都用这个,返回受影响的行数 statement.execute();//执行任何SQL 
 
ResultSet 查询的结果集,封装了所有的查询结果
 
获得指定的数据类型
1 2 3 4 5 6 7 8 9 10 //在不知道列类型的情况下使用 resultSet.getObject(); //如果知道列类型,就使用指定的类型 resultSet.getString(); resultSet.getInt(); resultSet.getDouble(); resultSet.getBigDecimal(); resultSet.getFloat(); resultSet.getDate(); //... 
 
遍历,指针
1 2 3 4 5 resultSet.beforeFirst();//移动到最前面 resultSet.afterLast();//移动到最后面 resultSet.next();//移动到下一个数据 resultSet.previous();//移动到前一行 resultSet.absolute(row);//移动到指定行 
 
释放资源
 
1 2 3 resultSet.close(); statement.close(); connection.close();//消耗资源 
 
statement对象详解 ==jdbc中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。==
Statement对象的executeUpdate方法,用于向数据库发送增、删、改的SQL语句,executeUpdate执行完后,将会返回一个整数(即增删改语句导致了数据库几行数据发送了变化)。
Statement.executeQuery方法用于向数据库发送查询语句,executeQuery方法返回代表查询结果的ResultSet对象。
CRUD操作-create
 
使用executeUpdate(String sql)方法完成数据添加操作,示例操作:
1 2 3 4 5 6 Statement statement = connection.createStatement(); String sql = "insert into user(...) values(...)"; int num = statement.executeUpdate(sql); if (num > 0) {     System.out.println("插入成功~"); } 
 
CRUD操作-delete
 
1 2 3 4 5 6 Statement statement = connection.createStatement(); String sql = "delete from user where id=1"; int num = statement.executeUpdate(sql); if (num > 0) {     System.out.println("删除成功~"); } 
 
CRUD操作-update
 
1 2 3 4 5 6 Statement statement = connection.createStatement(); String sql = "update user set name='' where name =''"; int num = statement.executeUpdate(sql); if (num > 0) {     System.out.println("修改成功~"); } 
 
CRUD操作-read
 
1 2 3 4 5 6 Statement statement = connection.createStatement(); String sql = "SELECT * FROM users"; ResultSet resultSet = statement.executeQuery(sql); while (resultSet.next()) {     //根据获取列的数据类型,分别调用resultSet的相应方法映射到java对象中 } 
 
代码实现
 
提取工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 package com.chang.lesson2.utils; import java.io.IOException; import java.io.InputStream; import java.sql.*; import java.util.Properties; /**  * @author 行初雾  * @PackageName:com.chang.lesson2.utils  * @ClassName: jdbcUtil  * @Description:  * @date 2022/1/21 2:55  */ public class jdbcUtil {     private static String driver = null;     private static String url = null;     private static String username = null;     private static String password = null;     static {         try {             InputStream in = jdbcUtil.class.getClassLoader().getResourceAsStream("db.properties");             Properties properties = new Properties();             properties.load(in);             driver = properties.getProperty("driver");             url = properties.getProperty("url");             username = properties.getProperty("username");             password = properties.getProperty("password");             //驱动只用加载一次             Class.forName(driver);         } catch (Exception e) {             e.printStackTrace();         }     }     //获取连接     public static Connection getConnection() throws SQLException {         return DriverManager.getConnection(url,username,password);     }     //释放连接资源     public static void release(Connection conn, Statement st, ResultSet rs){         if(rs!=null){             try {                 rs.close();             } catch (SQLException e) {                 e.printStackTrace();             }         }         if(st!=null){             try {                 st.close();             } catch (SQLException e) {                 e.printStackTrace();             }         }         if(conn!=null){             try {                 conn.close();             } catch (SQLException e) {                 e.printStackTrace();             }         }     } } 
 
配置文件db.properties
1 2 3 4 driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false username=root password=cjy521213 
 
编写增删改的方法,executeUpdate
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 package com.chang.lesson2; import com.chang.lesson2.utils.jdbcUtil; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; /**  * @author 行初雾  * @PackageName:com.chang.lesson2  * @ClassName: testInsert  * @Description:  * @date 2022/1/21 2:55  */ public class testInsert {     public static void main(String[] args) {         Connection conn = null;         Statement st = null;         ResultSet rs = null;         try {             conn = jdbcUtil.getConnection(); //获取数据库连接             st = conn.createStatement(); //获取SQL的执行对象             String sql = "INSERT INTO users(id,`name`,`password`,`email`,`birthday`)\n" +                     "VALUE(4,'行初雾','123456','1092315259@qq.com','1999-05-25')";             int i = st.executeUpdate(sql);             if(i > 0){                 System.out.println("插入成功!");             }         } catch (SQLException e) {             e.printStackTrace();         } finally {             jdbcUtil.release(conn,st,rs);         }     } } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 package com.chang.lesson2; import com.chang.lesson2.utils.jdbcUtil; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; /**  * @author 行初雾  * @PackageName:com.chang.lesson2  * @ClassName: testDelete  * @Description:  * @date 2022/1/21 3:15  */ public class testDelete {     public static void main(String[] args) {         Connection conn = null;         Statement st = null;         ResultSet rs = null;         try {             conn = jdbcUtil.getConnection(); //获取数据库连接             st = conn.createStatement(); //获取SQL的执行对象             String sql = "DELETE FROM users WHERE id = 4";             int i = st.executeUpdate(sql);             if(i > 0){                 System.out.println("删除成功!");             }         } catch (SQLException e) {             e.printStackTrace();         } finally {             jdbcUtil.release(conn,st,rs);         }     } } 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package com.chang.lesson2; import com.chang.lesson2.utils.jdbcUtil; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; /**  * @author 行初雾  * @PackageName:com.chang.lesson2  * @ClassName: testUpdate  * @Description:  * @date 2022/1/21 3:17  */ public class testUpdate {     public static void main(String[] args) {         Connection conn = null;         Statement st = null;         ResultSet rs = null;         try {             conn = jdbcUtil.getConnection(); //获取数据库连接             st = conn.createStatement(); //获取SQL的执行对象             String sql = "UPDATE users SET `name` = '行初雾',`email` = '1092315259@qq.com' WHERE id=1";             int i = st.executeUpdate(sql);             if(i > 0){                 System.out.println("更新成功!");             }         } catch (SQLException e) {             e.printStackTrace();         } finally {             jdbcUtil.release(conn,st,rs);         }     } } 
 
查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 package com.chang.lesson2; import com.chang.lesson2.utils.jdbcUtil; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; /**  * @author 行初雾  * @PackageName:com.chang.lesson2  * @ClassName: testSelect  * @Description:  * @date 2022/1/21 3:20  */ public class testSelect {     public static void main(String[] args) {         Connection conn = null;         Statement st = null;         ResultSet rs = null;         try {             conn = jdbcUtil.getConnection(); //获取数据库连接             st = conn.createStatement(); //获取SQL的执行对象             String sql = "SELECT * FROM users WHERE id = 1";             rs = st.executeQuery(sql);             while(rs.next()){                 System.out.println(rs.getString("name"));             }         } catch (SQLException e) {             e.printStackTrace();         } finally {             jdbcUtil.release(conn,st,rs);         }     } } 
 
 
sql注入问题 sql存在漏洞,会被攻击导致数据泄露 ==SQL会被拼接==
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 package com.chang.lesson2; import com.chang.lesson2.utils.jdbcUtil; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; /**  * @author 行初雾  * @PackageName:com.chang.lesson2  * @ClassName: sqlReinject  * @Description: sql注入  * @date 2022/1/21 3:34  */ public class sqlReinject {     public static void main(String[] args) {     	//正常登录     	login("行初雾","123456");     	     	//sql注入         login(" 'or '1=1","'or '1=1");     }     public static void login(String name,String password){         Connection conn = null;         Statement st = null;         ResultSet rs = null;         try {             conn = jdbcUtil.getConnection(); //获取数据库连接             st = conn.createStatement(); //获取SQL的执行对象             String sql = "SELECT * FROM users WHERE `name`= '"+name+"' AND `password`='"+password+"'";             rs = st.executeQuery(sql);             while(rs.next()){                 System.out.println(rs.getString("name"));                 System.out.println(rs.getString("password"));             }         } catch (SQLException e) {             e.printStackTrace();         } finally {             jdbcUtil.release(conn,st,rs);         }     } } 
 
导致结果:错误的用户名或者密码可以获取到全部的用户信息
PreparedStatement对象 PreparedStatement可以防止SQL注入,效率更好
增加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 package com.chang.lesson3; import com.chang.lesson2.utils.jdbcUtil; import java.sql.*; /**  * @author 行初雾  * @PackageName:com.chang.lesson3  * @ClassName: testInsert  * @Description:  * @date 2022/1/21 4:21  */ public class testInsert {     public static void main(String[] args) {         Connection conn = null;         PreparedStatement st = null;         ResultSet rs = null;         try {             conn = jdbcUtil.getConnection();             //使用?占位符代替参数             String sql = "INSERT INTO users(`id`,`name`,`password`,`email`,`birthday`) VALUES (?,?,?,?,?)";             //预编译SQL,先写SQL,然后不执行             st = conn.prepareStatement(sql);             //手动给参数赋值             st.setInt(1,4);             st.setString(2,"行初雾");             st.setString(3,"123456");             st.setString(4,"1092315259@qq.con");             st.setDate(5,new java.sql.Date(new java.util.Date().getTime()));             int i = st.executeUpdate();             if(i > 0){                 System.out.println("插入成功!");             }         } catch (SQLException e) {             e.printStackTrace();         } finally {             jdbcUtil.release(conn,st,rs);         }     } } 
 
删除
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 import com.zyy.lesson02.utils.JDBCUtils; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; /**  * @ClassName: TestDelete  * @Description: TODO 类描述  * @Author: zyy  * @Date: 2021/07/14 18:19  * @Version: 1.0  */ public class TestDelete {     public static void main(String[] args) {         Connection con = null;         PreparedStatement st = null;         ResultSet rs = null;         try {             con = JDBCUtils.getConnection();             //使用?占位符代替参数             String sql = "DELETE FROM users WHERE `id`=?";             //预编译SQL,先写SQL,然后不执行             st = con.prepareStatement(sql);             //手动给参数赋值             st.setInt(1, 5);             int num = st.executeUpdate();             if (num > 0) {                 System.out.println("删除成功!");             }         } catch (SQLException e) {             e.printStackTrace();         } finally {             JDBCUtils.release(con, st, rs);         }     } } 
 
更新
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 package com.chang.lesson3; import com.chang.lesson2.utils.jdbcUtil; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; /**  * @author 行初雾  * @PackageName:com.chang.lesson3  * @ClassName: testUpdate  * @Description:  * @date 2022/1/21 4:38  */ public class testUpdate {     public static void main(String[] args) {         Connection conn = null;         PreparedStatement st = null;         ResultSet rs = null;         try {             conn = jdbcUtil.getConnection();             //使用?占位符代替参数             String sql = "update users set `name`=? where `id` = ?";             //预编译SQL,先写SQL,然后不执行             st = conn.prepareStatement(sql);             //手动给参数赋值             st.setInt(2,5);             st.setString(1,"行初雾");             int i = st.executeUpdate();             if(i > 0){                 System.out.println("修改成功!");             }         } catch (SQLException e) {             e.printStackTrace();         } finally {             jdbcUtil.release(conn,st,rs);         }     } } 
 
查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 package com.chang.lesson3; import com.chang.lesson2.utils.jdbcUtil; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; /**  * @author 行初雾  * @PackageName:com.chang.lesson3  * @ClassName: testSelect  * @Description:  * @date 2022/1/21 4:40  */ public class testSelect {     public static void main(String[] args) {         Connection conn = null;         PreparedStatement st = null;         ResultSet rs = null;         try {             conn = jdbcUtil.getConnection();             //使用?占位符代替参数             String sql = "select * from users where id=?";             //预编译SQL,先写SQL,然后不执行             st = conn.prepareStatement(sql);             //手动给参数赋值             st.setInt(1,5);             rs = st.executeQuery();             while(rs.next()){                 System.out.println("id="+rs.getInt("id"));                 System.out.println("name=" + rs.getString("name"));                 System.out.println("======");             }         } catch (SQLException e) {             e.printStackTrace();         } finally {             jdbcUtil.release(conn,st,rs);         }     } } 
 
防止sql注入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 package com.chang.lesson3; import com.chang.lesson2.utils.jdbcUtil; import java.sql.*; import java.util.Properties; /**  * @author 行初雾  * @PackageName:com.chang.lesson3  * @ClassName: sqlReinject  * @Description:  * @date 2022/1/21 4:43  */ public class sqlReinject {     public static void main(String[] args) {         //正常登录         login("行初雾","123456");         //sql注入         //login("' or '1=1","123456");     }     public static void login(String name,String password){         Connection conn = null;         PreparedStatement st = null;         ResultSet rs = null;         try {             conn = jdbcUtil.getConnection(); //获取数据库连接             String sql = "SELECT * FROM users WHERE `name`=? AND `password`=?";             st = conn.prepareStatement(sql);             st.setString(1,name);             st.setString(2,password);             rs = st.executeQuery();             while(rs.next()){                 System.out.println(rs.getString("name"));                 System.out.println(rs.getString("password"));             }         } catch (SQLException e) {             e.printStackTrace();         } finally {             jdbcUtil.release(conn,st,rs);         }     } } 
 
执行结果:查不到任何结果
 
 
使用idea连接数据库 
连接成功后,就可以选择数据库
连接不上的话,可以看一下下面这里,配置对应的mysql版本
双击数据库
更新数据(提交)
idea编写sql
1 2 3 4 5 6 7 8 9 10 11 create table account (     id    int primary key auto_increment,     name  varchar(40),     money float ); insert into account(name, money) values ('A', 1000),        ('B', 1000),        ('C', 1000); 
 
JDBC操作事务 ==要么都成功,要么都失败==
ACID原则
 
原子性:要么全部成功,要么全部失败
一致性:总数不变
隔离性:多个进程互不干扰
持久性:一旦提交不可逆,持久化到数据库了
隔离性的问题:
脏读:一个事务读取了另外一个没有提交的事务
不可重复读:在同一个事务内,重复读取表中数据,表数据发生了改变
幻读:在一个事务内,读取到了别人插入的数据,导致前后读出来的结果不一致
代码实现
 
开启事务con.setAutoCommit(false); 
一组业务执行完毕,提交事务 
可以在catch语句中显示的定义回滚语句,但是默认失败就会回滚 
 
正常情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 package com.chang.lesson4; import com.chang.lesson2.utils.jdbcUtil; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; /**  * @author 行初雾  * @PackageName:com.chang.lesson4  * @ClassName: testTransaction  * @Description:  * @date 2022/1/21 5:07  */ public class testTransaction {     public static void main(String[] args) {         Connection conn = null;         PreparedStatement st = null;         ResultSet rs = null;         try {             conn = jdbcUtil.getConnection();             //关闭自动提交 自动开启事务             conn.setAutoCommit(false);//开启事务             String sql1 = "update account set money=money-100 where name='A";             st = conn.prepareStatement(sql1);             st.executeUpdate();             String sql2 = "update account set money=money+100 where name='B";             st = conn.prepareStatement(sql2);             st.executeUpdate();             //事务完毕,提交事务             conn.commit();             System.out.println("成功!");         } catch (SQLException e) {             try {                 conn.rollback();             } catch (SQLException ex) {                 ex.printStackTrace();             }             e.printStackTrace();         } finally {             jdbcUtil.release(conn,st,rs);         }     } } 
 
异常情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 package com.chang.lesson4; import com.chang.lesson2.utils.jdbcUtil; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; /**  * @author 行初雾  * @PackageName:com.chang.lesson4  * @ClassName: testTransaction  * @Description:  * @date 2022/1/21 5:07  */ public class testTransaction {     public static void main(String[] args) {         Connection conn = null;         PreparedStatement st = null;         ResultSet rs = null;         try {             conn = jdbcUtil.getConnection();             //关闭自动提交 自动开启事务             conn.setAutoCommit(false);//开启事务             String sql1 = "update account set money=money-100 where name='A";             st = conn.prepareStatement(sql1);             st.executeUpdate();                          //默认失败             int x = 1/0;//一定会异常             String sql2 = "update account set money=money+100 where name='B";             st = conn.prepareStatement(sql2);             st.executeUpdate();             //事务完毕,提交事务             conn.commit();             System.out.println("成功!");         } catch (SQLException e) {             try {                 conn.rollback();             } catch (SQLException ex) {                 ex.printStackTrace();             }             e.printStackTrace();         } finally {             jdbcUtil.release(conn,st,rs);         }     } } 
 
DBCP-C3P0连接池 数据库连接 – 执行完毕 – 释放
连接– 释放 是十分浪费系统资源的
池化技术:准备一些预先的资源,过来就连接预先准备好的
最小连接数:10(常用连接)
最大连接数:100 (业务最高承载上线)
等待超时:100ms
编写连接池,实现一个接口DataSource
开源数据源实现
 
DBCP
C3p0
Druid:阿里巴巴
使用了这些数据库连接池之后,我们在项目开发中就不需要编写连接数据库的代码了
DBCP
 
需要用到的jar包
commons-dbcp-1.4
commons-pool-1.6
配置文件dbcp.properties
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #连接设置 driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false username=root password=123456 #初始化连接 initialSize=10 #最大连接数量 maxActive=50 #最大空闲连接 maxIdle=20 #最小空闲连接 minIdle=5 #超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 maxWait=60000 #JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:【属性名=property;】 #注意:user 与 password 两个属性会被明确地传递,因此这里不需要包含他们。 connectionProperties=useUnicode=true;characterEncoding=UTF8 #指定由连接池所创建的连接的自动提交(auto-commit)状态。 defaultAutoCommit=true #driver default 指定由连接池所创建的连接的只读(read-only)状态。 #如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix) defaultReadOnly= #driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。 #可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE defaultTransactionIsolation=READ_COMMITTED 
 
工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 import org.apache.commons.dbcp.BasicDataSourceFactory; import javax.sql.DataSource; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties; /**  * @ClassName: JDBCDBCPUtils  * @Description: TODO 类描述  * @Author: zyy  * @Date: 2021/07/14 17:48  * @Version: 1.0  */ public class JDBCDBCPUtils {     private static DataSource dataSource = null;     static {         try {             InputStream in = JDBCDBCPUtils.class.getClassLoader().getResourceAsStream("dbcp.properties");             Properties properties = new Properties();             properties.load(in);             //创建数据源 工厂模式             dataSource = BasicDataSourceFactory.createDataSource(properties);         } catch (IOException e) {             e.printStackTrace();         } catch (ClassNotFoundException e) {             e.printStackTrace();         } catch (Exception e) {             e.printStackTrace();         }     }     /**      * 获取连接      */     public static Connection getConnection() throws SQLException {         //从数据源中获取连接         return dataSource.getConnection();     }     /**      * 释放资源      */     public static void release(Connection con, Statement st, ResultSet rs) {         if (rs != null) {             try {                 rs.close();             } catch (SQLException e) {                 e.printStackTrace();             }         }         if (st != null) {             try {                 st.close();             } catch (SQLException e) {                 e.printStackTrace();             }         }         if (con != null) {             try {                 con.close();             } catch (SQLException e) {                 e.printStackTrace();             }         }     } } 
 
测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 import com.zyy.lesson02.utils.JDBCUtils; import com.zyy.lesson05.utils.JDBCDBCPUtils; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; /**  * @ClassName: TestDBCP  * @Description: TODO 类描述  * @Author: zyy  * @Date: 2021/07/15 22:41  * @Version: 1.0  */ public class TestDBCP {     public static void main(String[] args) {         Connection con = null;         PreparedStatement st = null;         ResultSet rs = null;         try {             con = JDBCDBCPUtils.getConnection();             //使用?占位符代替参数             String sql = "INSERT INTO users(`id`,`name`,`password`,`email`,`birthday`) VALUES (?,?,?,?,?)";             //预编译SQL,先写SQL,然后不执行             st = con.prepareStatement(sql);             //手动给参数赋值             st.setInt(1, 5);             st.setString(2, "钱七");             st.setString(3, "123456");             st.setString(4, "qianqi@sina.com");             st.setDate(5, new java.sql.Date(new java.util.Date().getTime()));             int num = st.executeUpdate();             if (num > 0) {                 System.out.println("插入成功!");             }         } catch (SQLException e) {             e.printStackTrace();         } finally {             JDBCDBCPUtils.release(con, st, rs);         }     } } 
 
C3P0
 
需要用到的jar包
c3p0-0.9.5.5.jar
mchange-commons-java-0.2.19.jar
配置文件c3p0-config.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <?xml version="1.0" encoding="UTF-8"?> <c3p0-config>     <!--     c3p0的缺省(默认)配置     如果在代码中ComboPooledDataSource ds=new ComboPooledDataSource();这样写就表示使用的是c3p0的缺省(默认)     -->     <default-config>         <property name="driverClass">com.mysql.jdbc.Driver</property>         <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC</property>         <property name="user">root</property>         <property name="password">123456</property>         <property name="acquiredIncrement">5</property>         <property name="initialPoolSize">10</property>         <property name="minPoolSize">5</property>         <property name="maxPoolSize">20</property>     </default-config>     <!--     c3p0的命名配置     如果在代码中ComboPooledDataSource ds=new ComboPooledDataSource("MySQL");这样写就表示使用的是name是MySQL     -->     <name-config name="MySQL">         <property name="driverClass">com.mysql.jdbc.Driver</property>         <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC</property>         <property name="user">root</property>         <property name="password">123456</property>         <property name="acquiredIncrement">5</property>         <property name="initialPoolSize">10</property>         <property name="minPoolSize">5</property>         <property name="maxPoolSize">20</property>     </name-config> </c3p0-config> 
 
工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 import com.mchange.v2.c3p0.ComboPooledDataSource; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; /**  * @ClassName: JDBCC3P0Utils  * @Description: TODO 类描述  * @Author: zyy  * @Date: 2021/07/14 17:48  * @Version: 1.0  */ public class JDBCC3P0Utils {     private static DataSource dataSource = null;     //private static ComboPooledDataSource dataSource = null;     static {         try {             //代码的方式配置 //            dataSource = new ComboPooledDataSource(); //            dataSource.setDriverClass(); //            dataSource.setJdbcUrl(); //            dataSource.setUser(); //            dataSource.setPassword(); //            dataSource.setMaxPoolSize(); //            dataSource.setMinPoolSize();             //配置文件写法             dataSource = new ComboPooledDataSource("MySQL");         } catch (Exception e) {             e.printStackTrace();         }     }     /**      * 获取连接      */     public static Connection getConnection() throws SQLException {         //从数据源中获取连接         return dataSource.getConnection();     }     /**      * 释放资源      */     public static void release(Connection con, Statement st, ResultSet rs) {         if (rs != null) {             try {                 rs.close();             } catch (SQLException e) {                 e.printStackTrace();             }         }         if (st != null) {             try {                 st.close();             } catch (SQLException e) {                 e.printStackTrace();             }         }         if (con != null) {             try {                 con.close();             } catch (SQLException e) {                 e.printStackTrace();             }         }     } } 
 
测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 import com.zyy.lesson05.utils.JDBCC3P0Utils; import com.zyy.lesson05.utils.JDBCDBCPUtils; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; /**  * @ClassName: TestC3P0  * @Description: TODO 类描述  * @Author: zyy  * @Date: 2021/07/15 22:41  * @Version: 1.0  */ public class TestC3P0 {     public static void main(String[] args) {         Connection con = null;         PreparedStatement st = null;         ResultSet rs = null;         try {             con = JDBCC3P0Utils.getConnection();             //使用?占位符代替参数             String sql = "INSERT INTO users(`id`,`name`,`password`,`email`,`birthday`) VALUES (?,?,?,?,?)";             //预编译SQL,先写SQL,然后不执行             st = con.prepareStatement(sql);             //手动给参数赋值             st.setInt(1, 6);             st.setString(2, "刘八");             st.setString(3, "123456");             st.setString(4, "liuba@sina.com");             st.setDate(5, new java.sql.Date(new java.util.Date().getTime()));             int num = st.executeUpdate();             if (num > 0) {                 System.out.println("插入成功!");             }         } catch (SQLException e) {             e.printStackTrace();         } finally {             JDBCC3P0Utils.release(con, st, rs);         }     } } 
 
总结
 
无论用什么数据源,本质还是一样的,DataSource接口不会变,方法就不会变
Welcome to The Apache Software Foundation!