JAVA MySQL数据库 笔记
MySQL数据库
1. 初始MySQL
1.1 为什么学习数据库
- 岗位技能需求
- 现在的世界,得数据者得天下
- 网站中数据存储的地方
- 数据库是几乎软件体系中最核心的一个存在。
1.2 什么是数据库
数据库 ( DataBase , 简称DB ),是长期存放在计算机内,有组织,可共享的大量数据的集合,是一个数据 “仓库”。它可以安全管理数据,如:增删改查,减少冗余等。
1.3 数据库分类
1.3.1 关系型数据库(Sql)
- MySQL , Oracle , SQL Server , SQLite……
- 关系型数据库最典型的数据结构是表,由二维表及其之间的联系所组成的一个数据组织
1.3.2 非关系型数据库(NoSql)
- Redis , MongoDB ……
- 非关系型数据库通常指数据以对象的形式存储在数据库中,而对象之间的关系通过每个对象自身的属性来决定
1.4 数据库管理系统(DBMS)
数据库管理系统能够科学组织和存储数据 , 高效地获取和维护数据,而MySQL就属于一种数据库管理系统。
1.5 MySQL简介
MySQL是现在流行的,开源的,免费的关系型数据库,由瑞典MySQL AB公司开发,目前属于 Oracle 旗下产品。它有如下特点 :
- 免费 , 开源数据库
- 小巧 , 功能齐全
- 使用便捷
- 可运行于Windows或Linux操作系统
- 可适用于中小型甚至大型网站应用
官网 : https://www.mysql.com/
2. MySQL的安装与使用
2.1 下载MySQL
- MySQL 5.7.19 64位下载地址:点击下载
建议使用压缩版,虽然安装繁琐,但是卸载比较方便。
2.2 安装MySQL
把下载后的压缩包解压到想要安装的目录
添加环境变量:我的电脑->属性->高级->环境变量,选择PATH,在其后面添加:MySQL文件夹下面的bin文件夹
在MySQL文件夹下新建
my.ini
文件,并编辑为:[mysqld] basedir=D:\develop\mysql-5.7.19\ datadir=D:\develop\mysql-5.7.19\data\ port=3306 skip-grant-tables #可以不用输入密码登陆
启动管理员模式下的CMD,并将路径切换至MySQL下的bin目录
cd /d D:\develop\mysql-5.7.19
,然后输入mysqld –install
,安装mysql。输入
mysqld --initialize-insecure --user=mysql
初始化数据文件。初始化完成后MySQL会生成data文件夹,data文件夹下也添加了相关的配置文件执行
net start mysql
启动MySQL服务执行
mysql -uroot -p
登录MySQL,进入mysql管理界面(-u后面是用户名,-p后面是密码,因为在my.ini
文件里配置了可以不用输入密码,所以可以直接登陆)进入界面后更改root密码:
update mysql.user set authentication_string=password('123456') where user='root' and Host = 'localhost';
刷新权限
flush privileges;
修改
my.ini
文件删除最后一句skip-grant-tables,之后登陆就必须使用密码了先用
exit
命令退出MySQL管理界面,然后输入net stop mysql
停止服务,在执行net start mysql
启动MySQL服务输入
mysql -uroot -p123456
重新登陆,出现以下结果就安装好了
2.3 SQLyog的基本使用
2.3.1 SQLyog安装
SQLyog 是一个快速而简洁的图形化管理MYSQL数据库的工具,它能够在任何地点有效地管理你的数据库,由业界著名的Webyog公司出品。下载地址
下面学习使用SQLyog管理工具新建一个数据库,并且新建一张表
2.3.2 使用SQLyog创建数据库
右键,创建数据库
数据库的属性如下:
在SQLyog的操作本质对应着命令行的操作,可以在历史记录中查看
2.3.3 使用SQLyog创建数据表
右键,创建数据表
表的属性如下:
2.3.4 查看表里的数据
傻瓜式查看,选中想看的表,右键,打开表即可
2.3.5 往表里添加数据
类似EXCEL的操作,直接添加即可,记得保存
3. 数据库基础
3.1 MySQL常见命令
MySQL不区分大小写,但要记得以分号;结尾
update user set password=password('123456')where user='root'; --修改密码
flush privileges; --刷新数据库show databases; --显示所有数据库、
create database dbname; --创建数据库
use databasename; --选择数据库
show tables; --显示所有表
describe student; --显示student表的所有信息exit; --退出Mysql
? --命令关键词 : 寻求帮助
-- 表示注释
3.2 字段数据类型
3.2.1 数值类型
3.2.2 字符串类型
char(n)和 varchar(n)中括号中n代表字符的个数,并不代表字节个数,所以当使用了中文的时候(UTF8)意味着可以插入m个中文,但是实际会占用m*3个字节。
char和varchar最大的区别就在于char不管实际value都会占用n个字符的空间,而varchar只会占用实际字符应该占用的空间+1,并且实际空间+1<=n。
超过char和varchar的n设置后,字符串会被截断。
3.2.3 日期与时间类型
3.3 数据类型属性
3.3.1 auto_increment
auto_increment能为新插入的行赋一个唯一的整数标识符。为列赋此属性将为每个新插入的行赋值为上一次插入的ID+1。MySQL要求将auto_increment属性用于作为主键的列。此外,每个表只允许有一个auto_increment列。
3.3.2 default
default属性确保在没有任何值可用的情况下,赋予某个常量值,这个值必须是常量,因为MySQL不允许插入函数或表达式值。如果已经为此列指定了null属性,没有指定默认值时默认值将为null,否则默认值将依赖于字段的数据类型。
3.3.3 null和 not null
- 列指定null属性时,该列可以保持为空,而不论行中其它列是否已经被填充。记住,null精确的说法是“无”,而不是空字符串或0。
- 将一个列定义为not null,将不允许向该列插入null值。建议在重要情况下始终使用not null属性,因为它提供了一个基本验证,确保已经向查询传递了所有必要的值。
3.3.4 zerofill
zerofill属性可用于任何数值类型,用0填充所有剩余字段空间。例如,无符号int的默认宽度是10;因此,当“零填充”的int值为4时,将表示它为0000000004。
3.4 InnoDB 与 MyISAM
名称 | MyISAM | InnoDB |
---|---|---|
事务 | 不支持 | 支持 |
数据行锁定 | 不支持 | 支持 |
外键 | 不支持 | 支持 |
全文索引 | 支持 | 不支持 |
表空间大小 | 较小 | 较大 |
适用场合:
- 是否要支持事务,如果要请选择 InnoDB,如果不需要可以考虑 MyISAM
- 如果表中绝大多数都只是读查询,可以考虑 MyISAM,如果有读写也挺频繁,请使用InnoDB。
- 系统奔溃后,MyISAM恢复起来更困难,能否接受,不能接受就选 InnoDB;
- MyISAM的优势在于节约空间及相应速度,而InnoDB的优势在于安全性 , 事务处理及多用户操作数据表
4. 数据库的操作
操作数据库 -> 操作数据库中的表 -> 操作表中的数据
4.0 学习方法
- 对照
SQLyog
工具自动生成的语句学习 - 固定语法中的单词需要记忆
4.1 操作数据库
- 创建数据库:
CREATE DATABASE [IF NOT EXISTS] school;
- 删除数据库:
DROP DATABASE [IF NOT EXISTS] school;
- 使用数据库:
USE school;
- 查看数据库:
SHOW DATABASES;
4.2 命令行创建数据表
– 创建学生表(列,字段)
– 学号int 登录密码varchar(20) 姓名,性别varchar(2),出生日期(datatime),家庭住址,email
命令行创建新表模板
CREATE TABLE [IF NOT EXISTS] 表名('字段名' 数据类型 [属性] comment '','字段名' 数据类型 [属性] comment '',...
)ENGINE = InnoDB DEFAULT CHARSET=utf8
注意:
- 使用英文括号(),表的名称和字段尽量使用``括起来
- 字符串使用单引号括起来
- 所有语句后面加英文逗号,最后一个字段不用加
-- 创建学生表
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 '出生日期',`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',PRIMARY KEY (`id`)
) ENGINE = INNODB DEFAULT CHARSET=utf8
创建完成后,可通过DESC student
命令查看表结构
4.3 通过帮助查看创建语句
-- 模板
show create 想创建的东西 名称SHOW CREATE DATABASE school;
SHOW CREATE TABLE student;
4.4 表的修改和删除
修改
-- 修改表名
-- 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 INT(12);-- 修改字段名及属性
-- ALTER TABLE 表名 CHANGE 旧字段名 新字段名 列类型[属性]
ALTER TABLE teacher1 CHANGE age age1 INT(13);
删除
-- 删除表
-- DROP TABLE [IF EXISTS] 表名
DROP TABLE IF EXISTS teacher;
5. MySQL数据管理
5.1 外键
5.1.1 概念
表A中有字段年级id
做了主键,表B中也有年级id
这个字段,这里的年级id
一定来自表A同样字段里的内容,那么表B的这个字段就叫表A字段的外键,也就是两个表以年级id
这个字段建立了联系。
表A中年级id
字段里面的年级id
一定是唯一的,不能有重复,而表B里面的同一个年级id
可以出现多次。这称为表A年级id
字段与表B年级id
字段建立了一对多的关系。
外键的作用就是可以让年级id
保证是来自表A中,也就是保证了数据的规范性;如果要删除A表中的某个年级id
,那么首先要删除B表中同样的年级id
,这保证了数据的完整性。
5.1.2 创建外键
方式一:在创建表的时候,添加约束(不常用)
-- 创建外键的方式一 : 创建子表同时创建外键-- 年级表 (id\年级名称)
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 `student` (
`studentid` INT(4) NOT NULL COMMENT '学号',
`studentname` VARCHAR(20) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`sex` TINYINT(1) DEFAULT '1' COMMENT '性别',
`gradeid` INT(10) DEFAULT NULL COMMENT '年级',
`phoneNum` VARCHAR(50) NOT NULL COMMENT '手机',
`address` VARCHAR(255) DEFAULT NULL COMMENT '地址',
`borndate` DATETIME DEFAULT NULL COMMENT '生日',
`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
`idCard` VARCHAR(18) DEFAULT NULL COMMENT '身份证号',
PRIMARY KEY (`studentno`),
KEY `FK_gradeid` (`gradeid`), # 添加外键
CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade` (`gradeid`) #说明外键的主表
) ENGINE=INNODB DEFAULT CHARSET=utf8
方式二:创建子表完毕后,修改子表添加外键
-- 创建外键方式二 : 创建子表完毕后,修改子表添加外键
-- ALTER TABLE 表
-- ADD CONSTRAINT 约束名 FOREIGN KEY(外键的列)
-- REFERENCES 哪个表 (哪个字段);ALTER TABLE `student`
ADD CONSTRAINT `FK_gradeid` FOREIGN KEY(`gradeid`)
REFERENCES `grade` (`gradeid`);
5.2 DML语句
DML是Data Manipulation Language的缩写,意思是数据操纵语句,是指在SQL语言中,负责对数据库对象运行数据访问工作的指令集,以INSERT、UPDATE、DELETE三种指令为核心,分别代表插入、更新与删除,是开发以数据为中心的应用程序必定会使用到的指令。
5.2.1 插入记录(INSERT)
语法:INSERT INTO 表名[(字段1,字段2,字段3,…)] VALUES(‘值1’,‘值2’,‘值3’)
-- 单个值插入
INSERT INTO `grade`(`gradename`) VALUES('大二'); -- 多个值插入
INSERT INTO `grade`(`gradename`)
VALUES ('大三'),('大四');-- 多个字段插入
INSERT INTO `student`(`name`,`pwd`) VALUES ('李四','aaa');
注意 :
- 字段或值之间用英文逗号隔开 .
- ’ 字段1,字段2…’ 该部分可省略 , 但添加的值务必与表结构,数据列,顺序相对应,且数量一致 .
- 可同时插入多条数据 , values 后用英文逗号隔开 .
5.2.2 修改记录(UPDATE)
语法:UPDATE 表名 SET column_name=value [,column_name2=value2,…] [WHEREcondition];
-- 修改指定的学生名字
UPDATE `student` SET `name`='王五' WHERE id = 1;-- 不指定条件的情况下,会改动所有的表
UPDATE `student` SET `name`='王五';-- 修改多个属性
UPDATE `student` SET `name`='狄仁杰',`email`='xxxx@qq.com' WHERE id = 1;
注意 :
- column_name 为要更改的数据列
- value 为修改后的数据 , 可以为变量 , 具体指 , 表达式或者嵌套的SELECT结果
- condition 为筛选条件 , 如不指定则修改该表的所有列数据
5.2.3 删除记录(DELETE)
语法:DELETE FROM 表名 [WHERE condition];
-- 删除指定的数据
DELETE FROM `student` WHERE id = 3;-- 删除所有数据 (如果真的需要全部删除,请使用TRUNCATE命令)
DELETE FROM `student`;
- TRUNCATE:用于完全清空表数据
-- 语法:TRUNCATE [TABLE] table_name;-- 清空年级表
TRUNCATE grade
注意:区别于DELETE命令
相同 : 都能删除数据 , 不删除表结构 , 但TRUNCATE速度更快
不同 :
- 使用TRUNCATE TABLE 重新设置AUTO_INCREMENT计数器
- 使用TRUNCATE TABLE不会对事务有影响 (事务后面会说)
5.3 DQL语句(重点)
DQL,Data Query Language,数据查询语句,用以从表中获得数据,确定数据怎样在应用程序给出。保留字SELECT是DQL(也是所有SQL)用得最多的动词,其他DQL常用的保留字有WHERE,ORDER BY,GROUP BY和HAVING。这些DQL保留字常与其他类型的SQL语句一起使用。
- 使用模板 (顺序谐音:师傅叫我干活了,sfjwghol)
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}];-- 指定查询的记录从哪条至哪条
5.3.1 指定查询字段 (select)
语法:select 字段 as 别名 from 表名
-- 查询学生的所有信息
SELECT * FROM student;-- 查询指定字段
SELECT `studentno`,`studentname` FROM student-- 查询指定字段并用as起别名
SELECT `studentno` AS 学号,`studentname` AS 学生姓名
FROM student-- 函数 concat(a,b)
SELECT CONCAT('姓名:',studentname) AS 名字 FROM student
5.3.2 去重 (distinct)
作用:去掉SELECT查询返回的记录结果中重复的记录 ( 返回所有列的值都相同 ) , 只返回一条
-- 查询参加考试的同学,未去重
SELECT `studentno` FROM result
-- 查询参加考试的同学,去重
SELECT DISTINCT `studentno` FROM result
5.3.3 where条件语句
作用:用于检索数据表中符合搜索条件的记录。搜索条件可由一个或多个逻辑表达式组成 , 结果一般为真或假.
逻辑操作符 (请尽量使用英文字符)
运算符 | 语法 |
---|---|
and && | a and b a && b |
or || | a or b a || b |
not ! | not a !a |
-- 满足条件的查询(where)
SELECT `studentno`,`studentresult` FROM result;-- 查询考试成绩在95-100之间的
SELECT `studentno`, `studentresult`
FROM result
WHERE `studentresult` >=95 AND `studentresult` <=100;-- AND也可以写成 &&
SELECT `studentno`,`studentresult`
FROM result
WHERE `studentresult` >=95 && `studentresult`<=100;-- 模糊查询(对应的词:精确查询)
SELECT `studentno`,`studentresult`
FROM result
WHERE `studentresult` BETWEEN 95 AND 100;-- 除了1000号同学,要其他同学的成绩
SELECT `studentno`,`studentresult`
FROM result
WHERE `studentno` !=1000;-- 使用NOT
SELECT `studentno`,`studentresult`
FROM result
WHERE NOT `studentno` =1000;
5.3.4 模糊查询
操作符 | 语法 | 描述 |
---|---|---|
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 | 如果a匹配b,则结果为真 |
IN | a in (a1, a2, a3…) | 如果a为(a1, a2, a3…)中的某一个值,则结果为真 |
-- 查询姓张的同学
-- 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 '%国%' -- 查询1000,1001号学员
SELECT `studentno`,`studentname` FROM student
WHERE `studentno` IN (1000,1001)-- 查询出生日期没有填写的同学
-- 不能直接写=NULL , 这是代表错误的 , 用 is null
SELECT `studentname`FROM student
WHERE `borndate` IS NULL;
5.3.5 7种联表查询 (join)
- 左外连接:保持左边表的记录,右边表没有与之对应的记录补 NULL。
select *
from a
left join b
on a.id = b.id;
- 右外连接:保持右边表的记录,左边表没有与之对应的记录补 NULL。一般情况下可能更多考虑左连接,因此右连接用得很少。
select *
from a
right join b
on a.id = b.id;
- 内连接:查询两表之间都能找到的记录
select *
from a
inner join b
on a.id = b.id;
- 左独有:由于不使用外键,该查询通常用于处理过期数据
目前,生产环境的数据库已经不会考虑建立物理外键,比如现有 B 表含有字段 a_id,表示存储 A 表的主键,但由于一些历史原因等,a_id 的值并不一定存在 A 表中的一条记录与之对应,现在我们需要从 B 表中找到这些没有对应的 “垃圾数据”,进一步分析。
select *
from B
left join A
on B.a_id = A.id
where A.id is null;
- 右独有
select *
from a
right join b
on a.id = b.id
where a.id is null;
- 全连接:属于全连接取全集,用 UNION 代替 FULL JOIN。
select
a.id a_id,
a.name a_name,
b.id b_id,
b.name b_name
from a
left join b
on a.id = b.id
union
select
a.id a_id,
a.name a_name,
b.id b_id,
b.name b_name
from a
right join b
on a.id = b.id;
- 并集去交集:属于全连接 + 排除交集,使用关键字 FULL JOIN。
select *
from a full outer join b on a.id = b.id
where a.id is null or b.id is null;
但是,mysql 并没有 FULL 关键字,因此使用 UNION 联接 左连接和 右连接
select *
from a left join b on a.id = b.id
where b.id is null
union
select *
from a right join b on a.id = b.id
where a.id is null;
- 联表查询思路
- 分析需求,确定查询的列来源于几个表,进行连接查询
- 确定使用哪种连接查询
-- 内连接
SELECT s.`studentno`,`studentname`,`subjectno`,`studentresult`
FROM student AS s
INNER JOIN result AS r
ON 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`-- 查询缺考的同学
SELECT s.`studentno`,`studentname`,`subjectno`,`studentresult`
FROM student AS s
LEFT JOIN result AS r
ON s.`studentno` = r.`studentno`
WHERE r.`studentresult` IS NULL;-- 查询参考考试的同学信息:学号,学生姓名,科目名,分数
SELECT
s.`studentno` AS 学号,
s.`studentname` AS 学生姓名,
sj.`subjectname` AS 科目名,
r.`studentresult` AS 分数
FROM
student AS s
RIGHT JOIN result AS r
ON s.`studentno` = r.`studentno`
LEFT JOIN SUBJECT AS sj
ON r.`subjectno` = sj.`subjectno`
5.3.6 自连接
数据表与自身进行连接。(学了半天,感觉和inner join没区别啊,而且inner join也是可以使用where的…)
/*
自连接数据表与自身进行连接需求:从一个包含栏目ID , 栏目名称和父栏目ID的表中,查询父栏目名称和其他子栏目名称
*/
SELECT
a.`categoryname` AS 父栏目,
b.`categoryname`AS 子栏目
FROM `category` AS a,`category` AS b
WHERE a.`categoryid` = b.`pid`-- 内连接写法
SELECT
a.`categoryname` AS 父栏目,
b.`categoryname`AS 子栏目
FROM `category` AS a
INNER JOIN `category` AS b
WHERE a.`categoryid` = b.`pid`
5.4 排序(order by)
SELECT
s.`studentno` AS 学号,
s.`studentname` AS 姓名,
sj.`subjectname` AS 科目,
r.`studentresult` AS 分数
FROM student AS s
INNER JOIN result AS r
ON s.`studentno` = r.`studentno`
LEFT JOIN SUBJECT AS sj
ON r.`subjectno` = sj.`subjectno`
ORDER BY r.studentresult DESC # 降序排列
5.5 分页(limit)
limit子句用于限制查询结果返回的数量,常用于分页查询。分页主要用于控制大数据量表在前台(报表,表格,列表框之类)的分页显示。
这样做不仅能够提高查询效率,而且还能使前台看起来比较简洁。
语法: limit 当前页,页面大小
select * from table LIMIT 2,10; # 检索从第3行开始,累加10条记录,共显示id为3....12
select * from table LIMIT 6,10; # 检索从第7行开始,累加10条记录,共显示id为7,8...16-- 想要第一页
select * from table LIMIT 0,5; # 检索从第0行开始,累加5条记录,共显示id为0,1,2,3,4
-- 想要第二页
select * from table LIMIT 5,5; # 检索从第5行开始,累加5条记录,共显示id为5,6,7,8,9
...
-- 想要第N页
select * from table limit (n-1)*pageSize,pageSize;
5.6 子查询
子查询就是将一个查询(子查询)的结果作为另一个查询(主查询)的数据来源或判断条件的查询。常见的子查询有WHERE子查询,FROM子查询,等等。子查询要使用小括号()。
WHERE 子查询
-- 查询薪资比平均薪资低的员工信息
SELECT *
FROM EMP
WHERE SAL < (SELECT AVG(SAL) FROM EMP);
FROM子查询
-- 查询平均薪资高于2000的职位以及该职位的平均薪资
SELECT JOB,AVG(SAL)
FROM (SELECT JOB,AVG(SAL) AS AVGSAL FROM EMP GROUP BY JOB)TEMP
WHERE TEMP.AVGSAL>2000;
6. MySQL函数
6.1 常用函数
6.1.1 数据函数
SELECT ABS(-8); /*绝对值*/SELECT CEILING(9.4); /*向上取整*/SELECT FLOOR(9.4); /*向下取整*/SELECT RAND(); /*随机数,返回一个0-1之间的随机数*/SELECT SIGN(0); /*符号函数: 判断给定数字的正负性,负数返回-1,正数返回1,0返回0*/
6.1.2 字符串函数
SELECT CHAR_LENGTH('狂神说坚持就能成功'); /*返回字符串包含的字符数*/SELECT CONCAT('我','爱','程序'); /*合并字符串,参数可以有多个*/SELECT INSERT('我爱编程helloworld',1,2,'超级热爱'); /*替换字符串,从某个位置开始替换某个长度*/SELECT LOWER('KuangShen'); /*小写*/SELECT UPPER('KuangShen'); /*大写*/SELECT LEFT('hello,world',5); /*从左边截取*/SELECT RIGHT('hello,world',5); /*从右边截取*/SELECT REPLACE('狂神说坚持就能成功','坚持','努力'); /*替换字符串*/SELECT SUBSTR('狂神说坚持就能成功',4,6); /*截取字符串,开始和长度*/SELECT REVERSE('狂神说坚持就能成功'); /*反转-- 查询姓周的同学,改成邹SELECT REPLACE(studentname,'周','邹') AS 新名字FROM student WHERE studentname LIKE '周%';
注意:索引从1开始
6.1.3 日期和时间函数
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());
6.1.4 系统信息函数
SELECT VERSION(); /*版本*/SELECT USER(); /*用户*/
6.2 聚合函数
函数名称 | 描述 |
---|---|
COUNT() | 返回满足Select条件的记录总和数,如 select count(*) 【不建议使用 *,效率低】 |
SUM() | 返回数字字段或表达式列作统计,返回一列的总和。 |
AVG() | 通常为数值字段或表达列作统计,返回一列的平均值 |
MAX() | 可以为数值字段,字符字段或表达式列作统计,返回最大的值。 |
MIN() | 可以为数值字段,字符字段或表达式列作统计,返回最小的值。 |
/* count(1)、count(*)与count(列名)的执行区别 */SELECT COUNT(studentname) FROM student;SELECT COUNT(*) FROM student;SELECT COUNT(1) FROM student; /*推荐*/-- 从含义上讲,count(1) 与 count(*) 都表示对全部数据行的查询。-- count(字段) 会统计该字段在表中出现的次数,忽略字段为 null 的情况。即不统计字段为 null 的记录。-- count(*) 包括了所有的列,相当于行数,在统计结果的时候,包含字段为 null 的记录;-- count(1) 用1代表代码行,在统计结果的时候,包含字段为 null 的记录 。/*很多人认为count(1)执行的效率会比count(*)高,原因是count(*)会存在全表扫描,而count(1)可以针对一个字段进行查询。其实不然,count(1)和count(*)都会对全表进行扫描,统计所有记录的条数,包括那些为null的记录,因此,它们的效率可以说是相差无几。而count(字段)则与前两者不同,它会统计该字段不为null的记录条数。下面它们之间的一些对比:1)在表没有主键时,count(1)比count(*)快2)有主键时,主键作为计算条件,count(主键)效率最高;3)若表格只有一个字段,则count(*)效率较高。*/SELECT COUNT(studentname) 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;
- 查询不同课程的平均分、最高分、最低分,且平均分大于75 核心:分组、Having
SELECT
`subjectname` AS 科目,
AVG(`studentresult`) AS 平均分,
MAX(`studentresult`) AS 最高分,
MIN(`studentresult`) AS 最低分
FROM `result` AS r
LEFT JOIN SUBJECT AS sj
ON r.`subjectno` = sj.`subjectno`
GROUP BY `subjectname`
HAVING 平均分 > 75;
- 注意:
where
写在group by
前面.
要是放在分组后面的筛选
要使用having
。
6.3 MD5 加密函数
6.3.1 MD5简介
MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一,将数据(如汉字)运算为另一固定长度值,是杂凑算法的基础原理,MD5的前身有MD2、MD3和MD4。
6.3.2 MySQL数据加密
语法:MD5(‘ 需要加密的内容’)
-- 建表DROP TABLE IF EXISTS `testmd5`;CREATE TABLE IF NOT EXISTS `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` VALUES (1,'张三','123456');INSERT INTO `testmd5` VALUES (2,'李四','234567');INSERT INTO `testmd5` VALUES (3,'王五','2345678');-- 插入数据后通过更新加密UPDATE `testmd5` SET `pwd`=MD5(`pwd`)-- 插入数据的时候加密INSERT INTO `testmd5` VALUES (4,'孙六',MD5('774132'));
7. 事务
7.1 什么是事务?
事务是逻辑上的一组操作,要么都执行,要么都不执行。
事务最经典也经常被拿出来说例子就是转账了。假如小明要给小红转账1000元,这个转账会涉及到两个关键操作就是:将小明的余额减少1000元,将小红的余额增加1000元。万一在这两个操作之间突然出现错误比如银行系统崩溃,导致小明余额减少而小红的余额没有增加,这样就不对了。事务就是保证这两个关键操作要么都成功,要么都要失败。
7.2 事务的四大特性 (ACID)
原子性: 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用
一致性: 执行事务前后,数据保持一致,多个事务对同一个数据读取的结果是相同的
隔离性: 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的
**持久性:**一个事务被提交之后,它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响
口诀:原子太一致了,需要把它们隔离开,这样才能持久
7.3 并发事务带来的问题
在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对统一数据进行操作)。并发虽然是必须的,但可能会导致以下的问题:
**脏读(Dirty read): **当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。
**丢失修改(Lost to modify): **指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。例如:事务1读取某表中的数据A=20,事务2也读取A=20,事务1修改A=A-1,事务2也修改A=A-1,最终结果A=19,事务1的修改被丢失。
**不可重复读(Unrepeatableread): **指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
**幻读(Phantom read): **幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。
7.4 事务的隔离级别
SQL 标准定义了四个隔离级别:
- **READ-UNCOMMITTED(读取未提交):**最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
- **READ-COMMITTED(读取已提交):**允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
- **REPEATABLE-READ(可重复读):**对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
- **SERIALIZABLE(可串行化):**最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
READ-UNCOMMITTED | √ | √ | √ |
READ-COMMITTED | √ | √ | √ |
REPEATABLE-READ | × | × | √ |
**SERIALIZABLE | × | × | × |
MySQL InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读),可以通过SELECT @@tx_isolation;
命令来查看。
7.5 在MySQL中使用事务
注意:
- MySQL中默认是自动提交
- 使用事务时应先关闭自动提交
语法
-- 使用set语句来改变自动提交模式
SET autocommit = 0; /*关闭*/
SET autocommit = 1; /*开启*/-- 开始一个事务,标记事务的起始点
START TRANSACTION -- 提交一个事务给数据库
COMMIT-- 将事务回滚,数据回到本次事务的初始状态
ROLLBACK-- 还原MySQL数据库的自动提交
SET autocommit =1;-- 保存点
SAVEPOINT 保存点名称 -- 设置一个事务保存点
ROLLBACK TO SAVEPOINT 保存点名称 -- 回滚到保存点
RELEASE SAVEPOINT 保存点名称 -- 删除保存点
模拟测试
/*
模拟场景A在线买一款价格为500元商品,网上银行转账.
A的银行卡余额为2000,然后给商家B支付500.
商家B一开始的银行卡余额为10000创建数据库shop和创建表account并插入2条数据
*/CREATE DATABASE `shop` CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `shop`;CREATE TABLE `account` (`id` INT(11) NOT NULL AUTO_INCREMENT,`name` VARCHAR(32) NOT NULL,`money` DECIMAL(9,2) NOT NULL,PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8INSERT INTO account (`name`,`money`)
VALUES('A',2000.00),('B',10000.00)-- 转账实现
SET autocommit = 0; -- 关闭自动提交
START TRANSACTION; -- 开始一个事务,标记事务的起始点
UPDATE account SET cash=cash-500 WHERE `name`='A';
UPDATE account SET cash=cash+500 WHERE `name`='B';
COMMIT; -- 提交事务,一旦提交就被持久化,无法回滚
SET autocommit = 1; -- 恢复自动提交
8. 索引
8.1 什么是索引
MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构,通俗来讲索引就好比书本的目录,加快数据库的查询速度。
8.2 索引的作用
- 提高查询速度
- 确保数据的唯一性
- 可以加速表和表之间的连接 , 实现表与表之间的参照完整性
- 使用分组和排序子句进行数据检索时 , 可以显著减少分组和排序的时间
- 全文检索字段进行搜索优化.
8.3 索引的分类
8.3.1 主键索引
主键 : 某一个属性组能唯一标识一条记录
特点 :
- 最常见的索引类型
- 确保数据记录的唯一性
- 确定特定数据记录在数据库中的位置
-- 添加PRIMARY KEY(主键索引)
ALTER TABLE `table_name` ADD PRIMARY KEY ( `column` )
8.3.2 唯一索引
作用 : 避免同一个表中某数据列中的值重复
与主键索引的区别
- 主键索引只能有一个
- 唯一索引可能有多个
-- 添加UNIQUE(唯一索引)
ALTER TABLE `table_name` ADD UNIQUE ( `column` )
8.3.3 常规索引
作用 : 快速定位特定数据
注意 :
- index 和 key 关键字都可以设置常规索引
- 应加在查询找条件的字段
- 不宜添加太多常规索引,影响数据的插入、删除和修改操作
-- 添加INDEX(普通索引)
ALTER TABLE `table_name` ADD INDEX index_name ( `column` )
8.3.4 全文索引
MySQL 5.6 以前的版本,只有 MyISAM 存储引擎支持全文索引;
MySQL 5.6 及以后的版本,MyISAM 和 InnoDB 存储引擎均支持全文索引。只有字段的数据类型为 char、varchar、text 及其系列才可以建全文索引。
测试或使用全文索引时,要先看一下自己的 MySQL 版本、存储引擎和数据类型是否支持全文索引。
作用 : 快速定位特定数据
注意 :
- 只能用于CHAR , VARCHAR , TEXT数据列类型
- 适合大型数据集
-- 添加FULLTEXT(全文索引)
ALTER TABLE `table_name` ADD FULLTEXT (`column`)
8.4 索引的使用
两种使用方式:
在创建表的时候给字段增加索引
创建完毕后,增加索引
#方法一:创建表时CREATE TABLE 表名 (字段名1 数据类型 [完整性约束条件…],字段名2 数据类型 [完整性约束条件…],[UNIQUE | FULLTEXT | SPATIAL ] INDEX | KEY[索引名] (字段名[(长度)] [ASC |DESC]));#方法二:CREATE在已存在的表上创建索引CREATE [UNIQUE | FULLTEXT | SPATIAL ] INDEX 索引名ON 表名 (字段名[(长度)] [ASC |DESC]);
8.5 100W条数据测试索引
-- 建立索引前
SELECT * FROM app_user WHERE `name`='用户9999' -- 0.485秒-- 建立索引
CREATE INDEX id_app_user_name ON app_user(`name`);-- 建立索引后
SELECT * FROM app_user WHERE `name`='用户9999' -- 0.001秒
8.6 索引原则
- 索引不是越多越好
- 不要对经常变动的数据加索引
- 小数据量的表不需要加索引
- 索引一般加在常用来查询的字段上
8.7 索引的数据结构
- hash类型的索引:查询单条快,范围查询慢
- btree类型的索引:b+树,层数越多,数据量指数级增长
- InnoDB 和 MyISAM 都支持 B-tree、Full-text 等索引,不支持 Hash 索引
8.8 拓展阅读
MySQL索引背后的数据结构及算法原理
9. MySQL用户管理
9.1 SQLyog创建用户并授予权限
9.2 SQL语句创建用户并授予权限
本质:读取mysql.user表并进行增删改查
- 创建用户
-- 创建用户: CREATE USER 用户名 IDENTIFIED BY [PASSWORD] 密码(字符串)
CREATE USER abc IDENTIFIED BY '123456';
- 设置密码
-- SET PASSWORD = PASSWORD('密码') 为当前用户设置密码
-- SET PASSWORD FOR 用户名 = PASSWORD('密码') 为指定用户设置密码,得有权限
SET PASSWORD FOR abc = '123456';
- 用户重命名
-- 重命名用户 RENAME USER old_user TO new_user
RENAME USER abc TO abcd;
- 删除用户
-- 删除用户 DROP USER 用户名
DROP USER abcd;
- 授予权限
-- 授予权限:ALL PRIVILEGES 全部的权限
-- *.* 表示所有的表
GRANT ALL PRIVILEGES ON *.* TO abcd;
赋予所有权限后,可以看到所有权限变成了‘Y’,也就是被赋予了权限。
- 查看权限及撤销权限
-- 查询权限
SHOW GRANTS FOR abcd;-- 撤消权限
-- REVOKE 权限列表 ON 表名 FROM 用户名
REVOKE ALL PRIVILEGES ON *.* FROM abcd
撤销所有权限后,可以看到所有权限变成了’N’。
10.数据库备份
为什么要备份数据库
- 保证重要数据不丢失
- 数据转移
MySQL数据库备份方法
- mysqldump备份工具
-- CMD命令行 导出
1. 导出一张表 -- mysqldump -uroot -p123456 school student >D:/a.sqlmysqldump -u用户名 -p密码 库名 表名 > 文件名(D:/a.sql)
2. 导出多张表 -- mysqldump -uroot -p123456 school student result >D:/a.sqlmysqldump -u用户名 -p密码 库名 表1 表2 表3 > 文件名(D:/a.sql)
3. 导出所有表 -- mysqldump -uroot -p123456 school >D:/a.sqlmysqldump -u用户名 -p密码 库名 > 文件名(D:/a.sql)
4. 导出一个库 -- mysqldump -uroot -p123456 -B school >D:/a.sqlmysqldump -u用户名 -p密码 -B 库名 > 文件名(D:/a.sql)可以-w携带备份条件-- 导入
1. 在登录mysql的情况下:-- source D:/a.sqlsource 备份文件
2. 在不登录的情况下mysql -u用户名 -p密码 库名 < 备份文件
- 数据库管理工具,如SQLyog
- 直接拷贝数据库文件和相关配置文件
11. 三大范式
11.1 第一范式 (1NF)
第一范式(1NF):要求数据库表的每一列都是不可分割的原子数据项。
举例说明:
在上面的表中,“家庭信息”和“学校信息”列均不满足原子性的要求,故不满足第一范式,调整如下:
调整后的每一列都是不可再分的,因此满足第一范式(1NF)。
11.2 第二范式 (2NF)
第二范式(2NF):在1NF的基础上,第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)。也就是说在一个数据库表中,一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中。。
举例说明:
在上图所示的情况中,同一个订单中可能包含不同的产品,因此主键必须是“订单号”和“产品号”联合组成,但可以发现,产品数量、产品折扣、产品价格与“订单号”和“产品号”都相关,但是订单金额和订单时间仅与“订单号”相关,与“产品号”无关。这样就不满足第二范式的要求,调整如下,需分成两个表:
11.3 第三范式 (3NF)
在满足 1NF 和 2NF 基础上,第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。
举例说明:
上表中,所有属性都完全依赖于学号,所以满足第二范式,但是“班主任性别”和“班主任年龄”直接依赖的是“班主任姓名”,
而不是主键“学号”,所以需做如下调整:
12. JDBC
12.1 数据库驱动
驱动:声卡,显卡,数据库。JAVA程序会通过数据库驱动,和数据库打交道!
12.2 JDBC
SUN 公司为了简化开发人员的(对数据库的统一)操作,提供了一个Java操作数据库的规范——JDBC。这些规范的实现由具体的厂商去做,对于开发人员来说,只需要掌握JDBC的接口操作即可。
12.3 第一个JDBC程序
先要导入mysql的jar包
新建项目,在项目目录下建立一个lib文件夹,把
mysql-connector-java-5.1.47
放入lib目录下右键点击lib文件夹,点击add as lib,然后点击ok
jar包变成如下所示即可
步骤
加载驱动
连接数据库 DriverManager
获取执行SQL的对象 Statement
获得返回的结果集
释放连接
package com.kuang.lesson01;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;public class JdbcDemo01 {public static void main(String[] args) throws Exception {// 1. 加载驱动Class.forName("com.mysql.jdbc.Driver"); // 固定写法,加载驱动// 2.连接数据库String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";String username = "root";String password = "123456";// 3. 连接成功,获取数据库对象connectionConnection connection = DriverManager.getConnection(url, username, password);// 4. 获取执行SQL对象statementStatement statement = connection.createStatement();// 5.用SQL对象执行SQLString sql = "select * from users";ResultSet resultSet = statement.executeQuery(sql); //返回的结果集,封装了所有查询的结果while(resultSet.next()) {System.out.println("id=" + resultSet.getObject("id"));System.out.println("姓名=" + resultSet.getObject("NAME"));System.out.println("密码=" + resultSet.getObject("PASSWORD"));System.out.println("邮箱=" + resultSet.getObject("email"));System.out.println("生日=" + resultSet.getObject("birthday"));System.out.println("======================");}// 6. 释放连接resultSet.close();statement.close();connection.close();}
}
执行成功,结果如下:
12.4 JDBC对象解释
12.4.1 Connection
//connection代表数据库connection.rollback(); //事务回滚
connection.commit(); //事务提交
connection.setAutoCommit(); //数据库设置自动提交
12.4.2 URL
// URL地址解析
// 协议://主机地址:端口号/数据库名?参数1&参数2&参数3
// MySQL默认的端口号是3306String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
12.4.3 statement
Statement statement = connection.createStatement(); //获取statement对象statement.executeQuery(); // 查询
statement.execute(); //都可以执行
statement.executeUpdate();//更新,插入,删除,返回一个受影响的行数
12.4.4 ResultSet
ResultSet resultSet = statement.executeQuery(sql);//返回的结果集,结果集中封装了全部查询的结果resultSet.getObject();//在不知道列类型下使用
//如果知道则指定使用以下
resultSet.getString();
resultSet.getInt();
resultSet.getFloat();
resultSet.getDouble();//指针
resultSet.next();//移动到下一行数据
resultSet.beforeFirst();//移动到最前
resultSet.afterLast();//移动到最后
resultSet.previous();//移动到前一行
resultSet.absolute(i);//移动到第i行
12.5 jdbc工具类
jdbc工具类的作用就是把一些连接,释放资源等代码放到一起。因为对数据库的操作怎么变,连接的资源都不会变。
- 创建properties文件
在src目录下创建db.properties文件
,写上如下代码
driver = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true
username = root
password = 123456
- 创建jdbcUtils工具类
package com.kuang.lesson02.utils;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 c, Statement st, ResultSet rs) {if(c != null) {try {c.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if(st != null) {try {st.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if(rs != null) {try {rs.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}
}
12.6 Statement对象增删改查
JDBC中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。
Statement对象的executeUpdate方法,用于向数据库发送增、删、改的sq|语句, executeUpdate执行完后, 将会返回一个整数(即增删改语句导致了数据库几行数据发生了变化)。
Statement.executeQuery方法用于向数据库发生查询语句,executeQuery方法返回代表查询结果的ResultSet对象。
基于jdbc工具类对数据库进行修改
package com.kuang.lesson02;import com.kuang.lesson02.utils.jdbcUtils;import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;public class jdbcDemo02 {public static void main(String[] args){Connection conn = null;Statement st = null;ResultSet rs = null;try {conn = jdbcUtils.getConnection();st = conn.createStatement();/* CRUD 关键要修改的地方*/String sql = "INSERT INTO `users` (`id`,`NAME`,`PASSWORD`,`email`,`birthday`)\n" +"VALUES (4,'abc','123456','xxxxxxx@qq.com','2020-1-15');";int cnt = st.executeUpdate(sql);if(cnt > 0) {System.out.println("插入成功");}} catch (Exception e) {e.printStackTrace();} finally {jdbcUtils.release(conn, st, rs);}}
}
12.7 statement存在的问题——SQL注入问题
所谓SQL注入,就是通过把SQL命令插入到 Web表单提交 或 URL 或 页面请求等的查询字符串中,最终达到欺骗服务器执行恶意的SQL命令。SQL注入(SQLInjection)是这样一种漏洞:当我们的Web app 在向后台数据库传递SQL语句进行数据库操作时。如果对用户输入的参数没有经过严格的过滤处理,那么攻击者就可以构造特殊的SQL语句,**直接输入数据库引擎执行,获取或修改数据库中的数据。
比如登录业务中,需要查询账号密码所对应的用户(比对),可能用到如下sql语句:
select * from users where name='name' and password ='password'
其中name
和password
两个变量都是用户所传入的数据。如果用户构造合适的输入,比如:
String name=" ' or 1=1 -- ";
String password ="12412r1";//password在此例中的值不重要
那么如上sql语句拼接成了:
select * from users where name=' ' or 1=1 -- password ='12412r1'
密码被注释掉,而name
的匹配永远是对的,就可以匹配到表中所有用户的信息。
12.8 PreparedStatement对象
PreparedStatement 可以防止SQL注入 ,效率更高。
防止SQL注入本质:传递字符 带有‘’,转义字符会被转义。
package com.kuang.lesson03;import com.kuang.lesson02.utils.jdbcUtils;
import java.util.Date;import java.sql.*;public class jdbcDemo03 {public static void main(String[] args) {Connection conn = null;PreparedStatement pst = null;ResultSet rs = null;try {conn = jdbcUtils.getConnection();// ==============与statement的区别==============//使用问号占位符代替参数String sql = "INSERT INTO `users` (`id`,`NAME`,`PASSWORD`,`email`,`birthday`) VALUES (?,?,?,?,?)";pst = conn.prepareStatement(sql); //预编译SQL,先写sql,不执行//手动给参数赋值,下标从1开始pst.setInt(1,5);pst.setString(2,"abcd");pst.setString(3,"123456");pst.setString(4,"XXXX@Qqq.com");pst.setDate(5,new java.sql.Date(new java.util.Date().getTime()));// 执行SQLint i = pst.executeUpdate();if(i > 0) {System.out.println("插入成功");}} catch (SQLException throwables) {throwables.printStackTrace();} finally {jdbcUtils.release(conn, pst, null);}}
}
12.9 idea连接数据库
- 点击idea右侧database加号,选择MySQL
- 填写数据库登陆信息,测试链接时提示要下包,按照提示自动下载即可。连接过程中会出现
Server returns invalid timezone. Go to ‘Advanced’ tab and set ‘serverTimezone’ property manually.
错误,这时可以在idea中把时区设置成上海即可。
- 当呈现以下页面,即为登陆成功
- 选择数据库
选择数据库后,重新按ok即可。
- 更新数据库
- 编写SQL代码
- 切换数据库
12.10 JDBC操作事务
- 开启事务
conn.setAutoCommit(false);
- 一组业务执行完毕,提交事务
- 可以在catch语句中显示的定义回滚,但是默认失败会回滚
package com.kuang.lesson04;import com.kuang.lesson02.utils.jdbcUtils;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class jdbcDemo05 {public static void main(String[] args) {Connection conn = null;PreparedStatement pst = null;ResultSet rs = null;try {conn = jdbcUtils.getConnection();// 关闭数据库的自动提交,自动开启事务conn.setAutoCommit(false);String sql1 = "update account set money = money - 500 where name = 'A'";String sql2 = "update account set money = money + 500 where name = 'B'";pst = conn.prepareStatement(sql1);pst.executeUpdate();pst = conn.prepareStatement(sql2);pst.executeUpdate();//业务完毕,提交事务conn.commit();System.out.println("操作成功");} catch (SQLException e) {//如果失败则默认回滚try {conn.rollback();} catch (SQLException throwables) {throwables.printStackTrace();}e.printStackTrace();} finally {jdbcUtils.release(conn, pst, null);}}
}
13. 数据库连接池
13.1 不使用数据库连接池存在的问题
上面进行数据库操作的步骤
- 装载数据库驱动程序
- 通过jdbc建立数据库连接
- 访问数据库,执行sql语句
- 断开数据库连接
分析
程序开发过程中,存在很多问题:首先,每一次web请求都要建立一次数据库连接。建立连接是一个费时的活动,每次都得花费0.05s~1s的时间,而且系统还要分配内存资源。这个时间对于一次或几次数据库操作,或许感觉不出系统有多大的开销。可是对于现在的web应用,尤其是大型电子商务网站,同时有几百人甚至几千人在线是很正常的事。在这种情况下,频繁的进行数据库连接操作势必占用很多的系统资源,网站的响应速度必定下降,严重的甚至会造成服务器的崩溃。
上述的用户查询案例,如果同时有1000人访问,就会不断的有数据库连接、断开操作:
通过上面的分析,我们可以看出来,“数据库连接”是一种稀缺的资源,为了保障网站的正常使用,应该对其进行妥善管理。其实我们查询完数据库后,如果不关闭连接,而是暂时存放起来,当别人使用时,把这个连接给他们使用。就避免了一次建立数据库连接和断开的操作时间消耗。原理如下:
13.2 数据库连接池
上面的分析可以看出,问题的根源就在于对数据库连接资源的低效管理。我们知道,对于共享资源,有一个很著名的设计模式:资源池(resource pool)。该模式正是为了解决资源的频繁分配﹑释放所造成的问题。为解决上述问题,可以采用数据库连接池技术。数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。我们可以通过设定连接池最大连接数来防止系统无尽的与数据库连接。更为重要的是我们可以通过连接池的管理机制监视数据库的连接的数量﹑使用情况,为系统开发﹑测试及性能调整提供依据。
编写连接池:实现DataSource接口
开源数据源实现
- DBCP
- C3P0
- Druid:阿里巴巴
使用了数据库连接池之后,我们在项目开发中就不需要编写链接数据库的代码了!
JAVA MySQL数据库 笔记相关推荐
- JAVA+MySQL 数据库课设的问题及解答的整理 以【学生管理系统】为例
JAVA+MySQL 数据库课设的问题及解答的整理 以[学生管理系统]为例.帅气学长哦! 编写这篇博文初衷 MySQL的一些问题 Eclipse导入项目的一些问题 数据库的建立和连接 最后一步 编写这 ...
- JAVA+MySQL综合笔记
Java+MySQL综合运用笔记 一.Java连接使用mysql的5个思路过程 首先导入JDBC驱动jar包放到lib文件夹里面. 1.加载驱动方法 ①注册驱动:DriverManager.reg ...
- java mysql数据库编程_java JDBC数据库(mysql)编程
什么是JDBC • JDBC(Java Data Base Connectivity,Java数据库连接) • 是一种用于执行SQL语句的Java API,为多种关系数据库提供统一访问 • 它由一组用 ...
- MySQL数据库笔记——进阶篇
文章目录 存储引擎 MySQL体系结构 存储引擎简介 InnoDB介绍 MyISAM Memory 存储引擎的选择 小结 索引 概述 索引结构 概述 Btree B+Tree Hash "严 ...
- MySQL数据库笔记小结一
目录 一: MySQL 是一个关系型数据库管理系统(RDBMS) 二: MySQL中的对象: 三: 数据库对象的操作: 四:美国信息标准交换码:ASCII码 五: 表中一行数据代表一条记录 六: OR ...
- 狂神说java~MYSQL学习笔记
1.数据库 1.1.lue 1.2.什么是数据库 数据库 ( DataBase , 简称DB ) 概念 : 长期存放在计算机内,有组织,可共享的大量数据的集合,是一个数据 "仓库" ...
- MySQL数据库-笔记06【SQL的4种连接查询、事务】
学习地址:一天学会 MySQL 数据库 MySQL安装教程 MySQL专栏
- MySQL数据库-笔记05【查询练习题*25道(附解析)】
学习地址:一天学会 MySQL 数据库 MySQL安装教程 MySQL专栏
- MySQL数据库-笔记04【查询练习题*8道(附解析)】
学习地址:一天学会 MySQL 数据库 MySQL安装教程 MySQL专栏
最新文章
- 面试官问我:spring、springboot、springcloud的区别,我笑了
- mysql把一个数据库中的数据复制到另一个数据库中的表 2个表结构相同
- sequelize怎么看插入的数据成功不成功_MySQL的4种事务隔离级别你还不清楚吗?
- mekko 教程_Power BI桌面Mekko图表
- java常用类--------枚举的基本使用
- Not a git repository (or any of the parent directories): .git
- ps 读取计算机特定首选项时出错,PS操作中常见的疑难杂症之首选项
- BZOJ4816 数字表格
- 将RTSP网络摄像机进行网页和微信直播的方案
- collect2: error: ld returned 1 exit status(Linux下Gcc编译问题)
- dummy node
- 计算机更新80072f76,更新升级win10系统时出现错误代码0x80072f76怎么办
- 【小家Spring】注意BeanPostProcessor启动时对依赖Bean的“误伤”陷阱(is not eligible for getting processed by all...)
- 面经-软件测试面试常见面试题全套合集系列4-2
- java 代码的规范
- Android 机顶盒TV app开发
- 动画包bootanimation的制作及内置
- 基于51单片机的俄罗斯方块小游戏proteus仿真LCD12864原理图程序设计
- 出租车管理系统源码php,出租车管理系统((SSH+MYSQL+JSP))
- 怒怼管理层被标注“永不录用”?腾讯辟谣,应届生回应已找到新工作
热门文章
- ubuntu下安装大恒相机驱动并调用程序采集图像
- abp Volo.Abp.AbpException: Could not find the bundle file ‘/libs/abp/core/abp.css‘ for the bundle ‘B
- 快速编写数据库设计说明书的办法
- AD域根据组名称获取DirectoryEntry对象
- 魔兽世界怎么找回以前的服务器,魔兽世界怀旧服无法连接世界服务器怎么办?...
- php laravel框架笔记
- 【小型物体测速仪】只有原理,无代码
- 王燕《应用时间序列分析》学习笔记2
- #叉积#zoj 1041 poj 1106 ssl 1232 雷达覆盖问题 Transmitters
- Centos 7 装 Steam( 需要:libva-intel-driver(x86-32))