数据库笔记

作者:@冰山醉酒
本文为作者原创,转载请注明出处:https://www.cnblogs.com/douFrank/p/16117965.html


1|0初始MySQL

JAvaEE:企业级Java开发 web

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

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

数据库(存储数据,管理数据)

1|1数据库分类

关系型数据库 (SQl)

  • MySql ,Oracle, Sql Server ,DB2,SQLite

  • 通过表与表之间,行和列之间的关系进行数据的存储,学员信息表,考勤表……

非关系数据库 (NoSQl)Not Only

  • redis,MongDB

  • 非关系型数据库,对象存储,通过对象额自身属性来决定。

DBMS(数据库管理系统)

  • 数据库的管理软件,科学有效的管理我们的数据。维护和获取数据

  • MySQL,数据库管理系统

1|2MySQL简介

1|3安装MySql

  1. 解压

  2. 把这个给包放到自己的电脑环境目录下

  3. 配置环境变量(path中添加MySQL的bin文件的目录)

  4. 在mysql目录下新建my.ini文件 ,写入

    [mysqld] basedir=D:\MySql\mysql-8.0.22\ datadir=D:\MySql\mysql-8.0.22\data\ port = 3306 #skip-grant-tables
  5. 启动管理员模式下的CMD,运行所有的命令

  6. 安装mysql服务

    C:\WINDOWS\system32>D: C:\WINDOWS\system32>cd D:\MySql\mysql-8.0.22\bin //注意看前面的目录 D:\MySql\mysql-8.0.22\bin>mysqld -install D:\MySql\mysql-8.0.22\bin>mysqld --initialize-insecure --user=mysql //Service successfully installed.
  7. 初始化数据库文件

    D:\MySql\mysql-8.0.22\bin>mysqld --initialize-insecure --user=mysql
  8. 启动mysql,进去修改密码

    D:\MySql\mysql-8.0.22\bin>net start mysql //MySQL 服务正在启动 ... //MySQL 服务已经启动成功。 D:\MySql\mysql-8.0.22\bin>mysql -u root -p Enter password: //-p后面没有空格 password:后面也没有空格,都是直接回车
  9. 进入mysql通过命令行(-p后面不要加空格),修改密码(sql语句后面一营要加分号!)改为123456

    mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY '123456'; //Query OK, 0 rows affected (0.17 sec)
    刷新权限,关闭服务
  10. mysql> privileges; //Query OK, 0 rows affected (0.12 sec) mysql> exit //Bye D:\MySql\mysql-8.0.22\bin>net stop mysql //MySQL 服务正在停止. //MySQL 服务已成功停止。
  11. 重启mysql,连接测试,如果连接成功就OK了。

D:\MySql\mysql-8.0.22\bin>mysql -u root -p Enter password: ****** //Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 8 Server version: 8.0.22 MySQL Community Server - GPL Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. //最后退出就可以了 mysql> exit Bye

安装SQlyog

1|4连接数据库

命令行连接!

mysql -u root -p123456 -- 连接数据库 flush privileges; -- 刷新权限 ---------------------------- -- 所有的语句都是用;结尾 show databases; -- 查看所有的数据库 use school; -- 切换数据库 use 数据库名 Database changed show tables; -- 查看数据库中所有的表 describe student; -- 显示数据库中所有表的信息 create database; -- 创建一个数据库 exit -- 退出链接 -- 单行注释 /* 多行注释 */

数据库 XXX语言

DDL 定义

DML 操作

DQL 查询

DCL 控制

2|0操作数据库

操作数据库 > 操作数据库中的表 > 操作数据库中表的数据

mysql不区分大小写

  1. 创建数据库

    CREATE DATABASE IF NOT EXISTS westos;
  2. 删除数据库

    DROP DATABASE IF EXISTS westos;
  3. 使用数据库

    -- tab上面的键,如果你的表明或者字段名是一个特殊字符,就需要带`` USE `school`;
  4. 查看数据库

    SHOW DATABASES;

对比:SQLyog的可视化操作

学习思路:

  • 对照sqlyog可视化历史记录查看sql

  • 固定的语法或关键字必须强行记住!

数值

  • tinyint 十分小的数据 1字节

  • smallint 较小的数据 2个字节

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

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

  • bigint 较大的数据 8个字节

  • float 浮点数 4个字节

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

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

字符串

  • 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|1数据库的字段属性(重点)

unsigned:

  • 无符号的整数

  • 声明了该列不能为负数

zerofill

  • 0填充

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

自增

  • 通常理解为自增,自动在上一条记录的基础上+1(默认)

  • 通常用来设计唯一的主键~index,必须是整数类型

  • 可以自定义审计逐渐自增的起始值和步长

非空

  • 假设设置为not null 如果不给它赋值,就会报错

默认

  • 设置默认的值!

拓展:

/*每个表,都必须存在以下的字段 id 主键 `version` 乐观锁 is_delete 伪删除 gmt_create 创建时间 gmt_update 修改时间 */

2|2创建数据库表(重点)

-- 目标:创建一个school数据库
-- 创建学生表(列,字段)使用SQL创建
-- 学号int 登陆密码varchar(20)姓名,性别varchar(2),出生日期(datatime),家庭住址,Email


-- 注意点,使用英文(),表的名称和字段进俩个使用``括起来
-- AUTO_TNCREMENT 自增
-- 字符串使用 单引号括起来!
-- 所有的语句后面加;(英文版),最后一个不用加
-- PRIMARY KEY 主键,一般一个表只有一个唯一的主键!
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

格式

CREATE TABLE [IF NOT EXISTS] `表明`( `字段名` 列类型 [属性] [索引] [注释], `字段名` 列类型 [属性] [索引] [注释], `字段名` 列类型 [属性] [索引] [注释] )[表类型] [字符集设置] [注释]

常用命令

DESC student; -- 显示表的结构 SHOW CREATE DATABASE school; -- 查看定义表的语句 SHOW CREATE TABLE student; -- 查看定义数据库的语句

2|3数据表的类型

-- 关于数据库引擎 /* INNODB 默认使用~ MYISAM 早些年使用 */
 MYISAMINNODB
事务支持 不支持 支持
数据行锁定 不支持 支持
外键约束 不支持 支持
全文索引 支持 不支持
表空间的大小 较小 较大,约为2倍

常规使用操作:

  • MYISAM 节约空间 苏队较快

  • INNODB 安全性高,属的处理,多表多用户操作

在物理空间存在的位置

所有的数据库文件都存在data目录下,一个文件夹对应一个书库,本质还是文件的存储!

MySQL引擎在物理文件上的区别

  • innoDB在数据库表中只有一个*.frm文件,以及上级目录的ibdata1文件

  • MYISAM对应文件

    • *.frm 表结构的定义文件

    • *.MYD 数据文件(data)

    • *.MYI 索引文件(index)

设置数据库表的字符集编码

CHAREST=utf8

不设置的话,回事mysql默认的字符集编码~(不支持中文!)

MySQL的默认编码是Latin1 ,不支持中文

在my.ini中哦欸之默认的编码

character-set-server=utf8

2|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 VARCHAR(11) -- ALTER TABLE 表名 CHANGE 旧字段名 新字段名 列属性[] ALTER TABLE teacher1 CHANGE age age1 INT(3) -- 删除表的字段 ALTER TABLE 表名 DROP 字段名 ALTER TABLE teacher1 DROP age1

删除

-- 删除表 DROP TABLE IF EXISTS 表名 DROP TABLE IF EXISTS teacher1

2|5MySQL数据管理

2|6外键(了解即可)

创建表时添加外键

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 -- 给这个外键添加约束(执行引用)reference 引用 CREATE TABLE `student` ( `id` INT 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 AUTO_INCREMENT=2 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 -- 给这个外键添加约束(执行引用)reference 引用 CREATE TABLE `student` ( `id` INT 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 `student` ADD CONSTRAINT `FK_gradeid` FOREIGN KEY(`gradeid`) REFERENCES `grade`(`gradeid`); -- ALTER TABLE 表 ADD CONSTRAINT 约束名 FOREIGN KEY(作为外键的列) REFERENCES 哪个表(哪个字段)

以上操作都是物理外键,数据库级别的外键,不建议使用(避免数据库过多造成困扰)

最佳实践

  • 数据库就是单纯的表,只用来存储数据,只有行(数据)和列(字段)

  • 我们相使用多张表的数据,想使用外键(程序去实现)

2|7DML语言(全部记住)

2|8添加

insert

-- 插入语句(添加) -- INSERT INTO 表名 (字段名1,字段名2,字段名3) VALUES('值1'),('值2'),('值3') INSERT INTO `grade` (`gradename`) VALUES('大四') -- 一般写插入语句,我们呀数据和字段一一对应 INSERT INTO `grade` VALUES('2','大三') -- 插入多个字段 INSERT INTO `grade`(`gradename`) VALUES('大一'),('大二') INSERT INTO `student`(`name`,`pwd`,`sex`,`gradeid`) VALUES('张三','aaaaa','','3'),('王刚','12345678','','2')

语法:-- INSERT INTO 表名 (字段名1,字段名2,字段名3) VALUES('值1'),('值2'),('值3')

注意事项:

  1. 字段与字段之间使用逗号隔开

  2. 字段是可以省略的,但要一一对应

2|9修改

update 修改谁(条件) set 原来的值=新值

-- 修改学员名字,带了条件 UPDATE `student` SET `name`='韩信' WHERE id = 1; -- 不指定条件的情况下,会修改所有的表 UPDATE `student` SET `name`='狂铁'; -- 语法: -- UPDATE 表名 SET colnum_name = value,[colnum_name = value] WHERE 条件;

条件:where子句 运算符 id等于某个值,大于某个值,在某个区间内修改

操作符会返回 布尔值

操作符含义范围结果
=      
<>或!= 都是不等于    
>      
<      
<=      
>=      
betewwn......and..... 在某个范围内 [2,5]  
and   5>1 and 1>2 false
or   5>1 and 1>2 true
-- 通过多个条件定位数据 UPDATE student SET sex = '' WHERE gradeid = 2 AND sex = ''

注意:

  • colnum_name时数据库的列,尽量带上``

  • 条件,筛选的条件,若果没有指定,则会修改所有的列

  • value,是一个具体的值,也可以是一个变量

  • 多个设置的属性之间,使用逗号隔开

UPDATE student SET birthday = CURRENT_TIME WHERE `name`='阿珂'

2|10删除

delete命令

语法:delete from 表名 [where 条件]

-- 删除数据(避免这样写,会全部删除) DELETE FROM student -- 删除指定数据 DELETE FROM student WHERE id = ;

truncate命令

作用:完全清空一个数据库表,表的结构和索引约束不会变!

-- 清空studnet表 TRUNCATE TABLE student;

delete和truncate区别

  • 相同点:都能处理数据,都不会删除结构

  • 不同:

    • truncate 重新设置 自增列 计数器回归零

    • truncate 不会影响事务

delete删除的问题,重启数据库,现象:

  • innoDB 自增列重1开始 (存在内存当中的,断电即失)

  • MyISAM 继续从上一个子增量开始(存在文件中,不会丢失)

    3|04、DQL查询数据(最重点)

    3|1DQL

    (Data Query Language:数据查询语言)

    • 所有的查询操作都用它 select

    • 简单的查询,复杂的查询它都能做

    • 数据库中最核心的语言,最重要的语言

    • 使用频率最高的语句

    • select完整语句

    -- 查询全部的学生 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

    语法:select 字段, .... from 表

    有的时候,列名字不是南无的见明知意 我们起别名 。 as 字段名 as 别名 表名 as 别名

    去重 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 表

    3|2where条件子句

    作用:检索数据中符合条件的值

    搜索的条件有一个或者多个表达式组成!结果为布尔值

    逻辑运算符

    运算符语法描述
    and && a and b a&&b 逻辑与
    or || a or b a||b 一真则真
    not ! not a !a 逻辑非

    尽量使用英文字母

    -- 查询成绩大于95的数据 SELECT `studentno`,`studentresult` FROM result WHERE `studentresult`>=95 AND `studentresult`<=100 SELECT `studentno`,`studentresult` FROM result WHERE `studentresult`>=95 && `studentresult`<=100 -- 模糊查询(区间) SELECT `studentno`,`studentresult` FROM result WHERE `studentresult` BETWEEN 85 AND 100 -- 处理1000以外的成绩 SELECT `studentno`,`studentresult` FROM result WHERE NOT `studentno`= 1000 SELECT `studentno`,`studentresult` FROM result WHERE `studentno` != 1000

    模糊查询:比较运算符

    运算符语法描述
    is null a is null 判空
    is not null a is not null  
    between a between b and c  
    like a like b 可用% _
    in a in (a1,a2,a3) 在其中一个值,结果为true

     

    -- 查询姓刘的同学 -- like结合 %(代表0到人一个字符) _(一个字符)in不可以使用,因为In需要时具体值 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(具体的一个或者多个值) -- 查询在安徽的同学 SELECT `studentno`,`studentname` FROM `student` WHERE `Address` IN ('安徽','河南洛阳') -- null not null -- 查询地址为空 null '' SELECT `studentno`,`studentname` FROM `student` WHERE `Address` IS NULL OR `Address`='' -- 查询没有出生日期的同学 为空 SELECT `studentno`,`studentname` FROM `student` WHERE `BornDate` IS NULL

    联接查询join

    -- ====================联表查询join======================== -- 查询参加了考试的同学(学号,姓名,科目编号,分数) SELECT * FROM student SELECT * FROM result /*思路 1,分析需求,分析查询的子短短来自哪些表,(连接查询) 2,去欸的那个使用哪种来连接查询? 7种 去欸的那个交叉点(这两个表张哪个数据是相同的) 判断的条件:学生表的中studentNo = 成绩表 studentNo */ -- 内连接 inner join 查询两个表中的结果集中的交集 -- 外连接 outer join /* 左外连接 left join (以左表作为基准,右边表来一一匹配,匹配不上的,返回左表的记录,右表以NULL填充) 右外连接 right join */ -- join(链接的表) on(的条件) -- where 等值查询 SELECT s.studentNo,studentName,SubjectNo,StudentResult FROM student AS s INNER JOIN result AS r WHERE s.studentNo = r.studentNo SELECT s.studentNo,studentName,SubjectNo,StudentResult INNER JOIN result AS r ON s.studentNo = r.studentNo -- right join SELECT s.studentNo,studentName,SubjectNo,StudentResult FROM student s 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 ON s.studentNo=r.studentNo WHERE r.studentResult IS NULL -- 查询了参加考试的同学信息;学号,学生姓名,学科名,分数 SELECT s.studentno,studentname,subjectname,StudentResult FROM student s INNER JOIN result r ON r.studentno = s.studentno INNER JOIN `subject` sub ON sub.subjectno = r.subjectno

    自连接

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

    -- 创建一个表 CREATE TABLE `category` ( `categoryid` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主题id', `pid` INT(10) NOT NULL COMMENT '父id', `categoryName` VARCHAR(50) NOT NULL COMMENT '主题名字', PRIMARY KEY (`categoryid`) ) ENGINE=INNODB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 -- 插入数据 INSERT INTO `category` (`categoryid`, `pid`, `categoryName`) VALUES('2','1','信息技术'), ('3','1','软件开发'), ('4','3','数据库'), ('5','1','美术设计'), ('6','3','web开发'), ('7','5','ps技术'), ('8','2','办公信息')

    父类

    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,`category` AS b WHERE a.categoryid=b.pid

    排序

    -- 排序:升序 ASC ,降序 DESC -- order by 通过哪个字段排序,怎么排 SELECT s.studentno,studentname,subjectname,StudentResult FROM student s INNER JOIN result r ON r.studentno = s.studentno INNER JOIN `subject` sub ON sub.subjectno = r.subjectno WHERE sub.subjectname='高等数学-2' ORDER BY StudentResult DESC -- 降序

    分页

    -- ====================分页=================== -- 100万条数据 -- 缓解数据库压力,给人的体验更好,对应为瀑布流 -- 分页,每页只显示五条数据 -- 语法:linit 起始值,页面的大小 -- 页面应用:当前 总的页数,页的大小 -- limit 0,5 1~5 -- limit 1,5 2~6 SELECT s.studentno,studentname,subjectname,StudentResult FROM student s INNER JOIN result r ON r.studentno = s.studentno INNER JOIN `subject` sub ON sub.subjectno = r.subjectno WHERE sub.subjectname='高等数学-2' ORDER BY StudentResult DESC -- 降序 LIMIT 0,5 -- 第N页 : limit (pageNo-1)*pageSzie,pageSzie -- [pageNo:页码,pageSize:单页面显示条数]

    子查询

    /*============== 子查询 ================ 什么是子查询? 在查询语句中的WHERE条件子句中,又嵌套了另一个查询语句 嵌套查询可由多个子查询组成,求解的方式是由里及外; 子查询返回的结果一般都是集合,故而建议使用IN关键字; */ -- 查询 数据库结构-1 的所有考试结果(学号,科目编号,成绩),并且成绩降序排列 -- 方法一:使用连接查询 SELECT studentno,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 subjectno=( SELECT subjectno FROM `subject` WHERE subjectname = '数据库结构-1' ) ORDER BY studentresult DESC; -- 查询课程为 高等数学-2 且分数不小于80分的学生的学号和姓名 -- 方法一:使用连接查询 SELECT s.studentno,studentname FROM student s INNER JOIN result r ON s.`StudentNo` = r.`StudentNo` INNER JOIN `subject` sub ON sub.`SubjectNo` = r.`SubjectNo` WHERE subjectname = '高等数学-2' AND StudentResult>=80 -- 方法二:使用连接查询+子查询 -- 分数不小于80分的学生的学号和姓名 SELECT r.studentno,studentname FROM student s INNER JOIN result r ON s.`StudentNo`=r.`StudentNo` WHERE StudentResult>=80 -- 在上面SQL基础上,添加需求:课程为 高等数学-2 SELECT r.studentno,studentname FROM student s INNER JOIN result r ON s.`StudentNo`=r.`StudentNo` WHERE StudentResult>=80 AND subjectno=( SELECT subjectno FROM `subject` WHERE subjectname = '高等数学-2' ) -- 方法三:使用子查询 -- 分步写简单sql语句,然后将其嵌套起来 SELECT studentno,studentname FROM student WHERE studentno IN( SELECT studentno FROM result WHERE StudentResult>=80 AND subjectno=( SELECT subjectno FROM `subject` WHERE subjectname = '高等数学-2' ) )

    分组查询

    -- 查询不同课程的平均分,最高分,最低分 -- 核心:(根据不同的课程分组) SELECT subjectname, AVG(`studentResult`) 平均分,MAX(`studentResult`),MIN(`studentResult`) FROM result r INNER JOIN `subject` sub ON r.subjectno=sub.subjectno GROUP BY sub.subjectno HAVING 平均分>=70

    4|0MySQL函数

    4|1常用函数

    -- ============常用函数============== -- 数学运算 SELECT ABS(-8) -- 绝对值 SELECT CEILING(9.4) -- 向上取整 SELECT FLOOR(9.4) -- 向下取整 SELECT RAND() -- 返回一个0~1之间的随机数 SELECT SIGN(10) -- 判断一个数的符号 0-0,负数返回-1,正数返回1 -- 字符串函数 SELECT CHAR_LENGTH('即使再小的他妈的') -- 字符串的长度 SELECT CONCAT('','''丢你','老牟') -- 拼接字符串 SELECT INSERT('你是个呆瓜'1,2,'我是') -- 从某个位置开始替换字符串 SELECT LOWER('kuangshen') -- 小写 SELECT UPPER('kuangshen') -- 大写 SELECT INSTR('kuangshen','h') -- 返回第一次出现的索引位置 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 VERSION(); /*版本*/ SELECT USER(); /*用户*/

    4|2聚合函数(常用)

    函数名称描述
    count() 计数
    sum() 求和
    avg() 平均值
    max() 最大值
    min() 最小值
    ........... ...........
    SELECT COUNT(`BornDate`) FROM student; -- count(字段),会忽略null值 SELECT COUNT(*) FROM student; -- count(*),不会忽略null 本质 计算行数 SELECT COUNT(1) FROM student; -- count(*),不会忽略null 本质 计算行数 SELECT SUM(`studentResult`) AS 总和 FROM result SELECT AVG(`studentResult`) AS 平均数 FROM result SELECT MAX(`studentResult`) AS 最高分 FROM result SELECT MIN(`studentResult`) AS 最低分 FROM result -- 查询不同课程的平均分,最高分,最低分 -- 核心:(根据不同的课程分组) SELECT subjectname, AVG(`studentResult`) 平均分,MAX(`studentResult`),MIN(`studentResult`) FROM result r INNER JOIN `subject` sub ON r.subjectno=sub.subjectno GROUP BY sub.subjectno HAVING 平均分>=70

    4|3数据库级别的MD5加密

    什么是MD5?

    主要增强算法复杂度和不可逆性

    MD5不可逆,具体的值的md5是一样的

    MD5破解网站的原理,背后有一个字典,MD5加密后的值,加密前的值

    -- ===============MD5======================= CREATE TABLE testMD5 ( `id` INT(4) NOT NULL, `name` VARCHAR(20) NOT NULL, `pwd` VARCHAR(50) NOT NULL, PRIMARY KEY(`id`) )ENGINE=INNODB CHARSET=utf8 -- 明文密码 INSERT INTO testmd5 VALUES(1,'zhangsan','123456'),(2,'lisi','123456'),(3,'wangwu','123456') -- 加密 UPDATE testmd5 SET pwd=MD5(pwd) WHERE id=1; -- 插入时加密 INSERT INTO testmd5 VALUES(4,'xiaoming',MD5('123456')) -- 如何校验,将用户传递进来的密码,进行MD5加密,然后对比加密后的值 SELECT * FROM testmd5 WHERE pwd=MD5('123456')

    5|0事务

    5|1什么是事务

    要么都成功,要么都失败

    1,SQL执行,A给B转账 A1000 --->200 B200

    2,SQL执行 B收到A的钱 A800 ----> B400


    将一组SQL放在一个批次中去执行

    事务原则:ACID原则 原子性 一致性 隔离性 持久性 (脏读)(幻读)……

    参考博客:事务ACID理解dengjili的博客-CSDN博客acid

    原子性(Atomicity)

    事务中的操作要么都发生,要么都不发生

    一致性(Consistency)

    事务前后数据的完整性必须保持一致

    隔离性(Isolation)

    多个并发事务之间要相互隔离

    持久性(Durability)

    持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响

    隔离所导致的一些问题

    脏读:

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

    不可重复读:

    在一个事务内读取表中的某一行数据,多次读取结果不同。(这个不一定是错误,只是某些场合不对)

    虚读(幻读):

    是指在一个事务内读取到了别的事务插入的数据,导致前后读取数量总量不一致

    -- =====================事务======================== -- MySQL是默认开启事务自动提交的 SET autocommit = 0; /*关闭*/ SET autocommit = 1; /*开启*/ -- 手动处理事务 -- 事务开启 START TRANSACTION -- 标记一个事务的开始,从这个之后的sql都子啊同一个事务内 INSERT XX INSERT XX -- 事务结束 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(4) NOT NULL AUTO_INCREMENT, `name` VARCHAR(30) NOT NULL, `money` DECIMAL(9,2) NOT NULL, PRIMARY KEY(`id`) )ENGINE=INNODB CHARSET=utf8 ALTER TABLE accunt RENAME AS account 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 = 1; -- 回复默认值

    6|0索引

    MySQL官方对索引的定义:索引(index)是帮助MySQL高效获取数据的数据结构。0.5s 0.00001s 提取句子主干,就可以得到索引的本质:索引是数据结构

    7.1、索引的分类

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

    • 主键索引(primary key)

      • 唯一的标识,主键不可重复,只能有一个列作为主键

    • 唯一索引(unique key)

      • 避免重复的列出现,唯一索引可以重复,多个列都可以标识位 唯一索引

    • 常规索引(key/index)

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

    • 全文索引(fulltext)

      • 快速定位数据

      • 在特定的数据库引擎下才有

    -- 索引的使用 -- 1,在创建表的死后给字段增加索引 -- 2,创建完毕后,增加索引 -- 显示所有的索引信息 SHOW INDEX FROM student -- 增加一个全文索引 索引名(列名) ALTER TABLE student ADD FULLTEXT `studentname`(`studentname`) -- explain 分析sql执行的状况 EXPLAIN SELECT * FROM student; -- 非全文索引 EXPLAIN SELECT * FROM student WHERE MATCH(studentname) AGAINST('');

    6|1测试索引

    -- 插入一百万条数据 DELIMITER $$ -- 写函数之前必须写,标志 CREATE FUNCTION mock_data() 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),'2778408452@qq.com',CONCAT('18',FLOOR((RAND()*(999999999-100000000)+1000000000))), FLOOR(RAND()*2),UUID(),FLOOR(RAND()*100)); SET i = i+1; END WHILE; RETURN i; END; SELECT mock_data(); -- 执行函数 DROP FUNCTION mock_data; -- 删除函数 SELECT * FROM app_user WHERE `name`='用户9999'; -- 2.510 sec SELECT * FROM app_user WHERE `name`='用户9999'; -- 2.233 sec SELECT * FROM app_user WHERE `name`='用户9999'; -- 2.199 sec EXPLAIN SELECT * FROM app_user WHERE `name`='用户9999'; -- id_表名_字段名 -- create index 索引名 0n 表(字段) CREATE INDEX id_app_user ON app_user(`name`) SELECT * FROM app_user WHERE `name` = '用户9999'; -- 0.106 sec SELECT * FROM app_user WHERE `name` = '用户9999'; -- 0 sec SELECT * FROM app_user WHERE `name` = '用户9999'; -- 0 sec EXPLAIN SELECT * FROM app_user WHERE `name` = '用户9999';

    6|2索引原则

    • 索引不是越多越好

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

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

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

    索引的数据结构

    Hash类型的索引

    Btree:InnoDB的默认数据结构~

    阅读:http://blog.codinglabs.org/articles/theory-of-mysql-index.html

    7|0权限管理和备份

    7|1用户管理

    7|2MySQL备份

    为什么要备份:

    • 保证重要的数据不丢失

    • 数据转移

    MySQL数据库备份的方式

    • 直接拷贝物理文件

    • 在sqlyog这种可视化工具中手动导出

      • 在想要导出的表或者库中,右键,选择备份或导出

    • 使用命令行导出 mysqldump 命令行使用

    -- mysqldump -h主机 -u用户名 -p密码 数据库 表名>物理磁盘位置\文件名 C:\WINDOWS\system32>mysqldump -hlocalhost -uroot -p123456 school student >F:\个人资料(C盘移动)\桌面\a.sql -- mysqldump -h主机 -u用户名 -p密码 数据库 表1 表2>物理磁盘位置\文件名 C:\WINDOWS\system32>mysqldump -hlocalhost -uroot -p123456 school student result >F:\个人资料(C盘移动)\桌面\b.sql -- mysqldump -h主机 -u用户名 -p密码 数据库 >物理磁盘位置\文件名 C:\WINDOWS\system32>mysqldump -hlocalhost -uroot -p123456 school >F:\个人资料(C盘移动)\桌面\c.sql -- 导入 -- 在登录的情况下,切换到指定的数据库 source F:\个人资料(C盘移动)\桌面\a.sql -- 或者 mysql -u用户名 -p密码 库名<备份文件

    假如你要备份数据库,防止数据丢失

    把数据库给朋友, sql文件传给别人即可

    8|0规范数据设计

    8|1为什么需要设计

    糟糕的数据可设计

    良好的数据库设计

    三大范式

    第一范式(1NF)

    原子性:保证每一列不可再分

    第二范式(2NF)

    前提:满足第一范式

    每张表只描述一件事

    第三范式(3NF)

    前提:满足第一范式和第二范式

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

    (规范数据库的设计)

    规范性性能的问题

    关联查询的表不能超过三张表

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

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

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

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

    9|0JDBC(重点)

    9|1数据库驱动

    驱动:显卡,声卡,数据库

    我们的程序会通过数据库驱动,和数据库打交道

    9|2JDBC

    SUN公司为了简化开发人员的(对数据库的统一)操作,提供了一个(Java操作数据库的)规范,俗称JDBC。这些规范的事件有具体的厂商去做~

    java.sql

    javax.sql

    还需要导入一个数据库驱动包

    9|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','zhangsan','123456','zs@sina.com','1980-12-04'), ('2','lisi','123456','lisi@sina.com','1981-12-04'), ('3','wangwu','123456','wangwu@sina.com','1979-12-04')

    1,创建一个普通项目

    2,导入数据库驱动

    3,编写测试代码

    package com.study.day01; import java.sql.*; //我的第一个JDBC程序 public class jdbcFirstDemo { public static void main(String[] args) throws ClassNotFoundException, SQLException { //1,加载驱动 Class.forName("com.mysql.cj.jdbc.Driver");//固定写法,加载驱动 //2,用户信息和url String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8"; String username = "root"; String password = "123456"; //3,连接成功,数据库对象 Connection connection = DriverManager.getConnection(url, username, password); //4,执行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. 释放连接

    DiverManager

    Class.forName("com.mysql.jdbc.Diver");//固定写法,加载驱动 Connection connection = DriverManager.getConnection(url, username, password); //connection 代表数据库 //数据库设置自动提交 //事务提交 //事务滚回 connection.rollback(); connection.commit(); connection.setAutoCommit();

    URL

    String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8"; //mysql -- 3306 //协议://主机地址:端口号//数据库名?参数1&参数2&参数3 //oralce -- 1521 //jdbc:oracle:thin:@localhost:1521:sid

    Statement执行SQL的对象 PrepareStatement执行SQL的对象

    String sql = "select * from users"; statement.executeQuery();//查询操作返回ResultSet statement.execute();//查询任何sql statement.executeUpdate();//更新,插入,删除。都是用这个,返回一个受影响的行数

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

    获得指定的数据类型

    resultSet.getObject();//在不知道列类型的情况下使用 //如果知道列类型就是用指定的类型 resultSet.getString(); resultSet.getInt(); resultSet.getFloat(); resultSet.getDate(); ……

    遍历,指针

    resultSet.beforeFirst();//移动到最前面 resultSet.afterLast();//移动到最后面 resultSet.next();//移动到下一个数据 resultSet.previous();//移动到前一行 resultSet.absolute(row);//移动到指定行

    释放连接

    resultSet.close(); statement.close(); connection.close();//耗资源 使用完关闭

    代码实现

    1.提取工具类

     
    1 package com.study.day02.utils; 2 3 import java.io.InputStream; 4 import java.sql.*; 5 import java.util.Properties; 6 7 public class JdbcUtils { 8 private static String driver = null; 9 private static String url = null; 10 private static String username = null; 11 private static String password = null; 12 static{ 13 try{ 14 InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties"); 15 Properties properties = new Properties(); 16 properties.load(in); 17 18 driver = properties.getProperty("driver"); 19 url = properties.getProperty("url"); 20 username = properties.getProperty("username"); 21 password = properties.getProperty("password"); 22 //1,驱动只用加载一次 23 Class.forName(driver); 24 } catch (Exception e) { 25 e.printStackTrace(); 26 } 27 } 28 29 //获取连接 30 public static Connection getConnection() throws SQLException { 31 return DriverManager.getConnection(url,username,password); 32 } 33 34 //释放连接资源 35 public static void release(Connection conn,Statement st,ResultSet rs){ 36 if(rs!=null){ 37 try { 38 rs.close(); 39 } catch (SQLException e) { 40 e.printStackTrace(); 41 } 42 } 43 if(st!=null){ 44 try { 45 st.close(); 46 } catch (SQLException e) { 47 e.printStackTrace(); 48 } 49 } 50 if(conn!=null){ 51 try { 52 conn.close(); 53 } catch (SQLException e) { 54 e.printStackTrace(); 55 } 56 } 57 } 58 }

    2,编写增删改

    1 package com.study.day02; 2 3 import com.study.day02.utils.JdbcUtils; 4 5 import java.sql.Connection; 6 import java.sql.ResultSet; 7 import java.sql.SQLException; 8 import java.sql.Statement; 9 10 public class TestInsert { 11 public static void main(String[] args) { 12 Connection conn = null; 13 Statement st = null; 14 ResultSet rs = null; 15 try { 16 conn = JdbcUtils.getConnection();//获取数据库连接 17 st = conn.createStatement();//获取SQL的执行对象 18 String sql = "INSERT INTO users(`id`,`name`,`password`,`email`,`birthday`)" + 19 "VALUES(4,'kuangshen','123456','2784234567@qq.com','2022-01-01')"; 20 int i = st.executeUpdate(sql); 21 if(i>0){ 22 System.out.println("插入成功!"); 23 } 24 } catch (SQLException e) { 25 e.printStackTrace(); 26 }finally { 27 JdbcUtils.release(conn,st,rs); 28 } 29 30 } 31 } 32 package com.study.day02; 33 34 import com.study.day02.utils.JdbcUtils; 35 36 import java.sql.Connection; 37 import java.sql.ResultSet; 38 import java.sql.SQLException; 39 import java.sql.Statement; 40 41 public class TestUpdate { 42 public static void main(String[] args) { 43 Connection conn = null; 44 Statement st = null; 45 ResultSet rs = null; 46 try { 47 conn = JdbcUtils.getConnection();//获取数据库连接 48 st = conn.createStatement();//获取SQL的执行对象 49 String sql = "UPDATE users SET `name`='kuangshen',`password`='654321' WHERE id=1"; 50 int i = st.executeUpdate(sql); 51 if(i>0){ 52 System.out.println("更新成功!"); 53 } 54 } catch (SQLException e) { 55 e.printStackTrace(); 56 }finally { 57 JdbcUtils.release(conn,st,rs); 58 } 59 60 } 61 } 62 package com.study.day02; 63 64 import com.study.day02.utils.JdbcUtils; 65 66 import java.sql.Connection; 67 import java.sql.ResultSet; 68 import java.sql.SQLException; 69 import java.sql.Statement; 70 71 public class TestDelete { 72 public static void main(String[] args) { 73 Connection conn = null; 74 Statement st = null; 75 ResultSet rs = null; 76 try { 77 conn = JdbcUtils.getConnection();//获取数据库连接 78 st = conn.createStatement();//获取SQL的执行对象 79 String sql = "DELETE FROM users WHERE id =4"; 80 int i = st.executeUpdate(sql); 81 if(i>0){ 82 System.out.println("删除成功!"); 83 } 84 } catch (SQLException e) { 85 e.printStackTrace(); 86 }finally { 87 JdbcUtils.release(conn,st,rs); 88 } 89 90 } 91 } 92 3,查询 93 94 package com.study.day02; 95 96 import com.study.day02.utils.JdbcUtils; 97 98 import java.sql.Connection; 99 import java.sql.ResultSet; 100 import java.sql.SQLException; 101 import java.sql.Statement; 102 103 public class TestSelect { 104 public static void main(String[] args) { 105 Connection conn = null; 106 Statement st = null; 107 ResultSet rs = null; 108 try { 109 conn = JdbcUtils.getConnection();//获取数据库连接 110 st = conn.createStatement();//获取SQL的执行对象 111 String sql = "select * from users where id = 1"; 112 rs = st.executeQuery(sql); 113 while(rs.next()){ 114 System.out.println(rs.getString("name")); 115 } 116 } catch (SQLException e) { 117 e.printStackTrace(); 118 }finally { 119 JdbcUtils.release(conn,st,rs); 120 } 121 122 } 123 }

    SQL 注入问题

    1 package com.study.day02; 2 3 import com.study.day02.utils.JdbcUtils; 4 5 import java.sql.Connection; 6 import java.sql.ResultSet; 7 import java.sql.SQLException; 8 import java.sql.Statement; 9 10 public class SQL注入 { 11 public static void main(String[] args) { 12 Login("kuangshen","123456"); 13 } 14 15 public static void Login(String username,String password){ 16 Connection conn = null; 17 Statement st = null; 18 ResultSet rs = null; 19 try { 20 conn = JdbcUtils.getConnection();//获取数据库连接 21 st = conn.createStatement();//获取SQL的执行对象 22 23 // SELECT * FROM users WHERE `name`='kuangshen' AND `password`='123456' 24 String sql = "select * from users where `name`='"+username+"' and `password`='"+password+"'"; 25 rs = st.executeQuery(sql); 26 while(rs.next()){ 27 System.out.println(rs.getString("name")); 28 System.out.println(rs.getString("password")); 29 System.out.println("========================================"); 30 } 31 } catch (SQLException e) { 32 e.printStackTrace(); 33 }finally { 34 JdbcUtils.release(conn,st,rs); 35 } 36 37 } 38 }

    9|4SQL注入

    sql存在漏洞,会被攻击导致数据泄露,SQL会被拼接or

    SELECT * FROM users WHERE name='' OR '1=1' AND password='' OR '1=1'

    1 package com.study.day02; 2 3 import com.study.day02.utils.JdbcUtils; 4 5 import java.sql.Connection; 6 import java.sql.ResultSet; 7 import java.sql.SQLException; 8 import java.sql.Statement; 9 10 public class SQL注入 { 11 public static void main(String[] args) { 12 //Login("kuangshen","123456"); 13 Login(" 'or '1=1"," 'or '1=1");//返回所有的用户和密码 14 } 15 16 public static void Login(String username,String password){ 17 Connection conn = null; 18 Statement st = null; 19 ResultSet rs = null; 20 try { 21 conn = JdbcUtils.getConnection();//获取数据库连接 22 st = conn.createStatement();//获取SQL的执行对象 23 24 // SELECT * FROM users WHERE `name`='kuangshen' AND `password`='123456' 25 String sql = "select * from users where `name`='"+username+"' and `password`='"+password+"'"; 26 rs = st.executeQuery(sql); 27 while(rs.next()){ 28 System.out.println(rs.getString("name")); 29 System.out.println(rs.getString("password")); 30 System.out.println("========================================"); 31 } 32 } catch (SQLException e) { 33 e.printStackTrace(); 34 }finally { 35 JdbcUtils.release(conn,st,rs); 36 } 37 38 } 39 }

    9|5PreparedStatrment对象

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

    1. 新增

    1 package com.study.day03; 2 3 import com.study.day02.utils.JdbcUtils; 4 import java.sql.Connection; 5 import java.sql.PreparedStatement; 6 import java.sql.SQLException; 7 import java.util.Date; 8 9 public class TestInsert { 10 public static void main(String[] args) { 11 Connection conn = null; 12 PreparedStatement st = null; 13 try { 14 conn = JdbcUtils.getConnection(); 15 //区别 16 //使用? 占位符代表参数 17 String sql = "insert into users(`id`,`name`,`password`,`email`,`birthday`) values(?,?,?,?,?)"; 18 st = conn.prepareStatement(sql);//预编译sql,先写sql,然后不执行 19 //手动参数赋值 20 st.setInt(1,4); 21 st.setString(2,"sunwukong"); 22 st.setString(3,"12345643"); 23 st.setString(4,"243576432@qq.com"); 24 st.setDate(5,new java.sql.Date(new Date().getTime())); 25 //执行 26 int i = st.executeUpdate(); 27 if(i>0){ 28 System.out.println("插入成功!"); 29 } 30 } catch (SQLException e) { 31 e.printStackTrace(); 32 }finally { 33 JdbcUtils.release(conn,st,null); 34 } 35 } 36 }

    2, 删除

    1 package com.study.day03; 2 3 import com.study.day02.utils.JdbcUtils; 4 5 import java.sql.Connection; 6 import java.sql.PreparedStatement; 7 import java.sql.SQLException; 8 import java.util.Date; 9 10 public class TestDelete { 11 public static void main(String[] args) { 12 Connection conn = null; 13 PreparedStatement st = null; 14 try { 15 conn = JdbcUtils.getConnection(); 16 String sql = "delete from users where id = ?"; 17 st = conn.prepareStatement(sql); 18 st.setInt(1,4); 19 int i = st.executeUpdate(); 20 if(i>0){ 21 System.out.println("删除成功!"); 22 } 23 } catch (SQLException e) { 24 e.printStackTrace(); 25 }finally { 26 JdbcUtils.release(conn,st,null); 27 } 28 } 29 }

    3,更新

    1 package com.study.day03; 2 3 import com.study.day02.utils.JdbcUtils; 4 5 import java.sql.Connection; 6 import java.sql.PreparedStatement; 7 import java.sql.SQLException; 8 import java.util.Date; 9 10 public class TestUpdate { 11 public static void main(String[] args) { 12 Connection conn = null; 13 PreparedStatement st = null; 14 try { 15 conn = JdbcUtils.getConnection(); 16 String sql = "update users set `name` = ? where id = ?;"; 17 st = conn.prepareStatement(sql); 18 st.setString(1,"wanglaowu"); 19 st.setInt(2,1); 20 int i = st.executeUpdate(); 21 if(i>0){ 22 System.out.println("更新成功!"); 23 } 24 } catch (SQLException e) { 25 e.printStackTrace(); 26 }finally { 27 JdbcUtils.release(conn,st,null); 28 } 29 } 30 }

    4,查询

    1 package com.study.day03; 2 3 import com.study.day02.utils.JdbcUtils; 4 5 import java.sql.Connection; 6 import java.sql.PreparedStatement; 7 import java.sql.ResultSet; 8 import java.sql.SQLException; 9 10 public class TestSelect { 11 public static void main(String[] args) { 12 Connection conn = null; 13 PreparedStatement st = null; 14 ResultSet rs = null; 15 try { 16 conn = JdbcUtils.getConnection(); 17 String sql = "select * from users where id = ?"; 18 st = conn.prepareStatement(sql); 19 st.setInt(1,1); 20 rs = st.executeQuery(); 21 while(rs.next()){ 22 System.out.println(rs.getString("name")); 23 } 24 } catch (SQLException e) { 25 e.printStackTrace(); 26 }finally { 27 JdbcUtils.release(conn,st,rs); 28 } 29 } 30 }

    SQL注入

    1 package com.study.day03; 2 3 import com.study.day02.utils.JdbcUtils; 4 import java.sql.PreparedStatement; 5 import java.sql.*; 6 7 public class SQL注入 { 8 public static void main(String[] args) { 9 Login("lisi","123456"); 10 //Login(" 'or '1=1"," 'or '1=1");//返回所有的用户和密码 11 } 12 13 public static void Login(String username,String password){ 14 Connection conn = null; 15 PreparedStatement st = null; 16 ResultSet rs = null; 17 try { 18 conn = JdbcUtils.getConnection();//获取数据库连接 19 // SELECT * FROM users WHERE `name`='kuangshen' AND `password`='123456' 20 String sql = "select * from users where `name`=? and `password` =?"; 21 st = conn.prepareStatement(sql);//获取SQL的执行对象 22 st.setString(1,username); 23 st.setString(2,password); 24 rs = st.executeQuery(); 25 while(rs.next()){ 26 System.out.println(rs.getString("name")); 27 System.out.println(rs.getString("password")); 28 System.out.println("========================================"); 29 } 30 } catch (SQLException e) { 31 e.printStackTrace(); 32 }finally { 33 JdbcUtils.release(conn,st,rs); 34 } 35 36 } 37 }

    9|6IDEA连接数据库

    9|7事务

    要么都成功,要么都失败

    ACID原则

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

    一致性:总数不变

    隔离性:多个进程互不影响

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

    隔离性的问题:

    脏读:一个事务读取了另一个没有提交的事务

    不可重复读:在同一个事务内,重复读取表中的数据,表数据发生了改变

    虚读(幻读):在一个事务内,读取到了别人插入的数据,导致前后读出来的结果不一致

    代码实现

    1. 开启事务 conn.setAutoCommit(false);

    2. 一组业务执行完毕,提交事务

    3. 可以在catch语句中显示的定义回滚语句,但默认失败就会回滚

    1 package com.study.day03; 2 3 import com.study.day02.utils.JdbcUtils; 4 5 import java.sql.Connection; 6 import java.sql.PreparedStatement; 7 import java.sql.ResultSet; 8 import java.sql.SQLException; 9 10 public class TestTransaction2 { 11 public static void main(String[] args) { 12 Connection conn = null; 13 PreparedStatement st = null; 14 ResultSet rs = null; 15 try { 16 conn = JdbcUtils.getConnection(); 17 conn.setAutoCommit(false); 18 String sql1 = "update account set money = money-100 where `NAME`='A'"; 19 st = conn.prepareStatement(sql1); 20 st.executeUpdate(); 21 int i = 1/0; //报错,转账过程出现错误,观察是否会回滚 22 String sql2 = "update account set money = money+100 where `NAME`='B'"; 23 st = conn.prepareStatement(sql2); 24 st.executeUpdate(); 25 26 //业务完毕,提交事务 27 conn.commit(); 28 System.out.println("转账成功!"); 29 st.executeUpdate(); 30 } catch (SQLException e) { 31 //其实不写也会默认回滚 32 try { 33 conn.rollback();//如果失败,就回滚事务 34 } catch (SQLException ex) { 35 ex.printStackTrace(); 36 } 37 e.printStackTrace(); 38 }finally { 39 JdbcUtils.release(conn,st,rs); 40 } 41 } 42 }

    9|8数据库连接池

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

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

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

    最小连接数:10

    最大连接数:15

    等待超时:100ms

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

    开源数据源实现

    DBCP

    1 package com.study.day04; 2 3 import com.study.day02.utils.JdbcUtils; 4 import com.study.day04.utils.JdbcUtils_dbcp; 5 6 import java.sql.Connection; 7 import java.sql.ResultSet; 8 import java.sql.SQLException; 9 import java.sql.Statement; 10 11 public class TestDbcp { 12 public static void main(String[] args) { 13 Connection conn = null; 14 Statement st = null; 15 ResultSet rs = null; 16 try { 17 conn = JdbcUtils_dbcp.getConnection();//获取数据库连接 18 st = conn.createStatement();//获取SQL的执行对象 19 String sql = "INSERT INTO users(`id`,`name`,`password`,`email`,`birthday`)" + 20 "VALUES(4,'kuangshen','123456','2784234567@qq.com','2022-01-01')"; 21 int i = st.executeUpdate(sql); 22 if(i>0){ 23 System.out.println("插入成功!"); 24 } 25 } catch (SQLException e) { 26 e.printStackTrace(); 27 }finally { 28 JdbcUtils_dbcp.release(conn,st,rs); 29 } 30 31 32 } 33

    C3P0

    1 package com.study.day04; 2 3 import com.study.day04.utils.JdbcUtils_C3p0; 4 import com.study.day04.utils.JdbcUtils_dbcp; 5 6 import java.sql.Connection; 7 import java.sql.ResultSet; 8 import java.sql.SQLException; 9 import java.sql.Statement; 10 11 public class TestC3p0 { 12 public static void main(String[] args) { 13 Connection conn = null; 14 Statement st = null; 15 ResultSet rs = null; 16 try { 17 conn = JdbcUtils_C3p0.getConnection();//获取数据库连接 18 st = conn.createStatement();//获取SQL的执行对象 19 String sql = "INSERT INTO users(`id`,`name`,`password`,`email`,`birthday`)" + 20 "VALUES(5,'bajie','123456','2784234567@qq.com','2022-01-01')"; 21 int i = st.executeUpdate(sql); 22 if(i>0){ 23 System.out.println("插入成功!"); 24 } 25 } catch (SQLException e) { 26 e.printStackTrace(); 27 }finally { 28 JdbcUtils_C3p0.release(conn,st,rs); 29 } 30 31 32 } 33

    Druid:阿里巴巴

    使用了连接数据库连接池之后,我们在项目开发中就不需要编写连接数据库的代码了。

    结论

    无论使用什么数据源,本质还是一样的,DataSource接口不会变


__EOF__

本文作者冰山醉酒
本文链接https://www.cnblogs.com/douFrank/p/16117965.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   冰山醉酒  阅读(104)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
点击右上角即可分享
微信分享提示