MySQL
目录唉...好多
-
MySQL
- 一、什么是数据库,为什么要学习数据库
- 二、初识MySQL,关系型和非关系型数据库
- 三、安装MySQL详细说明
- 四、SQLyog软件安装和使用
- 五、基本的命令行操作
- 六、操作数据库语句
- 七、列的数据类型讲解
- 八、数据库的字段属性(重点)
- 九、创建数据库表
- 十、MyISAM和InnoDB的区别
- 十一、修改和删除数据表字段
- 十二、数据库级别的外键
- 十三、Insert语句详解
- 十四、Update语句详解
- 十五、Delete和Truncate详解
- 十六、基本的Select语句和别名使用
- 十七、去重及数据库的表达式
- 十八、Where子句之逻辑运算符
- 十九、模糊查询操作符详解
- 二十、联表查询JoinON详解
- 二十一、自链接
- 二十二、分页和排序
- 二十三、子查询和嵌套查询
- 二十四、MySQL常用函数
- 二十五、聚合函数及分组过滤
- 二十六、拓展之数据库级别的MD5加密
- 二十七、事务ACID原则、脏读、不可重复读、幻读
- 二十八、测试事务实现转账
- 二十九、索引介绍及索引的分类
- 三十、SQL编程创建100万条数据测试索引
- 三十一、索引原则
- 三十二、数据库用户管理
- 三十三、MySQL备份
- 三十四、如何设计一个项目的数据库
- 三十五、数据库的三大范式
- 三十六、数据库驱动和JDBC
- 三十七、第一个JDBC程序
- 三十八、JDBC中对象解释
- 三十九、Statement对象详解
- 四十、SQL注入问题
- 四十一、PreparedStatement对象
- 四十二、JDBC操作事务
- 四十三、DBCP-C3P0
一、什么是数据库,为什么要学习数据库
数据库用于存储体量较大的数据,我们之前学的交互方法最终的数据都属存于数据库中,数据库的必要性就不言而喻了吧。
二、初识MySQL,关系型和非关系型数据库
关系型:
- MySQL、Oracle、SQL Server、DB2、SQLlite
- 通过表表之间行列关系进行数据存储:人员表....
非关系型:
- Redis、MongDB
- 非关系型数据库,对象存储,通过对象自身属性决定
DBMS:数据库管理系统
- 数据库管理软件,科学有效的管理我们的数据,维护和获取数据
- MySQL,数据库管理系统!
MySQL简介:
MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件之一。
MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。
MySQL所使用的 SQL 语言是用于访问数据库的最常用标准化语言。MySQL 软件采用了双授权政策,分为社区版和商业版,由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,一般中小型网站的开发都选择 MySQL 作为网站数据库。大型网站也可使用:集群!
官网:www.mysql.com
安装建议:
- 不用exe,注册表恶心人
- 尽量使用压缩包的安装
三、安装MySQL详细说明
-
解压
-
包放到自己的环境目录下
-
加入环境变量,bin目录加入path中
-
加入配置文件my.int
[mysqld] basedir=安装目录\ datadir=安装目录\data\ port=3306 sqip=grant-tables
-
打开管理员模式的CMD,进入MySQL文件夹的bin目录,输入
mysqld -install
-
初始化data文件夹
mysqld --initialize-insecure --user=mysql
-
初始化成功后应该看见data文件夹中有许多文件,如果生成了.err文件说明配置文件没写对。然后启动MySQL服务。
net start mysql
-
进入MySQL命令行
mysql -u root -p
-
修改密码并且刷新权限
update mysql.user set authentication_string=password('123456') where user='root'and Host='localhost'; flush privileges;
-
重启MySQL
#先退出MySQL exit #结束服务 net stop mysql #启动服务 net start mysql
-
输入密码进入
mysql -u root -p #密码:123456
四、SQLyog软件安装和使用
安装
- 安装包无脑安装,用旗舰版的。
- 安装完后网上搜下密钥填进去就能用了。
使用
- 新建连接 localhost
- 端口3306
- 地址localhost
- 用户名root
- 密码123456
- 连接即可
操作:每一个sqlyog的操作本质就是命令行,可以在历史记录中查看自动生成的操作代码
- 新建数据库,右键localhost服务器即可新建,填入数据库名即可
- 新建表,输入表名,将字符集设置成utf8,校对utf8_general_ci,就可以设置行列了。
- 尝试添加多条记录
五、基本的命令行操作
mysql-u root -p -- 连接数据库
update mysql.user set authentication_string=password('123456') where user='root'and Host='localhost'; -- 修改密码
flush privileges; -- 刷新权限
-- 所有语句都是用;结尾
show databases; -- 查看所有的数据库
use school; -- 切换数据库
-- Database changed
show tables; --查 看数据库中所有表
describe student; -- 显示数据库中所有的表信息
create database westos; -- 创建一个数据库
exit; -- 退出连接
-- 单行注释
/*
多行注释
111
*/
选中语句在执行,这样安全点,养成习惯
六、操作数据库语句
操作数据库 > 操作数据库的表 > 操作数据库表中的数据
MySQL中的语法不区分大小写.
create database if not exists school;
# create database [条件] 数据库名,创建数据库
drop database if exists school;
# drop database [条件] 数据库名,删除数据库
use school;-- 使用数据库
#如果你的表名、列名或数据库名是关键字,可以使用``包裹,这样就不会判断为关键字
show databases; -- 查看所有数据库
七、列的数据类型讲解
数值
类型 | 描述 | 大小 |
---|---|---|
tinyint | 十分小的数据 | 1个字节 |
smallint | 较小的数据 | 2个字节 |
mediumint | 中等大小的数据 | 3个字节 |
int | 标准大小整数(常用) | 4个字节 |
bigint | 大的数据 | 8个字节 |
float | 浮点数 | 4个字节 |
double | 浮点数 | 8个字节 |
decimal | 字符串形式的浮点数金融计算使用。 |
字符串
类型 | 描述 | 大小 |
---|---|---|
char | 字符串 固定大小 | 0~255 |
varchar | 可变字符串 常用 | 0~65535 |
tinytext | 微型文本 | 2^8-1 |
text | 文本串 | 2^16-1 |
时间日期
类型 | 格式 | 描述 |
---|---|---|
date | YYYY-MM-DD | 日期格式 |
time | HH: mm: ss | 时间格式 |
datetime | YYYY-MM-DD HH: mm: ss | 对常用的时间格式 |
timestamp | long | 时间戳,1970到现在的毫秒数 |
year | yyyy | 年份表示 |
null
- 没有值,未知
- 不要使用NULL进行计算 结果为NULL
八、数据库的字段属性(重点)
Unsigned:无符号整数
- 声明了该列不能为负数
zerofill:零填充
- 不足的位数用0填充,int(3) ---5: ->005
自增:
- 通常理解为自增,自动在上一条的记录基础上+1
- 通常在主键上设置~index,必须是整数类型
- 可以自定义设计主键自增的起始值和步长
非空:NULL Not NULL
- 假如设置为NULL:则该属性可以为空
- 假如设置为:NOT NULL 则该属性不能为空
默认:
- 设置默认的值
九、创建数据库表
每个表基本的设计要素:
/*
id -- 主键
`version` -- 乐观锁
is_delete -- 伪删除
gmt_create -- 创建时间
gmt_update -- 修改时间
表名或者列名都用``包裹,以防有关键字。
AUTO_INCREMENT 自增
PRIMARY KEY(`id`) 主键列
*/
CREATE TABLE IF NOT EXISTS `student`(
`id` INT NOT NULL AUTO_INCREMENT COMMENT '学号',
`name` VARCHAR(100) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` VARCHAR(16) NOT NULL DEFAULT '123456' COMMENT '密码',
`gender` CHAR(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
格式:
CREATE TABLE [条件] `表名`(
`列名` [数据类型] [列属性] [索引] [注释],
`列名` [数据类型] [列属性] [索引] [注释],
...
[约束]
)[引擎] [字符集] [注释]
十、MyISAM和InnoDB的区别
SHOW CREATE DATABASE `school`; -- 查看创建数据库代码
SHOW CREATE TABLE `student`; -- 查看创建表代码
DESC `student`; -- 查看表结构
MyISAM | InnoDB | |
---|---|---|
事务支持 | F | T |
数据行锁定 | F | T |
外键约束 | F | T |
全文索引 | T | F |
表空间大小 | 较小 | 较大约为两倍 |
常规使用操作:
- MyISAM 节约空间,速度快
- INNODB 安全性高、事务处理、多表用户操作
在物理空间存在的位置
都在data目录下
本质还是文件的存储
MySQL引擎在物理文件上的区别
- InnoDB在数据库表中只有一个*.frm文件,以及上级目录下的ibdata1文件
- MyISAM对应文件
- *.frm 表结构的定义文件
- *.MYD 数据文件(data)
- *.MYI 索引文件(data)
设置数据库表的字符集编码:charset=utf8
MySQL的默认字符集编码不支持中文
十一、修改和删除数据表字段
修改
-- 修改表
ALTER TABLE `student` RENAME AS `student1` -- 重命名表
ALTER TABLE `student1` ADD age INT(3) -- 增加字段
ALTER TABLE `student1` CHANGE age age1 INT(2) -- 可以重命名,不可修改约束
ALTER TABLE `student1` MODIFY age1 VARCHAR(3) -- 无法重命名,可修改约束
-- 格式
ALTER TABLE `表名` [RENAME AS|ADD|CHANGE|MODIFY] [表列的属性|表名]
-- 删除表字段
ALTER TABLE `student1` DROP age1
删除
-- 删除表
DROP TABLE IF EXISTS `student1`
注意点:
- 用``包裹所有命名
- sql对大小写不敏感
- 所有符号用英文
十二、数据库级别的外键
外键:数据库中有两张表:学生表、年级表
学生表中有一列:年级
年级主键是年级id
学生的年级就是一个外键,因为它要和年级主键保持一致,外面的主键:外键
添加外键:
CREATE TABLE IF NOT EXISTS `grade`(
`id` INT(2) NOT NULL AUTO_INCREMENT COMMENT '年级号',
`gname` VARCHAR(20) NOT NULL DEFAULT '大一' COMMENT '年级名称',
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
CREATE TABLE IF NOT EXISTS `student`(
`id` INT NOT NULL AUTO_INCREMENT COMMENT '学号',
`name` VARCHAR(100) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`gradeid` INT(2) NOT NULL COMMENT '年级',
`pwd` VARCHAR(16) NOT NULL DEFAULT '123456' COMMENT '密码',
`gender` CHAR(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
ALTER TABLE `student`
ADD CONSTRAINT `fk_gradeid` FOREIGN KEY(`gradeid`) REFERENCES `grade`(`id`)
-- 格式
ALTER TABLE `要添加外键的表名`
ADD CONSTRAINT `外键名称` FOREIGN KEY(`需要添加外键表中变成外键的列名`) REFERENCES `外键参照表`(`外键参照列`)
- 不推荐使用数据库级别的外键,造成重构的混乱
- 数据库最好只存行列,不存关系
- 在程序中确定外键
十三、Insert语句详解
insert into `表名`[(字段一,字段二,字段三,字段四,……)]
values(值一,值二,值三,值四,……)
-- 字段和值一一匹配
-- 如果不写字段,那就是默认所有字段都要填
-- 插入多个字段
insert into `student`(`name`)
values('小明'),('小红')
十四、Update语句详解
update 谁 要修改什么 set 设置成什么
-- 修改表
UPDATE `student` SET `name`='xiaowei' WHERE `id`=1
-- 语法
UPDATE [表名] SET 设置属性 [条件]
-- 修改多个属性
UPDATE `student` SET `name`='xiaowei',`email`='1286225373@qq.com' WHERE `id`=1
条件:where 子句 运算符 id 等于某个值,在某个区间内修改
操作符 | 含义 | 范围 | 结果 |
---|---|---|---|
= | 等于 | 5=6 | false |
<> != | 不等于 | 5<>6 | true |
> | |||
< | |||
>= | |||
<= | |||
between ... and ... | 在某个范围内 | [2,5] | |
and | 我和你 && | ||
or | 我或你 || |
- colnum_name 是数据库的,进来带着``
- 条件,筛选的条件,如果没有指定则会修改所有的列
- value可以是个具体的值,也可以是一个变量
十五、Delete和Truncate详解
语法:delect from 表名 [where 条件]
-- 删除
DELETE FROM `student` WHERE `id`=1 -- 没有条件会全删了
truncate:完全清空数据库
TRUNCATE `student`
delete和truncate的区别
相同点:
- 都能删除数据,都不会删除表结构
不同点:
- truncate会重新设置自增列,把计数器归零
- delete不会
ps:
- InnoDB引擎下,自增列数据是存在于内存中,delete命令删除表行后,重启数据库就会重新开始.
- MyISAM引擎下,不会出现上面情况,因为他的自增列数据是在文件中的
十六、基本的Select语句和别名使用
增删查改百分之八十都是查。DQL:数据库查询语句
- 简单复杂的操作都用
- 最核心语言,最重要语句
- 高频率使用
- 左右的查询都用 select
base
-- SELECT 字段,... FROM 表
SELECT * FROM `student`
-- 查询指定字段& 别名
SELECT `name` AS 学生名字 FROM `student`
-- 函数 concat(a,b)
select concat('姓名:',`name`) as 新名字 from `student`
十七、去重及数据库的表达式
去重:去除select查询出的数据中重复的数据
-- 去重
SELECT DISTINCT `sex` FROM `student`;
select查询用法: select 表达式
SELECT VERSION(); -- 查询版本
SELECT 100-3*9 AS 计算结果; -- 计算表达式
SELECT @@auto_increment_increment; -- 变量
SELECT `stu_score`+1 AS 提分 FROM result;
十八、Where子句之逻辑运算符
作用检查符合条件的值
逻辑运算符
逻辑与 :两个真才真
逻辑或 ;一个真就能真
逻辑非: 反过来
SELECT * FROM `student`
WHERE `age` BETWEEN 13 AND 18 &&
`gender`!='男'
十九、模糊查询操作符详解
运算符 | 语法 | 描述 |
---|---|---|
IS NULL | a is null | 若操作符为NULL,结果为真 |
IS NOT NULL | a is not null | 反之 |
BETWEEN...AND... | a between c and b | 如果a在b和c之间则结果为真 |
LIKE | a like b | SQL匹配,如果两者匹配则为真 |
IN | a in(a1,a2,a3,...) | 如果后面的值有等于a的,则为真 |
select `stu_name` from `student`
where `stu_name` like '%梓_'
select `stu_name` from `student`
where `stu_id` in(1002,1003,1004)
二十、联表查询JoinON详解
JOIN 对比
inner join,有匹配值就回返回行
left join,以左边的为基准,左边的不匹配值也会出现在联表中
right join,以右边的为基准,左边的不匹配值也会出现在联表中
select `stu_result` from
`student` right join `result`
left join `subject`
二十一、自链接
自联接,自己连接自己
查询同一种数据下逻辑上的父子关系
select f.`id` as 父id,s.`id` as 子id from
`item` s, `item` f
where s.fid=f.id
二十二、分页和排序
分页
select * from student
limit 0,10
-- 语法:
limit [起始,每页多少条]
排序:order by
select * from result
order by result.score ASC|DESC 升序|降序
二十三、子查询和嵌套查询
子查询|嵌套查询:在where中使用一个select语句
select `stuNo`,`subNo`,`stuResult` from
`result`
where `subNo` = ( -- 先把数据结构这门科目的编号查出来,只要result表中subNo等于编号就是这门课了
select `subNo` from `subject`
where `subject`.`subName`='数据结构'
)
二十四、MySQL常用函数
-- ========================= 常用函数 ======================================
-- 数学运算
SELECT ABS(-8) -- 绝对值
SELECT CEILING(9.4) -- 向上取整
SELECT FLOOR(9.4) -- 向下取整
SELECT RAND() -- 随机数
SELECT SIGN(2) -- 判 断一个数的符号 负数返回-1 正数返回1
-- 字符串函数
SELECT CHARACTER_LENGTH('中国') -- 字符串长度
SELECT CONCAT('我','是') -- 拼接字符串
SELECT INSERT('我爱helloword',1,2,'超级') -- 查询 替换 从某个位置替换某个长度
SELECT LOWER('asdsAAAAadwa') -- 转小写
SELECT UPPER('aaFDSFSDdxd') -- 转大写
SELECT INSTR('kuang','u') -- 返回第一次出现字符的索引
SELECT REPLACE('坚持才能成功','坚持','努力') -- 替换字符串
SELECT SUBSTR('坚持才能成功',4,6) -- 截取字符串
SELECT REVERSE('坚持才能成功') -- 反转字符串
-- 时间和日期函数
SELECT CURRENT_DATE() -- 获取当前日期
SELECT CURDATE() -- 获取当前日期
SELECT NOW() -- 获取当前时间
SELECT LOCALTIME() -- 本地时间
SELECT SYSDATE() -- 系统时间
SELECT YEAR(NOW())
SELECT MONTH(NOW())
SELECT DAY(NOW())
SELECT HOUR(NOW())
SELECT MINUTE(NOW())
SELECT SECOND(NOW())
-- 系统
SELECT SYSTEM_USER() -- 当前用户
SELECT USER() -- 当前用户
SELECT VERSION() -- 版本
二十五、聚合函数及分组过滤
函数名称 | 描述 |
---|---|
COUNT() | 计数 |
SUM() | 求和 |
AVG() | 平均值 |
MAX() | 最大值 |
MIN() | 最小值 |
…. |
分组:group by
SELECT subjectname,AVG(studentresult) AS 平均分,MAX(studentresult),MIN(studentresult)
FROM result r
INNER JOIN `subject` sub
ON r.subjectno=sub.subjectno
GROUP BY r.subjectno #通过什么分组
HAVING 平均分>=80 #过滤
二十六、拓展之数据库级别的MD5加密
MD5不可逆,复杂度高,只能通过字典破解
UPDATE testmd5 SET pwd=MD5(pwd) WHERE id=1
-- 插入的时候加密
INSERT INTO `testmd5` VALUES(4,'xiaoming',MD5('123456'))
-- 如何校验 将用户传进来的密码加密 然后与数据库存储的比较
SELECT * FROM testmd5 WHERE `name` = 'xiaoming' AND pwd=MD5('123456')
二十七、事务ACID原则、脏读、不可重复读、幻读
什么是事务
要么都成功,要么都失败,
所有的操作并到一批做
ACID原则:原子性、一致性、隔离性、永久性(脏读:一个事务读取另一个事务尚未提交的数据、幻读:读到了别的事务插入的数据)
二十八、测试事务实现转账
mysql默认开启事务自动提交
-- 关闭事务自动提交
set autocommit=0; -- 关闭
set autocommit=1; -- 开启
-- 开启事务
start transaction -- 标记一个事务的开始,从这个之后的sql都在同一个事务
...
-- 提交事务(提交回滚都可以) 事务一旦提交则会持久化,不可回滚
commit
-- 回滚事务 没提交之前可以回滚事务
rollback
-- 事务结束
set autocommit=1; -- 开启自动提交
-- 了解
savepoint 保存点名 -- 设置事务的保存点
rollback to savepoint 保存点名称 -- 回滚到保存点
release savepoint 保存点
二十九、索引介绍及索引的分类
索引
索引的作用相当于图书的目录,可以根据目录中的页码快速找到所需的内容。
索引分类
- 主键索引(primary key)
- 唯一标识、不可重复、只有一个列可以作为索引
- 唯一索引(unique key)
- 避免重复的值出现,唯一索引一张表内可以有多个
- 常规索引(key/index)
- 默认的,index。key关键字来设置
- 全文索引(FullText)
- 在特定引擎下:MyISAM
- 快速定位数据
索引使用:
-- 创建表的时候给字段增加索引
-- 创建完毕后加索引
-- 显示所有的索引信息
show index key student;
-- 增加一个索引
alter table school.`student` add fulltext index `student_name`(`student_name`);
-- 需要索引名和列名
-- explain:分析sql执行状况
explain select * from student
三十、SQL编程创建100万条数据测试索引
--测试索引
CREATE TABLE `app_user`(
`id` INT(4) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(20) DEFAULT'' COMMENT'用户姓名',
`email` VARCHAR(20) NOT NULL COMMENT'用户邮箱',
`phone` VARCHAR(20) DEFAULT'' COMMENT'用户电话',
`gender` TINYINT(4) UNSIGNED DEFAULT'0' COMMENT'性别(1是男,2是女)',
`password` VARCHAR(50) NOT NULL COMMENT '密码',
`age` INT(3) DEFAULT'0' COMMENT'年龄',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
`update_name` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY(`id`)
)ENGINE INNODB DEFAULT CHARSET=utf8mb4 COMMENT'app用户表'
--插入100万条数据
--写函数之前必须写 标志
DELIMITER $$
CREATE FUNCTION mock_dat() #创建一个函数
RETURNS INT
BEGIN
DECLARE num INT DEFAULT 1000000;
DECLARE i INT DEFAULT 0;
WHILE i<num DO
INSERT INTO `app_user`(name,email,phone,gender,password,age)
VALUES(CONCAT('用户',i),'813794474@qq.com',CONCAT('18',FLOOR(RAND()*((999999999-1000000000)+1000000000))),
FLOOR((RAND()*2)+1),UUID(),FLOOR(RAND()*100));
SET i=i+1;
END WHILE;
RETURN i;
END;
--
SELECT mock_dat();
SELECT * FROM app_user WHERE name = '用户9999';
EXPLAIN SELECT * FROM app_user WHERE name = '用户9999';
EXPLAIN SELECT * FROM app_user WHERE name = '用户1';
--创建索引 id_表名_字段名 on 表(字段)
CREATE INDEX id_app_user_name ON app_user(`name`);
SELECT * FROM app_user WHERE name = '用户9999';
EXPLAIN SELECT * FROM app_user WHERE name = '用户9999';
索引在小数据的时候用处不大,在大数据的时候,区别十分明显。
三十一、索引原则
- 索引不是越多越好
- 不要对进程变动数据加索引
- 小数据量bu'xu'yao加索引
- 常用于查询多的字段
索引的数据结构
Hash类型的数据结构
Btree:InnoDB的默认数据结构
三十二、数据库用户管理
sqlyog可视化管理
小人进入可视化
可以添加和删除用户
sql命令
用户表 mysql.user
本质:对这张表进行增删改查
-- 创建用户;
CREATE USER xiaowei99 IDENTIFIED BY '123456';
-- 修改当前用户密码
SET PASSWORD = PASSWORD('111111');
-- 修改当前用户密码
SET PASSWORD = PASSWORD('111111');
-- 修改其他用户密码
SET PASSWORD FOR xiaowei99 = PASSWORD('123456');
-- 重命名
RENAME USER xiaowei99 TO xiaowei98;
-- 用户授权 ALL PRIVILEGES全部权限(除了给别人授权的权限)
GRANT ALL PRIVILEGES ON *.* TO xiaowei98;
SELECT * FROM USER;
-- 查看权限
SHOW GRANTS FOR xiaowei98;
SHOW GRANTS FOR root@localhost;
-- 撤销权限
REVOKE ALL PRIVILEGES ON *.* FROM xiaowei98
-- 删除用户
DROP USER xiaowei98
三十三、MySQL备份
保证重要的数据不丢失
数据转移
mysql数据库备份的方式
-
直接拷贝数据文件
-
在sqlyog等可视化工具中手动导出
- 在想要导出的表和库中右键选择备份和导出
-
使用命令行:mysqldump 命令行使用
mysqldump -h localhost -u root -p123456 school student >D:/a.sql # 格式:mysqldump -h 主机 -u 用户名 -p密码 数据库名 表名 >导出的路径
导入方式:登录的情况下
source d:/a.sql
三十四、如何设计一个项目的数据库
数据库比较复杂的时候需要设计。
糟糕的数据库设计
- 数据冗余,浪费空间
- 数据插入和删除都麻烦、异常【不要物理外键】
- 程序性能差
良好的数据库设计
- 节省内存空间
- 保证数据的完整性
- 方便我们开发系统
软件开发中,关于数据库的设计
- 分析需求:分析业务和需要处理的数据的需求
- 概要设计:设计关系图E-R图
设计数据库的步骤:个人博客
- 收集信息,分析需求
- 用户表(用户登录注销,用户个人信息,写博客,创建分类)
- 分类表(文章分类,谁创建的)
- 文章表(文章信息)
- 友链表(友链信息)
- 自定义表(系统信息,每个关键的子,或者一些主字段)
- 说说表(发表心情....)
- 标示实体(把需求落地到字段上)
- 标识实体之间的关系
- 写博客:user -->blog
- 创建分类:user -->catagory
- 关注:user -->user
- 友链:links
- 评论:user--user-->blog
三十五、数据库的三大范式
为什么需要数据规范化?
- 信息重复
- 更新异常
- 插入异常
- 无法正常显示信息
- 删除异常
- 丢失有效的信息
三大范式
- 第一范式
- 数据表每一个字段都是不可再分。原子性
- 第二范式
- 前提:满足第一范式
- 每张表只描述一件事,表中的字段保证全部互相相关
- 第三范式
- 前提:满足第二范式
- 确保所有的字段和主键直接相关而不能间接相关
规范性和性能的问题
- 关联查询的表不能超过三个
- 数据库性能和规范两个二选一,性能更加重要
- 在规范性能问题的时候适当的考虑规范性
- 故意给某些表增加一些冗余字段(从多表查询变成单表查询)
- 故意增加计算列(从大数据量降低为小数据量查询:索引)
三十六、数据库驱动和JDBC
Java操作数据库:
数据库驱动
驱动:声卡、显卡、数据库
通过数据库驱动和数据库打交道
JDBC:为了简化开发人员的操作,提供了规范:JDBC
这些规范的实现由具体的厂商去做。
对于开发人员只需要掌握jdbc接口操作即可
两个包
java.sql
javax.sql
三十七、第一个JDBC程序
导入mysql-connector-java的jar包
package com.xiaowei9s.lesson01;
import sun.util.resources.cldr.lag.CurrencyNames_lag;
import java.sql.*;
public class JdbcFirstDemo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.填入用户信息和url登录
String url = "jdbc:mysql://localhost:3306/school?" +
"useUnicode=true" +
"&characterEncoding=utf8" +
"&useSSL=false";
String username = "root";
String password = "123456";
// 3.连接成功,数据库对象
Connection connection = DriverManager.getConnection(url, username, password);
// 4.执行sql语句的对象
Statement statement = connection.createStatement();
// 5.第四步的对象执行语句,可能有结果,要去连接结果
String sqlstr = "select * from student;";
ResultSet resultSet = statement.executeQuery(sqlstr);
while (resultSet.next()){
System.out.println("id = " + resultSet.getObject("id"));
System.out.println("name = " + resultSet.getObject("name"));
System.out.println("gradeid = " + resultSet.getObject("gradeid"));
System.out.println("pwd = " + resultSet.getObject("pwd"));
System.out.println("gender = " + resultSet.getObject("gender"));
System.out.println("birthday = " + resultSet.getObject("birthday"));
System.out.println("address = " + resultSet.getObject("address"));
System.out.println("email = " + resultSet.getObject("email"));
}
// 6.释放连接
resultSet.close();
statement.close();
connection.close();
}
}
三十八、JDBC中对象解释
Class.forName("com.mysql.jdbc.Driver");是为了加载静态代码块,注册驱动
url
String url = "jdbc:mysql://localhost:3306/school?" + //主机地址:端口号/数据库名
"useUnicode=true" + // 参数1
"&characterEncoding=utf8" + // 参数2
"&useSSL=false"; // 参数3
String username = "root";
String password = "123456";
connection
Connection connection = DriverManager.getConnection(url, username, password);
//connection 代表数据库
//数据库事务自动提交
// 回滚
// 事务提交
statement 执行sql的对象 prepareStatement 执行sql的对象
String sqlstr = "select * from student;"; // 编写sql语句
statement.executeQuery(sqlstr); //返回结果集
statement.executeUpdate(sqlstr); // 更新、删除、插入、都用这个
statement.execute(sqlstr); // 执行任何sql
ResultSet 结果集
// 获得指定的列
resultSet.getObject("id");// 如果不知道列的类型则使用getObject
resultSet.getString("id");// 如果知道列的类型则使用相关的get方法
//指针
resultSet.next();//下一行
resultSet.beforeFirst();//第一行
resultSet.afterLast();//最后一行
resultSet.previous();//前一行
resultSet.absolute(row);//指定行
释放资源
//释放连接
resultSet.close();
statement.close();
connection.close(); //耗内存
三十九、Statement对象详解
jdbc中的statement对象用于向数据库发送sql语句,想完成对数据库的增删改查只需发送相应的sql语句即可。
executeUpdate执行完后,返回一个整数(即sql语句导致几行数据发生了变化)。
executeQuery执行完后,返回代表查询结果的resultset对象。
CRUD操作:create,使用Statement(sql)方法完成对数据库的添加操作,示例如下:
Statement st = connection.createStatement;
String sql = "insert into user(...) values(...) ";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println("插入成功!");
}
CRUD操作:delete,使用Statement(sql)方法完成对数据库的删除操作,示例如下:
Statement st = connection.createStatement;
String sql = "delete from user wherte id=1";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println("删除成功!");
}
CRUD操作:update,使用Statement(sql)方法完成对数据库的修改操作,示例如下:
statement st = connection.Statement;
String sql = "update user set name=`` where id=1";
int num = st.executeUpdate;
if(num>0){
System.out.println("修改成功!");
}
CRUD操作:read,使用Statement(sql)方法完成对数据库的查询操作,示例如下:
Statement st = connection.createStatement;
String sql = "select * from user ";
Resultset rs = st.executeQuery(sql);
if(rs.next()){
//根据获取的数据类型,分别调用rs的相应方法映射到Java对象中
}
工具类
package com.xiaowei9s.util;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.sql.*;
import java.util.Properties;
public class JdbcUtil {
static Connection conn = null;
static Statement st = null;
static String url =null;
static String username = null;
static String password = null;
static {
try {
InputStream in = JdbcUtil.class.getClassLoader().getResourceAsStream("db.properties");
Properties properties = new Properties();
properties.load(in);
// 加载驱动
Class.forName(properties.getProperty("driver"));
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
} catch (Exception e) {
e.printStackTrace();
}
}
// 获取连接
public static Connection getConnection() throws SQLException {
//获取连接
conn = DriverManager.getConnection(url, username, password);
return conn;
}
// 获取执行对象
public static Statement getStatement() throws SQLException {
Statement statement = conn.createStatement();
return statement;
}
//释放资源
public static void release(Connection conn,Statement st,ResultSet rs){
if (rs!=null){
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (st!=null){
try {
st.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn!=null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
四十、SQL注入问题
SQL存在漏洞,会被攻击导致数据泄露
package com.zr.lesson02.utils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
//sql注入
public class SqlInjection {
public static void main(String[] args) throws SQLException {
//正常登录 数据库中有的用户和密码
//login("韩信","111111");
//sql注入 会输出所有密码为123456的人的信息
login("'or'1=1","123456");
//sql注入 会查询所有信息
//login("'or'1=1","'or='1=1");
}
//登录业务
public static void login(String username,String password) throws SQLException {
Connection con = null;
Statement st = null;
ResultSet rs = null;
try {
con = JdbcUtils.getConnection();//获取数据库连接
st = con.createStatement();//创建执行sql的对象
//select * from users where name=''or'1=1' and password='123456'
//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);
//if只能查出一条数据 这里查询所有用户信息使用while
while (rs.next()){
System.out.println("id="+rs.getInt("id"));
System.out.println("name="+rs.getString("name"));
System.out.println("password="+rs.getString("password"));
System.out.println("email="+rs.getString("email"));
System.out.println("birthday="+rs.getDate("birthday"));
System.out.println("==========================");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(con,st,rs);
}
}
}
四十一、PreparedStatement对象
可以防止sql注入并且效率更加高
package com.zr.lesson03;
import com.zr.lesson02.JdbcUtils;
import java.util.Date;
import java.sql.*;
//PreparedStatement 插入
public class TestInsert {
public static void main(String[] args) throws SQLException {
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
con = JdbcUtils.getConnection();
//区别
String sql = "insert into users values(?,?,?,?,?)";//使用?占位符 代替参数
ps = con.prepareStatement(sql);//预编译 先写sql 然后不执行
//手动给参数赋值
ps.setInt(1,5);
ps.setString(2,"李白");
ps.setString(3,"123333");
ps.setString(4,"813794474@qq.com");
//sql.Date 数据库 java.sql.date()
//util.Date Java new date().gettime() 获得时间戳
ps.setDate(5,new java.sql.Date(new Date().getTime()));
//执行
int i = ps.executeUpdate();
if (i>0){
System.out.println("插入成功!");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(con,ps,rs);
}
}
}
四十二、JDBC操作事务
//开启事务
conn.setAutoCommit(false);
//提交事务
conn.commit();
//回滚(默认出错就回滚,可以不写)
conn.rollback();
四十三、DBCP-C3P0
连接到释放很浪费资源
池化技术:准备一些连接的资源,过来就用预先准备好的
最大链接数:业务最高承载上限
最小链接数:按照需求
排队等待:等待超时
编写连接池,实现接口DataSource
开源数据源实现
- DBCP
- C3P0
- Druid:阿里巴巴
使用了这些数据库连接池后我们在开发中就可以不需要编写连接数据库的代码了。
DBCP
使用这些数据库连接池之后,我们在项目开发中就不需要编写数据库连接的代码了。
DBCP:lib下导入 commens-dbcp-1.4.jar和commens-pool-1.6.jar
创建dbconfig.properties文件
#连接设置
driverClassname=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcStudy?useunicode=true&characterEncoding=utf8&useSSL=false
username=root
password=123456
#初始化连接
initialSize=10
#最大连接数量
maxActive=50
#最大空闲连接
maxIdle=20
#超时等待时间 毫秒
maxWait=60000
connectionProperties=useUnicode=true;characterEncoding=utf8
defaultAutoCommit=true
defaultReadOnly=
defaultTransactionIsolation=READ_UNCOMMITTED
创建DBCP工具类
package com.zr.lesson05;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class JdbcUtils_DBCP {
private static DataSource dataSource = null;
static{
try{
InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbconfig.properties");
Properties properties = new Properties();
properties.load(in);
//创建数据源 工厂模式
dataSource = BasicDataSourceFactory.createDataSource(properties);
}catch (Exception e){
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection(); //从数据源中获取连接
}
public static void release(Connection con, Statement st, ResultSet rs){
if (con!=null){
try {
con.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (st!=null){
try {
con.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (rs!=null){
try {
con.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
测试插入数据
package com.zr.lesson05;
import com.zr.lesson02.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
public class TestDBCP {
public static void main(String[] args) throws SQLException {
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
con = JdbcUtils_DBCP.getConnection();
//区别
String sql = "insert into users values(?,?,?,?,?)";//使用?占位符 代替参数
ps = con.prepareStatement(sql);//预编译 先写sql 然后不执行
//手动给参数赋值
ps.setInt(1, 5);
ps.setString(2, "李白");
ps.setString(3, "123333");
ps.setString(4, "813794474@qq.com");
//sql.Date 数据库 java.sql.date()
//util.Date Java new date().gettime() 获得时间戳
ps.setDate(5, new java.sql.Date(new Date().getTime()));
//执行
int i = ps.executeUpdate();
if (i > 0) {
System.out.println("插入成功!");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JdbcUtils_DBCP.release(con, ps, rs);
}
}
}
C3P0
C3P0:lib下导入c3p0-0.9.5.5.jar和mchange-commens-java-0.2.19.jar
先创建c3p0-config.xml文件,再创建JdbcUtils_C3P0工具类
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!-- 默认配置,如果没有指定则使用这个配置 -->
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcStudy</property>
<property name="user">root</property>
<property name="password">123456</property>
<property name="acquirIncrement">5</property>>
<property name="initialPoolSize">10</property>
<property name="maxPoolSize">20</property>
<property name="minPoolSize">5</property>
</default-config>
<!-- 命名的配置,可以通过方法调用实现 -->
<named-config name="Mysql">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcStudy</property>
<property name="user">root</property>
<property name="password">123456</property>
<!-- 如果池中数据连接不够时一次增长多少个 -->
<property name="acquireIncrement">5</property>
<!-- 初始化数据库连接池时连接的数量 -->
<property name="initialPoolSize">10</property>
<!-- 数据库连接池中的最大的数据库连接数 -->
<property name="maxPoolSize">25</property>
<!-- 数据库连接池中的最小的数据库连接数 -->
<property name="minPoolSize">5</property>
</named-config>
</c3p0-config>
创建C3P0工具类
package com.zr.lesson05;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class JdbcUtils_C3P0 {
private static ComboPooledDataSource dataSource = null;
static{
try{
/*//代码配置
dataSource = new ComboPooledDataSource();
dataSource.setDriverClass();
dataSource.setUser();
dataSource.setPassword();
dataSource.setJdbcUrl();
dataSource.setMaxPoolSize();
dataSource.setMinPoolSize();*/
dataSource = new ComboPooledDataSource("Mysql");//配置文件写法
//创建数据源 工厂模式
}catch (Exception e){
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection(); //从数据源中获取连接
}
public static void release(Connection con, Statement st, ResultSet rs){
if (con!=null){
try {
con.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (st!=null){
try {
con.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (rs!=null){
try {
con.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
测试插入代码
package com.zr.lesson05;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
public class TestC3P0 {
public static void main(String[] args) throws SQLException {
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
con = JdbcUtils_C3P0.getConnection();
//区别
String sql = "insert into users values(?,?,?,?,?)";//使用?占位符 代替参数
ps = con.prepareStatement(sql);//预编译 先写sql 然后不执行
//手动给参数赋值
ps.setInt(1, 6);
ps.setString(2, "李白");
ps.setString(3, "123333");
ps.setString(4, "813794474@qq.com");
//sql.Date 数据库 java.sql.date()
//util.Date Java new date().gettime() 获得时间戳
ps.setDate(5, new java.sql.Date(new Date().getTime()));
//执行
int i = ps.executeUpdate();
if (i > 0) {
System.out.println("插入成功!");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JdbcUtils_C3P0.release(con, ps, rs);
}
}
}
结论:无论使用什么数据源,本质还是一样的,DataSource不变,方法就不会变。
知识来源:kuangstudy.com