目录
MySQL数据库
第一章
1、什么是数据库
2、数据库分类
3、不同数据库的特点
4、MySQL常见命令:
5、MySQL基本语法
第二章
1、MySQL的常见数据类型
1、数值类型
2、字符类型
3、时间日期类型
2、SQL语句分类
1、DDL(数据定义语言)
2、DML(数据操作语言)
3、DQL(数据查询语言)
4、DCL(数据控制语言)
3、MySQL的查询
第三章
函数顺序
函数
排序函数
分组函数
聚合函数
日期函数
字符函数
数学函数
逻辑判断
第四章
1、数据完整性
1、实体完整性
2、域完整性
3、引用完整性
2、三范式
1、第一范式:确保数据表中每一列的原子性
2、第二范式:确保表中的每列都和主键相关
3、第三范式:数据表中的每一列,与主键直接相关,不能间接关联
3、多表连接查询(重点)
1、内连接 INNER JOIN
1、显式内连接
2、隐式内连接
2、外连接 OUTER JOIN
1、左外连接 left outer join
2、右外连接 right outer join
3、子查询
情况1
情况2
情况3
第五章
第六章
1、事务
1、概念:
2、特性:
2、四个特性(ACID)
1、原子性(Atomicity)
2、一致性(Consistency)
3、隔离性(Isolation)
4、持久性(Durability)
3、三个并发问题
1、脏读(Dirty read)
2、不可重复读(Unrepeatable read)
3、幻读(Phantom read)
4、视图(view)
1、视图的概念
2、视图的好处
3、sql展示
5、存储过程
1、什么是存储过程
2、存储过程的优点
第七章
1、jdbc的使用
jdbc几个重要方法
2、基于jdbc的增删改
3、基于jdbc的查询
4、数据库的dao模式
5、jdbc常见错误
第八章
1、数据库连接池的使用
2、jdbctemplate
jdbctemplate模板的使用步骤:
1、查询全部(返回的list集合)
2、根据id查询(返回的对象)
3、查询总人数
4、模糊查询
5、查询全部(返回的map集合)
6、 根据id查询(返回的是map集合)
7、多表联合查询(返回map集合)
MySQL数据库
第一章
1、什么是数据库
存储数据方式: 1、将数据存储在内存中,当程序关闭数据消失2、将数据存在文件中,通过流的方式写入文件3、将数据存储在数据库中,如mySQL
2、数据库分类
可分为:1、关系型数据库指定数据采用数据表的方式将数据存储在数据库中SQLserverMySQL(会学习)oracle(会学习)DB2..2、非关系型数据库它的数据是存储在内存中,读取数据快Redis(会学习)MongoDB..
3、不同数据库的特点
1、SQLserver它是微软开发工程师,主要用于.net项目 2、MySQL(重点)它是一个中小型数据库,比较方便、灵活。它主要用于中小项目3、 oracle甲骨文公司开发的数据库产品,主要中大型项目4、db2IMB开发的数据库,主要用于金融类项目5、redis mongodb一种非关系型数据库,数据存放在内存中速度会非常快
第三方工具
1、sqlyog 2、navicat
4、MySQL常见命令:
datebase:数据库
table:数据库
create:创建
drop:删除
use:使用
show:查看
show datebases----查看当前数据库系统包含几个数据库: use数据库名称------连接数据库 ------------创建数据库1,指定编码格式utf8 create datebase 新数据库名 default character set utf8; ------------创建数据库2,采用默认的编码格式 create datebase 新数据库名称; ------------创建数据库3,创建时判断数据库名是否存在 create datebase if not exists 数据库新名称; drop datebase if exists 数据库名--------判断是否存在删除
5、MySQL基本语法
#单行注释 --单行注释 /**/多行注释 --------------------------------------操作库 SHOW DATABASES;-- 查看数据库 CREATE DATABASE a DEFAULT CHARACTER SET utf8;--创建数据库 CREATE DATABASE b-- 创建数据库 CREATE DATABASE IF NOT EXISTS d-- 创建数据库 DROP DATABASE a-- 删除数据库 DROP DATABASE IF EXISTS b-- 删除数据库 -------------------------------------操作表 USE d118-- 选择数据库 SHOW TABLES-- 查看表 DROP TABLE student-- 删除表 DESC student-- 查看表结构 ALTER TABLE student RENAME stu_info;-- 修改表名称 --------------------------------------操作列 ALTER TABLE student MODIFY stu_id INT;-- 修改表的数据类型,只能修改类型,不能改名 ALTER TABLE student CHANGE stu_id id VARCHAR(20)-- 修改表的列名 并修改数据类型 ALTER TABLE student ADD stu_cla VARCHAR(20);-- 增加列 ALTER TABLE student DROP stu_cla;-- 删除列 --------------------------------------操作表的数据 1、向表中添加数据#添加数据 INSERT INTO student(stu_id,stu_name,stu_score,stu_cla) VALUES(1,'lwj',90,'D118');#添加数据-简化写法 INSERT INTO student VALUES(1,'lwj',90,'D118');#一次添加多条数据 INSERT INTO student VALUES(1,'lwj',90,'D118'),(2,'lw',95,'D113'),(4,'l',85,'D116'); #给部分列添加 INSERT INTO student(stu_id,stu_cla) VALUES(1,'D118'); 2、修改数据#修改全部数据//让表中的所有成绩都减10分 UPDATE student SET stu_score=stu_score-10;#根据条件修改 UPDATE student SET stu_score=0 WHERE stu_id=2; 3、删除数据#删除全部数据 DELETE FROM student;#根据条件删除//删除id为1的数据 DELETE FROM student WHERE stu_id=1; /*delete删除数据与truncate截断表删除的区别1、delete是一行一行删除 ,可以带条件删2、truncate一次截断表中的全部数据,只保留表结构,一次性删完,但不能带条件删drop删除与delete删除的区别1、drop只能删除对象(数据库),无法删除数据2、delete只能删除数据,不能删除对象(数据库) */ 4、查询数据#查看表的所有数据 SELECT *FROM student;#查询部分字段 SELECT stu_id,stu_score FROM student;#查询时,给字段指定别名(AS可以省略不写) SELECT stu_id AS 姓名,stu_score AS 成绩 FROM student;#按条件查询 SELECT *FROM student WHERE stu_id=4;#查询姓名不为空的数据 SELECT *FROM student WHERE stu_name IS NOT NULL;#查询成绩为空的数据 SELECT *FROM student WHERE stu_score IS NULL;
创建表结构
注释不会被保存 USE d118; CREATE TABLE student (stu_id INT,-- 学生编号stu_name VARCHAR(20),-- 学生名称,字符长度为20stu_score FLOAT(8,2)-- 成绩,浮点数,有效位数8位,小数点后保留2位 ); 注释会被保存 CREATE TABLE student (stu_id INT COMMENT'此方法可以导出注释',-- 学生编号stu_name VARCHAR (20) COMMENT'名称',-- 学生名称,字符长度为20stu_score FLOAT (8, 2) COMMENT'成绩'-- 成绩,浮点数,有效位数8位,小数点后保留2位 );
第二章
1、MySQL的常见数据类型
1、数值类型
INT -- 整数型BIGINT -- 相当于java的long类型,只能存储整数FLOAT -- 单精度浮点型DOUBLE -- 双精度浮点型DECIMAL -- 表示货币类型的数据LONG -- 大型文本类型,并不是long类型
2、字符类型
CHAR -- 字符类型VARCHAR -- 字符类型char和varchar都能表示字符类型的数据,不区分单双引号VARCHAR(20)与CHAR(20)有什么区别:1、CHAR(20)系统会分配20个存储空间,不满20个数据时,空间也不会缩放,造成空间浪费VARCHAR(20)存储不满20个数据时,空间会自动缩放,节省资源2、CHAR的速度会快一些,因为它不用检测存储空间是否占满VARCHAR会检查存储空间,判断是否要进行空间缩放推荐情况:如果确定存储数据长度,用char更快如:性别、电话、身份证号码如果不确定,则用varchar如:住址、姓名、备注
3、时间日期类型
1、DATE -- 只包含年月日,不带时分秒2、DATETIME -- 包含年月日,也包含时分秒3、TIMESTAMP(时间戳) -- 包含年月日,也包含时分秒给日期类型数据赋值:1、指定固定值(DATE DATETIME TIMESTAMP)INSERT INTO student VALUES(1,'JACK','2010-10-10','2010-10-10 11:22;33','2010-10-01 11:22:44') ;2、采用系统默认时间 NOW()--获得系统时间,包含年月日 时分秒INSERT INTO student VALUES(2,'zs',NOW(),NOW(),NOW())3、采用系统默认时间 CURDATE()--获得当前时间,只有年月日,没有时分秒INSERT INTO student VALUES(2,'zs',CURDATE(),NOW(),NOW())4、采用系统默认时间 CURTIME();--获得当前时间,只有时分秒datetime与timestamp的区别:datetime如果值为null,系统会显示nulltimestamp如果值为null,系统会显示默认时间
2、SQL语句分类
1、DDL(数据定义语言)
DDL: DATA DEFINITION DATACREATE-- 创建对象DROP-- 删除对象
2、DML(数据操作语言)
DML: DATA MANIPULATION DATAINSERT-- 添加数据 UPDATE-- 修改数据DELETE-- 删除数据
3、DQL(数据查询语言)
DQL: DATA QUERY DATASELECT-- 查询数据
4、DCL(数据控制语言)
GRANT-- 给用户授权REVOKE-- 撤销用户权限
3、MySQL的查询
增删改查(crud):最简单的就是增 删 改,查是最麻烦的
-- 普通查询#查询全部数据 *:代表所有列SELECT *FROM student;#只查询部分字段SELECT stu_id FROM student;#查询时设置别名SELECT stu_id 编号,stu_name 姓名 FROM student;;
-- 条件查询#精准查询SELECT *FROM student WHERE stu_id=1;#如果查询的条件是字符,需要加引号SELECT *FROM student WHERE stu_name='张三';#比较查询 > >= < <= = != <>SELECT *FROM student WHERE stu_score >=53;#日期类型也能比较,但只会比较数值大小 2000-10-10>1980-10-10SELECT *FROM student WHERE stu_bir >'1995-10-10';#区间查询 BETWEEN AND:-- 它用于区间查询-- 语法: 字段 BETWEEN 开始值 AND 结束值(包含开始和结束)-- 注意: 查询时较小值放在前面SELECT *FROM student WHERE stu_score BETWEEN 80 AND 90;#区间排除查询SELECT *FROM student WHERE stu_score NOT BETWEEN 80 AND 90;#日期区间查询 SELECT *FROM student WHERE stu_birT BETWEEN '1995-01-01' AND '1999-01-01' #范围查询IN:在某个范围中NOT IN:不在某个范围中SELECT *FROM student WHERE stu_class IN('d115','d119');#模糊查询LIKE:模糊查询的关键字,只能用于字符类型的查询,一般会使用通配符_ 代表任意的一个字符% 代表任意长度,任意内容SELECT *FROM student WHERE stu_name LIKE '刘_';#姓名必须两个字,必须以刘开头SELECT *FROM student WHERE stu_name LIKE '_文'姓名必须两个字,必须以文结尾SELECT *FROM student WHERE stu_name LIKE '刘%';必须以刘开头,无论多少字符SELECT *FROM student WHERE stu_name LIKE '%文%';所有包含文字的内容#逻辑运算符查询&& AND --表示连接的多个条件同时满足(用&&或者AND都可以)|| OR --表示连接的条件只满足一个就可以SELECT *FROM student WHERE stu_score>=60 AND stu_gender='男';#对查询的数据排序ORDER BY:排序的关键字(默认升序)ASC:升序(从小到大)DESC:降序(从大到小)SELECT *FROM student ORDER BY stu_score DESC;按成绩降序排序#当出现数据相同无法排序时,还可以按其他列排序SELECT *FROM student ORDER BY stu_score DESC,stu_id DESC#聚合查询一般用于统计汇总,它只能返回单行单列的唯一结果SUM() -- 计算某一个字段值相加的总和SELECT SUM(stu_score) FORM student; -- 统计总分数AVG() -- 计算某一个字段的平均分SELECT AVG(stu_score) FORM student; -- 统计总分数COUNT() -- 统计总条数据SELECT COUNT(*) FORM student; -- 统计总条数MIN() -- 统计某个字段的最小值MAX() -- 统计某个字段的最大值-- 统计考试合格的人数SELECT COUNT(*) FORM student WHERE stu_score>=60;#分组查询 where只能出现在group 之前GROUP BY:用于按某一个字段进行分组语法:SELECT 分组的列,聚合函数 FORM 表 GROUP BY 分组的列;#统计有哪些班级SELECT stu_class 班级名称 FORM student GROUP BY stu_class;#统计有哪些班级,以及每个班有多少学生--先分组,再聚合SELECT stu_class 班级名称,COUNT(*) FORM student GROUP BY stu_class;#多列分组#先分组班级,再分组性别,最后统计人数 SELECT stu_class 班级名称,stu_gender 性别 ,COUNT(*)人数 FORM student GROUP BY stu_class,stu_gender; #统计每一个班级男生女生考试合格的人数 SELECT stu_class 班级名称,stu_gender 性别 ,COUNT(*)人数 FORM student WHERE stu_score>=60 GROUP BY stu_class,stu_gender; #统计每一个班,考试合格人数,并且按合格人数,降序排列 SELECT stu_class 班级名称,COUNT(*) FORM student WHERE stu_score>=6 GROUP BY stu_class· ORDER BY COUNT(*) DESC; #显示所有班级人数在5人以上的班级where只能在group by之前使用,如果使用分组之后需要条件判断,只能用having设置条件SELECT stu_class,COUNT(*) FORM student GROUP BY stu_class HAVING COUNT(*)>=5
目前查询用到关键字:
where---过滤条件group by--分组having---分组之后设置条件order by--排序 如果同时出现,必须遵循下列顺叙where---gruop by---having---order by--
limit分页查询
LIMIT 指定从哪一个下标开始,查询几条数据语法: SELECT * FORM 表 LIMIT 开始下标,几条数据SELECT *FROM student LIMIT 0,3;#查找分数最高的三个学生信息SELECT *FROM student ORDER BY stu_score DESC LIMIT 0,3;
第三章
函数顺序
select * from 表名 where ... group by ... ha order by score desc limit 0,3
函数
排序函数
排序函数 ORDER BY (DESC降序) (ASC升序) SELECT * FROM 表 ORDER BY 字段; #没有指定排序方式,默认是升序 SELECT * FROM 表 ORDER BY 字段 ASC; SELECT * FROM 表 ORDER BY 字段 DESC; SELECT * FROM 表 ORDER BY 字段1 DESC,字段2 DESC;
分组函数
ROUP BYSELECT 分组字段名,聚合函数 FROM 表 GROUP BY 分组字段名;SELECT 字段名1,字段名2,聚合函数 FROM 表 GROUP BY 字段名1,字段名2;SELECT class,COUNT(*) FROM info GROUP BY class;SELECT class,gender,COUNT(*) FROM info GROUP BY class,gender;##分组之前设置条件用where,分组之后设置条件用having#分组之前设置条件SELECT class,COUNT(*) FROM info WHERE score>=60 GROUP BY class;#分组之后设置条件(只统计考试合格人数在5人以上的班级)SELECT class,COUNT(*) FROM info WHERE score>=60 GROUP BY class HAVINGCOUNT(*)>=5;SELECT class,COUNT(*) FROM info WHERE score>=60 GROUP BY class HAVINGCOUNT(*)>=5ORDER BY COUNT(*);
聚合函数
MAX() #求最大值MIN() #求最小值COUNT() #求总记录数SUM() #求总合AVG() #求平均值SELECT COUNT(*),MAX(score),MIN(score),AVG(score),SUM(score) FROM info;
日期函数
作用:用于执行与日期相关的操作NOW();#获得当前系统时间,包含年月日,时分秒SELECT NOW();INSERT INTO 表 VALUES(NOW());CURDATE();#获得当前系统时间,包含年月日SELECT CURDATE(); CURTIME();#获得当前系统时间,包含时分秒SELECT CURTIME();YEAR(),MONTH(),DAY(),HOUR(),MINUTE(),SECOND();#这一组函数,用于获得当前系统时间指定部分的值SELECT YEAR(NOW());SELECT MONTH(NOW());SELECT DAY(NOW());SELECT MINUTE(NOW());SELECT YEAR('2010-10-10');SELECT NAME,bir,YEAR(bir) FROM info;LAST_DAY();#获得指定日期所在月份的最后一天是哪一个日期SELECT LAST_DAY(NOW());SELECT NAME,bir,LAST_DAY(bir) FROM info;#在实际开发中,数据表中不会有年龄字段DATEDIFF() #该函数用于计算两个日期之间间隔的天数语法: DATEDIFF(较近的日期,较远的日期);SELECT DATEDIFF(CURDATE(),'2012-08-01');SELECT FLOOR(DATEDIFF(CURDATE(),'2012-08-01')/365) 年龄;TIMESTAMPDIFF() #该函数用于获得两个时间之间间隔的数值(单位由自己设置)语法: TIMESTAMPDIFF(时间单位,较远的日期,较近的日期)时间单位:YEAR,MONTH,DAY,HOUR,MINUTE,SECONDSELECT TIMESTAMPDIFF(YEAR,'2012-08-01',CURDATE());
字符函数
LENGTH() #计算所占字节长度 #注意:一个汉字占3个字节长度SELECT LENGTH('A');TRIM();#去掉字符两侧的空格SELECT TRIM(' aa ') 数据;LOWER(),UPPER();#转换字母的大小定#lower()转换成小写#upper()转换成大写SELECT LOWER('ABCabc') 小写,UPPER('ABCabc') 大写;SUBSTR(),SUBSTRING();#这两种函数都是用于截取字符串,没有区别SELECT SUBSTR(字符数据,开始位置,长度);SELECT SUBSTR('12345ABC678',6,3);SELECT SUBSTRING('12345ABC678',6,3);REPLACE()#替换字符串的指定内容SELECT REPLACE(字符内容,旧数据,新数据);SELECT REPLACE('你好!张三','张三','李四');SELECT REPLACE('13986141027','86141','*****');SELECT REPLACE('123ABC123','123','ttt');SELECT REPLACE('13999999999','99999','*****');INSERT()#替换字符串的指定内容SELECT INSERT(字符数据,开始位置,长度,新内容);SELECT INSERT('13999999999',4,5,'*****');CONCAT()#将多个字符数据。连接成在一起SELECT CONCAT(字符数据1,字符数据2,字符数据3);SELECT CONCAT('张三的成绩是','100','分');SELECT CONCAT(NAME,'的分数是:',score) FROM info;LPAD,RPADLPAD:截取字符数据,如果要截取的数据长度不够,就从左边填充指定字符数据SELECT LPAD('12345ABCDE123',5,'*');SELECT LPAD('12',5,'*');RPAD:截取字符数据,如果要截取的数据长度不够,就从右边填充指定字符数据SELECT RPAD('12345ABCDE123',5,'*');SELECT RPAD('12',5,'*');
数学函数
FLOOR();#向下取整,取一个小于当前浮点数的最大整数SELECT FLOOR(123.45);CEIL();#向上取整,取一个大于当前浮点数的最小整数SELECT CEIL(123.45);RAND();#获得一个介于0-1之间的随机浮点数SELECT RAND();POWER(X,Y);#计算x的y次方SELECT POWER(2,6);ROUND();#对浮点数,四舍五入,保留指定位数SELECT ROUND(123.45678,2);UUID();#产生一个36位的随机字符串,它由32个字符加四根横线构成SELECT UUID();
逻辑判断
IF()#作用:用于在查询语句,进行逻辑判断,生成新的信息SELECT IF(表达式,结果1,结果2);#如果表达式成立,就显示结果1,否则显示结果2SELECT NAME,score,IF(score>=60,'合格','不合格') 考核结果 FROM info;CASE ...WHEN#作用:用于进行多条件判断SELECT CASEWHEN 表达式1 THEN '结果1'WHEN 表达式2 THEN '结果2'WHEN 表达式3 THEN '结果3'ELSE '结果4'END 结果SELECT NAME,score,CASEWHEN score>=90 THEN '优秀'WHEN score>=80 THEN '良好'WHEN score>=60 THEN '合格'ELSE '不合格'END 考核结果FROM info;
第四章
1、数据完整性
数据完整性包含三个方面:
1、实体完整性
目的:保证数据表的每一条记录,可以被唯一标识
下列约束,可以保证数据的实体完整性
1、主键约束 PRIMARY KEY#此约束,该列的值不允许为空,并且不允许出现重复值2、唯一约束 UNIQUE#此约束不允许出现重复值3、自动增长列(自动标识列) AUTO_INCREMENT一#般在主键字段上,可以加上自动标识列,这样,主键值将会由系统自动生成连续的序号约束:CONSTRAINT #主键约束与唯一约束都要约束保证列不出现重复值,区别是:1、一张表只能有一个主键约束,一张表可以有多个唯一约束2、字段加了主键约束后,该字段不允许出现null值,字段加了唯一约束,可以出现null值,但null值只能出现一次3、字段加了主键约束,该字段可以被外键引用,加了唯一约束的字段无法被引用#为了让每一条数据可以被唯一的标识,建议每一张表一定要有主键#示例:CREATE TABLE student(id INT PRIMARY KEY AUTO_INCREMENT,name varCHAR(20),score INT)INSERT INTO student(id) VALUE(NULL); (但这样写毫无意义,我因此,我们用到域完整性,保证数据有效)
2、域完整性
目的:保证数据表中每一列的值,准确有效
1、非空约束 not null此约束不允许出现null值#示例:CREATE TABLE student(id INT PRIMARY KEY AUTO_INCREMENT,(主键)name varCHAR(20),score INT NOT NULL(非空约束))2、默认值约束 default此约束,如果没有给字段赋值,系统会使用默认值#示例: CREATE TABLE student{id INT PRIMARY KEY AUTO_INCREMENT,(主键)name varCHAR(20),score INT DEFAULT 0(如果没有赋值,则默认0分)}
3、引用完整性
目的:保证一张表引用另一张表的数据,引用的数据,在另一张表中是存在的
1、---------------------直接在创表的时候添加主键约束#省份表(主键表)CREATE TABLE province{pid INT PRIMARY KEY AUTO_INCREMENT,(主键 省份编号)pname VARCHAR(20)(省份名称)} INSERT INTO province VALUES(1,'湖北省'); INSERT INTO province VALUES(1,'广东省');#城市表(外键表)CREATE TABLE city{cid INT PRIMARY KEY AUTO_INCREMENT,(主键 城市编号)cname VARCHAR(20),(城市名称)pid INT, (城市所属省份编号)FOREIGN KEY (pid) REFERENCES province(pid)#外键约束} INSERT INTO city VALUES(1,'武汉',1); INSERT INTO city VALUES(2,'襄阳',1); INSERT INTO city VALUES(3,'广东',2); 2、-----------------------先创表,再添加约束#城市(主键表)CREATE TABLE city{cid INT ,cname VARCHAR(20),}//修改id为主键约束,并自动增长ALTER TABLE city MODIEY cid INT PRIMARY KEY AUTO_INCREMENT//修改城市名称非空ALTER TABLE city MODIEY cname varchar(20) not null#学生表CREATE TABLE stu{sid INT PRIMARY KEY AUTO_INCREMENT,sname VARCHAR(20) not null,cid INT}//ALTER TABLE stu ADD CONSTRAINT fk_cid FOREIGN KEY (cid) REFERENCES city(cid)1、外键约束 foreign key此约束,1、只有主键表中存在的主键字段,外键表才可以引用2、如果主键表的主键字段被外键引用,则当外键表数据删除之前,主键表的数据不允许被删除3、如果主键表被外键表关联,在外键表被删除之前,主键表不能被删除#主键表:被外键字段引用的数据表;#外键表:主动去引用数据的表FOREIGN KEY (外键表的外键字段名) REFERENCES 主键表(主键字段名)
2、三范式
在创建数据表时,我们一般遵循三范式原则:
采用三范式创建的数据表相对合理,避免产生过多的沉余
1、第一范式:确保数据表中每一列的原子性
翻译:数表的每一列都是不可拆分的最小单元
2、第二范式:确保表中的每列都和主键相关
翻译:一张表只描述一件事,如果描述了多件事,需要分解成不同的表
3、第三范式:数据表中的每一列,与主键直接相关,不能间接关联
翻译:一张表如果引用了另一张表的主键字段,就不能再包含另一张表的其他字段
3、多表连接查询(重点)
#在进行多表关联时,一定要正确设置关联条件,否则会产生“笛卡尔积” 笛卡尔积:数据表的数据交叉匹配(如果去掉on后面的,就会产生笛卡尔积) SELECT 字段.. FROM 表1 INNER JOIN 表2 ON(表1.字段=表2.字段) 例如:a表:5条数据 b表:4条数据 笛卡尔积就等于20条数据 2表至少要设置1个关联条件 3张表至少要设置2个关联条件 n张表要设置n-1个关联条件
1、内连接 INNER JOIN
#特点:它所连接的两张表是平级关系,必须要两张表都存在的数据,才可以建立连接语法:SELECT 字段.. FROM 表1 INNER JOIN 表2 ON(表1.字段=表2.字段);SELECT stu.sid,stu.sname,stu.sgender,stu.sclass,score.socres FROM stu INNER JOIN score ON(stu.sid=score.Sno)#问题:两张表进行连接是否一定要创建出外键关系? 不需要,外键的作用主要是限制,添加数据时只有主键表有的数据,外键表才能引用。 不论有没有主外键关系,两张表都可以进行连接查询#问题2: 在进行表连接时,字段名前面的表名称能不能省略不写? 如果当前显示的字段名在两张表中,没有重名的情况下,字段名前的表名可以省 SELECT stu.sid,sname,sgender,sclass,socres FROM stu INNER JOIN score ON(stu.sid=Sno)#如果表名太长 我们可以起别名(a和b) SELECT a.sid,sname,sgender,sclass,socres FROM stu a INNER JOIN score b ON(a.sid=Sno)
内连接有两种写法:
1、显式内连接
#两张表的连接条件用on指定,连接条件要写在括号中 SELECT 字段.. FROM 表1 INNER JOIN 表2 ON(表1.字段=表2.字段); #如果两张表连接后还要设置查询条件,在on的连接条件后,用where指定即可 SELECT 字段.. FROM 表1 INNER JOIN 表2 ON(表1.字段=表2.字段) where 条件
2、隐式内连接
语法:SELECT 字段.. FROM 表1,表2 where 表1.字段=表2.字段 SELECT a.sid,sname,sgender,sclass,socres FROM stu a,score b WHERE a.sid=Sno #如果要设置条件,在后面加and SELECT a.sid,sname,sgender,sclass,socres FROM stu a,score b WHERE a.sid=Sno AND socres=90
#三张表的连接1、显式语法:SELECT 字段.. FROM 表1 INNER JOIN 表2 ON(表1.字段=表2.字段) INNER JOIN 表3 ON(表1.字段=表3.字段) ...2、隐式语法:SELECT 字段.. FROM 表1,表2,表3 where 表1.字段=表2.字段 AND表1.字段=表3.字段
2、外连接 OUTER JOIN
#特点:外连接的两张表分为主表和副表,主表的数据必须全部显示,副表的数据与主表的数据对应才能显示 #三张表的外连接 SELECT a.sid 编号,sname 姓名,sage 年龄,sgender 性别,sclass 班级,stel 电话,sregtime 入学时间,socres 分数,cname 课程 FROM stu a LEFT JOIN score b ON (a.sid=Sno)LEFT JOIN course c ON (b.cid=c.cid);#问题:外连接与内连接有什么区别 1、内连接所连接的两张表是平级关系,必须要两张表都有的数据,才可以建立关联外连接所连接的两张表不是平级关系,分为主表与副表,主表的数据必须全部显示,副表的数据与主表的数据对应才能显示
1、左外连接 left outer join
#左侧的表是主表,右侧的表是副表 简写:left join a表 left outer join b表 SELECT a.sid,sname,sgender,sclass,socres FROM stu a LEFT JOIN score b ON(a.sid=Sno)
2、右外连接 right outer join
#右侧的表是主表,左侧的表是副表 简写:right join a表 right outer join b表 SELECT a.sid,sname,sgender,sclass,socres FROM stu a RIGHT JOIN score b ON(a.sid=Sno)
3、子查询
#在一条查询语句中,包含多个select子句,这样的查询语句,就称为:子查询(三种情况) 注意:在子查询中,括号里面的语句先执行,括号外面后执行select * from 表 where 字段 in (select *from 字段)
情况1
#如果子查询语句返回的是单行、单列的唯一结果,子查询语句一般作为查询条件进行数据的过滤,并且在匹配条件是,只能使用下列符号 > >= < <= = != <>第一步:查询班级考试的平均分select AVG(socres) FROM score -- 80.5第二步:查询考试成绩低于班级平均分的学生select * FROM score WHERE socres <80.5第三步:推理可得(相当于省略了获得平均分那一步,合并到第二步进行查询)select * FROM score WHERE socres <(select AVG(socres) FROM score)
情况2
#如果子查询语句的结果是返回的单列,多行,它一般也是用作为条件去过滤,并且只能用下列符号进行条件判断 in, not in题目:查询所有没有参加考试的学生1、首先查询成绩表,找到参加考试的学生idSELECT sno FROM score -- (1,2,3,4,5,6,7)这些学生参加考试了2、判断哪些学生没有参加考试select * from stu WHERE sid NOT in(1,2,3,4,5,6,7)3、推理可得(把第一步带入到第二步中)select * from stu WHERE sid NOT in(SELECT sno FROM score)
情况3
#如果子查询返回的是多行、多列,一般是把查询结果当做一张表来继续查询#如果要把查询的结果当做表使用,要求必须给查询的结果指定别名 select * from 第一步:先查询学生表SELECT *from stu第二步:连接学生表,成绩表,课程表,按分数来修改学生表的备注resSELECT sname,cname,socres,CASE WHEN socres>=90 THEN '优秀'WHEN socres>=80 THEN '良好' WHEN socres>=60 THEN '及格'ELSE '不及格'END res FROM score a, stu b,course c WHERE a.sno=b.sid AND a.cid=c.cid第三步:将第一步查询到的学生表结果,当做新的表来查询,指定新表名称为kSELECT *from (SELECT sname,cname,socres,CASE WHEN socres>=90 THEN '优秀'WHEN socres>=80 THEN '良好' WHEN socres>=60 THEN '及格'ELSE '不及格'END res FROM score a, stu b,course c WHERE a.sno=b.sid AND a.cid=c.cid) k ;拓展:将学生表的res分组,合并显示及格多少人,不及格多少人SELECT res 备注,COUNT(*) 人数 from (SELECT sname,cname,socres,CASE WHEN socres>=90 THEN '优秀'WHEN socres>=80 THEN '良好' WHEN socres>=60 THEN '及格'ELSE '不及格'END res FROM score a, stu b,course c WHERE a.sno=b.sid AND a.cid=c.cid) k GROUP BY k.res;
第五章
视图----事务-----jdbc
好家伙,看完第五章视频,结果光讲外连接和子查询去了,视图和事务还有jdbc是一点没讲啊
第六章
此章没有视频,在哔站看的
1、事务
事务:(Transaction)是用来维护数据库完整性的,它能够保证一系列MySQL操作要么全部执行,要么全部执行
1、概念:
事务指的是一个操作序列,该操作序列中的多个操作要么都做,要么都不做,是一个不可分割的工作单位,是数据库环境中逻辑工作单位,由DBMS(数据库管理系统)中的事务管理子系统负责事务处理。
2、特性:
事务处理可以确保非事务性序列内的所有操作都成功,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全执行,要么全不失败,可以简化错误恢复并使应用程序更加可靠 但不是所有的操作序列都可以称为事务,因为要成为事务,必须满足四个特性 C:\Program Files\MySQL\MySQL Server 5.5
示例:
DROP TABLE account 创建账户表 CREATE TABLE account ( id INT PRIMARY KEY auto_increment,uname VARCHAR (20) NOT NULL,balance DOUBLE 查看 SELECT * FROM account 插入数据 INSERT INTO account VALUES(null,'李白',2000),(null,'韩信',2000) 开启事务(开始转账) START TRANSACTION; 转账(此时改的数据只是缓存的数据,并不是数据库的数据) UPDATE account set balance=balance-200 WHERE id=1; UPDATE account set balance=balance+200 WHERE id=2; 回滚(这里之所以可以回滚,是因为数据库的真正数据并没有改变) ROLLBACK 提交(这时候才是真正改变数据库的数据) COMMIT
2、四个特性(ACID)
1、原子性(Atomicity)
原子是自然界最小的颗粒,,具有不可再分的特性。事务中的所有操作可以看做一个原子,事务是应用中不可再分的最小逻辑执行体。使用事务对数据进行修改的操作序列,要么全部执行,要么全部不执行。通常,某个事务中的操作都具有共同的目标,并且是相互依赖的。
2、一致性(Consistency)
一致性是指事务执行的结果必须是数据库从一个一致性状态,变到另一个一致性状态。当数据库只包含事务成功提交的结果时,数据库处于一致性状态。一致性是通过原子性来保证的例如:在转账时,只有保证转出和转入的金额一致才能构成事务。也就是说事务发生前和发生后,数据的总额依然匹配
3、隔离性(Isolation)
隔离性是指各个事务的执行互不干扰,任意一个事务的内部操作对其他并发的事务,都是隔离的。也就是说:并发执行的事务之间即不能看到对方的中间状态,也不能互相影响例如:在转账时,只有当a账户中的转出和b账户中的转入操作都执行成功后,才能看到a账户中的金额减少,以及b账户中的金额增多。并且其他事务对于转账操作的事务是不能产生任何影响的
4、持久性(Durability)
持久性指事务一旦提交,对数据所做的任何改变,都要记录到永久存储器中,通常是保存进物理数据库,即使数据库出现故障,提交的数据也应该能够恢复。但如果由于外部原因导致的数据库故障,如硬盘损坏那么之前提交的数据则有可能丢失
3、三个并发问题
1、脏读(Dirty read)
当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库这是另外一个事务也访问了这个数据然后使用了当前这个数据。因为数据是还没有提交的数据,那么另外一个事务读到的这个数据就是‘脏数据’,依据脏数据所做的操作可能是不正确的
时间点 | 事务A | 事务B |
---|---|---|
1 | 开启事务A | |
2 | 开启事务B | |
3 | 查询余额为100 | |
4 | 余额增加50(150) | |
5 | 查询余额为150(脏数据) | |
6 | 事务回滚 |
2、不可重复读(Unrepeatable read)
指在一个事务内多次读同一个数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次诉求的数据可能不太一样。这就发生了在一个事务内两次读到的数据不一样的情况,一次称为不可重复读
时间点 | 事务A | 事务B |
---|---|---|
1 | 开启事务A | |
2 | 开启事务B | |
3 | 查询余额为100 | |
4 | 余额增加50(150) | |
5 | 查询余额为100 | |
6 | 事务回滚 | |
7 | 查询余额为150 |
3、幻读(Phantom read)
幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时,在随后的查询中,第一个事务(T1)就发现多了一些原本不存在的记录,就好像发生了幻觉一样
时间点 | 事务A | 事务B |
---|---|---|
1 | 开启事务A | |
2 | 开启事务B | |
3 | 查询id<3的所有记录,共三条 | |
4 | 插入一条记录 id=2 | |
5 | 提交事务 | |
6 | 查询id<3的所有记录,共4条 |
不可重复读与幻读的区别:
不可重复读的重点是修改(这是操作的某一行) 幻读的重点在于新增或者删除(而它是操作整个表)
解决:
不可重复读:只需要锁住满足条件的行(通俗的讲就是将某一行锁住,不让修改数据) 幻读:需要锁住表(将整个表锁住,不让添加行数)
查看隔离级别 SELECT @@transaction_isolation; 先设置隔离级别(一共四个级别) set SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; 再开启事务 START TRANSACTION; 再进行操作数据
4、视图(view)
1、视图的概念
视图的本质:就是一个查询语句,是一个虚拟的表,不存在的表,你查看视图,其实就是查看视图对应的sql语句
视图是一个从单张或多张基础数据表或其他视图中构建出来的虚拟表。 同基础表一样,视图也包含了一系列带有名称的列和行数据,但是数据库中只是存放视图的定义,也就是动态检索数据的查询语句,而不是存放视图中的数据,这些数据依旧存放构建视图的基础表中。 只有当用户使用视图才去数据库请求相对应的数据,即视图中的数据是在引用视图时动态生成的,因此视图中的数据依赖于构建视图的基础表
2、视图的好处
简化用户操作:视图可以使用户将注意力集中在所关心的数据上,而不需要关心数据表的结构、与其他表的关联条件以及查询条件 对机密数据提供了保护:有了视图,就可以在设计数据库应用系统时,对不同的用户定义不同的视图,避免加密数据
3、sql展示
创建单表视图 CREATE view demoASSELECT sid,sname,sgender,sclass FROM stu 查询视图,只显示你想展示出来的数据SELECT * FROM demo 在视图中插入数据(此处插入数据会直接插到真实的学生表里面) INSERT INTO demo (sid,sname,sgender,sclass) VALUES(null,'韩信','男','d119'); CREATE OR REPLACE view demo(此处代码是如果不存在就创建,存在就替换)ASSELECT sid,sname,sgender,sclass FROM stu WITH CHECK OPTION(此处代码是检验) 创建多表视图: CREATE OR REPLACE view demo2 AS SELECT a.sid,a.sage,a.sname,a.sgender,a.sclass,b.cname FROM stu a JOIN city b ON a.cid=b.cid WHERE a.sage>18 SELECT * FROM demo2 创建统计视图; CREATE OR REPLACE view demo3 AS SELECT b.cname,COUNT(b.cid),AVG(sage),MIN(sage),MAX(sage) FROM stu a JOIN city b GROUP BY b.cid SELECT * FROM demo3 基于视图的视图 CREATE OR REPLACE view demo3 as select * from demo2 where sid=1;
5、存储过程
1、什么是存储过程
SQL基本是一个命令实现一个处理,是所谓的非程序语言。 在不能编写流程的情况下,所有的处理只能通过一个个命令来实现。 当然,通过使用连接及子查询,即使使用SQL单一的命令也能实现一些高级的处理,但是,其局限性是显而易见的。 例如,在sql中就很难实现针对不同条件进行不同处理以及循环等功能 这时就出现了存储过程概念:简单的说,存储过程就是在数据库中保存(stored)的一系列命令(procedure)的集合。也可以是相互之间有关系的SQL命令组织在一起的一个小程序
2、存储过程的优点
1、提高执行性能。存储过程执行效率之所以会增高,在于普通是SQL语句,每次都会对语法分析,编译,执行,而存储过程只是在第一次执行语法分析,编译,执行,以后都是对结果进行调用2、可减轻网络负担。使用存储过程,复杂的数据库操作也可以在数据库服务器中完成,只需要从客户端(或应用程序)传递给数据库必要的参数就行,比起需要多次传递SQL命令本身,这大大减轻网络负担3、可将数据库的处理黑匣子化。应用程序中完全不用考虑存储过程的内部详细处理,只需要知道调用哪个储存过程就可以了
定义一个没有返回值 存储过程实现:模糊查询创建存储过程(无返回值的函数) CREATE PROCEDURE myprocedure(name VARCHAR(20)) BEGINif name is NULL or name="" thenselect * from stu;ELSEselect * from stu where sname like CONCAT('%',name,'%');end if; END删除存储过程 drop PROCEDURE myprocedure调用存储过程call myprocedure(null)call myprocedure('张')创建存储过程(带返回值的函数) 参数前面的in可以省略不写 FOUND_ROWS()是mysql定义的函数,返回查询结果的条数 CREATE PROCEDURE myprocedure2(in name VARCHAR(20),out num int(3)) BEGINif name is NULL or name="" thenselect * from stu;ELSEselect * from stu where sname like CONCAT('%',name,'%');end if;SELECT FOUND_ROWS() INTO num; END调用函数CALL myprocedure2(null,@num) SELECT @num
第七章
1、什么是jdbc?它是sun公司开发的一组接口,用于连接数据库,执行与数据库相关的各种操作 2、不同的数据库提供商对这一组接口,进行了不同的实现,称为数据库驱动--如果使用的数据库类型不同,要导入的数据库驱动也不一样 3、在操作jdbc时,用完的资源一定要释放 释放顺序是:1、resultset--数据结果集2、PreparedStatement---语句执行对象3、Connection--连接对象
1、jdbc的使用
1、创建java工程 2、创建文件夹 lib 3、导入数据库驱动 mysql-connector-java-5.1.37-bin.jar 4、构建jar到项目中lin->右键>build path->add 5、编写测试类 import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; public class demo { /** 添加测试*/public static void main(String[] args) throws Exception{// TODO Auto-generated method stub//1、指定数据库驱动(可省略)Class.forName("com.mysql.jdbc.Driver");//2、指定数据库连接信息(localhost:3306可省略)String url="jdbc:mysql://localhost:3306/d118?useUnicode=true&characterEncoding=UTF-8";/*String url="jdbc:mysql:///d118?useUnicode=true&characterEncoding=UTF-8";*///3、产生数据库连接 ConnectionConnection con= DriverManager.getConnection(url,"root","123456");//4、编写要执行的sql语句String sql="insert into stu values(null,'海月' ,20,'女','d118','78532569856','2023-01-05',5,null)";//5、通过连接产生sql语句执行对象,用于加载、编译、执行sql语句PreparedStatement pst=con.prepareStatement(sql);//6、执行语句,返回受影响的行数(执行成功的行数)int rows=pst.executeUpdate();if (rows>0) {System.out.println("【执行成功】");}else {System.out.println("执行失败!");}//释放资源pst.close();con.close();} }
jdbc几个重要方法
1、Connection数据库连接对象作用:与数据库建立连接产生方式:Connection con= DriverManager.getConnection(url,"root","123456");重要方法:PreparedStatement pst=con.prepareStatement(sql);通过连接产生sql语句的执行对象con.close();关闭连接2、PreparedStatementSQ语句执行对象作用:用于加载、编译、执行sql语句产生方式:PreparedStatement pst=con.prepareStatement(sql);重要方法:pst.setObject(个数,变量)用于给sql语句中?赋值int rows=pst.executeUpdate();该方法用于执行:增、删、改,但不能执行查询,它返回执行成功的行数ResultSet rs=pst.executeQuery();该方法用于查询,并且返回查询到的结果集pst.close();关闭连接3、ResultSet数据结果集作用:用于保存查询的结果产生方式:ResultSet rs=pst.executeQuery();数据结果集的特点:1、数据结果集是根据查询语句得到的数据生成的一个结构,包含所有查询结果2、在数据结果集中,有一个光标,光标指向结果集中的哪一行,这一行数据才能被读取3、一开始时,光标指向的是第一行之前的位置,这一个位置没有任何数据。重要方法:rs.next()------让光标向下移动一位。该方法返回的结果是一个blooean 型,如果光标可以向下移动并且能得到数据,就会返回 true,否则就会返回fasle,/*第一种方式:用列的名称获取*/int val=rs.getInt("列的名称");获得光标指定的这一行,指定列的值,返回一个int型String val=rs.getString("列的名称")获得光标指定的这一行,指定列的值,返回一个string/*第二种方式:用列的编号*/(编号从1开始)int val=rs.getInt("列的编号");int val=rs.getInt(1);String val=rs.getString(2)rs.close();------关闭数据集
2、基于jdbc的增删改
1、增加数据
#1、要在sql语句中拼接,如果是字符数据,必须在变量名的两边用单引号包裹起来(不推荐)String sql="insert into stu values(null,'"+name+"','"+score+"')"; #2、更加简介的方法,如果有参数可以用?占位符String sql="insert into stu values(null,'?','?')";//此句在中间PreparedStatement pst=con.prepareStatement(sql);#给?动态赋值(?从1开始)pst.setString(1,name);//给第一个?赋值pst.setInt(2,score);//给第二个?赋值但是还有一个问题,一旦数据类型匹配错误也会报错,那么下面这种方法就解决了这个问题 #3、设置赋值时设定参数类型为obj,不管什么类型都不会报错(应用最多) pst.setobject(1,name);pst.setobject(2,score);
2、修改数据
//修改数据int age=22;//修改数据(把id为9的年龄该为22)String sql="update stu set sage=? where sid=9";//此句在中间PreparedStatement pst=con.prepareStatement(sql);//给?赋值pst.setobject(1,age);
3、删除数据
//删除数据int id=12;//删除数据,id为12的学生信息String sql="delete from stu where sid=?";//此句在中间PreparedStatement pst=con.prepareStatement(sql);//给?赋值//删除数据pst.setObject(1, id);
3、基于jdbc的查询
查询全部用法:
package select; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class demo { /** 读取单条数据,以及多条* */public static void main(String[] args) throws Exception {//指定连接数据库信息String url="jdbc:mysql:///d118?useUnicode=true&characterEncoding=UTF-8";//产生数据库连接Connection con= DriverManager.getConnection(url,"root","123456");//执行语句String sql="select * from stu";//通过连接产生sql语句执行对象,加载、编译、执行sql语句PreparedStatement pst=con.prepareStatement(sql);//执行查询,得到数据结果集ResultSet rs=pst.executeQuery(); ------------------------------------------------单行数据/*光标向下移动一行rs.next();//存数据结果集中,获得光标指定的某一行的某一列的值int id=rs.getInt("sid");String name=rs.getString("sname");int age=rs.getInt("sage");System.out.println(id+"\t"+name+"\t"+age);这是读取单行数据的用法*/ ------------------------------------------------全部数据/*这是获得全部数据(rs.next()返回的是boolean类型,如果取不到数据会返回false)*/while (rs.next()) {int id=rs.getInt("sid");String name=rs.getString("sname");int age=rs.getInt("sage");System.out.println(id+"\t"+name+"\t"+age);}rs.close();pst.close();con.close(); } }
按主键查询
int id=11;//执行语句String sql="select * from stu where sid=?";//通过连接产生sql语句执行对象,加载、编译、执行sql语句PreparedStatement pst=con.prepareStatement(sql);//给?赋值pst.setObject(1,id);//执行查询,得到数据结果集ResultSet rs=pst.executeQuery();if(rs.next()) {//此处用if,只会有一条数据int id=rs.getInt("sid");String name=rs.getString("sname");int age=rs.getInt("sage");System.out.println(id+"\t"+name+"\t"+age);}
4、数据库的dao模式
DAO: Date Access Object(数据访问对象)
#在开发中与数据库交互的层次,称为“数据访问层”-----dao层 dao层的作用:用于执行与数据库相关操作 #dao层的命名规范:如果是对stu表进行操作,一般会编写一个对应的实体类,用于封装stu对象的信息例如:数据表----stu实体类------Stu所在包:org.java.entity它对应的dao类就是-----StuDaoorg.java.dao在项目中使用jdbc的基本流程: 1、创建java工程 2、导入数据库驱动 mysql-connector-java-5.1.37-bin.jar 3、将驱动构建到项目中lin->右键>build path->add 4、创建项目的基本结构org.java.daoorg.java.entyorg.jav.demo 5、创建实体类与数据表的结构对应 6、编写dao类 7、编写测试类
完整代码分为三部分:
1、stu实体类
2、studao交互层
3、studemo测试类
实体类
package enty; public class Stu { /** 学生实体类* */private int id;//编号private String name;//姓名private int score;//分数public Stu() {super();}public Stu(int id, String name, int score) {super();this.id = id;this.name = name;this.score = score;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getScore() {return score;}public void setScore(int score) {this.score = score;}@Overridepublic String toString() {return id + "\t" + name + "\t" + score ;} }
交互层
package dao; import java.sql.*; import java.util.ArrayList; import java.util.List; import enty.Stu; public class StuDao { /** 学生表与数据库交互层* */private Connection con;//数据库连接private PreparedStatement pst;//通过连接产生sql语句,用来加载、编译、执行private ResultSet rs;//返回的数据结果集//编写公共方法//连接数据库的方法private Connection link(){ try {//1、指定数据库驱动(可省略)Class.forName("com.mysql.jdbc.Driver");//2、指定数据库连接信息(localhost:3306可省略)String url="jdbc:mysql://localhost:3306/d118?useUnicode=true&characterEncoding=UTF-8"; con=DriverManager.getConnection(url,"root","123456"); } catch (Exception e) {e.printStackTrace();} return con;//返回成功连接的对象 }//关闭连接的方法private void close() {try {if (rs!=null)rs.close();if (pst!=null)pst.close();if (con!=null)con.close();} catch (Exception e) {e.printStackTrace();}}//添加学生的方法public boolean add(String name,int score) { try { //编写sql语句String sql="insert into stuDemo values(null,?,?)"; //编译sql语句pst=link().prepareStatement(sql);pst.setObject(1, name);pst.setObject(2, score);return pst.executeUpdate()>0;} catch (Exception e) {e.printStackTrace();}finally {close();}return false;//默认添加失败}//修改学生的方法public boolean update(int id,String name,int score) {try { //编写sql语句String sql="update stuDemo set name=?,score=? where id=?"; //编译sql语句pst=link().prepareStatement(sql);pst.setObject(1, name);pst.setObject(2, score);pst.setObject(3, id);return pst.executeUpdate()>0;} catch (Exception e) {e.printStackTrace();}finally {close();}return false;//默认修改失败}//删除学生的方法public boolean delete(int id) {try { //编写sql语句String sql="delete from stuDemo where id="+id; //编译sql语句pst=link().prepareStatement(sql);return pst.executeUpdate()>0;} catch (Exception e) {e.printStackTrace();}finally {close();}return false;//默认删除失败}//查询全部学生public List<Stu> selectAll() {List<Stu> list=new ArrayList<Stu>();//创建学生集合try {//编写sql语句String sql="select * from stuDemo"; //编译sql语句pst=link().prepareStatement(sql);rs=pst.executeQuery();while (rs.next()) {//读取表中所有学生Stu stu=new Stu();stu.setId(rs.getInt(1));stu.setName(rs.getString(2));stu.setScore(rs.getInt(3));list.add(stu);//将表中的学生存入到集合中}} catch (Exception e) {e.printStackTrace();}finally {close();}return list;} }
测试类
package demo; import java.util.List; import java.util.Scanner; import dao.StuDao; import enty.Stu; public class stuDemo {private StuDao sdao=new StuDao();Scanner sc=new Scanner(System.in);/** * 学生类的测试类* */public static void main(String[] args) {new stuDemo().init();}private void init() {System.out.println("学生管理系统");System.out.println("1、添加学生");System.out.println("2、查看学生");System.out.println("3、修改学生");System.out.println("4、删除学生");System.out.print("请选择:");switch (sc.nextInt()) {case 1:add();break;case 2:show();break;case 3:update();break;case 4:delete();break;default:System.out.println("【页面走丢了...】");break;}}private void show() {System.out.println("******************查询学生************************");List<Stu> list=sdao.selectAll();//接受返回的学生集合System.out.println("编号\t名称\t成绩"); // 遍历集合list.forEach(k->System.out.println(k));} public void add() {System.out.println("******************添加学生************************");System.out.println("请输入学生姓名及成绩(空格隔开):");boolean flag= sdao.add(sc.next(), sc.nextInt());if (flag) {System.out.println("【添加成功】");}else {System.out.println("【添加失败】");} System.out.print("1、继续 2、返回上一级:");if (sc.nextInt()==1) {add();}else {init();}}public void update() {System.out.println("******************修改学生************************");System.out.println("请输入要修改的学生id:");int id=sc.nextInt();System.out.println("请输入该学生的新名字:");String name=sc.next();System.out.println("请输入该学生的新成绩:");int score=sc.nextInt();boolean flag=sdao.update(id, name, score);if (flag) {System.out.println("【修改成功】");}else {System.out.println("【修改失败】");}System.out.print("3秒后返回主界面...");try {Thread.sleep(3000);init();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}public void delete() {System.out.println("******************删除学生************************");System.out.println("请输入要修改的学生id:");int id=sc.nextInt();boolean flag=sdao.delete(id);if (flag) {System.out.println("【删除成功】");}else {System.out.println("【删除失败】");}System.out.print("3秒后返回主界面...");try {Thread.sleep(3000);init();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}} }
5、jdbc常见错误
com.mysql.jdbc.Driver-------驱动包没有构建到项目中no value specified for parameter 2---第二个?没有赋值access denied for user 'root'@'localhost----密码错误communications link failure -------mysql服务没有开启
第八章
数据库连接池的使用-----使用jdbctemplate模板简化数据库操作
1、数据库连接池的使用
为了解决频繁创建连接,频繁销毁连接的问题,jdbc提供一种“”数据库连接池的机制
#数据库连接池的特点:配置好数据库连接池后,系统会提前创建一定数量的链接,放在连接池中。关闭时,数据库连接并不会真的销毁,而是回到连接池中,其他用户可以继续使用 #连接池解决了:数据库连接对象可以重复使用的问题(提高性能) initialSize=5#初始连接数,程序一启动,就会向内存中的连接池放入5个数据库连接 maxActive=10#最大连接数 maxWait=3000 (毫秒)#如果连接池的连接数已经到达最大值,就不会再产生新的连接,此时如果需要连接数据库, 就 需要等待其他用户将用完的连接进行释放 #当调用连接对象的close方法,连接 就会回到连接池中
数据库连接池的分类:
dbcp c3p0,druid
目前使用最好的是阿里巴巴的druid连接池
druid:德鲁依连接池的测试 1、创建java工程 2、导入druid的相关jar(依赖) druid-1.0.9.jar以及mysql-connector-java-5.1.37 3、创建一个源文件夹 sourceFolder命名为:conf,用于存储配置文件配置文件 druid.propertiesdriverClassName=com.mysql.jdbc.Driverurl=jdbc:mysql:///d118username=rootpassword=123456initialSize=5maxActive=10maxWait=5000 4、编写测试类
测试代码:
package demo; import java.io.InputStream; import java.sql.Connection; import java.util.Properties; import javax.sql.DataSource; import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.pool.DruidDataSourceFactory; public class firstDemo { public static void main(String[] args) throws Exception{//1、加载指定的属性文件,获得输入流InputStream in=firstDemo.class.getClassLoader().getResourceAsStream("druid.properties");//2、创建一个属性类,用于记载输入流的配置信息Properties pro=new Properties();//3、属性类从输入流中加载配置信息pro.load(in);//4、产生druid数据源(数据连接池)(pool结尾的)DataSource ds= DruidDataSourceFactory.createDataSource(pro);//5、通过连接池,获得连接for (int i = 0; i <10; i++) {Connection con=ds.getConnection();System.out.println(i+"----"+con);con.close();//返回连接池}} }
2、jdbctemplate
数据库连接池可以提升程序性能
如何简化jdbc的操作? 后期我们会学习一些持久层的框架来简化数据库操作,例如:mybatis,tkmybatis,mybatis-plus 现阶段我们可以使用jdbctemplate模板机制简化数据库操作 jdbctemplate是spring框架提供的一种简化jdbc操作的持久层技术,目前我们只是采用jdbctemplate简化数据库操作,不涉及到任何spring知识点
jdbctemplate模板的使用步骤:
1、创建java工程 2、导入依赖(jar)1、mysql2、druid3、springjdbc3、创建源文件夹放配置文件 sourceFolder命名为:conf,用于存储配置文件 4、将druid.properties导入到源文件夹中 ->conf 5、编写一个jdbcytil工具类,用于产生druid连接池(只需要编写一次,以后复制就可以了)org.java.demoorg.java.entityorg.java.daoorg.java.util--------->工具包6、编写实体类与数据表结构对应 7、编写dao层 8、编写测试类
创建工具类
package util; import java.io.InputStream; import java.util.Properties; import javax.sql.DataSource; import com.alibaba.druid.pool.DruidDataSourceFactory; /** jdbc工具类,用于产生数据源* * */ public class JdbcUtil { //数据源private static DataSource ds;//静态块,一加载创建连接池static {try {//创建输入流,加载指定属性文件InputStream in=JdbcUtil.class.getClassLoader().getResourceAsStream("druid.properties");//创建属性类Properties pro=new Properties();//加载输入流中的配置信息pro.load(in);//关闭流in.close();//产生数据源ds=DruidDataSourceFactory.createDataSource(pro);} catch (Exception e) {e.printStackTrace();} }//静态方法调用该方法,即可获得数据源public static DataSource getDs() { return ds;} }
dao层
package dao; import java.util.List; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import enty.Stu; import util.JdbcUtil; public class stuDao { /** 使用jdbctemplate模板创建的dao类* * *///创建jdbctemplateprivate JdbcTemplate jt=new JdbcTemplate(JdbcUtil.getDs());//添加的方法public void add(String name,int score) {String sql="insert into stuDemo values(null,?,?)";//执行sql语句(增删改都是同一个方法,只是语句不同)jt.update(sql,name,score);}//修改的方法public void update(Integer id,String name,int score) {String sql=("update stuDemo set name=?,score=? where id=?");//执行sql语句(增删改都是同一个方法,只是语句不同)jt.update(sql,name,score,id);}//删除的方法(返回受影响行数,大于0说明删除成功)public boolean del(Integer id) {String sql=("delete from stuDemo where id=?");//执行sql语句(增删改都是同一个方法,只是语句不同) return jt.update(sql,id) >0;}//查询全部public List<Stu> selAll() {String sql="select * from stuDemo";//返回时,只需要指定每一条数据要封装成什么类型的对象进行返回return jt.query(sql, new BeanPropertyRowMapper<>(Stu.class)); }}
1、查询全部(返回的list集合)
//增删改的方法只需要该查询语句就可以,关键的是查询 jt.query()---------它的返回结果一定是List<对象>jt.query(执行语句,返回类型,参数1,参数2) jt.queryForObject---该方法返回一个对象 jt.queryForList()-------他返回的类型是一个List<Map> jt.queryForMap()-------他返回的类型是一个Map //如果是单表操作,一般List<stu>这种方式,可读性好 //如果是多表操作,一般list<map>这种方式更方便 //查询全部 1、要把查询到的一条记录中所有字段赋值给对象中的属性,要求如下:字段名需要与属性名相同public List<Stu> selAll() {String sql="select * from stuDemo";//返回时,只需要指定每一条数据要封装成什么类型的对象进行返回return jt.query(sql, new BeanPropertyRowMapper<>(Stu.class)); 2、而当字段名与属性名不同时,可以起别名来解决此问题public List<Stu> selAll2() {//联合stu表和score成绩表 起的别名与属性名一致也能运行成功String sql="select a.sid id,sname name,b.socres score from stu a,score b where a.sid=b.sno";//返回时,只需要指定每一条数据要封装成什么类型的对象进行返回return jt.query(sql, new BeanPropertyRowMapper<>(Stu.class));3、如果字段名中包含下划线,在将字段值赋值给属性时,系统将会把下划线去掉,然后将下划线首字母大写 例如数据库中字段名是stu_id,而当印射时系统会自动变成stuId(stu_id---->stuId)
2、根据id查询(返回的对象)
//根据id查询(如果没找到,返回null)public Stu selId(int id) {//用聚合查询来判断是否存在该id//查询总人数String sql="select count(*) from stuDemo where id=?";//得到执行成功的行数int rows=jt.queryForObject(sql, Integer.class,id);if (rows==0) {//说明不存在,返回空值return null;}else {sql="select * from stuDemo where id=?";//返回时,只需要指定每一条数据要封装成什么类型的对象进行返回return jt.queryForObject(sql, new BeanPropertyRowMapper<>(Stu.class),id);}} ---------------测试类//根据id查找System.out.println(selId(1));
3、查询总人数
//聚合查询public int selCount() {//查询总人数String sql="select count(*) from stuDemo ";//返回的是一个数值return jt.queryForObject(sql, Integer.class); } -----测试类 //查询总人数System.out.println("学生总人数:"+selCount());
4、模糊查询
//带条件查询(模糊查询)public List<Stu> selCondition(String name,int score) {//查询stu表中所有带有参数name的姓名,以及分数在参数score以上的String sql="SELECT * FROM studemo where name LIKE ? AND score>=? ";return jt.query(sql, new BeanPropertyRowMapper<>(Stu.class),"%"+name+"%",score);} ---测试类 //模糊查询List<Stu> list=selCondition("三", 50);list.forEach((k)->System.out.println(k));
5、查询全部(返回的map集合)
//将查询结果封装成map集合返回public List<Map<String, Object>> selAllMap() {//将个查询到的每一条数据,封装成mapString sql="select * from stuDemo";return jt.queryForList(sql);} ----测试类//查询全部,返回的mapList<Map<String, Object>> list=selAllMap();list.forEach((k)->System.out.println(k));
6、 根据id查询(返回的是map集合)
//根据id查询,返回的是map集合public Map selId2(int id) {String sql="select count(*) from stuDemo where id=?";int rows=jt.queryForObject(sql, Integer.class,id);if (rows==0) {return null;}else {sql="select * from stuDemo where id=?";return jt.queryForMap(sql,id);}} ---测试类System.out.println(selId2(2));
7、多表联合查询(返回map集合)
//使用map多表连接public List<Map<String, Object>> selAllMap2() {//连接stu表,score表,city表,course表String sql="SELECT a.sid id,a.sname name,c.cname cla,b.socres score,d.cname city FROM stu a,score b,course c,city d WHERE a.sid=b.sno AND b.cid=c.cid AND a.cid=d.cid";return jt.queryForList(sql);} -----测试类 //查询全部2,返回四个表的联合查询List<Map<String, Object>> list=selAllMap2();list.forEach((k)->System.out.println(k));
优化多表查询
//这条sql语句太过繁琐 String sql="SELECT a.sid id,a.sname name,c.cname cla,b.socres score,d.cname city FROM stu a,score b,course c,city d WHERE a.sid=b.sno AND b.cid=c.cid AND a.cid=d.cid"; //我们可以创建先视图,而后对视图进行查询也一样 /*这是创建视图的语句 CREATE VIEW stuView AS SELECT a.sid id,a.sname name,c.cname cla,b.socres score,d.cname city FROM stu a,score b,course c,city d WHERE a.sid=b.sno AND b.cid=c.cid AND a.cid=d.cid */ //这是已经创建好的视图,我们直接引用,同样我们也可以对视图进行带条件查询 String sql="select * FROM stuView";