MySQL学习

1.初识MySQL

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

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

数据库(存数据)

数据库分类

关系型数据库

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

非关系型数据库

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

DBMS(数据库管理系统)

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

连接数据库

命令行连接

mysql -uroot -p   --连接数据库
update mysql.user set authentication_string=password('123456') where user='root' and Host = 'localhost'; --修改密码
flush privileges; --刷新权限
-------------------
--所有的语句都使用分号(;)结尾
show databases; --查看所有的数据库

mysql> use school; --切换数据库
Database changed

show tables;--查看数据库中所有的表
describe **(表名);--显示数据库中所有表的信息

create database **(要创建的数据库名);--创建一个数据库

exit;--退出连接
--单行注释
/*
多行注释
*/

数据库语言

数据库D*L(定义/操作/查询/控制)语言

DDL 定义

DML 操作

DQL 查询

DCL 控制

2.操作数据库

2.1操作数据库

1.创建数据库

CREATE DATABASE [IF NOT EXISTS] school;(数据库名) --中括号[]代表可选

2.删除数据库

DROP DATABASE [IF EXISTS] school;

3.使用数据库

--如果你的表名或者字段名是一个特殊字符,就需要在两边带上``
USE `school`;

4.查看数据库

SHOW DATABASES;--查看所有的数据库

2.2数据库的列类型

数值

  • tinyint 十分小的数据 1个字节
  • smallint 较小的数据 2个字节
  • mediumint 中等大小的数据 3个字节
  • int 标准的整数 4个字节
  • bigint 较大的数据 8个字节
  • float 浮点数 4个字节
  • double 浮点数 8个字节
  • decimal 字符串形式的浮点数,金融计算的时候,一般使用decimal

字符串

  • char 字符串固定大小的 0~255
  • varchar 可变字符串 0~65535 (相对于String)
  • tinytext 微型文本 2^8-1 (博客)
  • text 文本串 2^16-1

时间日期

Java.util.Date(Java下的日期类)

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

null

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

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

Unsigned:

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

zerofill

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

自增

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

非空

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

默认

  • 设置默认的值

2.4创建数据库表

-- 目标:创建一个student数据库
-- 创建学生表(列,字段) 使用SQL创建
-- 学号int 姓名varchar(30) 登录密码varchar(20) 性别varchar(2)  出生日期datetime 家庭住址,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] `表名`(
    `字段名` 列类型 [属性] [索引] [注释],
    `字段名` 列类型 [属性] [索引] [注释],
    ......
    `字段名` 列类型 [属性] [索引] [注释]
)[表类型][字符集设置][注释]

逆向查看创建数据库的sql语句

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

2.5数据表的类型(数据库引擎)

INNODB(默认使用)

NULL INNODB MyISAM
事务支持 支持 不支持
数据行锁定 支持 不支持
外键约束 支持 不支持
全文索引 不支持 支持
表空间的大小 较大,约为后者的2倍 较小

MyISAM(早些年使用)

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

在物理空间存在的位置

所有数据库的文件都存在data目录下,本质还是文件的存储

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

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

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

CHARSET=utf8

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

也可在my.ini配置文件中设置默认代码

character_set_server=utf8

2.6修改删除表

修改

-- 修改表名: ALTER TABLE 旧表名 RENAME AS 新表名
ALTER TABLE `student` RENAME AS `student1`
-- 增加表的字段: ALTER TABLE 表名 ADD 字段名 列属性
ALTER TABLE `student1` ADD age INT(11)

-- 修改表的字段: (重命名,修改约束)
-- ALTER TABLE 表名 MODIFY 字段名 列属性[]
ALTER TABLE student1 MODIFY age VARCHAR(12) -- 修改约束
-- ALTER TABLE 表名 CHANGE 旧名字 新名字 列属性[]
ALTER TABLE student1 CHANGE age age1 INT(1) -- 字段重命名

删除

-- 删除表的字段:ALTER TABLE 表名 DROP 字段名
ALTER TABLE student1 DROP age

-- 删除表(如果表存在再删除)
DROP TABLE IF EXISTS student1 

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

3.MySQL数据库管理

3.1外键

-- 如果创建表的时候没有外键关系
ALTER TABLE `student`
ADD CONSTRAINT `FK_gradeid` FOREIGN KEY(`gradeid`) REFERENCES `grade`(`gradeid`);

-- ALTER TABLE 表
-- ADD CONSTRAINT 约束名 FOREIGN KEY(作为外键的列) REFERENCES 哪个表(哪个字段)

删除有外键关系的表时候,必须要先删除引用自己的那张表(从表),再删除自己这张表(主表)

(这里了解即可,避免因数据库过多造成困扰)

  • 数据库就是单纯的表,只用来存数据,只有行(数据)和列(字段)。
  • 当使用多张表的数据时,可以用程序去实现。

3.2DML语言(增删改,重点)

DML语言:数据库操作语言

  • Insert
  • Update
  • Delete

3.3添加

-- student这个表 有 id,name,sex.其中id是主键,且是自增的
-- 插入数据
-- insert into 表名([字段名1,字段名2,字段名3]) values('值1','值2','值3`student`')
INSERT INTO `student`(`name`,`sex`) VALUES('你好','女')

-- 由于主键自增我们可以省略,不用插入主键的内容
-- 数据和字段一一对应

-- 插入多个字段
INSERT INTO `student`(`name`,`sex`) VALUES('小王','男'),('小李','女')
-- 字段可以省略
INSERT INTO `student` VALUES(15,'小王','男'),(16,'小李','女')

3.4修改

-- 修改student的名字
UPDATE `student` SET `name`='章茂淳' WHERE id=1;

-- 不指定条件的情况下,会改动所有的表!
UPDATE `student` SET `name`='长江七号' ;

-- 修改多个属性,逗号隔开
UPDATE `student` SET `name`='章茂淳',`sex`='男' WHERE id=1;

-- 语法
-- UPDATE 表名 SET colnum_name = value WHERE [条件]

-- 通过多个条件定位数据
UPDATE `student` SET `name`='章茂淳' WHERE id=1 AND sex='男';

条件:where子句 运算符+id(例如:id<2;id=2;id>2) 等于某个值,大于某个值,在某个区间内修改

操作符 含义 范围 结果
= 等于 5=6 false
<> 或 != 不等于 5<>6 true
BETWEEN…and… 在某个范围内 [2,5]都是闭区间 /
AND && 5>1 and 1>2 false
OR | | 5>1 or 1>2 true

3.5删除

DELETE命令

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

-- 清空表
TRUNCATE `student`;

TRUNCATE命令

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

-- 清空表
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 继续从上一个增量开始(存在文件中的,不会丢失)

4.DQL查询数据

4.1DQL

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

这是一个示例表,在创建这些表并插入数据之后,将使用SELECT来查询表

CREATE DATABASE IF NOT EXISTS `school`;
-- 创建一个school数据库
USE `school`;-- 创建学生表
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;

-- 插入学生数据
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');

-- 创建年级表
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 `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 = 19 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);

-- 创建成绩表
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);

4.2指定查询字段

简单查询

-- SELECT 字段 FROM 表
SELECT * FROM `student`

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

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

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

去重 DISTINCT

-- 查询有哪些同学参加了考试
SELECT `studentno` FROM `result` 
-- 发现重复数据,去重
SELECT DISTINCT `studentno` FROM `result`

SELECT的其它用法

-- 查询MySQL系统版本 (函数)
SELECT VERSION()
-- 用来计算 (表达式)
SELECT 100*3-1 AS 计算结果
-- 查询自增的步长 (变量)
SELECT @@auto_increment_increment

-- 学生考试成绩 +1分查看
SELECT `studentno`,`studentresult`+1 AS '提分后' FROM `result`

4.3where条件子句

between/and/or/and 用法

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

搜索的条件由一个或者多个表达式组成,结果返回的是 布尔值

运算符 语法 描述
and && a and b / a&&b 逻辑与
or | | a or b / a | | b 逻辑或
Not ! not a / ! a 逻辑非
-- 查询考试成绩在95~100分之间
-- and的使用
SELECT `studentno`,`studentresult` FROM `result`
WHERE `studentresult`>95 AND `studentresult`<=100

-- a&&的使用
SELECT `studentno`,`studentresult` FROM `result`
WHERE `studentresult`>95 && `studentresult`<=100

-- 模糊查询(between的用法)
SELECT `studentno`,`studentresult` FROM `result`
WHERE `studentresult` BETWEEN 95 AND 100

-- 查询除了1000号学生之外的成绩
-- not的使用
SELECT `studentno`,`studentresu`lt` FROM result
WHERE NOT `studentno`=1000

-- !=的使用
SELECT `studentno`,`studentresult` FROM result
WHERE `studentno`!=1000 

模糊查询

运算符 语法 描述
IS NULL a is null 如果操作符为NULL,结果为真
IS NOT NULL a is not null 如果操作符不为NULL,结果为真
BETWEEN a between b and c 若a在b和c之间,则结果为真
Like a like b SQL匹配,如果a匹配b,则结果为真
In a in(a1,a2,a3…) 假设a在a1或者a2…其中的某一个值,则结果为真

like和in的用法

-- like结合 %(代表0到任意个字符)查询所有姓“刘”的同学
SELECT `studentno`,`studentname` FROM `student`
WHERE `studentname` LIKE "刘%"

-- like结合_ 查询姓“刘”姓后只有一个字的同学(两个_ ,就是其后有两个字,可以更多叠加)
SELECT `studentno`,`studentname` FROM `student`
WHERE `studentname` LIKE "刘_"

-- 查询名字中间有“强”的同学 即:%强%
SELECT `studentno`,`studentname` FROM `student`
WHERE `studentname` LIKE '%强%'

-- 模糊查询 in
-- 查询 1001,1002号的学员
SELECT `studentno`,`studentname` FROM `student`
WHERE `studentno` IN (1001,1002,1003);

-- 查询在北京的学生
SELECT `studentno`,`studentname` FROM `student`
WHERE `address` IN ('安徽合肥','北京朝阳')

4.4联表查询

七种"join"理论

MySQL学习_第1张图片

联表查询的基本思路与方法

思路:

1.分析需求,分析查询的字段来自哪些表(连接查询)

2.确定使用哪种连接查询? 7种"join"理论

3.确定交叉点(这两个表中哪个数据是相同的)
判断的条件:学生表中的studentNo == 成绩表中的studentNo

join+(连接的表) on+(判断的条件) 连接查询

where 等值查询

-- Inner Join
SELECT s.`studentno`,`studentname`,`subjectno`,`studentresult`
FROM `student` AS s
INNER JOIN `result` AS r
ON s.`studentno` = r.`studentno`

-- Right Join
SELECT s.`studentno`,`studentname`,`subjectno`,`studentresult`
FROM `student` 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 会从右表中返回所有的值,即使左表中没有匹配
-- 查询缺考的同学
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 r.`studentno`=s.`studentno`
INNER JOIN `subject` sub
ON r.`subjectno`=sub.`subjectno`

自连接

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

父类

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` 
-- 查询了参加 数据库结构-1 考试的同学信息:学号,学生姓名,科目名,分数
SELECT s.`studentno`,`studentname`,`subjectname`,`studentresult`
FROM `student` s
INNER JOIN `result` r
ON s.`studentno`=r.`studentno`
INNER JOIN `subject` sub
ON r.`subjectno`=sub.`subjectno`
WHERE `subjectname`='C语言-1'

4.5分页和排序

排序(可以让前端做排序)

Order By默认是升序排列的

-- 排序:升序ASC,降序DESC
-- ORDER BY 字段 排序方法
-- 查询结果根据 成绩降序 排序
SELECT s.`studentno`,`studentname`,`subjectname`,`studentresult`
FROM `student` s
INNER JOIN `result` r
ON s.`studentno`=r.`studentno`
INNER JOIN `subject` sub
ON r.`subjectno`=sub.`subjectno`
WHERE `subjectname`='C语言-1'
ORDER BY `studentresult` DESC

分页

-- 分页是为了缓解数据库压力,给人的体验更好
-- 分页,每页只显示五条数据
-- limit 起始值,页面的大小(显示的行数)
SELECT s.`studentno`,`studentname`,`subjectname`,`studentresult`
FROM `student` s
       INNER JOIN `result` r
                  ON s.`studentno`=r.`studentno`
       INNER JOIN `subject` sub
                  ON r.`subjectno`=sub.`subjectno`
WHERE `subjectname`='C语言-1'
ORDER BY `studentresult` DESC
  LIMIT 0,5

-- 第一页 limit 0,5
-- 第二页 limit 5,5
-- 第三页 limit 10,5

4.6子查询

在where语句中嵌套一个子查询语句
where(select*from)

-- 方式一:查询 C语言-1 的所有考试结果(学号,科目编号,成绩),降序排列
SELECT `studentno`,r.`subjectno`,`studentresult`
FROM `result` r
INNER JOIN `subject` sub
ON r.`subjectno`=sub.`subjectno`
WHERE `subjectname`='C语言-1'
ORDER BY `studentresult` DESC

-- 方式二:使用子查询(由里及外)
SELECT `studentno`,`subjectno`,`studentresult`
FROM `result`
WHERE `subjectno`=(
	SELECT `subjectno` FROM `subject`
	WHERE `subjectname`='C语言-1'
)

4.7分组和过滤

-- 查询不同课程的平均分,最高分,最低分,平均分大于80
-- 核心:根据不同的课程分组
SELECT `subjectname`,AVG(`studentresult`) AS 平均分,MAX(`studentresult`),MIN(`studentresult`)
FROM `result` r
INNER JOIN `subject` sub
ON r.`subjectno`=sub.`subjectno`
GROUP BY r.`subjectno`  -- 如果有多种分组标准,可以写成 GROUP BY 属性名,属性名,属性名....
HAVING 平均分>80 -- having用于“过滤分组”,根据已查询的字段分组,后面可以使用聚合函数(这是where做不到的)

5.MySQL函数

5.1常用函数

-- 数学运算
SELECT ABS(-8) -- 绝对值
SELECT CEILING(9.4) -- 10,向上取整 
SELECT FLOOR(9.4) -- 9,向下取整
SELECT RAND() -- 返回一个0~1的随机数
SELECT SIGN() -- 判断一个数的符号  0返回0 负数返回 -1 正数返回 1

-- 字符串函数
SELECT CHAR_LENGTH('你好') -- 字符串长度
SELECT CONCAT('我','和','你') -- 拼接字符串
SELECT INSERT('我爱编程',2,1,'no') -- 查询,从某个位置开始替换某个长度为成要替换的字符串,例子就是从2这个位置开始,将长度为1的字符串“爱”替换成“no”(第一个字符是在1的位置而不是0)
SELECT LOWER('ZMC') -- 小写字母
SELECT UPPER('zmc') -- 大写字母
SELECT INSTR('zmc666','6') -- 返回第一次出现字串的索引
SELECT REPLACE('坚持就能成功','坚持','努力') -- 替换出现的指定的字符串
SELECT SUBSTR('坚持就能成功',4,6) -- 返回指定的字符串
SELECT REVERSE('坚持就能成功') -- 反转

-- 时间和日期函数
SELECT CURRENT_DATE() -- 获取当前日期 年-月-日
SELECT CURDATE() -- 同上
SELECT NOW() -- 年-月-日 时:分:秒
SELECT LOCALTIME() -- 同上 本地时间
SELECT SYSDATE() -- 同上 系统时间

date=2022-04-21
year(date)=2022
month(date)=4
date_format(date, "%Y%m")="202108"

DATE_ADD(date,INTERVAL expr type) --DATE_ADD() 函数向日期添加指定的时间间隔。
-- date 参数是合法的日期表达式。expr 参数是您希望添加的时间间隔

SELECT YEAR(NOW()) 
SELECT MONTH(NOW()) -- 可以此类推

-- 系统
SELECT SYSTEM_USER()
SELECT USER()
SELECT VERSION()

DATE_ADD函数

MySQL学习_第2张图片

CASE函数

是一种多分支的函数,可以根据条件列表的值返回多个可能的结果表达式中的一个。
可用在任何允许使用表达式的地方,但不能单独作为一个语句执行。
分为:
简单CASE函数
搜索CASE函数

简单 CASE函数

CASE 测试表达式
WHEN 简单表达式1 THEN 结果表达式1
WHEN 简单表达式2 THEN 结果表达式2WHEN 简单表达式n THEN 结果表达式n
[ ELSE 结果表达式n+1 ]
END计算测试表达式,按从上到下的书写顺序将测试表达式的值与每个WHEN子句的简单表达式进行比较。
如果某个简单表达式的值与测试表达式的值相等,则返回第一个与之匹配的WHEN子句所对应的结果表达式的值。
如果所有简单表达式的值与测试表达式的值都不相等,
若指定了ELSE子句,则返回ELSE子句中指定的结果表达式的值;
若没有指定ELSE子句,则返回NULL

例48. 查询班级表中的学生的班号、班名、系号和班主任号,并对系号作如下处理:
当系号为1时,显示 “计算机系”;
当系号为2时,显示 “软件工程系”;
当系号为3时,显示 “物联网系”。

SELECT 班号 ,班名,
CASE 系号
WHEN 1 THEN '软件工程系'
WHEN 2 THEN '计算机系'
WHEN 3 THEN '物联网系'
END AS 系号,班主任号
FROM 班级表

搜索CASE函数

CASE
WHEN 布尔表达式1 THEN 结果表达式1
WHEN 布尔表达式2 THEN 结果表达式2WHEN 布尔表达式n THEN 结果表达式n
[ ELSE 结果表达式n+1 ]
END

按从上到下的书写顺序计算每个WHEN子句的布尔表达式。
返回第一个取值为TRUE的布尔表达式所对应的结果表达式的值。
如果没有取值为TRUE的布尔表达式,
则当指定了ELSE子句时,返回ELSE子句中指定的结果;
如果没有指定ELSE子句,则返回NULL。

例48用搜索CASE来做:

SELECT 班号 ,班名,
CASE
WHEN 系号=1 THEN '软件工程系'
WHEN 系号=2 THEN '计算机系'
WHEN 系号=3 THEN '物联网系'
END AS 系号,班主任号
FROM 班级表

例49.查询“M01F011”号课程的考试情况,列出学号、课程号和成绩,同时将百分制成绩显示为等级。

SELECT 学号,课程号,
CASE
WHEN 成绩 >= 90 THEN '优'
WHEN 成绩 BETWEEN 80 AND 89 THEN '良'
WHEN 成绩 BETWEEN 70 AND 79 THEN '中'
WHEN 成绩 BETWEEN 60 AND 69 THEN '及格'
WHEN 成绩 <60 THEN '不及格'
END 成绩
FROM 成绩表
WHERE 课程号 = 'M01F011'

CASE函数(续)

例50.统计每个班男生和女生的数量各是多少,统计结果的表头为,班号,男生数量,女生数量。

SELECT 班号,
COUNT(CASE WHEN 性别=‘男’ THEN ‘男’ END) 男生数,
COUNT(CASE WHEN 性别=‘女’ THEN ‘女’ END) 女生数
FROM 学生表 GROUP BY 班号

例51.判断成绩的等级,85-100为“优”,70-84为“良”,60-69为“及格”,60以下为“不及格”,并统计每一等级的人数。

SELECT
CASE
WHEN GRADE BETWEEN 85 AND 100 THEN '优'
WHEN GRADE BETWEEN 70 AND 84 THEN '良'
WHEN GRADE BETWEEN 60 AND 69 THEN '及格'
ELSE '不及格'
END 等级, COUNT(*) 人数
FROM SC
GROUP BY
CASE
WHEN GRADE BETWEEN 85 AND 100 THEN '优'
WHEN GRADE BETWEEN 70 AND 84 THEN '良'
WHEN GRADE BETWEEN 60 AND 69 THEN '及格'
ELSE '不及格'
END

substring_index字符串截取

substring_index(str,delim,count)
str:要处理的字符串
delim:分隔符
count:计数

例子: str=www. wikibt.com
substring_ index(str,‘.’,1)
结果是: www
substring_ index(str,‘,2)
结果是: www.wikibt
也就是说,如果count是正数,那么就是从左往右数,第N个分隔符的左边的全部内容
相反,如果是负数,那么就是从右边开始数,第N个分隔符右边的所有内容,如:
substring_ index(str,’.’,-2)
结果为: wikibt.com
有人会问,如果我要中间的的wikibt怎么办?
很简单的,两个方向:
从右边第二个分隔符的右边全部,再从左数的第一个分隔符的左边
substring_index(substring_index(str,‘.’,-2),‘.’,1);

IF函数

IF(expr,v1,v2)
其中:表达式 expr 得到不同的结果,当 expr 为真是返回 v1 的值,否则返回 v2.

5.2聚合函数

函数名称 描述
COUNT() 计数
SUM() 求和
AVG() 平均值
MAX() 最大值
MIN() 最小值
-- 聚合函数
-- 这三个select都能统计表中的数据,区别:
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`

5.3数据库级别的MD5加密

MD5不可逆

MD5破解网站的原理,背后存在一个字典

-- 加密
UPDATE `test` SET pwd=MD5(pwd) -- 加密全部的密码

-- 插入的时候加密
INSERT INTO `test` VALUES (1,'zhangsan',MD5('123456'))

-- 如何校验:将用户传递进来的密码,进行md5加密,然后比对加密后的值

6.事务

事务原则:ACID原则 原子性,一致性,隔离性,持久性

原子性(Atomicity)

要么都成功,要么都失败

一致性(Consistency)

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

隔离性(Isolation)

事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干涉,事务之间需要隔离

持久性(Durability)

事务一旦提交则不可逆,被持久化到数据库中

隔离所导致的一些问题

脏读

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

不可重复读

在一个事务内读取表中的某一行数据,多次读取结果不同

虚读(幻读)

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

执行事务

-- mysql 是默认开启事务自动提交的
set autocommit = 0 -- 关闭事务的自动提交
set autocommit = 1 -- 开启事务的自动提交

-- 手动处理事务
SET autocommit = 0 
-- 事务开启
start transaction -- 标记一个事务的开始,从这个之后的 sql 都在同一个事务内

-- 提交:持久化
commit -- 一旦提交事务,就被持久化了
-- 回滚:回到原来的样子
rollback 
-- 事务结束
SET autocommit = 1 

-- 拓展
savepoint 保存点名 -- 设置一个事务的保存点
rollback to savepoint 保存点名 -- 回滚到保存点
release savepoint 保存点名 -- 撤销保存点

7.索引

7.1索引的分类

  • 主键索引 (PRIMARY KEY)
    • 唯一的标识,主键不可重复
  • 唯一索引 (UNIQUE KEY)
    • 避免重复的列出现,唯一索引可以重复,多个列都可以标识为唯一索引
  • 常规索引 (KEY/INDEX)
  • 全文索引 (FullText)
    • 在特定的数据库引擎下才有
    • 快速定位数据
-- 索引的使用
-- 1、在创建表的时候给字段增加索引
-- 2、创建完毕后,增加索引

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

-- 增加一个索引
ALTER TABLE `student` ADD FULLTEXT INDEX `studentname`(`studentname`)

-- EXPLAIN 分析sql执行的状况
EXPLAIN SELECT * FROM `student`

7.2测试索引(100万条数据)

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 NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT = 'app用户表'

-- 插入100万条数据
DELIMITER $$ -- 写函数之前必须要写,标记

CREATE FUNCTION mock_data()
RETURNS INT -- 返回一个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'; -- 0.018 sec
SELECT * FROM `app_user` WHERE `name` = '用户9999'; -- 0.048 sec
SELECT * FROM `app_user` WHERE `name` = '用户9999'; -- 0.053 sec
EXPLAIN SELECT * FROM `app_user` WHERE `name` = '用户9999';

-- id_表名_字段名
-- CREATE INDEX 索引名 on 表(字段)
CREATE INDEX id_app_user_name ON `app_user`(`name`); -- INDEX是常规索引
SELECT * FROM `app_user` WHERE `name` = '用户9999'; -- 0.009 sec
SELECT * FROM `app_user` WHERE `name` = '用户9999'; -- 0.002 sec
EXPLAIN SELECT * FROM `app_user` WHERE `name` = '用户9999';

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

  • 索引不是越多越好
  • 不要对经常变动的数据加索引
  • 小数据量的表不需要加索引
  • 索引一般加在常用来查询的字段上

索引的数据结构

Btree:InnoDB的默认数据结构

https://blog.csdn.net/zhizhengguan/article/details/109193886

8.权限管理和备份

8.1用户管理

SQLyog可视化管理

MySQL学习_第3张图片
MySQL学习_第4张图片

SQL命令操作

系统用户表:mysql.user

-- 创建用户 create user 用户名 identified by 密码
CREATE USER zmc IDENTIFIED BY '123456'

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

-- 修改密码 (修改指定用户密码)
SET PASSWORD FOR zmc = PASSWORD('111111')

-- 重命名
RENAME USER zmc TO zmc2

-- 用户授权   *.*(所有的表)
-- ALL PROVILEGES 除了给别人授权(GRANT),其他都能干
GRANT ALL PRIVILEGES ON *.* TO zmc2

-- 查询权限
SHOW GRANTS FOR zmc2 -- 查看指定用户的全部权限
SHOW GRANTS FOR root@localhost

-- 撤销权限 
REVOKE ALL PRIVILEGES ON *.* FROM zmc2

-- 删除用户
DROP USER zmc

8.2MySQL备份

备份的方式:

  • 直接拷贝物理文件
  • 在Sqlyog这种可视化工具手动导出(SQL转储)
  • 命令行导出 mysqldump 命令行使用
--musqldummp -h表名 -u用户名 -p密码 数据库 数据库表1 数据库表2.... >导入位置
--导出
mysqldump -hlocalhost -uroot -pehero000921 school sudent >D:/a.sql

--导入
--登录的情况下,切换到指定的数据库

--导入,登录的情况下
source D:/文件.sql

--没有登录的情况

mysql -u用户 -p密码  数据库名字<备份文件

9.规范数据库设计

9.1如何设计一个项目的数据库

暂时不想听

9.2数据库三大范式

暂时不想听

10.JDBC

10.1数据库驱动

MySQL学习_第5张图片

10.2JDBC

Java操作数据库的规范,俗称JDBC

10.3第一个JDBC程序

1.创建一个普通项目

CREATE DATABASE `jdbcstudy`;

CREATE TABLE  users
(
`id` INT (4) PRIMARY KEY,
`name` VARCHAR(40),
`password` VARCHAR(40),
`birthday` DATE
)ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT INTO `users` (`id`,`name`,`password`,`birthday`) 
VALUES ('1','张三','123456','1999-02-02'),('2','李四','1234556','1999-08-02'),('3','王五','1288556','1998-02-15')
,('4','赵六','752156','1999-12-12')

2.导入数据库驱动

创建一个lib文件夹,将数据库驱动的jar包复制进去,然后右击文件夹,选择 Add as Library

3.第一个jdbc程序

package MySQL_Study.JDBC;

import java.sql.*;

public class JdbcFirstDemo {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //1.加载驱动
        Class.forName("com.mysql.jdbc.Driver"); // 固定写法,加载驱动

        //2.连接用户信息和url
        String url="jdbc:mysql://localhost:3306/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
        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.print("name="+resultSet.getObject("name"));
            System.out.print("password="+resultSet.getObject("password"));
            System.out.println("birthday="+resultSet.getObject("birthday"));

        }
        //6.释放连接
        resultSet.close();
        statement.close();
        connection.close();
    }
}

DriverManager

 对数据库的操作都可以在这里写
connection.rollback();
connection.commit();
connection.setAutoCommit();

Statement/PreparedStatement

编写sql
statement.executeQuery();//查询
statement.execute();//执行任何SQL
statement.executeUpdate();//更新,插入,删除

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

获得指定的数据类型

resultset.getint();
resultset.getobject(); 在不知道列类型的情况下使用
resultset.getDate();

指针

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

##10.4statement对象

配置类

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false
username=root
password=123456

工具类

package MySQL_Study.utils;

import java.io.InputStream;
import java.sql.*;
import java.util.Properties;


public class JdbcUtils {
    private static String driver=null;
    private static String url=null;
    private static String username=null;
    private static String password=null;

    static {
        try{
            InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("MySQL_Study/source/db.properties");
            Properties properties = new Properties();
            properties.load(inputStream);

            driver =properties.getProperty("driver");
            url =properties.getProperty("url");
            username =properties.getProperty("username");
            password =properties.getProperty("password");
            Class.forName(driver);


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

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

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

操作类

package MySQL_Study.JDBC;

import MySQL_Study.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

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();
            String sql="INSERT INTO `users`(`id`,`name`,`password`,`birthday`) VALUES (5,'ZMC','123456','2022-01-01') ";

            int i = st.executeUpdate(sql);

            if(i>0){
                System.out.println("插入成功!");
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}

10.5 SQL注入问题

sql存在漏洞,会导致被拼接

package MySQL_Study.JDBC;

import MySQL_Study.utils.JdbcUtils;

import java.sql.*;

public class SQL注入 {
    public static void main(String[] args) {
        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();

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

            rs = st.executeQuery(sql);

            while(rs.next()){
                System.out.println(rs.getString("NAME"));
                System.out.println(rs.getString("PASSWORD"));
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            JdbcUtils.release(conn, st, rs);
        }
    }
}

这样会查出所有的数据

10.6 PreparedStatement对象

PreparedStatement可以放止SQL注入,效率更高

1.新增

package MySQL_Study.JDBC;

import MySQL_Study.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;

public class PreparedInsert {
    public static void main(String[] args) {
        Connection conn=null;
        PreparedStatement st=null;

        try {
            conn = JdbcUtils.getConnection();

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

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

            //手动给参数赋值
            st.setInt(1,6);
            st.setString(2,"aotuman");
            st.setString(3,"123321");
            // sql.Date 数据库   java.sql.Date()
            // util.Date Java   new Date().getTime()
            st.setDate(4,new java.sql.Date(new Date().getTime()));

            //执行
            int i = st.executeUpdate();
            if(i>0){
                System.out.println("插入成功!");
            }


        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            JdbcUtils.release(conn,st,null);
        }
    }
}

2.删除

package MySQL_Study.JDBC;

import MySQL_Study.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class PreparedDelete {
    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);//预编译SQL,先写sql,然后不执行

            //手动给参数赋值
            st.setInt(1,1);

            //执行
            int i = st.executeUpdate();
            if(i>0){
                System.out.println("删除成功!");
            }


        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            JdbcUtils.release(conn,st,null);
        }
    }
}

3.修改

package MySQL_Study.JDBC;

import MySQL_Study.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class PreparedUpdate {
    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);//预编译SQL,先写sql,然后不执行

            //手动给参数赋值
            st.setString(1,"zmc");
            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.查询

package MySQL_Study.JDBC;

import MySQL_Study.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class PreparedSelect {
    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,2);

            //执行
            rs=st.executeQuery();

            if(rs.next()){
                System.out.println(rs.getString("name"));
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}

10.7 JDBC操作事务

package MySQL_Study.JDBC;

import MySQL_Study.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

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 sql="update account set money = money-100 where name='A'";
            st=conn.prepareStatement(sql);
            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,rs);
        }
    }
}

10.8 数据库连接池

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

连接–释放 十分浪费资源

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

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

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

DBCP
C3P0
Druid:阿里巴巴

DBCP

需要用到的jar包
commons-dbcp2-2.9.0
commons-logging-1.2
commons-pool2-2.11.1

配置类

#连接设置,这里面的名字是DBCP数据源中定义好的
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false
username=root
password=123456

#
initialSize=10

#最大连接数量
maxActive=50

#最大空闲连接
maxIdle=20

#最小空闲连接
minIdle=5

#超时等待时间以毫秒为单位/s
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

工具类

package MySQL_Study.utils;

import org.apache.commons.dbcp2.BasicDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class JdbcUtils_DBCP {
    private static DataSource dataSource = null;
    static {
        try{
            InputStream inputStream = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("MySQL_Study/source/dbcpconfig.properties");
            Properties properties = new Properties();
            properties.load(inputStream);

            //创建数据源
            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 throwables) {
                throwables.printStackTrace();
            }
        }
        if(st!=null){
            try {
                st.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

调用类

package MySQL_Study.JDBC;

import MySQL_Study.utils.JdbcUtils_DBCP;

import java.sql.*;

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`,`birthday`) VALUES (?,?,?,?) ";

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

            //手动给参数赋值
            st.setInt(1,10);
            st.setString(2,"aotuman");
            st.setString(3,"123321");
            // sql.Date 数据库   java.sql.Date()
            // util.Date Java   new Date().getTime()
            st.setDate(4,new java.sql.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-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">3property>

        
        <property name="initialPoolSize">10property>

        
        <property name="maxIdleTime">30property>

        
        <property name="maxPoolSize">100property>

        
        <property name="minPoolSize">15property>
    default-config>



    
    <named-config name="MySQL">
        <property name="driverClass">com.mysql.jdbc.Driverproperty>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/jbdcstudy?useUnicode=true&characterEncoding=utf8&useSSL=falseproperty>
        <property name="user">rootproperty>
        <property name="root">123456property>

        <property name="acquireIncrement">3property>
        <property name="initialPoolSize">10property>
        <property name="maxIdleTime">30property>
        <property name="maxPoolSize">100property>
        <property name="minPoolSize">10property>
    named-config>


    
c3p0-config>

工具类

package MySQL_Study.utils;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;


public class JdbcUtils_C3P0 {
    private static ComboPooledDataSource dataSource = null;
    static {
        try{

//            new ComboPooledDataSource();
//            dataSource.setDriverClass();
//            dataSource.setUser();
//            dataSource.setPassword();
//            dataSource.setJdbcUrl();
//
//            dataSource.setMaxPoolSize();
//            dataSource.setMinPoolSize();
            //创建数据源
            dataSource = new ComboPooledDataSource(); //配置文件写法


        } 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 throwables) {
                throwables.printStackTrace();
            }
        }
        if(st!=null){
            try {
                st.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

调用类

package MySQL_Study.JDBC;

import MySQL_Study.utils.JdbcUtils_C3P0;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

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`,`birthday`) VALUES (?,?,?,?) ";

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

            //手动给参数赋值
            st.setInt(1,7);
            st.setString(2,"aotuman");
            st.setString(3,"123321");
            // sql.Date 数据库   java.sql.Date()
            // util.Date Java   new Date().getTime()
            st.setDate(4,new java.sql.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);
        }
    }
}

总结

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

你可能感兴趣的:(JavaEE,mysql)