2.2数据库的列类型
数值
-
tinyint 十分小的数值 1个字节
-
smallint 较小的数据 2个字节
-
mediumint 中等大小的数据 3个字节
-
int 标准的整数 4个字节(常用的)
-
bigint 较大的数据 8个字节
-
float 浮点数 4个字节
-
double 浮点数 8个字节(精度问题)
-
decimal 字符串形式的浮点数 金融计算的时候,一般使用
-
char 字符串固定大小 0-255
-
varchar 可变字符串 0-65535 常用的变量(String)
-
tinytext 微型文本 2^8-1
-
text 文本串 2^16-1 保存大文本
时间日期
java.util.Date
-
date YYYY-MM-DD,日期
-
time HH:mm:ss 时间格式
-
datetime YYYY-MM-DD HH:mm:ss 最常用的时间格式
-
timestamp 时间戳, 1970.1.1到现在的毫秒数,也较为常用
-
year 年份表示
null
-
空值,未知
-
==注意,不要是用NULL进行运算,使用的结果为NULL
2.3 数据库的字段属性(重点)
Unsigned:
-
无符号的整数
-
声明了该列不能声明为负数
zreofill:
-
0填充的
-
不足的位数,使用0来填充,int(3) 5---005
自增
-
通常理解为自增,自动在上一条记录的基础+1(默认)
-
通常用来设计唯一的主键 index,必须是整数型
-
可以自定义主键自增的起始值和步长
非空 NULL not null
-
假设设置为 not null,如果不给它赋值,就会报错
-
NULL,如果不写值,默认就是null
默认
-
设置默认的值
-
sex,默认值为男,如果不指定该列的值,则会有默认的值
2.4 创建数据库表
CREATE TABLE IF NOT EXISTS `student`(
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT ‘学号‘,
`name` VARCHAR(30) NOT NULL DEFAULT ‘匿名‘ COMMENT‘姓名‘,
`password` VARBINARY(20) NOT NULL DEFAULT ‘123456‘ COMMENT‘密码‘,
`birthday` DATETIME DEFAULT NULL COMMENT ‘出生日期‘,
`address` VARBINARY(100) DEFAULT NULL COMMENT ‘家庭地址‘,
`email` VARBINARY(50) DEFAULT NULL COMMENT ‘邮箱‘,
PRIMARY KEY(`id`)
?
) ENGINE=INNODB DEFAULT CHARSET=utf8
格式
CREATE TABLE [IF NOT EXISTS] `表名`(
`字段名` 列类型 [属性] [索引] [注释],
`字段名` 列类型 [属性] [索引] [注释],
`字段名` 列类型 [属性] [索引] [注释],
.........
`字段名` 列类型 [属性] [索引] [注释]
)[表类型][字符集设置][注释]
常用命令
SHOW CREATE DATABASE 库名 --查看创建数据库的语句
SHOW CREATE TABLE 表名 --查看表的定义语句
DESC 表名 --显示表的结构
2.5 数据表的类型
--数据库引擎
/*
INNODB 默认使用
MYISAM 早些年使用
*/
MYISAM | INNODB | |
---|---|---|
事务支持 | 不支持 | 支持 |
数据行锁定 | 不支持 | 支持 |
外键约束 | 不支持 | 支持 |
全文索引 | 支持 | 支持 |
表空间的大小 | 较小 | 较大,约为MYSAM的两倍 |
常规使用操作:
-
MYISAM 节约空间,速度较快
-
INNODB 安全性高,事务的处理,多表多用户操作
在物理空间存在的位置
所有的数据库文件都存在 data 目录下
本质还是文件的存储
MySQL引擎在物理文件上区别
-
INNODB 在数据库表中只有一个*.frm文件,以及上级目录下的 ibdata1 文件
-
MYISAM 对应文件
-
*.frm - 表结构的定义文件
-
*.MYD 数据文件(data)
-
*.MYI 索引文件(index)
-
设置数据库表的字符集编码
CHARSET=utf8
不设置的话,会是mysql默认的字符集编码
默认是Latin1,不支持中文
-
在my.ini中配置默认的编码
character-set-server=utf8
2.6 修改
修改
--修改表名: 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
?
--删除表
DROP TABLE IF EXISTS 表名
删除
--删除表
DROP TABLE IF EXISTS 表名
注意点:
-
` 所有字段名使用````包裹
-
注释 -- /**/
-
sql 关键字大小写不敏感,建议小写
-
所有的符号用英文
3 MySQL数据管理
3.1外键 (了解)
方式一、在创建表的时候,增加约束(麻烦, 比较复杂)
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 --学生表的gradeid字段要去引用年级表的gradeid --定义外键key --给这个外键添加约束(执行引用) references引用 CREATE TABLE IF NOT EXISTS `student`( `id` INT(4) NOT NULL AUTO_ INCREMENT COMMENT ‘学号‘, `name` VARCHAR(30) NOT NULL DEFAULT ‘匿名‘ COMMENT ‘姓名‘, `pwd` VARCHAR (20) NOT NULL DEFAULT ‘123456‘ COMMENT ‘密码‘, `sex` VARCHAR(2) NOT NULL DEFAULT ‘女‘ COMMENT ‘性别‘ , `birthday` DATETIME DEFAULT NULL COMMENT ‘出生日期‘, `gradeid` INT(10) NOT NULL COMMENT ‘ 学生的年级‘, `address` VARCHAR (100) DEFAULT NULL COMMENT ‘家庭住址‘ , `email` VARCHAR(50) DEFAULT NULL COMMENT ‘邮箱‘, PRIMARY KEY(`id`), KEY‘FK_ gradeid ( gradeid ), CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade` (`gradeid`) )ENGINE=INNODB DEFAULT CHARSET=utf8
删除有外键关系的表的时候,必须要先删除引用别人的表 (从表) 再删除被引用的表(主表)
方式二:创建成功表后,添加外键约束
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 --学生表的gradeid 字段要去引用年级表的gradeid --定义外键key --给这个外键添加约束(执行引用) references 引用 CREATE TABLE IF NOT EXISTS`student`( `id`INT(4) NOT NULL AUTO_ INCREMENT COMMENT‘学号‘, `name` VARCHAR(30) NOT NULL DEFAULT ‘匿名‘ COMMENT ‘姓名‘, `pwd` VARCHAR (20)NOT NULL DEFAULT ‘123456‘ COMMENT ‘密码‘, `sex` VARCHAR(2) NOT NULL DEFAULT ‘女‘ COMMENT ‘性别‘, `birthday` DATETIME DEFAULT NULL COMMENT ‘出生日期‘, `gradeid` INT(10) NOT NULL COMMENT ‘学生的年级‘, `address` VARCHAR (100) DEFAULT NULL COMMENT ‘家庭住址‘, `emai1` VARCHAR(50) 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 那个表(哪个字段)
以上操作都是物理外键,数据库级别的外键,不建议使用(避免数据库过多造成混乱)
==最佳实践==
-
数据库就是单纯的表,只用来存数据,只有行(数据)和列(字段) 我们想使用多张表的数据,想使用外键(程序去实现)
3.2 DML语言(记住)
-
insert
-
update
-
delete
3.3 添加
insert
插入语句(添加) insert into 表名([字段名1,字段2,字段3])values(‘值1‘),(‘值2‘),(‘值3‘),... INSERT INTO `grade` (`gradename`) VALUES(‘ 大四‘) --由于主键自增我们可以省略(如果不写表的字段,他就会一- -匹配) INSERT INTO `grade` VALUES(‘大三‘) --一般写插入语句,我们一定要数据和字段一一对应! --插入多个字段 INSERT INTO `grade` (`gradename`) VALUES(‘大二‘),(‘大一‘) INSERT INTO `student` (`name`) VALUES (‘张三‘) INSERT INTO `student` ( `name`,`pwd`,`sex`) VALUES (‘张三‘ ,‘aaaaaa‘,‘男‘) INSERT INTO `student` (`name`,`pwd`,`sex` ) VALUES (‘李四‘,‘aaaaa‘,‘男‘),(‘王五‘,‘aaaaa‘,‘男‘)
语法:
insert into 表名([字段名1,字段2,字段3])values(‘值1‘),(‘值2‘),(‘值3‘),
注意:
-
字段和字段之间使用英文逗号隔开
-
字段是可以省略的,但是后面的值必须要要一- 对应,不能少
-
可以同时插入多条数据,VALUES 后面的值,需要使用,隔开即可 `VALUES(),()``
3.4 修改
update 修改谁 (条件) set原来的值=新值
--修改学员名字,带了简介 UPDATE `student` SET `name`=‘冬冬‘ WHERE id = 1; --不指定条件的情况下,会改动所有表! UPDATE`student` SET `name`=‘冬冬1号‘ --修改多个属性,逗号隔开 UPDATE `student` SET `name` =‘冬冬‘,`email` =‘77511593@qq. com‘ WHERE id = 1; --语法: -- UPDATE 表名set colnum_name = value,[colnum_name = value,....] where [条件]
条件:where子句 运算符id等于某个值,大于某个值,在某个区间内修改.
操作符 | 含义 |
---|---|
= | 等于 |
<>或!= | 不等于 |
> | |
< | |
>= | |
<= | |
BETWEEN...AND... | 在某个范围内 |
AND | |
OR |
-
通多多个条件定位数据
语法:UPDATE 表名 set colnum_name = vlaue,[colnum_name = value,....] where[条件]
注意:
-
colnum_name是数据库的列,尽量带上"
-
条件,筛选的条件,如果没有指定,则会修改所有的列
-
value,是一个具体的值,也可以是一个变量
-
多个设置的属性之间,使用英文逗号隔开
3.5 删除
delete 命令
语法:dalete from 表名 [where 条件]
--删除数据(避免这样写,会全部删除) DEL ETE FROM `student` --删除指定数据 DELETE FROM `student` WHERE id = 1;
TRUNCATE 命令
完全清空一个数据库表,表的结构和索引约束不会变
TRUNCATE 表名
delete的TRUNCATE区别
-
不同:
-
TRUNCATE重新设置自增列计数器会归零
-
TRUNCATE不会影响事务
-
--测试delete和TRUNCATE 区别 CREATE TABLE `test` ( id INT(4) NOT NULL AUTO_INCREMENT, `co11` VARCHAR(20) NOT NULL, PRIMARY KEY (`id`) )ENGINE=INNODB DEFAULT CHARSET=utf8 INSERT INTO `test` ( `coll`) VALUES(‘1‘),(‘2‘),(‘3‘) DELETE FROM `test` -- 不会影响自增 TRUNCATE TABLE `test` --自增会归零
了解:DELETE删除的问题。删除之后重启数据库,现象
-
InnoDB 自增列会重1开始(存在内存当中的, 断电即失)
-
MyISAM 继续从上一个自增量开始(存在文件中的, 不会丢失)
4 DQL查询数据(最重点)
4.1 DQL
(Data Query Language:数据查询语言)
-
所有的查询操作都用它Select
-
简单的查询,复杂的查询它都能做~
-
数据库中最核心的语言,最重要的语句
-
使用频率最高的语句
4.2 指定查询字段
--查询全部的学生 SELECT字段 FROM表 SELECT * FROM student --查询指定字段 SELECT `StudentNo`,`StudentName` FROM student --别名,给结果起一个名字 AS,可以给字段起别名, 也可以给表起别名 SELECT `StudentNo` AS 学号,`StudentName` AS 学生姓名 FROM student AS 新名字 --函数Concat (a,b) SELECT CONCAT(‘姓名:‘,StudentName) AS 新名字 FROM student
语法:select 字段,.....from 表
去重 distinct
作用:去除SELECT 查询出来的结果中重复的数据,重复的只显示一条
查询一下有哪些同学参加了考试,成绩 SELECT * FROM result -- 查询全部的考试成绩 SELECT `StudentNo` FROM result --查询有哪些同学参加了考试 SELECT DISTINCT `StudentNo` FROM result --发现重复数据,去重
数据库的列 (表达式)
SELECT VERSION() -- 查询系统版本(函数) SELECT 100*3-1 AS计算结果 --用来计算(表达式) SELECT @@auto_increment_increment --查询自增的步长(变量) 学员考试成绩+ 1分查看 SELECT `StudentNo`,`StudentResult`+1 AS ‘提分后‘ FROM result
数据库中的表达式: 文本值,列,Null,函数,计算表达式,系统变量....
select 表达式
from 表达式
4.3 where 条件子句
作用: 检索数据中符合条件
的值
逻辑运算符
运算符 | 语法 | 描述 |
---|---|---|
and && | a and b a&&b | 逻辑与,两个都为真,结果为真 |
or || | a or b a||b | 逻辑或,其中一个为真,则结果为真 |
Not ! | not a !a | 逻辑非,真为假,假为真 |
尽量使用英文字母
--查询考试成绩在95~100 分之间 SELECT `studentNo`,`StudentResult` FROM result WHERE StudentResult>=95 AND StudentResult<=100 模糊查询(区间) SELECT `studentNo`,`StudentResult` FROM result WHERE `StudentResult` BETWEEN 95 AND 100 --除了1000号学生之外的同学的成绩 SELECT `studentNo`,`StudentResult` FROM result WHERE NOT `StudentResult` =1000 (WHERE `StudentResult` !=1000 )
模糊查询: 比较运算符
运算符 | 语法 | 描述 |
---|---|---|
IS NULL | a is null | 如果操作符为NULL,结果为真 |
IS NOT NULL | a is not null | 如果操作符不为NULL,结果真 |
BETWEEN | a between b and c | 若a在b和c之间,则结果为真 |
Like | a like b | SQL匹配,如果a匹配b,则结果为真 |
In | a in (a1,a2,a3...) | 假设a在a1,或者a2...其中的某一个值中,结果为真 |
--===================模糊查询====================== --查询姓刘的同学 -- like结合 号(代表0到任意个字符)_ (一 个字符) SELECT `StudentNo`,`StudentName` FROM `student` WHERE StudentName LIKE ‘刘%‘ --查询姓刘的同学,名字后面只有一个字的 SELECT `StudentNo`,`StudentName` FROM `student` WHERE StudentName LIKE ‘刘_‘ --查询姓刘的同学,名字后面只有两个字的 SELECT `StudentNo`,`StudentName` FROM `student` WHERE StudentName LIKE ‘刘__‘ --查询名字中间有嘉字的同学 %嘉% SELECT `StudentNo`,`StudentName` FROM `student` WHERE StudentName LIKE ‘%嘉%‘ -- ====== in (具体的一个或者多个值) === --查询1001, 1002, 1003号学员 SELECT `StudentNo`,`StudentName` FROM `student` WHERE StudentNo IN (1001,1002,1003); --查询在北京的学生 SELECT `StudentNo`,`StudentName` FROM `student` WHERE `Address` IN (‘安徽‘,‘河南洛阳‘) ; -- ==== nullnot null==== 查询地址为空的学生null SELECT `StudentNo`,`StudentName` FROM `student` WHERE addrress=‘‘ OR address IS NULL --查询有出生日期的同学 不为空 SELECT `StudentNo`,`StudentName` FROM `student` WHERE `BornDate` IS NOT NULL --查询没有有出生日期的同学I为空 SELECT `StudentNo`,`StudentName` FROM `student` WHERE `BornDate` IS NULL
4.4 联表查询
JOIN 对比
--INNER JOIN /* 思路 1.分析需求,分析查询的字段来自哪些表, (连接查询) 2.确定使用哪种连接查询?7种 确定交叉点(这两个表中哪个数据是相同的). 判断的条件:学生表的中 studentNo =成绩表studentNo */ SELECT s.studentNO,studentName,SubjectNo,StudentResult FROM student AS s INNER JOIN result AS r WHERE s.studentNO = r.studentNO
-- Right Join SELECT s.studentNO,studentName,SubjectNo,StudentResult FROM student AS s RIGHT JOIN result AS r ON s.studentNO = r.studentNO
-- Left Join SELECT s.studentNO,studentName,SubjectNo,StudentResult FROM student AS s LEFT JOIN result AS r ON s.studentNO = r.studentNO
操作 | 描述 |
---|---|
Inner Join | 如果表中至少有一个匹配,就返回行 |
Right Join | 会从左表中返回所有的值,即使右表中没有匹配 |
Left Join | 会从右表中返回所有的值,即使左表中没有匹配 |
-
join (连接的表) on (判断的条件) 连接查询
-
where 等值查询
--思考题(查询了参加考试的同学信息:学号, 学生姓名,科目名,分数) /*思路 分析需求,分析查询的字段来自哪些表,: student、result、 subject ( 连接查询) 2.确定使用哪种连接查询?7种 确定交叉点(这两个表中哪个数据是相同的) 判断的条件:学生表的中studentNo =成绩表studentNo */ SELECT s.studentNo,studentName,SubjectName,`StudentResult` FROM student s RIGHT JOIN result r ON r.studentNo = s.studentNo INNER JOIN、 subject sub ON r.SubjectNo = sub.SubjectNo --我要查询哪些数据: --select --从那几个表中查FROM 表XXX Join连接的表 --on 交叉条件 --假设存在--种多张表查询,慢慢来,先查询两张表然后再慢慢增加
自连接(了解)
自己的表和自己的表连接,核心:一张表拆为两张一样的表即可
CREATE TABLE `school`.`category`( `categoryid` INT(3) NOT NULL COMMENT ‘id‘, `pid` INT(3) NOT NULL COMMENT ‘父id 没有父则为1‘, `categoryname` VARCHAR(10) NOT NULL COMMENT ‘种类名字‘, PRIMARY KEY (`categoryid`) ) ENGINE=INNODB CHARSET=utf8 COLLATE=utf8_general_ci; INSERT INTO `school`.`category` (`categoryid`, `pid`, `categoryname`) VALUES (‘2‘, ‘1‘, ‘信息技术‘); insert into `school`.`CATEGOrY` (`categoryid`, `pid`, `categoryname`) values (‘3‘, ‘1‘, ‘软件开发‘); insert into `school`.`category` (`categoryid`, `PId`, `categoryname`) values (‘5‘, ‘1‘, ‘美术设计‘); insert iNTO `School`.`category` (`categoryid`, `pid`, `categoryname`) VAlUES (‘4‘, ‘3‘, ‘数据库‘); insert into `school`.`category` (`CATEgoryid`, `pid`, `categoryname`) values (‘8‘, ‘2‘, ‘办公信息‘); insert into `school`.`category` (`categoryid`, `pid`, `CAtegoryname`) values (‘6‘, ‘3‘, ‘web开发‘); inserT INTO `SCHool`.`category` (`categoryid`, `pid`, `categoryname`) valueS (‘7‘, ‘5‘, ‘ps技术‘);
父类
categoryid | categoryname |
---|---|
2 | 信息技术 |
3 | 软件开发 |
5 | 美术设计 |
子类
pid | categoryid | categoryname |
---|---|---|
3 | 4 | 数据库 |
2 | 8 | 办公信息 |
3 | 6 | web开发 |
5 | 7 | ps技术 |
操作:查询父类对应的子类关系
父类 | 子类 |
---|---|
信息技术 | 办公信息 |
软件开发 | 数据库 |
软件开发 | web开发 |
美术设计 | ps技术 |
SELECT a.`categoryname` AS ‘父栏目‘,b.`categoryname`AS ‘子栏目‘ FROM `category` AS a,`category` AS b WHERE a.`categoryid` = b.`pid`
4.5 分页和排序
排序
--===分页limit 和排序order by =============== --排序:升序ASC,降序DESC --ORDER BY通过那个字段排序,怎么排 --查询的结果根据成绩降序排序 SELECT s.`StudentNo`,`StudentName`,`SubjectName`,`StudentResult` FROM student s INNER JOIN‘ result r ON s.`StudentNo` = r.`StudentNo` INNER JOIN `subject` sub ON r.`SubjectNo` = sub.`Subj ectNo` WHERE subjectName = ‘数据库结构-1‘ ORDER BY StudentResult ASC
分页
-- 100万 --为什么要分页? --缓解数据库压力,给人的体验更好,瀑布流 --分页,每页只显示五条数据 --语法: limit 起始值,页面的大小 --网页应用:当前,总的页数,页面的大小 -- LIMIT 0, 5 1~5 -- LIMIT 1,5 2~6 -- Limit 5,5 SELECT s.`StudentNo`,`StudentName`,`SubjectName`,`StudentResult` FROM `student` s INNER JOIN `result` r ON s.`StudentNo`= r.`StudentNo` INNER JOIN `subject` sub ON r.`SubjectNo` = sub.`SubjectNo` WHERE `subjectName` = ‘数据库结构-1‘ ORDER BY `StudentResult` ASC LIMIT 5,5 --第一页limit 0,5 (1-1) *5 --第二页1imit 5,5 (2-1) *5 --第三页1imit 10,5 (3-1) *5 --第N页 limit 0,5 (n-1) * pagesize, pagesize -- [pagesize: 页面大小] -- [(n-1)* pagesize :起始值] -- [n:当前页] -- [数据总数/页面大小=总页数]
语法: limit(查询起始下标)
4.6子查询(由里及外)
--分数不小于80分的学生的学号和姓名 SELECT DISTINCT s.`StudentNo`,`StudentName` FROM student s INNER JOIN result r ON r.studentNo = s.studentNo WHERE `StudentResult`>=80 --在这个基础上增加一个科目, 高等数学-2 --查询高等数学-2的编号 SELECT DISTINCT s.`StudentNo`,`StudentName` FROM student S INNER JOIN result r ON r.StudentNo = s.StudentNo WHERE `StudentResul`>=80 AND `SubjectNo` = ( SELECT SubjectNo FROM `subject` WHERE `subjectName` = ‘高等数学-2‘ ) --在改造(由里及外) SELECT StudentNo,studentName FROM student WHERE StudentNo IN ( SELECT StudentNo FROM result WHERE StudentResult>80 AND SubjectNo = (SELECT subjectNo FROM `subject` WHERE `SubjectName` = ‘高等数学-2‘) )
4.7分组和过滤
--查询不同课程的平均分,最高分,最低分,平均分大于80 ! --核心: (根据不同的课程分组) SELECT SubjectName,AVG(StudentResult) AS平均分, MAX(StudentResu1t) AS最高分, MIN(StudentResult) AS 最低分 FROM result r INNER JOIN `subject` sub ON r.`subjectNo` = sub.`SubjectNo` GROUP BY r.SubjectNo --通过什么字段来分组 HAVING平均分>80
MySQL函数
https://www.runoob.com/mysql/mysql-functions.html
5.1 常用函数
MySQL 数字函数 (一部分)
函数名 | 描述 | 实例 |
---|---|---|
ABS(x) | 返回 x 的绝对值 | 返回 -1 的绝对值:SELECT ABS(-1) -- 返回1 |
ACOS(x) | 求 x 的反余弦值(参数是弧度) | SELECT ACOS(0.25); |
ASIN(x) | 求反正弦值(参数是弧度) | SELECT ASIN(0.25); |
ATAN(x) | 求反正切值(参数是弧度) | SELECT ATAN(2.5); |
ATAN2(n, m) | 求反正切值(参数是弧度) | SELECT ATAN2(-0.8, 2); |
AVG(expression) | 返回一个表达式的平均值,expression 是一个字段 | 返回 Products 表中Price 字段的平均值:SELECT AVG(Price) AS AveragePrice FROM Products; |
CEIL(x) | 返回大于或等于 x 的最小整数 | SELECT CEIL(1.5) -- 返回2 |
CEILING(x) | 返回大于或等于 x 的最小整数 | SELECT CEIL(1.5) -- 返回2 |
MySQL 字符串函数
函数 | 描述 | 实例 |
---|---|---|
ASCII(s) | 返回字符串 s 的第一个字符的 ASCII 码。 | 返回 CustomerName 字段第一个字母的 ASCII 码:SELECT ASCII(CustomerName) AS NumCodeOfFirstChar FROM Customers; |
CHAR_LENGTH(s) | 返回字符串 s 的字符数 | 返回字符串 RUNOOB 的字符数SELECT CHAR_LENGTH("RUNOOB") AS LengthOfString; |
CHARACTER_LENGTH(s) | 返回字符串 s 的字符数 | 返回字符串 RUNOOB 的字符数SELECT CHARACTER_LENGTH("RUNOOB") AS LengthOfString; |
CONCAT(s1,s2...sn) | 字符串 s1,s2 等多个字符串合并为一个字符串 | 合并多个字符串SELECT CONCAT("SQL ", "Runoob ", "Gooogle ", "Facebook") AS ConcatenatedString; |
CONCAT_WS(x, s1,s2...sn) | 同 CONCAT(s1,s2,...) 函数,但是每个字符串之间要加上 x,x 可以是分隔符 | 合并多个字符串,并添加分隔符:SELECT CONCAT_WS("-", "SQL", "Tutorial", "is", "fun!")AS ConcatenatedString; |
FIELD(s,s1,s2...) | 返回第一个字符串 s 在字符串列表(s1,s2...)中的位置 | 返回字符串 c 在列表值中的位置:SELECT FIELD("c", "a", "b", "c", "d", "e"); |
MySQL 日期函数
数名 | 描述 | 实例 |
---|---|---|
ADDDATE(d,n) | 计算起始日期 d 加上 n 天的日期 | SELECT ADDDATE("2017-06-15", INTERVAL 10 DAY); ->2017-06-25 |
ADDTIME(t,n) | 时间 t 加上 n 秒的时间 | SELECT ADDTIME(‘2011-11-11 11:11:11‘, 5) ->2011-11-11 11:11:16 (秒) |
CURDATE() | 返回当前日期 | SELECT CURDATE(); -> 2018-09-19 |
CURRENT_DATE() | 返回当前日期 | SELECT CURRENT_DATE(); -> 2018-09-19 |
CURRENT_TIME | 返回当前时间 | SELECT CURRENT_TIME(); -> 19:59:02 |
CURRENT_TIMESTAMP() | 返回当前日期和时间 | SELECT CURRENT_TIMESTAMP() -> 2018-09-19 20:57:43 |
CURTIME() | 返回当前时间 | SELECT CURTIME(); -> 19:59:02 |
5.2聚合函数(常用)
AVG | 求平均值 |
---|---|
COUNT | 统计行的数量 |
MAX | 求最大值 |
MIN | 求最小值 |
SUM | 求累加和 |
COUNT() 函数返回匹配指定条件的行数。
SQL COUNT(column_name) 语法
COUNT(column_name) 函数返回指定列的值的数目(NULL 不计入):
SELECT COUNT(column_name) FROM table_name;
SQL COUNT(*) 语法
COUNT(*) 函数返回表中的记录数:
SELECT COUNT(*) FROM table_name;
SQL COUNT(DISTINCT column_name) 语法
COUNT(DISTINCT column_name) 函数返回指定列的不同值的数目:
SELECT COUNT(DISTINCT column_name) FROM table_name;
注释:COUNT(DISTINCT) 适用于 ORACLE 和 Microsoft SQL Server,但是无法用于 Microsoft Access。
--===========聚合函数=============== --都能够统计表中的数据( 想查询一个表中有多少个记录,就使用这个count () ) SELECT COUNT (`BornDate`) FROM student; --Count(字段),会忽略所有的null 值 SELECT COUNT (*) FROM student; -- Count (*),不会忽略null值, 本质计算行数 SELECT COUNT (1) FROM result; -- Count (1),不会忽略忽略所有的null 值本质计算行数 SELECT SUM(`StudentResult`) AS总和FROM result SELECT AVG(`StudentResulti`) AS平均分FROM result SELECT MAX(`StudentResult`) AS最高分FROM result SELECT MIN(`StudentResult`) AS最低分FROM result
5.3 数据库级别的MD5加密(扩 展)
--=========测试MD5加密======= CREATE TABLE `testmd5`( id INT(4) NOT NULL, name VARCHAR(20) NOT NULL, pwd VARCHAR(50) NOT NULL, PRIMARY KEY(`idi`) )ENGINE=INNODB DEFAULT CHARSET=utf8 --明文密码 INSERT INTO testmd5 VALUES(1,‘ zhangsan‘,‘123456‘),(2,‘lisi‘,‘123456‘),(3,‘wangwu‘,‘123456‘) --加密 UPDATE testmd5 SET pwd=MD5 (pwd) WHERE id = 1 UPDATE testmd5 SET pwd=MD5 (pwd) -- 加密全部的密码 --插入的时候加密 INSERT INTO testmd5 VALUES(4,‘xiaoming‘,MD5(‘123456‘)) --如何校验:将用户传递进来的密码,进行md5加密,然后比对加密后的值 SELECT * FROM testmd5 WHERE `name` =‘xiaoming‘ AND pwd=MD5(‘123456‘)
6 事务
6.1 什么是事务
要么都成功,要么都失败
参考链接https://blog.csdn.net/dengjili/article/details/82468576
事务原则: ACID原则 原子性,一致性,隔离性,持久性 (脏读,幻读....
原子性(Atomicity) 要么都成功,要么都失败 一致性 (Consistency) 事务前后的数据完整性要保证一致,1000 持久性(Durability) -- 事务提交 事务一旦提交则不可逆,被持久化到数据库中! 隔离性(Isolation) 事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
隔离所导致的一些问题
脏读: 指一个事务读取了另外-个事务未提交的数据。 不可重复读: 在一个事务内读取表中的某一行数据,多次读取结果不同。(这个不一 -定是错误, 只是某些场合不对) 虚读(幻读) 是指在- -个事务内读取到了别的事务插入的数据,导致前后读取不- -致。
--====================事务========================== -- mysq1 是默认开启事务自动提交的 SET autocommit = 0 /*关闭*/ SET autocommit = 1 /*开启(默认的) */ --手动处理事务 SET autocommit = 0 --关闭自动提交 --事务开启 START TRANSACTION -- 标记一个事务的开始,从这个之后的sq1 都在同一个事务内 INSERT xx INSERT XX --提交:持久化(成功! ) COMMIT --回滚: 回到的原来的样子(失败! ) ROLLBACK --事务结束 SET autocommit = 1 --开启自动提交 --了解 SAVEPOINT 保存点名--设置一个事务的保存点 ROLLBACK To SAVEPOINT 保存点名--回滚到保存点 RELEASE SAVEPOINT 保存点名--撤销保存点
--转账 CREATE DATABASE shop CHARACTER SET utf8 COLLATE utf8_ general_ ci USE shop CREATE 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=utf8 INSERT INTO account( name,money ) VALUES (‘A‘ ,2000.00),(‘B‘,10000.00) --模拟转账:事务 SET autocommit = 0; -- 关闭自动提交 START TRANSACTION --开启一个事务(一组事务) UPDATE account SET money=money-500 WHERE `name` = ‘A‘ -- A减500 UPDATE account SET money=money+500 WHERE `name` = ‘B‘ -- A加500 COMMIT; --提交事务,就被持久化了! ROLLBACK; -- 回滚 SET autocommit = 1; --恢复默认值
7 索引
MySQL官方对索引的定义为:索引(Index) 是帮助MySQL高效获取数据的数据结构。 提取句子主干,就可以得到索引的本质:索弓|是数据结构。
7.1 索引的分类
-
主键索引(PRIMARY KEY )
-
唯一的标识,主键不可重复,只能有一-个列作为主键
-
-
唯一索引(UNIQUE KEY)
-
避免重复的列出现,唯一 索引可以重复,多个列都可以标识位唯一索引
-
-
常规索引(KEY/INDEX)
-
默认的,index。 key关键字来设置
-
-
全文索引(FullText)
-
在特定的数据库|擎下才有,MylSAM
-
快速定位数据
-
基础语法
--索引的使用 --1、在创建表的时候给字段增加索引 -- 2、创建完毕后,增加索引 --显示所有的索引信息 SHOW INDEX EROM student --增加一个全文索引 (索引名) 列名 ALTER TABLE school.student ADD FULLTEXT INDEX studentName`(`studentName`) ; --id_表名_字段名 --CREATE INDEX 索引名 on 表(字段) CREATE INDEX id app user name ON app user(`name`) ; -- EXPLAIN 分析sq1执行的状况 EXPLAIN SELECT * FROM student; -- 非全文索引 EXPLAIN SELECT * FROM student WHERE MATCH(studentName) AGAINST(‘ 刘‘);
索引在小数据量的时候,用处不大,但是在大数据的时候,区别十分明显~
7.3 索引原则
-
索引不是越多越好
-
不要对经常变动的数据加索引
-
小数据量的表不需要加索引
-
索引一般加在常用来查询的字段上
索引的数据结构
https://www.cnblogs.com/tgycoder/p/5410057.html
Hash类型的索引 Btree :InnoDB的默认数据结构
8 权限管理和备份
8.1 用户管理
SQLyog 可视化管理
SQL 命令操作
用户表: mysql.user 本质:读这张表进行增删改查
--创建用户CREATE USER用户名IDENTIFIED BY ‘密码‘ CREATE USER dongdong IDENTIFIED BY ‘123456‘ --修改密码(修改当前用户密码) SET PASSWORD = PASSWORD(‘123456‘) --修改密码( 修改指定用户密码) SET PASSWORD FOR dongdong = PASSWORD(‘123456‘ ) --重命名RENAME USER原来名字TO新的名字 RENAME USER dongdong To dongdong2 --用户授权ALL PRIVILEGES 全部的权限,库.表 -- ALL PRIVILEGES 除了给别人授权,其他都能够干 GRANT ALL PRIVILEGES ON *.* TO dongdong2 --查询权限 SHOW GRANTS FOR dongdong2 -- 查看指定用户的权限 SHOW GRANTS FOR root@localhost -- ROOT用户权限: GRANT ALL PRIVILEGES ON *.* TO ‘ root‘@ ‘localhost‘ WITH GRANT OPTION --撤销权限REVOKE哪些权限,在哪个 库撒销,给谁撤销 REVOKE ALL PRIVILEGES ON *.* FROM dongdong2 --删除用户 DROP USER dongdong
8.2 MySQL 备份
为什么要备份:
-
保证重要的数据不丢失
-
数据转移
MySQL数据库备份的方式
-
直接拷贝物理文件
-
在Sqlyog 这种可视化工具中手动导出
-
在想要导出的表或者库中,右键,选择备份或导出
-
-
使用命令行导出mysqldump
# mysq1dump -h主机-u 用户名 -p 密码 数据库表名 > 物理磁盘位置/文件名 mysq1dump -hTocalhost -uroot -p123456 schoo1 student >D:/a.sq1 # mysq1dump -h主机-u 用户名 -p 密码 数据库 表1 表2 表3 > 物理磁盘位置/文件名 mysqldump -h1ocalhost -uroot -p123456 schoo1 student >D:/b.sq1 # mysq1dump -h主机-u 用户名 -p 密码数据库 > 物理磁盘位置/文件名 mysq1dump -hTocalhost -uroot -p123456 schoo1 >D:/c.sq1 #导入 #登录的情况下,切换到指定的数据库 # source 备份文件 source d:/a.sq1 mysq1 -u 用户名 -p 密码 库名 < 备份文件
9 规范数据库设计
9.1 为什么需要设计
当数据库比较复杂的时候,我们就需要设计了 糟糕的数据库设计: 数据冗余,浪费空间
-
数据库插入和删除都会麻烦、异常[屏蔽使用物理外键]
-
程序的性能差
良好的数据库设计:
-
节省内存空间
-
保证数据库的完整性
-
方便我们开发系统
软件开发中,关于数据库的设计
-
分析需求:分析业务和需要处理的数据库的需求
-
概要设计:设计关系图E-R图
设计数据库的步骤:(个人博客)
-
收集信息,分析需求
-
用户表(用户登录注销,用户的个人信息,写博客,创建分类)
-
分类表(文章分类,谁创建的)
-
文章表(文章的信息)
-
友链表(友链信息)
-
自定义表(系统信息,某个关键的字,或者一 些主字段) key : value
-
-
标识实体 (把需求落地到每个字段)
-
标识实体之间的关系
-
写博客: user -> blog
-
创建分类: user -> category
-
关注: user ->user
-
友链: links
-
评论: user-user-blog
-
9.2 三大范式
三大范式
第一范式(1NF) 原子性:保证每-列不可再分 第二范式(2NF) 前提:满足第一范式 每张表只描述- -件事情 第三范式(3NF) 前提:满足第一范式和第二范式 第三范式需要确保数据表中的每一列数据都和主键直 接相关,而不能间接相关。 (规范数据库的设计)
规范性和性能的问题
关联查询的表不得超过三张表
-
考虑商业化的需求和目标,(成本, 用户体验! )数据库的性能更加重
-
在规范性能的问题的时候,需要适当的考虑一下 规范性!
-
故意给某些表增加一-些冗余的字段。(从多 表查询中变为单表查询)、
-
故意增加一-些计算列(从大数据 量降低为小数据量的查询:索引)
JDBC(重点)
10.1 数据库驱动
我们的程序会通过数据库驱动,和数据库打交道
10.2 JDBC
导入驱动包mysql-connector-java-5.1.47.jar
10.3 第一个JDBC程序
创建测试数据库
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,‘zhansan‘,‘123456‘,‘zs@sina. com‘,‘1980-12-04‘), (2,‘lisi‘,‘123456‘,‘1isi@sina.com‘,‘1981-12-04‘), (3,‘wangwu‘,‘123456‘,‘wangwu@sina.com‘,‘1979-12-04‘);
-
创建一个普通项目
-
导入数据库驱动
编写测试代码
package com.zeng.lesson01; import java.sql.*; //我的一个JDBC程序 public class JdbcFirstDemo { public static void main(String[] args) throws ClassNotFoundException, SQLException { //1.加载驱动 Class.forName("com.mysql.jdbc.Driver"); //固定写法:加载驱动 //2.用户信息和url //useUnicode=true&characterEncoding=utf8&useSSL=true String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true"; String username = "root"; String password = "123456"; //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("pwd=" + resultSet.getObject("PASSWORD")); System.out.println("email=" + resultSet.getObject("email")); System.out.println("birth=" + resultSet.getObject("birthday")); System.out.println("===================="); } //6、释放连接 resultSet.close(); statement.close(); connection.close(); } }
1、加载驱动 2、连接数据库DriverManager 3、获得执行sql的对象Statement 4、获得返回的结果集 5、释放连接
DriverManager
// Drivermanager . regi sterDriver(new com. mysq1. jdbc. Driver()); Class.forName ("com.mysq1.jdbc.Driver"); //固定写法,加载驱动 Connection connection = DriverManager.getConnection(ur1, username, password); // connection代表数据库 //数据库设置自动提交 //事务提交 //事务滚回 connection. ro11back(); connecti on. commit(); connecti on. setAutoCommit() ;
url
String ur1 = "jdbc:mysq1://1ocaThost:3306/jdbcstudy? useUnicode-true&characterEncoding=utf8&usessL=true"; // mysq1 -- 3306 // 协议://主机地址:端口 号/数据库名?参数1&参数2&参数3 // oralce -- 1521 //jdbc:oracle:thin:@localhost:1521:sid
Statement执行SQL的对象 PrepareStatement 执行SQL的对象
statement.executequery(); //查 询操作返回ResultSet statement.execute(); //执行任何SQL statement.executeUpdate(); // 更新、插入、删除。都是用这个,返回一个受影响的行数
ResultSet查询的结果集:封装了所有的查询结果
获得指定的数据类型
resultset. getobject(); //在不知道列类型的情况下使用 //如果知道列的类型就使用指定的类型 resultSet.getstring(); resultSet.getInt(); resultset.getFloat(); resultSet.getDate() ; resultset.getobject();
resultSet.beforeFirst(); // 移动到最前面 resultset.afterLast();//移动到最后面 resultset.next(); //移动到下一 -个数据 resultSet.previous(); //移动到前一行 resultset.absolute(row); //移动到指定行
释放资源
//6、释放连接 resultSet.close() ; statement.close() ; connection.close(); // 耗资源,用完关掉!
10.4 statement对象
Jdbc中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。
Statement对象的executeUpdate方法,用于向数据库发送增、删、改的sq|语句, executeUpdate执行完后, 将会返回-个整数(即增删改语句导致了数据库几行数据发生了变化)。
Statement.executeQuery方法用于向数据库发送查询语句,executeQuery方 法返回代表查询结果的ResultSet对象。
CRUD操作- create
使用executeUpdate(String sql)方法完成数据添加操作,示例操作:
Statement st = conn.createstatement(); String sql = "insert into user(...) value(.....)"; int num = st. executeUpdate(sql); if (num>0){ System. out. print1n("插入成功!"); }
CRUD操作-delete
使用executeUpdate(String sq|)方法完成数据删除操作,示例操作:
Statement st = conn.createstatement(); string sq1 = "delete from user where id=1"; int num = st.executeUpdate(sql); if (num>0){ System. out. print1n("删除成功!"); }
CRUD操作-update
使用executeUpdate(String sq|)方法完成数据删除操作,示例操作:
Statement st = conn.createstatement(); string sq1 = "update user set name‘‘ where name=‘‘"; int num = st.executeUpdate(sql); if (num>0){ System. out. print1n("修改成功!"); }
CRUD操作-read
使用executeQuery(String sq|)方法完成数据查询操作,示例操作:
Statement st = conn.createstatement(); string sq1 = "select * from user where id=1"; ResultSet rs = st.executeUpdate(sq1); whi1e(rs.next()){ //根据 获取列的数据类型,分别调用rs的相应方法映射到java对象中 }
代码实现
-
提取工具类
import java.io.IOException; import java.io.InputStream; import java.sql.*; import java.util.Properties; public class JdbcUtils { private static String driver =null; private static String url =null; private static String username =null; private static String password =null; static { try { InputStream in = JdbcUtils.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(); } } } }
-
编写增删改
executeUpdate
package com.zeng.lesson02; import com.zeng.lesson02.utils.JdbcUtils; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class TsetInsert { public static void main(String[] args) { Connection conn = null; Statement st = null; ResultSet rs = null; try { conn = JdbcUtils.getConnection();//获取数据库连接 st = conn.createStatement(); //获得SQL的执行对象 String sql = "INSERT INTO users(id,`NAME`,`PASSWORD`,`email`,`birthday`)" + "VALUE(6,‘dongdong‘,‘123456‘,‘77511593@qq.com‘,‘2020-04-07‘)"; int i = st.executeUpdate(sql); if(i>0){ System.out.println("插入成功"); } } catch (SQLException e) { e.printStackTrace(); } finally { JdbcUtils.release(conn,st,rs); } } }
package com.zeng.lesson02; import com.zeng.lesson02.utils.JdbcUtils; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class TestDelete { public static void main(String[] args) { Connection conn = null; Statement st = null; ResultSet rs = null; try { conn = JdbcUtils.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 { JdbcUtils.release(conn,st,rs); } } }
package com.zeng.lesson02; import com.zeng.lesson02.utils.JdbcUtils; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class TestUpdate { public static void main(String[] args) { Connection conn = null; Statement st = null; ResultSet rs = null; try { conn = JdbcUtils.getConnection();//获取数据库连接 st = conn.createStatement(); //获得SQL的执行对象 String sql = "UPDATE users SET `NAME`=‘dongdong2‘,`email`=‘123@qq.com‘ WHERE id=5"; int i = st.executeUpdate(sql); if(i>0){ System.out.println("更改成功"); } } catch (SQLException e) { e.printStackTrace(); } finally { JdbcUtils.release(conn,st,rs); } } }
-
查询
executeQuery
package com.zeng.lesson02; import com.zeng.lesson02.utils.JdbcUtils; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class TestSelect { public static void main(String[] args) { Connection conn = null; Statement st = null; ResultSet rs = null; try { conn = JdbcUtils.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 { JdbcUtils.release(conn,st,rs); } } }
SQL注入的问题
sql存在漏洞,会被攻击导致数据泄露,SQL会被拼接or
package com.zeng.lesson02; import com.zeng.lesson02.utils.JdbcUtils; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class Sql注入 { public static void main(String[] args) { login(" ‘or‘1=1"," ‘or‘1=1"); } public static void login(String username,String password){ Connection conn = null; Statement st = null; ResultSet rs = null; try { conn = JdbcUtils.getConnection();//获取数据库连接 st = conn.createStatement(); //获得SQL的执行对象 //select * from users where `NAME` = ‘‘or‘1=1‘and `PASSWORD` = ‘‘or‘1=1‘; String sql = "select * from users where `NAME` = ‘"+username+"‘and `PASSWORD` = ‘"+password+"‘"; rs = st.executeQuery(sql);//查询完毕会返回一个结果集 while (rs.next()){ System.out.println(rs.getString("NAME")); System.out.println(rs.getString("PASSWORD")); System.out.println("================"); } } catch (SQLException e) { e.printStackTrace(); } finally { JdbcUtils.release(conn,st,rs); } } }
10.5 PreparedStatement对象
PreparedStatement可以防止SQL注入。
1.增
package com.zeng.lesson03; import com.zeng.lesson02.utils.JdbcUtils; import java.sql.Connection; import java.sql.Date; import java.sql.PreparedStatement; import java.sql.SQLException; public class TsetInsert { public static void main(String[] args) { Connection conn = null; PreparedStatement st = null; try { conn = JdbcUtils.getConnection(); //区别 //使用?占位符代替参数 String sql = "INSERT INTO users(id,`NAME`,`PASSWORD`,`email`,`birthday`) values(?,?,?,?,?)"; st = conn.prepareStatement(sql); //预编译sql先写sql,然后不执行 //手动给参数赋值 /* 注意点:sql.Date 数据库 java.sql.Date() util.Date Java new Date().getTime() 获得时间戳 */ st.setInt(1,4); st.setString(2,"dongdong4"); st.setString(3,"123456"); st.setString(4,"77511593@qq.com"); 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 { JdbcUtils.release(conn,st,null); } } }
2.删
package com.zeng.lesson03; import com.zeng.lesson02.utils.JdbcUtils; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; public class TestDelete { public static void main(String[] args) { Connection conn = null; PreparedStatement st = null; try { conn = JdbcUtils.getConnection(); //区别 //使用?占位符代替参数 String sql = "delete from users where id = ?"; st = conn.prepareStatement(sql); //预编译sql先写sql,然后不执行 //手动给参数赋值 st.setInt(1,4); //执行 int i = st.executeUpdate(); if (i>0){ System.out.println("删除成功"); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(conn,st,null); } } }
3.改
package com.zeng.lesson03; import com.zeng.lesson02.utils.JdbcUtils; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; public class TestUpdate { public static void main(String[] args) { Connection conn = null; PreparedStatement st = null; try { conn = JdbcUtils.getConnection(); //区别 //使用?占位符代替参数 String sql = "update users set `NAME`=? where id=?;"; st = conn.prepareStatement(sql); //预编译sql先写sql,然后不执行 //手动给参数赋值 st.setString(1,"dongdong"); st.setInt(2,4); //执行 int i = st.executeUpdate(); if (i>0){ System.out.println("更新成功"); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(conn,st,null); } } }
4.查
package com.zeng.lesson03; import com.zeng.lesson02.utils.JdbcUtils; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class TestSelect { public static void main(String[] args) { Connection conn = null; PreparedStatement st = null; ResultSet rs = null; try { conn = JdbcUtils.getConnection(); String sql = "select * from users where id = ?"; st = conn.prepareStatement(sql); st.setInt(1,1); rs = st.executeQuery(); if (rs.next()){ System.out.println(rs.getString("NAME")); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(conn,st,rs); } } }
5.防止sql注入
package com.zeng.lesson03; import com.zeng.lesson02.utils.JdbcUtils; import java.sql.*; public class Sql注入 { public static void main(String[] args) { login("wangwu","123456"); //login(" ‘or‘1=1"," ‘or‘1=1"); } public static void login(String username,String password){ Connection conn = null; PreparedStatement st = null; ResultSet rs = null; try { conn = JdbcUtils.getConnection(); // PreparedStatement 防止:SQL注入的本质,把传递进来的参数当做字符 // 假设其中存在转义字符,比如说‘会被直接转义 String sql = "select * from users where `NAME`=? and `PASSWORD`=?"; st = conn.prepareStatement(sql); st.setString(1,username); st.setString(2,password); rs = st.executeQuery(); while (rs.next()){ System.out.println(rs.getString("NAME")); System.out.println(rs.getString("password")); System.out.println("================"); } } catch (SQLException e) { e.printStackTrace(); } finally { JdbcUtils.release(conn,st,rs); } } }
10.6 使用IDEA连接数据库
编写sql代码的地方
切换数据库
驱动
10.7 事务
要么都成功,要么都失败
ACID原则 原子性,一致性,隔离性,持久性
代码实现
-
开启事务
conn.setAutoCommit(false);
-
一组业务完毕,提交事务
-
可以在catch语句中显示的定义回滚语句,但默认失败就会回滚
package com.zeng.lesson04; import com.zeng.lesson02.utils.JdbcUtils; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class TestTransaction2 { public static void main(String[] args) { Connection conn = null; PreparedStatement st= null; ResultSet rs = null; try { conn = JdbcUtils.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 { JdbcUtils.release(conn,st,rs); } } }
10.8 数据库连接池
数据库连接--执行完毕--释放 ? 连接-释放 十分浪费系统资源 所以会有有连接池 池化技术:准备-些预先的资源,过来就连接预先准备好的 最小连接数: 10 最大连接数: 15 等待超时: 100ms 编写连接池,实现-个接口DataSource
开源数据源实现
DBCP
C3P0
Druid:阿里巴巴的
使用了这些数据库连接池之后,我们在项目开发中就不需要编写连接数据库的代码了!
BDCP
需要用到的
commons-dbcp-1.4
commons-pool-1.6
C3P0
需要用到的
c3p0-0.9.5.5
mchange-commons-java-0.2.19
结论