MIKU MOE

MySQL_学习

MySQL


1. 初识数据库

JavaEE:企业级Java开发 Web

前端(页面,展示,数据)

后台(连接点:连接数据库JDBC,连接前端(控制,视图转跳,给前端传递数据))

数据库(Txt,Excel,Word)

操作系统,数据结构,算法

离散数学,数字电路,体系结构,编译原理 + 实战

数据库是所有软件体系中最核心的存在 DBA

DB(DataBase数据库)

 

  1.1 数据库分类

关系型数据库 (SQL)

  • MySQL , Oracle , Sql Server , DB2 , SQLlite

  • 通过表与表,行与行之间的关系进行数据存储

非关系型数据库 (NoSQL -- Not Only SQL)

  • Redis , MongDB

  • 对象存储,通过对象的自身属性决定

DBMS(数据库管理系统)

MySQL:

  • MySQL是最好的RDBMS(Relational Database Management System,关系数据库管理系统)应用软件之一。

  • 开源

  • 体积小,速度快,总体拥有成本低,招人成本低

  • 中小型网站可以做集群

  • 稳定版 5.7

安装:略

数据化可视化:SQLyog

 

  1.2 数据库操作

CRUD 增删改查 ( CV程序员 API程序员 CRUD程序员 )

  • DDL 数据库定义语言

  • DML 数据库操作语言

  • DQL 数据库查询语言

  • DCL 数据库控制语言

 CREATE DATABASE [IF NOT EXISTS] 数据库名;  --创建数据库[如果不存在,则创建]
 DROP...  --删除数据库
 USE 数据库名;     --使用数据库
 SELECT...  -
 show DATABASE;  --查看数据库
 

  1.3 数据类型

数值

  • tinyint 十分小的数据 1个字节

  • smallint 较小的数据 2个字节

  • mediumint 中等大小的数据 3个字节

  • int 标准的整数 4个字节 (常用int)

  • bigint 较大的数据 8个字节

  • float 浮点数 4个字节

  • double 浮点数 8个字节 (精度问题!)

  • decimal 字符串形式的浮点数 (金融计算的时候,一般是使用decimal)

字符串

  • char 字符串固定大小的 0~255

  • varchar 可变字符串 0~65535 (常用String)

  • tipytext 微型文本 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. 没有值,未知

  1.4 字段属性

Unsigned:

  • 无符号的整数

  • 声明则该列不能声明为负数

zerofill:

  • 0填充

  • 不足的位数,使用0自动填充

自增:

  • 通常设计唯一主键 index 必须是整数类型

  • 可自定义设计主键的起始值和步长

非空

默认

  • 扩展

每一个表,都必须存在以下五个字段 !

未来做项目用的,表示一个记录存在意义!

  • id 主键

  • 'version' 乐观锁

  • is_delete 伪删除

  • gmt_create 创建时间

  • gmt_update 修改时间

  1.5 常用命令

CREATE TABLE IF NOT EXISTS `stu`(
     `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`)
 )ENGINE=INNODB DEFAULT CHARSET=utf8   --建表
ALTER TABLE stu RENAME AS stu1  --修改表名
 ALTER TABLE stu1 ADD age INT(3) --新增字段
 ALTER TABLE stu1 MODIFY age vARCEAR(11) --修改约束和字段类型(不能重命名)
 ALTER TABLE stu1 CHANGE age age1 INT(1) --字段重命名(...) 
 ALTER TABLE stu1 DROP age1 --删除字段名
 DROP TABLE IF EXISTS stu  --删除表
 --`所有的创建和删除操作尽量加上判断IF EXISTS,以免报错`
 ALTER TABLE stu1 ADD CONSTRAINT `FK_gradeid` FOREIGN KEY(`gradeid`)
 REFERENCES `grade`(`gradeid`) 
 --添加外键,CONSTRAINT约束名,FOREIGN KEY作为外键的列,REFERENCES引用那个表那一列
 --物理外键,数据库级别,不建议使用(避免数据库过多)
DESC stu  --显示表的结构
 SHOW CREATE TABLE stu  --查看stu表的定义语句
 SHOW CREATE DATABASE stu st  --查看创建数据库的定义语句
/*数据库引擎
 INNODB 默认使用
     支持:事务支持,数据行锁定,外键约束 - 不支持:全文索引
     安全性高,事务处理,多表多用户操作
 MYISAM  早些使用
     支持:全文索引 - 不支持:事务支持,数据行锁定,外键约束
     节约空间,速度较快
 */

 

2. MySQL数据管理

  DML语言

DML语言:数据操作语言

 -- 增添数据
 insert into 表名([字段名1,字段名2,字段名3,...]) values ('值1'),('值2'),('值3',...)
 -- 修改数据
 update 表名 set 字段名1=值1,[字段名2=值2,...] where [判断条件]
 -- 删除数据
 delete from 表名 where [判断条件]
 -- 完全清空数据库表
 truncate 表名

 

delete与truncate区别 :

  • 相同 : 都可以删除数据,都不会删除表结构

  • 不同 :

    • truncate重新设置自增列计数器归零 , 不会影响事务

    • delete : 重启数据库 -- 在InnoDB下 自增列从1开始(存储内存) ; 在MyISAM下继续从上一个自增量开始

3. DQL查询数据 ***

DQL(Data Query LANGUAGE)数据查询语言

  • Select

  • 完整语法

  •  SELECT [ALL | DISTINCT]
     {* | table.* | [table.field1[as alias1][,table.field2[as alias2]][,...]]}
     FROM table_name [as table_alias]
         [left | right | inner join table_name2] -- 联合查询
         [WHERE ...]      -- 指定结果需满足的条件
         [GROUP BY ...]   -- 指定结果按照哪几个字段来分组
         [HAVING]         -- 过滤分组的记录必须满足的次要条件
         [ORDER BY ...]   -- 指定查询记录按一个或多个条件排序
         [LIMIT {[offset,]row_count | row_countOFFSET offset}];  -- 指定查询的记录从哪条至哪条
     -- []代表可选,{}代表必选
     -- 有顺序要求
  • 数据库最核心的语言,最重要的语句

-- 查询SELECT - 别名AS
 SELECT 字段名1 AS 别名1,[字段名2 别名2,...] FROM 表名 [AS 表的别名]
 -- 函数CONCAT(a,b)
 SELECT CONCAT('拼接的字符串:',字段名) AS 别名 FROM 表名
 ​
 -- 去重DISTINCT
 SELECT DISTINCT 字段名 FROM 表名
 ​
 -- 查询系统版本(函数)
 SELECT VERSION()
 -- 用来计算(表达式)
 SELECT 100*3-1 AS 计算结果
 -- 查询自增的步长(变量)
 SELECT @@auto_increment_increment

  3.1 where

  • AND && 与

  • OR || 或

  • NOT != 非

运算符语法描述
IS NULL a is null 如操作符结果为NULL,结果为真
IS NOT NULL a is not null 如操作符结果为NOT 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

 -- 查询姓刘的学生,且刘字后面只有一个字( _ 指代一个字符 '刘__ 代表后面三个字')
 SELECT 字段名 FROM 表名 WHERE 字段名 LIKE '刘_'
 -- 查询名字中间是,且刘字后面只有一个字( % 指代一个字符)
 SELECT 字段名 FROM 表名 WHERE 字段名 LIKE '%刘%'

IN (具体的一个值或多个值 , 不能使用 % _ )

-- 查询住在北京或上海的人
 SELECT 字段名 FROM 表名 WHERE 字段名 IN('北京','上海');
 

  3.2 联表查询

在这里插入图片描述

image-20210824163611484

image-20210824163801325

 /*思路
 1.分析需求,分析查询的字段来自哪些表 (连接查询)
 2.确定使用哪种连接查询? (7种)
 确定交叉点(这两个表中哪个数据是相同的)
 判断的条件:学生表的中 studentNo = 成绩表 studentNo
 */
 -- JOIN(连接的表) ON(判断条件)  连接查询
 -- WHERE    等值查询
-- INNER JOIN
 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 s   -- AS可以省略
 RIGHT JOIN result r
 ON s.studentNO = r.studentNO
 -- LEFT JOIN   --缺考(右表无数据的学生)可以查出,因为左查询包含左表所有内容
 SELECT s.studentNO,studentName,SubjectNo,StudentResult 
 FROM student s
 LEFT JOIN result r
 ON s.studentNO = r.studentNO
 -- 查询缺考学生
 SELECT s.studentNO,studentName,SubjectNo,StudentResult 
 FROM student s
 LEFT JOIN result r
 WHERE StudentResult IS NULL;

 

巩固 :

 -- 查询学员所属的年级(学号,学生的姓名,年级名称)
 SELECT studentNo,studentName,GradeName
 FROM student s
 INNER JOIN grade g
 ON s.GradeID = g.GradeID
 -- 查询科目所属的年级(科目名称,年级名称)
 SELECT SubjectName,GradeName
 FROM subject sub
 INNER JOIN grade g
 ON sub.GradeID = g.GradeID
 -- 查询了参加"数据库结构-1"考试的同学信息:学号,学生姓名,科日名,分数)
 SALECT 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'

 

image-20210824165605210

 /*三表查询 : 学号 学生姓名 科目名 分数
      三表 : student result subject
 */
 SELECT s.studentNO,studentName,SubjectName,StudentResult
 FROM student s
 RIGHT JOIN result r
 ON s.studentNO = r.studentNO
 INNER JOIN subject sub
 ON r.SubjectNo = sub.SubjectNo

 

操作描述
INNER JOIN 如果表中至少有一个匹配,就返回
RIGHT JOIN 会从左表返回所有的值,即使右表中没有匹配
LEFT JOIN 会从右表返回所有的值,即使左表中没有匹配

  3.3 自连接(了解)

自己的表和自己的表连接,核心 : 一张表拆为两张一样的表即可

image-20210824172323273

categoryid - 当前层级 pid - 父类层级 categoryName - 名字

  • 父类表 :

categoryidcategoryName
2 信息技术
3 软件开发
5 美术设计
  • 子类表 :

PIDcategoryidcategoryName
3 4 数据库
2 8 办公信息
3 6 web开发
5 7 ps技术
  • 关系 :

父类子类
信息技术 办公信息
软件开发 数据库
软件开发 web开发
美术设计 ps技术
 -- 查询父子信息
 SELECT a.categoryName AS '父栏',b.categoryName AS '子栏'
 FROM category AS a,categoryid AS b
 WHERE a.categoryid = b.pid

  3.4 分页和排序

排序 : order by

 -- 排序:升序ASC,降序DESC
 -- ORDER BY 通过哪个字段排序,怎么排
 -- 查询的结果根据成绩升序排序
 ORDER BY StudentResult ASC 

 

分页 : limit

 -- 缓解数据库压力,给人更好的体验(瀑布流) 
 -- 语法: LIMIT 起始值,页面大小
 -- LIMIT 0,5    1~5   第一页
 -- LIMIT 1,5    2~6
 -- LIMIT 5,5    6~10  第二页
 -- LIMIT x,5    第N页 (n-1)*pageSize,pageSize
 -- 【pageSize:页面大小】
 -- 【(n-1)*pageSize:起始值】
 -- 【n:当前页】
 LIMIT 1,5

 -- 测试题:
 -- 查询JAVA第一学年课程成绩排名前十的学生,并且分数要大于80的学生信息
 -- (学号,姓名,课程名称,分数)
 SELECT s.studentNo,studentName,subjectName,StudentResult
 FROM student s
 INNER JOIN result r
 ON s.studentNo = r.studentNo
 INNER JOIN subject sub
 ON sub.SubjectNo = r.subjectNo 
 WHERE SubjectName = 'JAVA第一学年' AND StudentResult>=80
 ORDER BY studentResult DESC
 LIMIT 0,10

 

  3.5 子查询

在where语句中嵌套一个子查询语句

 -- 1、查询"数据库结构-1"的所有考试结果(学号,科目编号,成绩),降序排列
 -- 方式一:使用连接查询
 SELECT  `tudentNo`,r.`subjectNo`,`studentResult`
 FROM `result` r
 INNER JOIN `subject` sub
 ON r.SubjectNo = sub .subjectNo
 WHERE subjectName ='数据库结构-1'
 ORDER BY studentResult DESC
 -- 方法二:使用子查询
 SELECT `StudentNo`,`SubjectNo`,`StudentResult`
 FROM `result`
 WHERE StudentNo = (
     SELECT SubjectNo FROM `subject` 
     WHERE SubjectName = '数据库结构-1'
 )
 ORDER BY studentResult DESC-- 分数不小于80分的学生的学号和姓名 + 加上 查询科目"高等数学-2" 条件
 SELECT DISTINCT s.`StudentNo`,`studentName`
 FROM student s
 INNER JOIN result r
 ON r.studentNo = s.studentNo
 WHERE `studentResult` >=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. MySQL函数

官网参考手册 : https://dev.mysql.com/doc/refman/5.7/en/built-in-function-reference.html

  4.1 常用函数

 -- 数字运算 
 SELECT ABS(-8)  -- 绝对值
 SELECT CEILING(9.4)  -- 向上取整
 SELECT FLOOR(9.4) -- 向下取整
 SELECT RAND()  -- 返回一个0~1随机数
 SELECT SIGN(10)  -- 判断一个数的符号 - 负数返回-1,正数返回1,0返回0
-- 字符串函数
 SELECT CHAR_LENGTH('xxxx')  -- 长度
 SELECT CONCAT('x','cc','zzz')  -- 拼接
 SELECT INSERT('xzcvbn',1,2,'qqq') -- 查询,从某个位置开始体换某个长度
 SELECT LOWER('x')  -- 小写字母
 SELECT UPPER('x')  -- 大写字母
 SELECT INSTR('qwert','w')  -- 返回第一次出现的子串的索引
 SELECT REPLACE('qwertyuiop','wer','zzz')  -- 替换出现的指定字符串
 SELECT SUBSTR('qwer',2,3)-- 返回子字符串(源字符串,截取的位置,截取的长度)
 SELECT REVERSE('zx') -- 反转
-- 时间和日期函数 **
 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 ()
 

  4.2 聚合函数 ***

函数名称描述
COUNT() 计数
SUM() 求和
AVG() 平均值
MAX() 最大值
MIN() 最小值
 -- COUNT
 SELECT COUNT (`BornDate`) FROM student; -- Count(字段),会忽略所有的null值
 SELECT COUNT (*) FROM student;  -- count (*),不会忽略null值,计算行数
 SELECT COUNT (1) FROM result;   -- Count (1),不会忽略所有null值,本质计算行数
/* 分组过滤 - 案例 */
 -- 查询不司课程的平均分,最高分,最低分,平均分大于80
 -- 核心: (根据不同的课程分组)
 SELECT SubjectName,AVG(studentResult) AS 平均分,
 MAX(StudentResult) AS 最高分,MIN(StudentResult) AS 最低分
 FROM result r
 INNER JOIN `subject` sub
 ON r.`subjectNo` = sub.`SubjectNo`
 GROUP BY r.subjectNo  -- 通过什么宁段来分组
 HAVING 平均分>80


  4.3 MD5加密(扩展)

MD5 不可逆

-- 明文密码
 INSERT INTO testmd5 VALUES (1,'zhangsan','123456')
 -- 加密
 UPDATE testmd5 SET pwd=MD5(pwd) WHERE id = 1
 UPDATE testmd5 SET pwd=MD5(pwd) -- 加密全部的密码
 -- 插入的时候加密
 INSERT INTO testmd5 VALUES (2,'wangwu',MD5('123456'))
 -- 如何校验:将用户传递进来的密码,进行md5加密,然后比对加密后的值
 SELECT * FROM testmd5 WHERE `name`=`zhangsan` AND pwd=MD5('123456')
 

 

5. 事务

事务原则 : ACID原则

  • 原子性(Atomicity)

    • 要么都成功,要么都失败

  • 一致性(Consistency)

    • 事务前后数据完整性保持一致

  • 隔离性(Isolation)

    • 针对多个用户同时操作,主要是排除其他事务对本次事务的影响

  • 持久性(Transaction) - 事务提交

    • 表示事务结束后的数据不随着外界原因导致数据丢失

    • 出现意外 : 事务未提交则恢复原状 , 事务以提交则持久化到数据库 , 事务一旦提交不可逆


  • 事务的隔离级别

    • 脏读:指一个事务读取了另外一个事务未提交的数据

    • 不可重复读:—个事务内读取表中的某一行数拒多次读取结果不同(这个不一定是错误)

    • 虚读(幻读):指在一个事务内读到了别的事务插入的数据,导致前后读取不一致(一般是行影响,多一行)

 -- mysql是认开启事务自动提交的
 SET autocommit = 0 /*关闭*/
 SET autocommit = 1 /*开启(默认的)*/-- 手动处理事务
 SET autocommit = 0 -- 关闭自动条件
 -- 事务开启
 START TRANSACTION  -- 标记一个事务的开始,从这个之后的sql都在同一个事务内
 INSERT XX
 INSERT XX
 -- 提交:持久化(成功!)
 COMMIT
 -- 回滚:回到的原来的样子(失败!)
 ROLLBACK
 -- 事务结束
 SET autocommit = l -- 开启自动提交I
-- (了解)
 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'  -- B加500
 COMMIT;     -- 提交事务,持久化
 ROLLBACK;   -- 回滚
 SET autocommit = l; -- 恢复默认值

 

 



 

6. 索引

MySQL官方对索引的定义为 :

索引(Index)是帮助MySQL高效获取数据的数据结构。

提取句子主干,就可以得到索引的本质:索引是数据结构。

  6.1分类 :

在一个表中,主键索引只能有一个,唯一索引可以有多个

  • 主键索引(PRIMARY KEY)

    • 唯一标识,不可重复,只有一列

  • 唯一索引(UNIQUE KEY)

    • 避免重复的列,唯一索引可以重复,

  • 常规索引(KEY/INDEX)

    • 默认的 , index key关键字设置

  • 全文索引(FullText)

    • 在特定的引擎下有, MyISAM , 快速定位数据

  6.2使用 :

 -- 最示所有的索引信息
 SHOW INDEX FROM student
 -- 增加一个全文索引(索引名)列名
 ALTER TABLE 库名.student ADD FULLTEXT INDEX `studentName` (`studentName`);
 ​
 ​
 -- EXPLAIN 分析sql执行的状况
 EXPLAIN SELECT * FROM student; -- 非全文索引
 EXPLAIN SELECT * FROw student WHERE MATCH(studentName) AGAINST('');

 

  6.3测试索引 :

 -- 插入100万数据
 DELIMITER $$  -- 写函数之前必须要写,标志
 CREATE FUNCTION mock_data ()
 RETURN 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),'24736743@qq.com',
                CONCAT ('18',FLOOR(RAND()*((999999999-100000000)+100000000))),
                FLOOR(RAND()*2),UUID(),FLOOR(RAND()*100))
         SET i = i+1;
     END WHILE
     RETURN i
 END;
 SELECT mock_data();
 ​
 ​
 -- id     _ 表名 _ 字段名
 -- CREATE INDEX 索引名 on 表(字段)
 CREATE INDEX id_app_user_name ON app_user(`name`);

 

索引在小数据量的时候,用处不大,但是在大数据的时候,区别十分明显~

  6.4索引原则

MySQL索引背后的数据结构及算法原理

https://blog.csdn.net/wufuhuai/article/details/79631466

  • 索引不是越多越好

  • 不要对进程变动数据加索引

  • 小数据量的表不需要加索引

  • 索引一般加在常用来查询的字段上!


7. 权限管理和备份

  权限管理

SQL命令

用户表: mysql.user

 -- 创建用户
 CREATE USER 用户名 IDENTIFIED BY '密码'
 -- 修改密码(修改当前用户密码)
 SET PASSWORD =  PASSWORD('123456')
 -- 修改密码(修改指定用户密码)
 SET PASSWORD FOR 用户名 = PASSWORD('111111')
 -- 重命名
 RENAME USER 旧名字 TO 新名字
 -- 用户授权   ALL PRIVILEGES全部权限,除了给别人授权
 GRANT ALL PRIVILEGES ON *.* TO 用户名
 -- 查询权限
 SHOW GRANTS FOR 用户名 -- 查看指定用户的权限
 SHOW GRANTS FOR root@localhost  -- root用户权限
 -- 撤销权限 REVOKE (什么权限,那个库,给谁撤销)
 REVOKE ALL PRIVILEGES ON *.* FROM 用户名
 --删除用户
 DROP USER 用户名

  备份

  • 命令行

    • 导入 mysqldump 导出 source

  • SQLyog

  • 拷贝物理文件


8. 规范数据库设计

糟糕的数据库设计:

  • 数据冗余,浪费空间

  • 数据库插入和删除都会麻烦、异常【屏蔽使用物理外键】

  • 程序的性能差

良好的数据库设计:

  • 节省内存空间

  • 保证数据库的完整性

  • 方便我们开发系统

开发中,数据库设计:

  • 分析需求 : 分析业务和需要处理的数据库的需求

  • 概要设计 : 设计关系图E-R图

  三大范式

  • 第一范式(1NF):要求数据库表的每一列都是不可分割的原子数据项。

    • 原子性 : 每一列不可再分

  • 第二范式(2NF):在1NF的基础上,非码属性必须完全依赖于候选码(在1NF基础上消除非主属性对主码的部分函数依赖)

    • 第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)。

    • 即每张表只描述一件事情

  • 第三范式(3NF):在2NF基础上,任何非主属性不依赖于其它非主属性(在2NF基础上消除传递依赖)

    • 第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。

  规范性和性能的问题

  • 关联查询的表不得超过三张表I

    • 考虑商业化的需求和目标,(成本,用户体验! )数据库的性能更加重要

    • 在规范性能的问题的时候,需要适当的考虑一下规范性!

    • 故意给某些表增加一些冗余的字段。(从多表查询中变为单表查询)

    • 故意增加一些计算列(从大数据量降低为小数据量的查询:索引)


9. JDBC ***

SUN公司为了简化开发人员的(对数据库的统一)操作,提供了一个(Java操作数据库)规范,俗称JDBC

 public static void main(String[] args) throws ClassNotFoundException, SQLException {
         //1.加载驱动
         Class.forName("com.mysql.jdbc.Driver");//固定写法,加载驱动
         //2.用户信息和url
         String url = "jdbc:mysql://localhost:3306/库名?useUnicode=true&characterEncoding=utf8&useSSL=true";
         String username = "root";
         String password = "root";
         //3.连接数据库 DriverManager (Connection 代表数据库)
         Connection conn = DriverManager.getConnection(url, username, password);
         //4.执行SQL的对象Statement执行sql的对象
         Statement statement = conn.createStatement();
         //5.执行SQL的对象去执行  执行SQL,可能存在结果,查看返回结果
         String sql = "SELECT * FROM 表名";
         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"));
         }
         //6.释放连接
         resultSet.close();
         statement.close();
         connection. close();
     }

 

Statement 执行SQL对象

 String sql = "SELECT * FROM users"; //编写SQL
 ​
 statement.executeQuery();//查询操作返回Resu1tSet
 statement.execute(); //执行任何SQL
 statement.executeUpdate();//更新、插入、删除。都是用这个,返回一个受影响的行数

ResultSet 查询的结果集 封装了所有查询结果

 resultSet.getObject(); //如果知道列类型则换成相应类型
 /***********遍历***********/
 resultset.beforeFirst(); //移动到最前面
 resultset.afterLast();   //移动到最后面
 resultset.next();        //移动到下一个数据 ***
 resultset.previous();    //移动到前一行
 resultset.absolute(row); //移动到指定行

  9.1 statement

  • Jdbc中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。

  • Statement对象的executeUpdate方法,用于向数据库发送增、删、改的sql语句,executeUpdate执行完后,将会返回一个整数(即增删改语句导致了数据库几行数据发生了变化)。

  • Statement.executeQuery方法用于向数据库发送查询语句,executeQuery方法返回代表查询结果的ResultSet对象。

增删改使用 executeUpdate 查一般使用 executeQuery

  9.2 SQL注入

SQL注入即是指web应用程序对用户输入数据的合法性没有判斯或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非投权的任意查询,从而进一步得到相应的数据信息。即漏洞

 //判断:如果账号存在且密码正确则登路
 SELECT * FROM users WHERE `NAME`='"+username+"' AND `password`='"+password+"'";
//调用函数使用此语句时Login(String username,String passward)
 Login(" 'or' 1=1"," 'or' 1=1");
 //登路成功
//导致SELECT语句变化,可能会导致数据泄露
 SELECT * FROM users WHERE `Name`=''or'1=1' AND `password`=''or'1=1';

  9.3 PreparedStatement

可以防止SQL注入,且效率更好

 Connection conn = JdbcUtils.getConnection();
 //区别
//使用 ? 占位符代替参数
 String sql = "insert into users(id,`NAME`,`PASSMORD`,`DATE`) values(?,?,?)";
 //预编译SQL,先写sql,然后不执行
 PrepareStatement st = conn.prepareStatement(sql);
 //手动给参数赋值
 st.setInt(1,4); //第几个参数,参数值
 st.setString(2,"NAME");
 st.setString(3,"PASSMORD");
 //sql.Date数据库使用 ; util.Date JAVA使用  -- new Date().getTime()获得时间戳
 st.setDate(4,new java.sql.Date(new java.util.Date().getTime()));
 //执行
 st.executeUpdate();
 ​
 //PreparedStatement防止注入的本质,将闯进来的参数全当作字符,转义字符将被转义
 //改进登录
 conn =JdbcUt1ls.getConnection();
 String sql = "SELECT * FROM users WHERE `NAME`=? AND `password`=?"; //编写SQL
 st = conn. preparestatement(sql); //预编译
 st.SetString(1,username); //传递参数
 st.SetString(2,password);
 rs = st.executeQuery; //执行

  9.4 事务

ACID

原子性:要么全部完成,要么都不完成

一致性:总数不变

隔离性:多个进程互不干扰 (问题 : 脏读 , 不可重复读 , 幻读)

持久性:一旦提交不可逆,持久化到数据库

 conn = JdbcUtils.getConnection();
 //关闭数据库的自动提交,自动会开启事务
 conn.setAutoCommit(false); //开启事务
 ​
 String sql1 = "update account set money = money-100 where name = 'A'";
 st = conn.prepareStatement(sql1);
 st.executeUpdate();
 String sql2 = "update account set money = money+100 where name = 'B'";
 st = conn.prepareStatement(sql2);
 st.executeUpdate();
 //业务完毕,提交事务
 conn.commot();
 //conn.rollback();  --如果失败则回滚事务.判断
 JdbcUtils.release(conn,st,rs);

  9.5 数据库连接池

  • 数据库连接 -- 执行完毕 -- 释放

  • 连接 -- 释放十分浪费系统资源

池化技术 : 准备一些预先的资源,过来就连接预先准备好的

连接池:

最小连接数 : 10

最大连接数 : 100 业务最高承载上限

等待超时 : 100ms

编写连接池,实现一个接口DataSource

  • 开源数据源实现

    • DBCP

    • C3P0

    • Druid : 阿里

  • 使用了数据库连接池后,项目开发中就不需要编写链接数据库代码

    编写连接池,实现一个接口DataSource

    DBCP

需要用到的jar包:

commons-dbcp-1.4 commons-pool-1.6

 //配置  文件名:dbcpconfig.properties
 #连接设置
 driverClassName=com.mysql.jdbc.Driver
 url=jdbc:mysql://localhost:3306/库名?useUnicode=true&characterEncoding=utf8&useSSL=true
 username=root
 password=123456
 ​
 #<!-- 初始化连接 -->
 initialSize=10
 ​
 #最大连接数量
 maxActive=50
 ​
 #<!-- 最大空闲连接 -->
 maxIdle=20
 ​
 #<!-- 最小空闲连接 -->
 minIdle=5
 ​
 #<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
 maxWait=60000
 #JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:【属性名=property;】
 #注意:user 与 password 两个属性会被明确地传递,因此这里不需要包含他们。
 connectionProperties=useUnicode=true;characterEncoding=UTF8
 ​
 #指定由连接池所创建的连接的自动提交(auto-commit)状态。
 defaultAutoCommit=true
 ​
 #driver default 指定由连接池所创建的连接的只读(read-only)状态。
 #如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
 defaultReadOnly=
 ​
 #driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
 #可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
 defaultTransactionIsolation=READ_UNCOMMITTED

 private static DataSource dataSource = null;
 static {
     try {
         InputStream in = JdbcUtils_DBCP.class.getClassLoader( ).getResourceAsStream("dbcpconfig.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();//从数据源获取连接
 }

    C3P0

需要用到的jar包:

commons-dbcp-1.4 commons-pool-1.6

 配置   文件名:c3p0-config.xml


posted @ 2021-08-25 22:58  miku_moe  阅读(44)  评论(0)    收藏  举报