MySQL

MySQL

初识MySQL

JavaEE:企业级Java开发 Web

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

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

数据库(存数据,txt,Excel,word)

只会写代码,学好数据库,基本混饭吃;

操作系统,数据结构与算法! 当一个不错的程序猿!

离散数学,数字电路,体系结构,编译原理。+实战经验,高级程序猿 优秀的程序猿

什么是数据库

数据库(DB,DataBase)

概念:数据仓库,软件,安装在操作系统( window ,linux, mac、…)之上! SQL,可以存储大量的数据。500万!

作用:存储数据,管理数据

数据库分类

关系型数据库:(SQL)

  • MySQL,Oracle,Sql Server,DB2,SQLlite
  • 通过表和表之间,行和列之间的关系进行数据的存储,学员信息表,考勤表,……

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

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

DBMS(数据库管理系统)

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

MySQL安装建议

  • 尽量不要使用exe,注册表
  • 尽可能使用压缩包安装~
  • 最好选5.7版本

安装MySQL

  • 官网下载地址

  • 下载压缩版

  • 解压到自己想要安装到的目录,本人解压到的是G:\JavaSE\mysql-5.7.38

  • 添加环境变量

    1. 我的电脑->属性->高级->环境变量

    2. 选择PATH,在其后面添加:你的mysql安装文件下面的bin文件夹

    3. 在G:\JavaSE\mysql-5.7.38下新建my.ini文件

    4. 编辑my.ini文件,注意替换路径位置

      [mysqld]
      #目录换成自己安装的目录
      basedir=G:\JavaSE\mysql-5.7.38\
      #data文件夹会自动生成,不需要手动建文件夹
      datadir=G:\JavaSE\mysql-5.7.38\data\
      #端口号
      port=3306
      #跳过密码验证
      skip-grant-tables
      #设置默认字符集编码
      #character-set-server=utf8
      
    5. 启动管理员模式下的CMD,并将路径切换至mysql 下的bin目录

      cd /d G:\JavaSE\mysql-5.7.38\bin
      
    6. 然后输入mysqld -install (安装mysql)

      mysqld -install
      
    7. 再输入下面代码,初始化数据文件

      mysqld --initialize-insecure --user=mysql
      
    8. 然后再次启动mysql

      net start mysql
      
    9. 然后用命令mysql -u root -p进入mysql管理界面(密码可为空)

      mysql -u root -p
      
    10. 看到Enter password:时,不要输入任何内容,直接回车

    11. 进入界面后更改root密码

      update mysql.user set authentication_string=password('123456') where user='root' and Host = 'localhost';
      
    12. 最后输入下面代码刷新权限

      flush privileges;
      
    13. 修改my.ini文件skip-grant-tables前加一个#号

    14. 退出mysql

      exit
      
    15. 重启mysql即可正常使用

      #关闭
      net stop mysql
      #启动
      net start mysql
      
    16. 连接上测试

      mysql -u root -p
      #出现Enter password:,就输入之前设置的密码
      
    17. 出现以下结果就安装好了

    MySQL_第1张图片

卸载MySQL

#停止mysql服务
net stop mysql
#卸载mysql
mysql remove
#清空服务
sc delete mysql

安装MySQL可视化软件:SQLyog

  • SQLyog下载

  • 安装好后运行输入名称,和证书密钥(注册码序列号)

  • 名称:英文随便命名

  • 证书密钥:

8d8120df-a5c3-4989-8f47-5afc79c56e7c

MySQL_第2张图片

  • 点击连接,完成

简单使用

  • 新建一个数据库school:

MySQL_第3张图片

每一个sqlyog的执行操作,本质就是对应了一个sql,可以在软件的历史记录中查看

  • 新建一张表student
字段:  id,name,age

MySQL_第4张图片

  • 查看表

    • 右键点击表名,打开表

    MySQL_第5张图片

连接数据库

命令行连接

#关闭
net stop mysql
#启动
net start mysql

mysql -u root -p123456  -- 连接数据库

update mysql.user set authentication_string=password('123456') where user='root' and Host = 'localhost'; -- 修改用户密码
flush privileges;  -- 刷新权限

---------------------
-- 所有的语句都使用;结尾
show databases; -- 查询所有的数据库

-- mysql> 中写:
use school -- 切换数据库 use 数据库名
Database changed

show tables;  -- 查看数据库中所有的表
describe student; -- 显示student数据库中所有的表的信息

create database westos; -- 创建一个数据库

exit; -- 退出连接

-- 单行注释(SQL的本来的注释)
/*  (sql的多行注释)
hello
*/

数据库xxx语言 CRUD增删改查! CV程序员 API程序员 CRUD程序员(业务)

  • DDL 定义
  • DML 操作
  • DQL 查询
  • DCL 控制

操作数据库

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

了解:操作一次就行

精通:背下来

操作数据库(了解)

  • 1、创建数据库

创建名为westos的数据库,[]里的代码可以省略

CREATE DATABASE [IF NOT EXISTS] westos;
  • 2、删除数据库

删除westos数据库

DROP DATABASE [IF EXISTS] westos
  • 3、使用数据库

使用school数据库

-- ``在 tab 键的上面,如果你的表名或者字段名是一个特殊字符,就需要带``
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 常用的变量 String
  • tinytext 微型文本 2^8 - 1
  • text 文本串 2^16 - 1 保存大文本

时间日期

java.util.Date

  • date YYYY-MM-DD , 日期
  • time HH:mm:ss , 时间格式
  • datetime 时间戳, 1970.1.1 到现在的毫秒数! 也较为常用!
  • year 年份表示

null

  • 没有值,未知
  • 注意,不要使用NULL进行运算,结果为NULL

数据库的字段属性(重点)

Unsigned:

  • 无符号的整数
  • 声明了该列不能声明为负数

zerofill:

  • 0填充的
  • 不足的位数,使用0来填充, int (3) , 5 — 005

自增:

  • 通常理解为自增,自动在上一条记录的基础上+1 (默认)
  • 通常用来设计唯—的主键~ index,必须是整数类型
  • 可以自定义设计主键自增的起始值和步长

非空 NUII not null

  • 假设设置为not null ,如果不给它赋值,就会报错!
  • NUII,如果不填写值,默认就是null!

默认:

  • 设置默认的值!
  • sex,默认值为男,如果不指定该列的值,则会有默认的值!

拓展:

/*  每一个表,都必须存在以下五个字段!未来做项目用的,表示一个记录存在意义!
id  主键
`version`  乐观锁
is_delete  伪删除
gmt_create  创建时间
gmt_update  修改时间
*/

创建数据库表(重点)

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

-- 注意点,使用英文(),表的名称 和 字段尽量使用 `` 括起来
-- AUTO_INCREMENT  自增
-- 字符串使用单引号括起来!
-- 所有的语句后面加,(英文的),最后一个不用加
-- 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] `表名`(
	`字段名` 列类型 [属性] [索引] [注释], 
    `字段名` 列类型 [属性] [索引] [注释], 
    ......
    `字段名` 列类型 [属性] [索引] [注释]
)[表类型][字符集设置][注释]

常用命令

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

数据表的类型

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

常规使用操作:

  • MYISAM:节约空间,速度较快
  • INNODB:安全性高,事务的处理,多表多用户操作

在物理空间存在的位置

所有的数据库文件都存在data目录下

本质还是文件的存储!

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

  • InnoDB:在数据库表中只有一个*.frm文件,以及上级目录下的ibdata1文件
  • MYISAM 对应文件
    • *.frm 表结构的定义文件
    • *.MYD 数据文件(data)
    • *.MYI 索引文件( index)

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

CHARSET=utf8

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

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

在my.ini中配置默认的编码

character-set-server=utf8

修改删除表

修改

-- 修改表名:  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 表名 MODIFY 旧字段名 新字段名
ALTER TABLE teacher1 MODIFY age VARCHAR(11) -- 修改约束
ALTER TABLE teacher1 CHANGE age age1 INT(2) -- 字段重名名

删除

-- 删除表的字段: ALTER TABLE 表名 DROP 字段名
ALTER TABLE teacher1 DROP age1

-- 删除表(如果表存在再册删除): DROP TABLE IF EXISTS 表名
DROP TABLE IF EXISTS teacher1

所有的创建和删除操作尽量加上判断,以免报错~

注意点:

  • `` 字段名,使用这个包裹!
  • 注释 – /**/
  • sql关键字大小写不敏感,建议大家写小写
  • 所有的符号全部用英文!

MySQL数据管理

外键(了解)

方式一、在创建表的时候,增加约束(麻烦,比较复杂)

CREATE TABLE `grade`(
	`gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT '年级id',
	`gradename` VARCHAR(50) NOT NULL COMMENT '年级名称',
	PRIMARY KEY(`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8

-- 学生表的 gradeid 字段 要去引用年级表的 gradeid
-- 定义外键key
-- 给这个外键添加约束 (执行引用) references 引用
CREATE TABLE IF NOT EXISTS `student`(
	`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
	`name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
	`pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密码',
	`sex` VARCHAR(2) NOT NULL DEFAULT '女' COMMENT '性别',
	`birthday` DATETIME DEFAULT NULL COMMENT '出生日期',
	`gradeid` INT(10) NOT NULL COMMENT '学生的年级',
	`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',
	`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
	PRIMARY KEY(`id`),
	KEY `FK_gradeid` (`gradeid`),
    CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade`(`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8

删除有外键关系的表的时候,必须要先删除引用别人的表(从表),再删除被引用的表(主表)

方式二∶创建表成功后,添加外键约束

CREATE TABLE `grade`(
	`gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT '年级id',
	`gradename` VARCHAR(50) NOT NULL COMMENT '年级名称',
	PRIMARY KEY(`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8

-- 学生表的 gradeid 字段 要去引用年级表的 gradeid
-- 定义外键key
-- 给这个外键添加约束 (执行引用) references 引用
CREATE TABLE IF NOT EXISTS `student`(
	`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
	`name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
	`pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密码',
	`sex` VARCHAR(2) NOT NULL DEFAULT '女' COMMENT '性别',
	`birthday` DATETIME DEFAULT NULL COMMENT '出生日期',
	`gradeid` INT(10) NOT NULL COMMENT '学生的年级',
	`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',
	`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 哪个表(哪个字段);

以上的操作都是物理外键,数据库级别的外键,我们不建议使用!(避免数据库过多造成困扰,这里了解即可~)

最佳实践

  • 数据库就是单纯的表,只用来存数据,只有行(数据)和列(字段)
  • 我们想使用多张表的数据,想使用外键(程序去实现)

DML语言(全部记住)

数据库意义:数据存储,数据管理

DML语言:数据操作语言

  • Insert
  • update
  • delete

添加

insert

-- 插入语句(添加)
-- insert into 表名([字段名1,字段名2,字段名3])values('值1'),('值2'),('值3'),(...)
INSERT INTO `grade`(`gradename`)VALUES('大三')
-- 由于主键自增我们可以省略 (如果不写表的字段,他就会一一匹配)
-- 一般写插入语句,我们一定要数据利和字段一一对应!
-- 插入多个字段
INSERT INTO `grade`(`gradename`) VALUES('大二'),('大一')

INSERT INTO `student`(`name`) VALUES('张三')

INSERT INTO `student`(`name`,`pwd`,`sex`) VALUES('张三','123','男')

INSERT INTO `student`(`name`,`pwd`,`sex`) VALUES('张三','123','男'),('李四','1234','女'),('王五','12345','男')

INSERT INTO `student` VALUES(6,'张三','123','男','2000-01-01',1,'重庆','email')

语法:insert into 表名([字段名1,字段名2,字段名3])values('值1'),('值2'),('值3'),(...)

注意事项:

  1. 字段和字段之间使用英文逗号隔开
  2. 字段是可以省略的,但是后面的值必须要要——对应,不能少
  3. 可以同时插入多条数据,VALUES 后面的值,需要使用,隔开即可 VALUES(),(),...

修改

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

-- 修改学员名字,带了条件
UPDATE `student` SET `name`='潆勖' WHERE id=1;

-- 不指定条件的情况下,会改动所有表!
UPDATE `student` SET `name`='鲁班7号'

-- 语法:
-- UPDATE 表名 set colnum_name = value[,colnum_name = value,...] where [条件]

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

操作符会返回 布尔值

操作符 含义 范围 结果
= 等于 5=6 false
<>或!= 不等于 5<>6 true
> 大于
< 小于
<= 小于等于
>= 大于等于
between … and … 区间,在某个范围内 between 2 and 5 [2,5]
and 和,&& 5>1 and 1>2 false
or 或,|| 5>1 or1>2 true
-- 通过多个条件定位数据
UPDATE `student` SET `name`='鲁班7号' WHERE `name`='潆勖' AND sex='女'

语法:UPDATE 表名 set colnum_name = value[,colnum_name = value,...] where [条件]

注意:

  • colnum_name 是数据库的列,尽量带上``
  • 条件,筛选的条件,如果没有指定,则会修改所有的列
  • value,是一个具体的值,也可以是一个变量
  • 多个设置的属性之间,使用英文逗号隔开
UPDATE `student` SET `birthday`=CURRENT_TIME WHERE `name`='潆勖' AND sex='女'

删除

delete 命令

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

-- 删除数据(避免这样写,会全部删除)
DELETE FROM `student`

-- 删除指定数据
DELETE FROM `student` WHERE id=1

truncate 命令

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

-- 清空 student 表
TRUNCATE `student`

delete 和 truncate 区别

  • 相同点:都能删除数据,都不会删除表结构
  • 不同:
    • truncate 重新设置 自增列 计数器会归零
    • truncate 不会影响事务
-- 测试 delete 和  truncate 区别
CREATE TABLE `test`(
	`id` INT(4) NOT NULL AUTO_INCREMENT,
	`coll` VARCHAR(20) NOT NULL,
	PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO `test`(`coll`) VALUES('1'),('2'),('3')

DELETE FROM `test` -- 不会影响自增

TRUNCATE TABLE `test` -- 自增会归零

了解即可:DELETE删除的问题,重启数据库,现象

  • InnoDB:自增列会重1开始(存在内存当中的,断电即失)
  • MyISAM:继续从上一个自增量开始(存在文件中的,不会丢失)

DQL查询数据(最重点)

DQL

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

  • 所有的查询操作都用它 Select
  • 简单的查询,复杂的查询它都能做~
  • 数据库中最核心的语言,最重要的语句
  • 使用频率最高的语句

Select完整语法:

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}];
   -- 指定查询的记录从哪条至哪条

注意 : [ ] 括号代表可选的 , { }括号代表必选得


school.sql文件:

CREATE DATABASE IF NOT EXISTS `school`;
-- 创建一个school数据库
USE `school`;-- 用school数据库

-- 创建年级表
DROP TABLE IF EXISTS `grade`;

CREATE TABLE `grade`(
	`gradeid` INT(11) NOT NULL AUTO_INCREMENT COMMENT '年级编号',
	`gradename` VARCHAR(50) NOT NULL COMMENT '年级名称',
	PRIMARY KEY (`gradeid`)
) ENGINE=INNODB AUTO_INCREMENT = 6 DEFAULT CHARSET = utf8

-- 插入年级数据
INSERT INTO `grade` (`gradeid`,`gradename`) VALUES(1,'大一'),(2,'大二'),(3,'大三'),(4,'大四'),(5,'预科班');



-- 创建成绩表
DROP TABLE IF EXISTS `result`;

CREATE TABLE `result`(
	`studentno` INT(4) NOT NULL COMMENT '学号',
	`subjectno` INT(4) NOT NULL COMMENT '课程编号',
	`examdate` DATETIME NOT NULL COMMENT '考试日期',
	`studentresult` INT (4) NOT NULL COMMENT '考试成绩',
	KEY `subjectno` (`subjectno`)
)ENGINE = INNODB DEFAULT CHARSET = utf8

-- 插入成绩数据  这里仅插入了一组,其余自行添加
INSERT INTO `result`(`studentno`,`subjectno`,`examdate`,`studentresult`)
VALUES
(1000,1,'2013-11-11 16:00:00',85),
(1000,2,'2013-11-12 16:00:00',70),
(1000,3,'2013-11-11 09:00:00',68),
(1000,4,'2013-11-13 16:00:00',98),
(1000,5,'2013-11-14 16:00:00',58);



-- 创建学生表
DROP TABLE IF EXISTS `student`;

CREATE TABLE `student`(
	`studentno` INT(4) NOT NULL COMMENT '学号',
	`loginpwd` VARCHAR(20) DEFAULT NULL,
	`studentname` VARCHAR(20) DEFAULT NULL COMMENT '学生姓名',
	`sex` TINYINT(1) DEFAULT NULL COMMENT '性别,0或1',
	`gradeid` INT(11) DEFAULT NULL COMMENT '年级编号',
	`phone` VARCHAR(50) NOT NULL COMMENT '联系电话,允许为空',
	`address` VARCHAR(255) NOT NULL COMMENT '地址,允许为空',
	`borndate` DATETIME DEFAULT NULL COMMENT '出生时间',
	`email` VARCHAR (50) NOT NULL COMMENT '邮箱账号允许为空',
	`identitycard` VARCHAR(18) DEFAULT NULL COMMENT '身份证号',
	PRIMARY KEY (`studentno`),
	UNIQUE KEY `identitycard`(`identitycard`),
	KEY `email` (`email`)
)ENGINE=MYISAM DEFAULT CHARSET=utf8

-- 插入学生数据 其余自行添加 这里只添加了2行
INSERT INTO `student` (`studentno`,`loginpwd`,`studentname`,`sex`,`gradeid`,`phone`,`address`,`borndate`,`email`,`identitycard`)
VALUES
(1000,'123456','张伟',0,2,'13800001234','北京朝阳','1980-1-1','[email protected]','123456198001011234'),
(1001,'123456','赵强',1,3,'13800002222','广东深圳','1990-1-1','[email protected]','123456199001011233');
(1002,'123456','张三',1,3,'13800002223','广东深圳','1990-1-1','[email protected]','123456199001011235');
(1003,'123456','张三丰',0,2,'13800002225','广东深圳','1990-1-1','[email protected]','123456199001011236');


-- 创建科目表
DROP TABLE IF EXISTS `subject`;

CREATE TABLE `subject`(
	`subjectno`INT(11) NOT NULL AUTO_INCREMENT COMMENT '课程编号',
	`subjectname` VARCHAR(50) DEFAULT NULL COMMENT '课程名称',
	`classhour` INT(4) DEFAULT NULL COMMENT '学时',
	`gradeid` INT(4) DEFAULT NULL COMMENT '年级编号',
	PRIMARY KEY (`subjectno`)
)ENGINE = INNODB AUTO_INCREMENT = 18 DEFAULT CHARSET = utf8

-- 插入科目数据
INSERT INTO `subject`(`subjectno`,`subjectname`,`classhour`,`gradeid`)VALUES
(1,'高等数学-1',110,1),
(2,'高等数学-2',110,2),
(3,'高等数学-3',100,3),
(4,'高等数学-4',130,4),
(5,'C语言-1',110,1),
(6,'C语言-2',110,2),
(7,'C语言-3',100,3),
(8,'C语言-4',130,4),
(9,'Java程序设计-1',110,1),
(10,'Java程序设计-2',110,2),
(11,'Java程序设计-3',100,3),
(12,'Java程序设计-4',130,4),
(13,'数据库结构-1',110,1),
(14,'数据库结构-2',110,2),
(15,'数据库结构-3',100,3),
(16,'数据库结构-4',130,4),
(17,'C#基础',130,1);

指定查询字段

-- 查询全部的学生   SELECT 字段 FROM 表
SELECT * FROM student

SELECT * FROM result

-- 查询指定字段
SELECT `studentno`,`studentname` FROM student

-- 别名,给结果起一个名字  As  可以给字段起别名,也可以给表起别名
SELECT `studentno` AS 学号,`studentname` AS 学生姓名 FROM student AS s

-- 函数 Concat (a,b)
SELECT CONCAT('姓名:',studentname) AS 新名字 FROM student

语法:SELECT 字段1,字段2,... 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 表

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

模糊查询:比较运算符

运算符 语法 描述
IS BULL a is null 如果操作符为NUll结果为真
IS NOT NULL a is not null 如果操作符不为null,结果为真
BETWEEN a between b and c 若a 在 b 和c 之间,则结果为真
Like a like b SQL匹配,如果a匹配b,则结果为真
In a in (a1,a2,a3…) 假设a在a1,或者a2…其中的某一个值中,结果为真
-- ==============  模糊查询  ===================
-- 查询姓张的同学
-- like结合   %(代表0到任意个字符)  _(一个字符)
SELECT `studentno`,`studentname` FROM `student`
WHERE studentname LIKE '张%'

-- 查询姓张的同学,名字后面只有一个字的
SELECT `studentno`,`studentname` FROM `student`
WHERE studentname LIKE '张_'

-- 查询姓张的同学,名字后面只有两个字的
SELECT `studentno`,`studentname` FROM `student`
WHERE studentname LIKE '张__'

-- 查询名字中间有嘉字的同学 %三%
SELECT `studentno`,`studentname` FROM `student`
WHERE studentname LIKE '%三%'

-- ========= in  (具体的一个或者多个值)  ===========
-- 查询 1001,1002,1003号学员
SELECT `studentno`,`studentname` FROM `student`
WHERE studentno IN (1001,1002,1003)

-- 查询在北京的学生
SELECT `studentno`,`studentname` FROM `student`
WHERE `address` IN ('北京朝阳','广东深圳')


-- =====null not null====

-- 查询地址为空的学生nul1  ''
SELECT `studentno`,`studentname` FROM `student`
WHERE `address`='' OR `address` IS NULL

-- 查询有出生日期的同学   不为空
SELECT `studentno`,`studentname` FROM `student`
WHERE `borndate` IS NOT NULL

-- 查询没有出生日期的同学   为空
SELECT `studentno`,`studentname` FROM `student`
WHERE `borndate` IS NULL

联表查询

JOIN 对比

MySQL_第6张图片

七种Join:

MySQL_第7张图片

-- join (连接的表) on (判断的条件)  连接查询
-- where    等值查询

-- Inner Join
SELECT s.studentno,`studentname`,`subjectno`,`studentresult`
FROM student s
INNER JOIN result 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
操作 描述
Inner Join 如果表中至少有一个匹配,就返回行
left Join 会从左表中返回所有的值,即使右表中没有匹配
right Join 会从右表中返回所有的值,即使左表中没有匹配
-- ========= 联表查询 join  ===========

-- 查询参加了考试的同学(学号,姓名,科目编号,分数)
SELECT * FROM student
SELECT * FROM result

/*
1.分析需求,分析查询的字段来自哪些表 (连接查询)
2.确定使用哪种连接查询?  7种
确定交叉点(这两个表中哪个数据是相同的)
判断的条件 : 学生表的中 studentno =成绩表 studentno
*/

-- join (连接的表) on (判断的条件)  连接查询
-- where    等值查询

-- Inner Join
SELECT s.studentno,`studentname`,`subjectno`,`studentresult`
FROM student s
INNER JOIN result 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 studentresult IS NULL

-- 思考题(查询了参加考试的同学信息:学号,学生姓名,科目名,分数)
/*
1.分析需求,分析查询的字段来自哪些表 student、result、subject (连接查询)
2.确定使用哪种连接查询?  7种
确定交叉点(这两个表中哪个数据是相同的)
判断的条件 : 学生表的中 studentno =成绩表 studentno
*/
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


-- 我要查询哪些数据 select ...
-- 从那几个表中查 FROM 表 XXX Join 连接的表 on 交叉条件
-- 假设存在一种多张表查询,慢慢来,先查询两张表然后再慢慢增加

-- FROM a left join b   以a为准
-- FROM a right join b  以b为准

自连接 (了解)

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

-- =========== 自连接 ===============

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','办公信息')

父类:

categoryid categoryname
2 信息技术
3 软件开发
5 美术设计

子类:

pid categoryid categoryname
3 4 数据库
2 8 办公信息
3 6 web开发
5 7 ps技术

操作:查询父类对应的子类关系

父类 子类
信息技术 办公信息
软件开发 数据库
软件开发 web开发
美术设计 ps技术
-- 查询父子信息: 把一张表看为两个一模一样的表
SELECT a.`categoryname` AS '',b.`categoryname` AS ''
FROM category AS a,category AS b
WHERE a.`categoryid`=b.`pid`

分页和排序

排序

-- 排序 : 升序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 r.subjectno = sub.subjectno
WHERE subjectname LIKE '高等数学%'
ORDER BY studentresult DESC

分页

-- 100万
-- 为什么要分页?
-- 缓解数据库压力,给人的体验更好,瀑布流

-- 分页,每页只显示三条数据
-- 语法: limit 当前页,页面的大小
-- 网页应用: 当前,总的页数,页面的大小
-- LIMIT 0,3   l~3
-- LIMIT 1,3   2~4
SELECT s.studentno,studentname,subjectname,studentresult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON r.subjectno = sub.subjectno
WHERE subjectname LIKE '高等数学%'
ORDER BY studentresult DESC
LIMIT 0,3

/*
推导:
   第一页 : limit 0,5
   第二页 : limit 5,5
   第三页 : limit 10,5
   ......
   第N页 : limit (pageNo-1)*pageSzie,pageSzie
   [pageNo:当前页码,pageSize:单页面显示条数]
   [(pageNo-1)*pageSzie:起始值]
   [数据总数/页面大小 = 总页数]
*/

语法:limit(查询起始下标,pagesize)

子查询

where (这个值是计算出来的)
本质:在where语句中嵌套一个子查询语句

-- ============== where ====================

-- 查询 高等数学-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 且分数不小于70分的学生的学号和姓名
-- 方法一:使用连接查询
SELECT DISTINCT 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>=70

-- 方法二:使用连接查询+子查询
SELECT r.studentno,studentname 
FROM student s
INNER JOIN result r 
ON s.`StudentNo`=r.`StudentNo`
WHERE StudentResult>=70 AND subjectno=(
   SELECT subjectno FROM `subject`
   WHERE subjectname = '高等数学-2'
)

-- 方法三:使用子查询(由里及外)
-- 分步写简单sql语句,然后将其嵌套起来
SELECT studentno,studentname FROM student WHERE studentno IN(
   SELECT studentno FROM result WHERE StudentResult>=70 AND subjectno=(
       SELECT subjectno FROM `subject` WHERE subjectname = '高等数学-2'
  )
)

分组和过滤

-- 查询不同课程的平均分,最高分,最低分
-- 核心: (根据不同的课程进行分组)
SELECT subjectname,AVG(studentresult) AS 平均分,MAX(StudentResult) AS 最高分,MIN(StudentResult) AS 最低分
FROM result AS r
INNER JOIN `subject` AS s
ON r.subjectno = s.subjectno
GROUP BY r.subjectno
HAVING 平均分>80;

/*
where写在group by前面.
要是放在分组后面的筛选
要使用HAVING..
因为having是从前面筛选的字段再筛选,而where是从数据表中的>字段直接进行的筛选的
*/

Select 小结

MySQL_第8张图片

MySQL函数

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

常用函数

-- =========== 常用函数 ===================

-- 数学运算
SELECT ABS(-8);  /*绝对值*/
SELECT CEILING(9.4); /*向上取整*/
SELECT FLOOR(9.4);   /*向下取整*/
SELECT RAND();  /*随机数,返回一个0-1之间的随机数*/
SELECT SIGN(0); /*符号函数: 负数返回-1,正数返回1,0返回0*/

-- 字符串函数
SELECT CHAR_LENGTH('神说坚持就能成功'); /*返回字符串包含的字符数*/
SELECT CONCAT('我','爱','程序');  /*合并字符串,参数可以有多个*/
SELECT INSERT('我爱编程helloworld',1,2,'超级热爱');  /*替换字符串,从某个位置开始替换某个长度*/
SELECT LOWER('yingxu'); /*小写*/
SELECT UPPER('yingxu'); /*大写*/
SELECT INSTR('yingxu','n');/*返回第一次出现的子串的索引*/
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 '张%';

-- 时间和日期函数 (记住)
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() 最小值
-- ========== 聚合函数 ===============
-- 都能够统计表中的数据 ( 想查询一个表中有多少个记录,就使用这个count() )
/*无主键 推荐*/
SELECT COUNT(studentname) FROM student; -- COUNT(指定列),会忽略所有的 null值
SELECT COUNT(*) FROM student; -- COUNT(*),不会忽略 null 值
/*有主键 推荐*/
SELECT COUNT(1) FROM student; -- COUNT(1),不会忽略所有的 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;

数据库级别的MD5加密 (扩展)

MD5简介

MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程语言普遍已有MD5实现。将数据(如汉字)运算为另一固定长度值,是杂凑算法的基础原理,MD5的前身有MD2、MD3和MD4。

实现数据加密

新建一个表 testmd5:

-- ============测试MD5 加密==================
CREATE TABLE `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,'zhangsan','123456'),(2,'yingxu','123456'),(3,'yingxu','123456')

-- 加密
UPDATE testmd5 SET pwd = MD5(pwd) WHERE id = 1;

UPDATE testmd5 SET pwd = MD5(pwd); -- 加密全部的密码

-- 插入的时候加密
INSERT INTO testmd5 VALUES(4,'kyingxu2',MD5('123456'))

-- 如何校验:将用户传递进来的密码,进行md5加密,然后比对加密后的值
SELECT * FROM testmd5 WHERE `name`='kyingxu2' AND pwd=MD5('123456');

事务

什么是事务

要么都成功,要么都失败

  • 事务就是将一组SQL语句放在同一批次内去执行
  • 如果一个SQL语句出错,则该批次内的所有SQL都将被取消执行
  • MySQL事务处理只支持InnoDB和BDB数据表类型

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

原子性(Atomic)

  • 要么都成功,要么都失败
  • 整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(ROLLBACK)到事务开始前的状态,就像这个事务从来没有执行过一样。

一致性(Consist)

  • 事务前后的数据完整性要保证一致,1000
  • 一个事务可以封装状态改变(除非它是一个只读的)。事务必须始终保持系统处于一致的状态,不管在任何给定的时间并发事务有多少。也就是说:如果事务是并发多个,系统也必须如同串行事务一样操作。其主要特征是保护性和不变性(Preserving an Invariant),以转账案例为例,假设有五个账户,每个账户余额是100元,那么五个账户总额是500元,如果在这个5个账户之间同时发生多个转账,无论并发多少个,比如在A与B账户之间转账5元,在C与D账户之间转账10元,在B与E之间转账15元,五个账户总额也应该还是500元,这就是保护性和不变性。

隔离性(Isolated)

  • 事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰事务之间要相互隔离。
  • 隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作。如果有两个事务,运行在相同的时间内,执行相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。这种属性有时称为串行化,为了防止事务操作间的混淆,必须串行化或序列化请求,使得在同一时间仅有一个请求用于同一数据。

持久性(Durable)

  • 事务一旦提交则不可逆,被持久化到数据库中!
  • 在事务完成以后,该事务对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。

执行事务

-- =========== 事务 ===============

-- mysql是默认开启事务自动提交的
SET autocommit = 0;   /*关闭*/
SET autocommit = 1;   /*开启(默认的)*/

-- 手动处理事务
SET autocommit = 0 -- 关闭自动条件

-- 事务开启
START TRANSACTION  -- 标记一个事务的开始,从这个之后的 sql 都在同一个事务内

-- 提交:持久化(成功!)
COMMIT

-- 回滚:回到的原来的样子(失败!)
ROLLBACK

-- 事务结束
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=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';
UPDATE account SET money=money+500 WHERE `name`='B';

COMMIT; -- 提交事务
# rollback; -- 回滚
SET autocommit = 1; -- 恢复自动提交

索引

MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构。

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

索引的分类

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

  • 主键索引 (Primary Key)
    • 唯一的标识,主键不可重复,只能有一个列作为主键
  • 唯一索引 (Unique Key)
    • 避免重复的列出现,唯一索引可以重复,多个列都可以标识位唯一索引
  • 常规索引 (KEY/Index)
    • 默认的, index / key关键字来设置
  • 全文索引 (FullText)
    • 在特定的数据库引擎下才有,MylSAM
    • 快速定位数据

基础语法:

-- 索引使用
-- 1、在创建表的时候给字段增加索引
-- 2、创建完毕后,增加索引

-- 显示所有的索引信息
SHOW INDEX FROM student

-- 增加一个全文索引 (索引名)  列名
ALTER TABLE school.`student` ADD FULLTEXT INDEX `studentname`(`studentname`);

-- EXPLAIN 分析sq1执行的状况
EXPLAIN SELECT * FROM student; -- 非全文索引

EXPLAIN SELECT * FROM student WHERE MATCH(studentname) AGAINST('张');

测试索引

建表app_user:

CREATE TABLE `app_user` (
	`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
	`name` VARCHAR(50) DEFAULT '' COMMENT '用户昵称',
	`email` VARCHAR(50) NOT NULL COMMENT '用户邮箱',
	`phone` VARCHAR(20) DEFAULT '' COMMENT '手机号',
	`gender` TINYINT(4) UNSIGNED DEFAULT '0' COMMENT '性别(0:男;1:女)',
	`password` VARCHAR(100) NOT NULL COMMENT '密码',
	`age` TINYINT(4) DEFAULT '0' COMMENT '年龄',
	`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
	`update_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
	PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COMMENT='app用户表'

-- 插入100万条数据
DROP FUNCTION IF EXISTS mock_data;

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), '[email protected]', 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();

测试:

SELECT * FROM app_user WHERE `name` = '用户9999';
EXPLAIN SELECT * FROM app_user WHERE `name` = '用户9999'; -- 0.458 sec

-- 创建索引
-- id _ 表名 _ 字段名
-- CREATE INDEX 索引名 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'; -- 0.001 sec

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

索引准则

  • 索引不是越多越好
  • 不要对经常变动的数据加索引
  • 小数据量的表建议不要加索引
  • 索引一般应加在查找条件的字段

索引的数据结构

-- 我们可以在创建上述索引的时候,为其指定索引类型,分两类
hash 类型的索引:查询单条快,范围查询慢
btree 类型的索引:b+树,层数越多,数据量指数级增长(我们就用它,因为innodb默认支持它)

-- 不同的存储引擎支持的索引类型也不一样
InnoDB 支持事务,支持行级别锁定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
MyISAM 不支持事务,支持表级别锁定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
Memory 不支持事务,支持表级别锁定,支持 B-tree、Hash 等索引,不支持 Full-text 索引;
NDB 支持事务,支持行级别锁定,支持 Hash 索引,不支持 B-tree、Full-text 等索引;
Archive 不支持事务,支持表级别锁定,不支持 B-tree、HashFull-text 等索引;

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

权限管理和备份

用户管理

SQLyog 可视化管理

MySQL_第9张图片

SQL命令操作

用户表:mysql.user

本质:读这张表进行增删改查

-- 创建用户 CREATE USER 用户名 IDENTIFIED BY '密码'
CREATE USER yingxu IDENTIFIED BY '123456'

-- 修改密码 (修改当前用户密码) SET PASSWORD = PASSWORD('密码')
SET PASSWORD = PASSWORD('123')

-- 修改密码 (修改指定用户密码) SET PASSWORD FOR 用户名 = PASSWORD('密码') 
SET PASSWORD FOR yingxu = PASSWORD('123') 

-- 重命名 RENAME USER 原名字 TO 新名字
RENAME USER yingxu TO yingxu2

-- 用户授权 ALL PRIVILEGES 全部的权限 ,库.表
-- ALL PRIVILEGES 除了给别人授权,其他都能够干
GRANT ALL PRIVILEGES ON *.* TO yingxu2

-- 查看权限
SHOW GRANTS FOR yingxu2 -- 查看指定用户的权限
SHOW GRANTS FOR root@localhost

-- ROOT用户权限:GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION

-- 撤消权限 REVOKE 哪些权限,在哪个库撤销,给谁撤销
REVOKE ALL PRIVILEGES ON *.* FROM yingxu2

-- 删除用户 DROP USER 用户名
DROP USER kuangshen2

MySQL备份

数据库备份必要性:

  • 保证重要数据不丢失
  • 数据转移

MySQL数据库备份方法:

  • 直接拷贝数据库文件和相关配置文件
  • 在Sqlyog这种可视化工具中手动导出
    • 在想要导出的表或者库中,右键,选择备份或导出
  • 使用命令行导出 mysqldump备份工具 命令行使用
# cmd导出

# 导出一张表
# mysqldump -u用户名 -p密码 库名 表名 > 文件名(G:/a.sql)
mysqldump -uroot -p123456 school student >G:/a.sql

# 导出多张表
# mysqldump -u用户名 -p密码 库名 表1 表2 表3 > 文件名(G:/a.sql)
mysqldump -uroot -p123456 school student result >G:/a.sql

# 导出所有表
# mysqldump -u用户名 -p密码 库名 > 文件名(G:/a.sql)
mysqldump -uroot -p123456 school >G:/a.sql

# 导出一个库
# mysqldump -u用户名 -p密码 -B 库名 > 文件名(G:/a.sql)
mysqldump -uroot -p123456 -B school >G:/a.sql


# 导入
# 1.在登录mysql的情况下
# 2.切换到指定的数据库 use 库名
# 3.source 备份文件
source G:/a.sql

# 在不登录的情况下
# mysql -u用户名 -p密码 库名 < 备份文件

什么时候用:

  • 假设你要备份数据库,防止数据丢失。

  • 把数据库个朋友! sql文件给别人即可!

规范数据库设计

为什么需要设计

当数据库比较复杂时我们需要设计数据库

糟糕的数据库设计 :

  • 数据冗余,存储空间浪费
  • 数据更新和插入的异常
  • 程序性能差

良好的数据库设计 :

  • 节省数据的存储空间
  • 能够保证数据的完整性
  • 方便进行数据库应用系统的开发

软件项目开发周期中数据库设计 :

  • 需求分析阶段:分析客户的业务和数据处理需求
  • 概要设计阶段:设计数据库的E-R模型图 , 确认需求信息的正确和完整.

设计数据库步骤:

  • 收集信息,分析需求

    • 与该系统有关人员进行交流 , 座谈 , 充分了解用户需求 , 理解数据库需要完成的任务.
  • 标识实体(把需求落地到每个字段)[Entity]

  • 标识实体之间的关系[Relationship]

三大范式

问题 : 为什么需要数据规范化?

不合规范的表设计会导致的问题:

  • 信息重复

  • 更新异常

  • 插入异常

    • 无法正确表示信息
  • 删除异常

    • 丢失有效信息

三大范式(了解)

第一范式 (1NF)

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

第二范式(2NF)

  • 前提:满足第一范式

  • 每张表只描述一件事情

第三范式(3NF)

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

(规范数据库的设计)

规范性 和 性能的问题

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

  • 考虑商业化的需求和目标,(成本,用户体验! )数据库的性能更加重
  • 要在规范性能的问题的时候,需要适当的考虑一下规范性!
  • 故意给某些表增加一些冗余的字段。(从多表查询中变为单表查询)
  • 故意增加一些计算列 (从大数据量降低为小数据量的查询:索引)

JDBC(重点)

数据库驱动

程序会通过数据库驱动,和数据库打交道!

JDBC

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

这些规范的实现由具体的厂商去做~

对于开发人员来说,我们只需要掌握JDBC接口的操作即可!

学习JDBC需要:

  • java.sql
  • javax.sql
  • 还需要导入一个数据库驱动包(mysql-connector-java-5.1.47.jar)
    • mvnrepository下载地址
    • MySQL官网下载

第一个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','[email protected]','1980-12-04'),
(2,'lisi','123456','[email protected]','1981-12-04'),
(3,'wangwu','123456','[email protected]','1979-12-04')

1、创建一个普通项目

2、导入数据库驱动

3、编写测试代码

//1.加载驱动
// MySQL8.0以上版本:com.mysql.cj.jdbc.Driver
Class.forName("com.mysql.jdbc.Driver");//固定写法,加载驱动
//2.用户信息和url
// jdbc:mysql://主机:3306/数据库名?useUnicode=true&characterEncoding=utf8&useSSL=false
// 出现Communications link failure错误时useSSL=true改为false
// MySQL8.0以上版本加时区:severTimezone=UTC (UTC要比中国时区早8个小时) 或者 severTimezone=Asia/Shanghai 或者 severTimezone=Hongkong
String url="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false";
String username="root";
String password="123456";
//3.连接成功,数据库对象  Connection 代表数据库
Connection connection = DriverManager.getConnection(url, username, password);
//4.执行sQL的对象  Statement  执行sql的对象
Statement statement = connection.createStatement();
//5.执行sQL的对象 去 执行SQL,可能存在结果,查看返回结果
String sql="SELECT * FROM users";
ResultSet resultSet = statement.executeQuery(sql);//返回的结果集,结果集中封装了我们全部的查询出来的结果
while (resultSet.next()){
    System.out.println("id="+resultSet.getObject("id"));
    System.out.println("name="+resultSet.getObject("NAME"));
    System.out.println("password="+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. 加载驱动 Class.forName()
  2. 连接数据库 DriverManager
  3. 获得执行sql的对象 Statement
  4. 获得返回的结果集
  5. 释放连接

DriverManager

// MySQL8.0以上版本:com.mysql.cj.jdbc.Driver
// DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName("com.mysql.jdbc.Driver");//固定写法,加载驱动

Connection connection = DriverManager.getConnection(url, username, password);
// connection 代表数据库
// 数据库设置自动提交
// 事务提交
// 事务回滚
connection.rollback();
connection.commit();
connection.setAutoCommit();

URL

// 出现Communications link failure错误时useSSL=true改为false
// MySQL8.0以上版本加时区:severTimezone=UTC (UTC要比中国时区早8个小时) 或者 severTimezone=Asia/Shanghai 或者 severTimezone=Hongkong

String url="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false";

// mysql -- 默认端口:3306
// jdbc:mysql://主机地址:端口号/数据库名?参数1&参数2&参数3

// oralce -- 默认端口:1521
// jdbc:oralce:thin:@localhost:1521:sid


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

String sql="SELECT * FROM users";//编写SQL

statement.executeQuery();//查询操作返回 ResultSet
statement.execute();// 执行任何SQL
statement.executeUpdate();//更新、插入、删除。都是用这个,返回一个受影响的行数
statement.executeBatch();// 执行多个SQL

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

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

遍历,指针

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

释放资源

//6、释放连接
resultSet.close();
statement.close();
connection.close();// 耗资源,用完关掉!

statement对象

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

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

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

CRUD操作-create

使用executeUpdate(String sql)方法完成数据添加操作,示例操作:

Statement st=conn.createStatement();
String sql="INSERT INTO user(...) VALUES(....)";
int num = st.executeUpdate(sql);
if (num>0){
    System.out.println("插入成功");
}

CRUD操作-delete

使用executeUpdate(String sql)方法完成数据删除操作,示例操作:

Statement st=conn.createStatement();
String sql="DELETE FROM user WHERE id=1";
int num = st.executeUpdate(sql);
if (num>0){
    System.out.println("删除成功");
}

CRUD操作-update

使用executeUpdate(String sql)方法完成数据修改操作,示例操作:

Statement st=conn.createStatement();
String sql="UPDATE user SET `NAME`='',`email`='' WHERE id=1";
int num = st.executeUpdate(sql);
if (num>0){
    System.out.println("修改成功");
}

CRUD操作-read

使用executeQuery(String sql)方法完成数据查询操作,示例操作:

Statement st=conn.createStatement();
String sql="SELECT * FROM user WHERE id=1";
ResultSet rs = st.executeQuery(sql);
while (rs.next()){
    //根据获取列的数据类型,分别调用rs的相应方法映射到java对象中
}

代码实现

db.properties文本:

# MySQL8.0以上版本:com.mysql.cj.jdbc.Driver
driver=com.mysql.jdbc.Driver

# 出现Communications link failure错误时useSSL=true改为false
# MySQL8.0以上版本加时区:severTimezone=UTC (UTC要比中国时区早8个小时) 或者 severTimezone=Asia/Shanghai 或者 severTimezone=Hongkong

url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false

username=root
password=123456

1、提取工具类

JdbcUtils工具类:

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");

            //1.驱动只用加载一次
            Class.forName(driver);

        }catch (Exception e) {
            e.printStackTrace();
        }
    }

    //获取连接
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url,username,password);
    }

    //释放连接资源
    public static void release(Connection conn, Statement st, ResultSet rs){
        if (rs!=null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (st!=null){
            try {
                st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

2、编写增删改的方法executeUpdate

增:

public class TestInsert {
    public static void main(String[] args) {
        Connection conn =null;
        Statement st=null;
        ResultSet rs=null;
        try {
            conn = JdbcUtils.getConnection();//获取数据库连接
            st=conn.createStatement();//获得SQL的执行对象

            String sql="INSERT INTO users(id,`NAME`,`PASSWORD`,`email`,`birthday`)" +
                    "VALUES(4,'yingxu','123456','[email protected]','2022-5-8')";
            int i = st.executeUpdate(sql);
            if (i>0){
                System.out.println("插入成功");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}

删:

public class TestDelete {
    public static void main(String[] args) {
        Connection conn =null;
        Statement st=null;
        ResultSet rs=null;
        try {
            conn = JdbcUtils.getConnection();//获取数据库连接
            st=conn.createStatement();//获得SQL的执行对象

            String sql="DELETE FROM users WHERE id=4";

            int i = st.executeUpdate(sql);
            if (i>0){
                System.out.println("删除成功");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}

改:

public class TestUpdate {
    public static void main(String[] args) {
        Connection conn =null;
        Statement st=null;
        ResultSet rs=null;
        try {
            conn = JdbcUtils.getConnection();//获取数据库连接
            st=conn.createStatement();//获得SQL的执行对象

            String sql="UPDATE users SET `NAME`='yingxu',`email`='[email protected]' WHERE id=1";

            int i = st.executeUpdate(sql);
            if (i>0){
                System.out.println("修改成功");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}

3、查询executeQuery

public class TestSelect {
    public static void main(String[] args) {
        Connection conn =null;
        Statement st=null;
        ResultSet rs=null;
        try {
            conn = JdbcUtils.getConnection();//获取数据库连接
            st=conn.createStatement();//获得SQL的执行对象

            String sql="select * from users where id='1'";

            rs = st.executeQuery(sql);//查询完毕会返回一个结果集
            while (rs.next()){
                System.out.println("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("birth="+rs.getDate("birthday"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}

SQL注入

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

public class SQL注入 {
    public static void main(String[] args) {
        //login("yingxu","123456");//正常登录
        login("'or ' 1=1","'or ' 1=1");//SQL注入
    }
    //登录业务
    public static void login(String username,String password){
        Connection conn =null;
        Statement st=null;
        ResultSet rs=null;
        try {
            conn = JdbcUtils.getConnection();//获取数据库连接
            st=conn.createStatement();//获得SQL的执行对象

            String sql="select * from users where `NAME`='"+username+"' AND `PASSWORD`='"+password+"'";

            rs = st.executeQuery(sql);//查询完毕会返回一个结果集
            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("birth="+rs.getDate("birthday"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}

PreparedStatement对象

PreparedStatement 可以防止SQL注入。效率更好!

1、新增

public class TestInsert {
    public static void main(String[] args) {
        Connection conn =null;
        PreparedStatement st =null;
        try {
            conn = JdbcUtils.getConnection();

            //区别
            //使用?  占位符代替参数
            String sql="INSERT INTO users(id,`NAME`,`PASSWORD`,`email`,`birthday`) VALUES(?,?,?,?,?)";

            st = conn.prepareStatement(sql);//预编译SQL,先写sqL,然后不执行

            //手动给参数赋值
            st.setInt(1,4);//id
            st.setString(2,"yingxu");
            st.setString(3,"123");
            st.setString(4,"[email protected]");
            //注意点: sql.Date    数据库    java.sql.Date
            //        util.Date   Java     java.util.Date().getTime() 获得时间戳
            st.setDate(5,new Date(new java.util.Date().getTime()));

            //执行
            int i=st.executeUpdate();
            if (i>0){
                System.out.println("插入成功");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,null);
        }
    }
}

2、删除

public class TestDelete {
    public static void main(String[] args) {
        Connection conn =null;
        PreparedStatement st =null;
        try {
            conn = JdbcUtils.getConnection();
            String sql="delete from users where id=?";
            st = conn.prepareStatement(sql);

            st.setInt(1,4);

            int i = st.executeUpdate();
            if (i>0){
                System.out.println("删除成功");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,null);
        }
    }
}

3、更新

public class TestUpdate {
    public static void main(String[] args) {
        Connection conn =null;
        PreparedStatement st =null;
        try {
            conn = JdbcUtils.getConnection();
            String sql="update users set NAME=? where id=?";

            st = conn.prepareStatement(sql);

            st.setString(1,"yingxu2");
            st.setInt(2,1);

            int i = st.executeUpdate();
            if (i>0){
                System.out.println("修改成功");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,null);
        }
    }
}

4、查询

public class TestSelect {
    public static void main(String[] args) {
        Connection conn =null;
        PreparedStatement st =null;
        ResultSet rs =null;
        try {
            conn = JdbcUtils.getConnection();
            String sql="select * from users where id=?";
            st = conn.prepareStatement(sql);
            st.setInt(1,1);

            rs = st.executeQuery();
            while (rs.next()){
                System.out.println("name="+rs.getString("NAME"));
                System.out.println("password="+rs.getString("PASSWORD"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}

防止SQL注入

public class SQL注入 {
    public static void main(String[] args) {
        //login("yingxu2","123456");//正常登录
        login("' ' or 1=1","' ' or 1=1");//SQL注入
    }
    //登录业务
    public static void login(String username,String password){
        Connection conn =null;
        PreparedStatement st=null;
        ResultSet rs=null;
        try {
            conn = JdbcUtils.getConnection();//获取数据库连接

            String sql="select * from users where `NAME`=? AND `PASSWORD`=?";

            st=conn.prepareStatement(sql);//获得SQL的执行对象

            st.setString(1,username);
            st.setString(2,password);

            rs = st.executeQuery();//查询完毕会返回一个结果集
            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("birth="+rs.getDate("birthday"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}

使用IDEA连接数据库

MySQL_第10张图片

连接成功后,可以选择数据库

MySQL_第11张图片

查看:

MySQL_第12张图片

更新数据:

MySQL_第13张图片

MySQL_第14张图片

连接失败查看原因:

MySQL_第15张图片

事务

要么都成功,要么都失败

ACID原则

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

一致性:总数不变

隔离性:多个进程互不干扰

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

隔离性的问题:

  • 脏读:一个事务读取了另一个没有提交的事务
  • 不可重复读:在同一个事务内,重复读取表中的数据,表数据发生了改变
  • 虚读(幻读):在一个事务内,读取到了别人插入的数据,导致前后读出来结果不一致

代码实现

1、开启事务 conn.setAutoCommit(false);
2、一组业务执行完毕,提交事务
3、可以在catch语句中显示的定义回滚语句,但默认失败就会回滚

表:

CREATE TABLE account(
    id INT PRIMARY KEY AUTO_INCREMENT,
    NAME VARCHAR(40),
    money FLOAT
);

/*插入测试数据*/
INSERT INTO account(NAME,money) VALUES('A',1000);
INSERT INTO account(NAME,money) VALUES('B',1000);
INSERT INTO account(NAME,money) VALUES('C',1000);

代码:

public class TestTransaction {
    public static void main(String[] args) {
        Connection conn =null;
        PreparedStatement st=null;
        ResultSet rs=null;
        try {
            conn = JdbcUtils.getConnection();
            //关闭数据库的自动提交,自动会开启事务
            conn.setAutoCommit(false);

            String sql1="Update account set money=money-100 where NAME='A'";
            st=conn.prepareStatement(sql1);
            st.executeUpdate();

            //int x=1/0;//报错

            String sql2="Update account set money=money+100 where NAME='B'";
            st=conn.prepareStatement(sql2);
            st.executeUpdate();

            //业务完毕,提交事务
            conn.commit();
            System.out.println("成功");

        } catch (SQLException e) {
            try {
                //若果失败,则默认回滚,不写下面的语句也会回滚
                conn.rollback();//如果失败则回滚事务
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,null);
        }

    }
}

数据库连接池

数据库连接 — 执行完毕 — 释放

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

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

------ 开门–业务员:等待 – 服务—

常用连接数10个

最小连接数:10

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

超过最大连接数:排队等待

等待超时:100ms

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

开源数据源实现 ( 拿来即用 )

  • DBCP

  • C3P0

  • Druid:阿里巴巴的

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

DBCP

DBCP

下载:

  • commons-dbcp2-2.9.0.jar
  • commons-pool2-2.11.1.jar
  • commons-logging-1.2.1.1.jar

dbcpconfig.properties文件:

#连接设置(每一个名称不能改动)
driverClassName=com.mysql.jdbc.Driver
#jdbcstudy为数据库名
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false
username=root
password=123456


#
initialSize=10

#最大连接数量
maxActive=50

#
maxIdle=20

#
minIdle=5

#
maxWait=60000


#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;]
#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=UTF8

#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true

#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED

代码:

public class JdbcUtils_DBCP {
    private static BasicDataSource 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();//从数据源中获取连接
    }

    //释放连接资源
    public static void release(Connection conn, Statement st, ResultSet rs){
        if (rs!=null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (st!=null){
            try {
                st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
public class TestDBCP {
    public static void main(String[] args) {
        Connection conn =null;
        PreparedStatement st =null;
        try {
            conn = JdbcUtils_DBCP.getConnection();

            //区别
            //使用?  占位符代替参数
            String sql="INSERT INTO users(id,`NAME`,`PASSWORD`,`email`,`birthday`) VALUES(?,?,?,?,?)";

            st = conn.prepareStatement(sql);//预编译SQL,先写sqL,然后不执行

            //手动给参数赋值
            st.setInt(1,4);//id
            st.setString(2,"yingxu");
            st.setString(3,"123");
            st.setString(4,"[email protected]");
            //注意点: sql.Date    数据库    java.sql.Date
            //        util.Date   Java     java.util.Date().getTime() 获得时间戳
            st.setDate(5,new Date(new java.util.Date().getTime()));

            //执行
            int i=st.executeUpdate();
            if (i>0){
                System.out.println("插入成功");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils_DBCP.release(conn,st,null);
        }
    }
}

C3P0

C3P0

  • 下载地址 c3p0-0.9.5.5.jar 和 mchange-commons-java-0.2.19.jar 都在 lib 文件夹里面

c3p0-config.xml


<c3p0-config>
    
    <default-config>
        
        <property name="driverClass">com.mysql.jdbc.Driverproperty>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=falseproperty>
        <property name="user">rootproperty>
        <property name="password">123456property>
        
        
        <property name="acquireIncrement">5property>
        <property name="initialPoolSize">10property>
        <property name="minPoolSize">5property>
        <property name="maxPoolSize">20property>
        
    default-config>
    
    
    <named-config name="MySQL">
    	
        <property name="driverClass">com.mysql.jdbc.Driverproperty>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=falseproperty>
        <property name="user">rootproperty>
        <property name="password">123456property>
        
        
        <property name="acquireIncrement">5property>
        <property name="initialPoolSize">10property>
        <property name="minPoolSize">5property>
        <property name="maxPoolSize">20property>
    named-config>
c3p0-config>

代码:

public class JdbcUtils_C3P0 {
    private static ComboPooledDataSource dataSource =null;
    static {
        try {
            //代码版配置(不建议使用)
//            dataSource = new ComboPooledDataSource();
//            dataSource.setDriverClass("com.mysql.jdbc.Driver");
//            dataSource.setUser("root");
//            dataSource.setPassword("123456");
//            dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false");
//
//            dataSource.setMaxPoolSize(5);
//            dataSource.setMinPoolSize(20);

            //创建数据源  工厂模式-->创建
            dataSource = new ComboPooledDataSource("MySQL");//配置文件写法

        }catch (Exception e) {
            e.printStackTrace();
        }
    }

    //获取连接
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();//从数据源中获取连接
    }

    //释放连接资源
    public static void release(Connection conn, Statement st, ResultSet rs){
        if (rs!=null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (st!=null){
            try {
                st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
public class TestC3P0 {
    public static void main(String[] args) {
        Connection conn =null;
        PreparedStatement st =null;
        try {
            conn = JdbcUtils_C3P0.getConnection();

            //区别
            //使用?  占位符代替参数
            String sql="INSERT INTO users(id,`NAME`,`PASSWORD`,`email`,`birthday`) VALUES(?,?,?,?,?)";

            st = conn.prepareStatement(sql);//预编译SQL,先写sqL,然后不执行

            //手动给参数赋值
            st.setInt(1,5);//id
            st.setString(2,"yingxu");
            st.setString(3,"123");
            st.setString(4,"[email protected]");
            //注意点: sql.Date    数据库    java.sql.Date
            //        util.Date   Java     java.util.Date().getTime() 获得时间戳
            st.setDate(5,new Date(new java.util.Date().getTime()));

            //执行
            int i=st.executeUpdate();
            if (i>0){
                System.out.println("插入成功");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils_C3P0.release(conn,st,null);
        }
    }
}

结论

结论

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

apache(阿帕奇)

  • 圈出来的是要学习的
  • 其他箭头的是与大数据相关的

MySQL_第16张图片

你可能感兴趣的:(MySQL,mysql,数据库,database)