MySQL

MySQL

狂神说java视频


1、初识MySQL


1.1、用途

  • javaEE:企业级java开发 Web
  • 前端(页面:展示,数据!)
  • 后台(连接点:连接数据库 JDBC,连接前端(控制,控制视图跳转,和给前端传递数据))
  • 数据库(存数据,Txt,Excel,word)

1.2、什么是数据库

  • DataBase
  • 概念: 长期存放在计算机内,有组织,可共享的大量数据的集合,是一个数据 “仓库”
  • 作用:存储数据,管理数据
  • 数据库是所有软件体系中最核心的存在 DBA

1.3、数据库分类

  • 关系型数据库(SQL)

    • MySQL
    • Oracle
    • SQL Server
    • DB2
    • SQLlite
    • 通过表与表之间,行和列之间的关系进行数据的存储
  • 非关系型数据库(NoSQL)

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

1.4、DBMS(数据库管理系统)

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

1.5、MySQL简介

MySQL百度百科

MySQL最新版本安装下载地址

MySQL旧版本安装下载地址

MySQL_第1张图片

1.6、安装MySQL

配置文件ini

# mysql配置文件ini
[mysqld]
# 目录一定要换成自己的 最后的 "\"也要加上
basedir=D:\Environment\mysql-5.7.19\
# data目录在D:\Environment\mysql-5.7.19\下找不到,不要自己新建,配置文件写好了,到时候自动生成。否则初始化的时候可能会失败。
datadir=D:\Environment\mysql-5.7.19\data\
port=3306
# 跳过密码验证
skip-grant-tables

注意:

  • 第5步的时候一定要管理员模式下启动cmd
  • 第七步的时候 -u 后面可以空格再接root,也可以不用空格直接后面就是root,但是-p后面一定不能有空格,-p后面直接接着输入密码,或者-p之后直接回车,然后出现要输入密码,输入密码即可,输入的密码是不显示的,所以一定要注意写对密码。
    MySQL_第2张图片
    MySQL_第3张图片MySQL_第4张图片

1.7、数据库 XXX语言


MySQL_第5张图片

2、操作数据库


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

MySQL关键字不区分大小写

2.1、操作数据库


2.1.1、数据库操作

#修改密码
update user set password=password('123456')where user='root'; 
#刷新数据库
flush privileges;
#显示所有数据库
show databases; 
#打开某个数据库
use dbname;
#显示数据库mysql中所有的表
show tables; 
#显示表mysql数据库中user表的列信息
describe user; 
#创建数据库
create database name; 
#选择数据库
use databasename; 

exit; 退出Mysql
? 命令关键词 : 寻求帮助
#查看数据库的所有存储引擎
show engines;
#查看当前默认的存储引擎
show variables like '%storage_engine%';
#查看表的存储引擎
use db_waremanage;
show table status like "ware";
#操作数据库
#1、新建数据库 
CREATE DATABASE[ IF NOT EXISTS] 数据库名 数据库选项
数据库选项:
        CHARACTER SET charset_name(字符集)
        COLLATE collation_name(排序规则)
CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE IF NOT EXISTS `TEST1`;
#2、使用数据库
USE `TEST1`;
#3、查询所有数据库
SHOW DATABASES[ LIKE 'PATTERN']
SHOW DATABASES;
#4、删除数据库(同时删除该数据库相关的目录及其目录内容)
DROP DATABASE[ IF EXISTS] 数据库名
DROP DATABASE TEST1;
SHOW DATABASES;
#查看当前数据库
SELECT DATABASE();
#查看创建数据库语句
SHOW CREATE DATABASE `数据库名`
#修改库的选项信息
ALTER DATABASE 库名 选项信息
#显示当前时间、用户名、数据库版本
SELECT now(), user(), version();
utf8_general_ci

2.1.2、数据库的存储引擎

MyISAM是MySQL的默认数据库引擎(5.5版之前)。虽然性能极佳,而且提供了大量的特性,包括全文索引、压缩、空间函数等,但MyISAM不支持事务和行级锁,而且最大的缺陷就是崩溃后无法安全恢复。不过,5.5版本之后,MySQL引入了InnoDB(事务性数据库引擎),MySQL 5.5版本后默认的存储引擎为InnoDB。

两者的对比:

  • 是否支持行级锁 : MyISAM 只有表级锁(table-level locking),而InnoDB 支持行级锁(row-level locking)和表级锁,默认为行级锁。
  • 是否支持事务和崩溃后的安全恢复: MyISAM 强调的是性能,每次查询具有原子性,其执行速度比InnoDB类型更快,但是不提供事务支持。但是InnoDB 提供事务支持,外部键等高级数据库功能。 具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。
  • 是否支持外键: MyISAM不支持,而InnoDB支持。
  • 是否支持MVCC :仅 InnoDB 支持。应对高并发事务, MVCC比单纯的加锁更高效;MVCC只在 READ COMMITTED 和 REPEATABLE READ 两个隔离级别下工作;MVCC可以使用 乐观(optimistic)锁 和 悲观(pessimistic)锁来实现;各数据库中MVCC实现并不统一。推荐阅读:MySQL-InnoDB-MVCC多版本并发控制
  • 。。。。

2.2、数据库的列类型


MySQL_第6张图片

MySQL_第7张图片

MySQL_第8张图片


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


MySQL_第9张图片
MySQL_第10张图片
拓展:
MySQL_第11张图片

2.4、创建数据库表(重点)


扩展:

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

/* 建表规范 */ ------------------
    -- Normal Format, NF
        - 每个表保存一个实体信息
        - 每个具有一个ID字段作为主键
        - ID主键 + 原子表
    -- 1NF, 第一范式
        字段不能再分,就满足第一范式。
    -- 2NF, 第二范式
        满足第一范式的前提下,不能出现部分依赖。
        消除复合主键就可以避免部分依赖。增加单列关键字。
    -- 3NF, 第三范式
        满足第二范式的前提下,不能出现传递依赖。
        某个字段依赖于主键,而有其他字段依赖于该字段。这就是传递依赖。
        将一个实体信息的数据放在一个表内实现。
/*
目标:创建一个school数据库
创建学生表(列,字段)使用SQL创建
学号int 登录密码varchar(20) 姓名,性别varchar(2),出生日期datatime 家庭住址email

注意点:
-- 使用英文(),表的名称和字段尽量使用` `括起来
-- AUTO_INCREMENT 自增
-- 字符串使用单引号括起来!
-- 所有的语句后面加,(英文的),最后一个不用加
-- PRIMARY KEY主键,一般一个表只有一个唯一的主键!

*/
#创建一个school数据库
CREATE DATABASE	if not EXISTS `school` CHARACTER SET UTF8 COLLATE UTF8_GENERAL_CI; 
#使用school数据库
use `school`;
-- 创建学生表
CREATE  TABLE IF NOT EXISTS  `student`(
	`id` INT(10) not null AUTO_INCREMENT comment '学号',
	`name` varchar(20) not null default '匿名' comment '姓名',
	`pwd` varchar(20) not null default '123456'comment '密码',
	`sex` varchar(4) NOT null DEFAULT '男' comment '性别',
	`birthday` datetime  default NULL comment '出生日期',
	`address` varchar(255)  default NULL comment '地址',
	`email` varchar(50)  default null comment '邮箱',
	PRIMARY key(`id`)	
		
) engine=INNODB  DEFAULT charset=utf8

MySQL_第12张图片
常见操作表的命令:

-- 查看所有表
    SHOW TABLES[ LIKE 'pattern']
    SHOW TABLES FROM  库名
-- 查看表结构
    SHOW CREATE TABLE 表名 (信息更详细)
	SHOW CREATE TABLE `student`;
    DESC 表名 / DESCRIBE 表名 / EXPLAIN 表名 / SHOW COLUMNS FROM 表名 [LIKE 'PATTERN']
	DESC `student`;
    SHOW TABLE STATUS [FROM db_name] [LIKE 'pattern']
	SHOW TABLE STATUS FROM school LIKE 'student';

2.5、数据表的类型

MySQL_第13张图片
MySQL_第14张图片
MySQL_第15张图片

在物理控件存在的位置

MySQL_第16张图片

设置数据库表的字符编码

MySQL_第17张图片

2.6、修改、删除数据库表


-- 修改表
    -- 修改表本身的选项
        ALTER TABLE 表名 表的选项
        eg: ALTER TABLE 表名 ENGINE=MYISAM;
		ALTER TABLE `student` ENGINE=INNODB;
    -- 对表进行重命名
        RENAME TABLE 原表名 TO 新表名
        RENAME TABLE 原表名 TO 库名.表名 (可将表移动到另一个数据库)
		RENAME TABLE `student1` to school.student;
        -- RENAME可以交换两个表名
    -- 修改表的字段机构(13.1.2. ALTER TABLE语法)
        ALTER TABLE 表名 操作名
        -- 操作名
            ADD[ COLUMN] 字段定义       -- 增加字段
                AFTER 字段名          -- 表示增加在该字段名后面
                FIRST               -- 表示增加在第一个
            ADD PRIMARY KEY(字段名)   -- 创建主键
            ADD UNIQUE [索引名] (字段名)-- 创建唯一索引
            ADD INDEX [索引名] (字段名) -- 创建普通索引
            DROP[ COLUMN] 字段名      -- 删除字段
            MODIFY[ COLUMN] 字段名 字段属性     -- 支持对字段属性进行修改,不能修改字段名(所有原有属性也需写上)
            CHANGE[ COLUMN] 原字段名 新字段名 字段属性      -- 支持对字段名修改
            DROP PRIMARY KEY    -- 删除主键(删除主键前需删除其AUTO_INCREMENT属性)
            DROP INDEX 索引名 -- 删除索引
            DROP FOREIGN KEY 外键    -- 删除外键
						
			ALTER TABLE `student` ADD age int(4) after id;
			ALTER TABLE `student` ADD age1 int(4) FIRST;
			ALTER TABLE `student` MODIFY age1 varchar(4);
			DESC  `student`;
			ALTER TABLE `student` CHANGE age1 age2 int(4);
			ALTER TABLE `student` DROP age2;
-- 删除表
    DROP TABLE[ IF EXISTS] 表名 ...
	DROP TABLE IF EXISTS `test2`;
-- 清空表数据
    TRUNCATE [TABLE] 表名
-- 复制表结构
    CREATE TABLE 表名 LIKE 要复制的表名
	CREATE TABLE test1 LIKE `student`;
	DESC test1;
-- 复制表结构和数据
    CREATE TABLE 表名 [AS] SELECT * FROM 要复制的表名
	CREATE TABLE test2 SELECT * FROM student;
-- 检查表是否有错误
    CHECK TABLE tbl_name [, tbl_name] ... [option] ...
	CHECK TABLE `student`;
		
-- 优化表
    OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...
-- 修复表
    REPAIR [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ... [QUICK] [EXTENDED] [USE_FRM]
-- 分析表
    ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...

3、MySQL数据管理


3.1、外键(了解即可)

MySQL_第18张图片

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

MySQL_第19张图片

MySQL_第20张图片

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

MySQL_第21张图片

3.2、DML语言(全部记住)


数据库意义:数据存储,数据管理
DML语言:数据操作语言

  • insert
  • update
  • delete

3.3、添加


insert

/* 数据操作 */ ------------------
-- 增
    INSERT [INTO] 表名 [(字段列表)] VALUES (值列表)[, (值列表), ...]
        REPLACEINSERT 完全一样,可互换。
    INSERT [INTO] 表名 SET 字段名=[, 字段名=, ...]
		use school;
		DESC student;
		INSERT INTO `student`(`age`)VALUES(1);
		replace into `student`(age)VALUES(2);
		-- 一般写插入语句,我们一定要数据和字段一一对应
		-- 插入多个字段
		insert into student (`age`,`name`,`pwd`,`sex`)VALUES(3,'san','san','男'),(4,'si','si','男');

注意事项:

  1. 字段和字段之间使用英文逗号隔开
  2. 字段是可以省略的,但是后面的值必须要一一对应,不能少
  3. 如果要插入的值列表包含所有字段并且顺序一致,则可以省略字段列表。
  4. 可以同时插入多条数据,VALUES后面的值,需要使用,隔开即可VALUES(),()…

3.4、修改

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

-- 改
    UPDATE 表名 SET 字段名=新值[, 字段名=新值] [更新条件]      
		-- 查看表中的数据
		select * from student;
		-- 修改id为1的学生的姓名
		update `student` set name='yi' where id=1;
		-- 在不指定条件的情况下,会将表中所有name字段都修改为yi
		update student set name='yi';

MySQL_第22张图片

MySQL_第23张图片

3.5、删除


delete

-- 删
    DELETE FROM 表名[ 删除条件子句]
        没有条件子句,则会删除全部
		-- 删除全部数据(避免这样写,会全部删除)
		delete from student;
		-- 删除指定数据
		delete from student where id=2;
		-- 查询所有数据
		select * from student;

truncate命令
作用:完全清空一个数据库表中的数据,但是表的结构和索引约束都不变。

		select * from student;
		create table test3 select * from student;
		select * from test3;
		truncate test3;
/* TRUNCATE */ ------------------
TRUNCATE [TABLE] tbl_name
清空数据
删除重建表
deletetruncate的区别:
相同点:都能删除数据,都不会删除表结构
区别:
1.truncate 是删除表再创建,delete 是逐条删除
2.truncate 重置auto_increment的值。而delete不会
3.truncate 不知道删除了几条,而delete知道。
4.当被用于带分区的表时,truncate 会保留分区
5.truncate 不会影响事务

MySQL_第24张图片

MySQL_第25张图片

4、DQL查询数据(重点)


4.1、DQL

MySQL_第26张图片

/* SELECT */ ------------------
SELECT [ALL|DISTINCT] select_expr FROM -> WHERE -> GROUP BY [合计函数] -> HAVING -> ORDER BY -> LIMIT
a. select_expr
    -- 可以用 * 表示所有字段。
        select * from tb;
    -- 可以使用表达式(计算公式、函数调用、字段也是个表达式)
        select stu, 29+25, now() from tb;
    -- 可以为每个列使用别名。适用于简化列标识,避免多个列标识符重复。
        - 使用 as 关键字,也可省略 as.
        select stu+10 as add10 from tb;
b. FROM 子句
    用于标识查询来源。
    -- 可以为表起别名。使用as关键字。
        SELECT * FROM tb1 AS tt, tb2 AS bb;
    -- from子句后,可以同时出现多个表。
        -- 多个表会横向叠加到一起,而数据会形成一个笛卡尔积。
        SELECT * FROM tb1, tb2;
    -- 向优化符提示如何选择索引
        USE INDEXIGNORE INDEXFORCE INDEX
        SELECT * FROM table1 USE INDEX (key1,key2) WHERE key1=1 AND key2=2 AND key3=3;
        SELECT * FROM table1 IGNORE INDEX (key3) WHERE key1=1 AND key2=2 AND key3=3;
c. WHERE 子句
    -- 从from获得的数据源中进行筛选。
    -- 整型1表示真,0表示假。
    -- 表达式由运算符和运算数组成。
        -- 运算数:变量(字段)、值、函数返回值
        -- 运算符:
            =, <=>, <>, !=, <=, <, >=, >, !, &&, ||,
            in (not) null, (not) like, (not) in, (not) between and, is (not), and, or, not, xor
            is/is not 加上ture/false/unknown,检验某个值的真假
            <=><>功能相同,<=>可用于null比较
d. GROUP BY 子句, 分组子句
    GROUP BY 字段/别名 [排序方式]
    分组后会进行排序。升序:ASC,降序:DESC
    以下[合计函数]需配合 GROUP BY 使用:
    count 返回不同的非NULL值数目  count(*)count(字段)
    sum 求和
    max 求最大值
    min 求最小值
    avg 求平均值
    group_concat 返回带有来自一个组的连接的非NULL值的字符串结果。组内字符串连接。
e. HAVING 子句,条件子句
    与 where 功能、用法相同,执行时机不同。
    where 在开始时执行检测数据,对原数据进行过滤。
    having 对筛选出的结果再次进行过滤。
    having 字段必须是查询出来的,where 字段必须是数据表存在的。
    where 不可以使用字段的别名,having 可以。因为执行WHERE代码时,可能尚未确定列值。
    where 不可以使用合计函数。一般需用合计函数才会用 having
    SQL标准要求HAVING必须引用GROUP BY子句中的列或用于合计函数中的列。
f. ORDER BY 子句,排序子句
    order by 排序字段/别名 排序方式 [,排序字段/别名 排序方式]...
    升序:ASC,降序:DESC
    支持多个字段的排序。
g. LIMIT 子句,限制结果数量子句
    仅对处理好的结果进行数量限制。将处理好的结果的看作是一个集合,按照记录出现的顺序,索引从0开始。
    limit 起始位置, 获取条数
    省略第一个参数,表示从索引0开始。limit 获取条数
h. DISTINCT, ALL 选项
    distinct 去除重复记录
    默认为 all, 全部记录

MySQL_第27张图片

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

MySQL_第28张图片

SELECT * FROM student

MySQL_第29张图片

SELECT `studentno`,`studentname` FROM student

MySQL_第30张图片

SELECT `studentno` as 学号,`studentname` as 学生姓名 FROM student as s

MySQL_第31张图片

SELECT CONCAT('姓名:',studentname) as 新名字 FROM student

MySQL_第32张图片

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

MySQL_第33张图片

4.3、Where条件字句


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

MySQL_第34张图片

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

SELECT studentno,`studentresult` FROM result

-- 查询考试成绩再 95-100 分之间
-- and 

SELECT studentno,`studentresult` FROM result WHERE studentresult>=95 AND studentresult<=100
-- &&
SELECT studentno,`studentresult` FROM result WHERE studentresult>=95 && studentresult<=100


-- 模糊查询(区间) BETWEEN  AND
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;

MySQL_第35张图片

测试:

-- ============================= 模糊查询 ================================
-- 查询姓刘的同学
-- 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 ==============================
-- 查询地址为空的学生 null ''
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;

4.4、联表查询


join

join对比
MySQL_第36张图片


MySQL_第37张图片

/* 连接查询(join) */ ------------------
    将多个表的字段进行连接,可以指定连接条件。
-- 内连接(inner join)
    - 默认就是内连接,可省略inner- 只有数据存在时才能发送连接。即连接结果不能出现空行。
    on 表示连接条件。其条件表达式与where类似。也可以省略条件(表示条件永远为真)
    也可用where表示连接条件。
    还有 using, 但需字段名相同。 using(字段名)
    -- 交叉连接 cross join
        即,没有条件的内连接。
        select * from tb1 cross join tb2;
-- 外连接(outer join)
    - 如果数据不存在,也会出现在连接结果中。
    -- 左外连接 left join
        如果数据不存在,左表记录会出现,而右表为null填充
    -- 右外连接 right join
        如果数据不存在,右表记录会出现,而左表为null填充
-- 自然连接(natural join)
    自动判断连接条件完成连接。
    相当于省略了using,会自动查找相同字段名。
    natural join
    natural left join
    natural right join
select info.id, info.name, info.stu_num, extra_info.hobby, extra_info.sex from info, extra_info where info.stu_num = extra_info.stu_id;
-- ============================= 联表查询 join ==============================

-- 查询参加了考试的同学(学号,姓名,科目编号,分数)
/*思路:
1.分析需求,分析查询的字段来自哪些表,(连接查询)
2.确定使用哪些连接查询?7种
3.确定交叉点(这两个表中哪个数据是相同的)
4.判断的条件:学生表中的 studentno=成绩表中的 studentno
*/
-- INNER Join
SELECT s.studentno,studentname,subjectno,studentresult FROM student as s INNER JOIN result as r 
WHERE s.studentno =r.studentno

-- on 和 where的区别:on是先筛选后关联,where是先关联后筛选。on用于批量,where用于单个
-- join(连接的表) on(判断的条件) 连接查询
-- where   等值查询

-- 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


MySQL_第38张图片

student表数据:

MySQL_第39张图片

result表数据:

MySQL_第40张图片

-- INNER Join
SELECT s.studentno,studentname,subjectno,studentresult FROM student as s INNER JOIN result as r 
WHERE s.studentno =r.studentno

测试结果:

MySQL_第41张图片

-- Right Join
SELECT s.studentno,studentname,subjectno,studentresult FROM student  s RIGHT JOIN result  r 
on s.studentno =r.studentno

测试结果:

MySQL_第42张图片

-- Left Join
SELECT s.studentno,studentname,subjectno,studentresult FROM student  s LEFT JOIN result  r 
on s.studentno =r.studentno

测试结果:

MySQL_第43张图片

-- 查询缺考的同学
SELECT s.studentno,studentname,subjectno,studentresult FROM student  s LEFT JOIN result  r 
on s.studentno =r.studentno
WHERE studentresult is null;

测试结果:

MySQL_第44张图片

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

subject表数据:

MySQL_第45张图片

测试结果:

MySQL_第46张图片

自连接

自连接:

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

category表数据:


MySQL_第47张图片

MySQL_第48张图片

MySQL_第49张图片

-- 查询category表中父子信息
SELECT a.`categoryname` as '父栏目',b.`categoryname` as '子栏目'
FROM `category` as a,`category` as b
WHERE a.categoryid=b.pid

测试结果:
MySQL_第50张图片

-- 查询学员所属的年级(学号,学生的姓名,年级名称)
SELECT studentno,studentname,gradename
FROM student s
INNER Join grade g
on s.gradeid=g.gradeid

-- 查询科目所属的年级(科目名称,年级名称)
SELECT subjectname,gradename
FROM subject sub
INNER JOIN grade g
on sub.gradeid=g.gradeid


-- 查询了参加 数据库结构-1 考试的同学信息:学号,学生姓名,科目名,分数
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='数据库结构-1'

4.5、分页和排序

分页
-- ============================= 分页 limit 和排序 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='数据库结构-1'
ORDER BY studentresult ASC
排序
-- ========================== 排序 ORDER BY ====================
-- 100万
-- 为什么要分页?
-- 缓解数据库压力,给人的体验更好,瀑布流
-- 分页,每页只显示2条数据
-- 语法:limit 起始值,页面大小
-- 网页应用:当前,总的页数,页面的大小
-- LIMIT 0,2 1-2
-- LIMIT 1,2 2-3
-- LIMIT 3,5 
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='数据库结构-1'
ORDER BY studentresult ASC
LIMIT 2,5

MySQL_第51张图片

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

-- 思考:
-- 查询JAVA第一学年 课程成绩排名前十的学生,并且分数要大于80的学生信息(学号,姓名,课程名称,分数)
SELECT s.studentno,studentname,subjectname,studentresult
FROM student s
INNER JOIN result r
on s.studentno=r.studentno
INNER JOIN subject sub
on r.subjectno=sub.subjectno
WHERE subjectname='Java第一学年' AND r.studentresult>=80
ORDER BY studentresult DESC
LIMIT 0,10

4.6、子查询


subject表的数据:

MySQL_第52张图片

result表数据:

MySQL_第53张图片

SELECT studentno,subjectno,studentresult
FROM result 
WHERE subjectno = (
      SELECT subjectno FROM `subject`
      WHERE subjectname='数据库结构-1'
)
-- 错误:
-- Subquery returns more than 1 row
-- 解决方法:
-- 1)如果是写入重复,去掉重复数据。然后写入的时候,可以加逻辑判断(php)或者外键(mysql),防止数据重复写入。
--    (我实际开发中遇到的就是数据重复写入的情况,在数据库查到有相同的数据两条,这不符原本的原本的业务需求)
-- 2)在子查询条件语句加limit 1,找到一个符合条件的就可以了(只是找到子查询中的一个符合条件,但是符合该条件的数据可能在result表中不存在,因此该方法可能查出数据为空)
SELECT studentno,subjectno,studentresult
FROM result 
WHERE subjectno = (
      SELECT subjectno FROM `subject`
      WHERE subjectname='数据库结构-1'
			LIMIT 1
)
-- 错误:没有数据显示。将=改为IN
SELECT studentno,subjectno,studentresult
FROM result 
WHERE subjectno IN (
      SELECT subjectno FROM `subject`
      WHERE subjectname='数据库结构-1'
			LIMIT 1
) 
-- 错误:This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'  改为如下,子查询多嵌套一层
SELECT studentno,subjectno,studentresult
FROM result 
WHERE subjectno IN (
      SELECT sub.subjectno FROM (
			      SELECT * FROM `subject`
            WHERE subjectname='数据库结构-1'
		      	LIMIT 1
						)as sub
)
-- 错误:也是没有数据显示,原因是limit 1使得当找到一条subjectname='数据库结构-1'时就返回subjectno,但是这个编号在result表中找不到对应的,所有显示数据为空。正确的做法应该是第三中,在子查询前加any关键字。还可以只要in不要limit,如下:
SELECT studentno,subjectno,studentresult
FROM result 
WHERE subjectno IN (
     SELECT subjectno FROM `subject`
      WHERE subjectname='数据库结构-1'
)
-- 3)在子查询前加any关键字
  select * from table1 where table1.colums=any(select columns from table2);

练习

-- ============================= 子查询练习1 ==============================
-- 1、查询数据库结构-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

-- 方式二:使用子查询(由里及外)
-- 查询所有数据库结构-1 的学生学号
SELECT studentno,subjectno,studentresult
FROM result 
WHERE subjectno in(
    SELECT subjectno FROM `subject`WHERE subjectname='数据库结构-1'
		      	
)
ORDER BY studentresult DESC

-- =============================== 子查询练习2 ============================
-- 2.分数不小于80分的学生的学号和姓名
-- 在这个基础上增加一个科目,高等数学-2
-- 查询高等数学-2的编号
-- 方式一:
SELECT s.studentno,studentname
FROM student s
INNER JOIN result r
ON s.studentno=r.studentno
INNER JOIN `subject` sub
ON sub.subjectno=r.subjectno
WHERE r.studentresult>=80 AND sub.subjectname='高等数学-2'

-- 方式二:
-- 分数不小于80分的学生的学号和姓名
SELECT DISTINCT s.studentno,studentname
FROM student s
INNER JOIN result r
ON r.studentno=s.studentno
WHERE studentresult >=80

-- 在这个基础上增加一个科目,高等数学-2
-- 查询高等数学-2的编号
SELECT DISTINCT s.studentno,studentname
FROM student s
INNER JOIN result r
ON r.studentno=s.studentno
WHERE studentresult >=80 AND subjectno IN(
      SELECT subjectno FROM `subject` WHERE subjectname='高等数学-2'
)

-- 方式三:(由里及外)
SELECT studentno,studentname FROM student WHERE studentno IN (
			 SELECT studentno FROM result WHERE studentresult >=80 AND subjectno =ANY(
			        SELECT subjectno FROM `subject` WHERE subjectname='高等数学-2' 
							)
)

-- ============================== 子查询练习三 =====================================
-- 查询C语言-1 前5名同学的成绩的信息(学号,姓名,分数)
-- 方式一:
SELECT s.studentno,studentname,studentresult
FROM  student s
INNER JOIN result r
ON s.studentno=r.studentno
INNER JOIN `subject` sub
ON r.subjectno=sub.subjectno
WHERE sub.subjectname='C语言-1'
ORDER BY studentresult DESC
LIMIT 0,5
-- 方式二:
SELECT s.studentno,studentname,studentresult
FROM  student s
INNER JOIN result r
ON s.studentno=r.studentno
WHERE subjectno = ANY(
      SELECT subjectno FROM `subject` WHERE subjectname='C语言-1'
)
ORDER BY studentresult DESC

4.7、分组和过滤

-- 查询不同课程的平均分,最高分,最低分
-- 核心:(根据不同的课程分组)
SELECT subjectname, AVG(studentresult) as 平均分,MAX(studentresult) as 最高分,MIN(studentresult) as 最低分
FROM result r
INNER JOIN `subject` sub
ON r.subjectno=sub.subjectno
GROUP BY r.subjectno -- 通过什么字段来分组
HAVING 平均分>80

4.8、UNION(将select结果组合成一个结果集合)

/* UNION */ ------------------
    将多个select查询的结果组合成一个结果集合。
    SELECT ... UNION [ALL|DISTINCT] SELECT ...
    默认 DISTINCT 方式,即所有返回的行都是唯一的
    建议,对每个SELECT查询加上小括号包裹。
    ORDER BY 排序时,需加上 LIMIT 进行结合。
    需要各select查询的字段数量一样。
    每个select查询的字段列表(数量、类型)应一致,因为结果中的字段名以第一条select语句为准。

4.9、备份与还原

/* 备份与还原 */ ------------------
备份,将数据的结构与表内数据保存起来。
利用 mysqldump 指令完成。
-- 导出
mysqldump [options] db_name [tables]
mysqldump [options] ---database DB1 [DB2 DB3...]
mysqldump [options] --all--database
1. 导出一张表
  mysqldump -u用户名 -p密码 库名 表名 > 文件名(D:/a.sql)
2. 导出多张表
  mysqldump -u用户名 -p密码 库名 表123 > 文件名(D:/a.sql)
3. 导出所有表
  mysqldump -u用户名 -p密码 库名 > 文件名(D:/a.sql)
4. 导出一个库
  mysqldump -u用户名 -p密码 --lock-all-tables --database 库名 > 文件名(D:/a.sql)
可以-w携带WHERE条件
-- 导入
1. 在登录mysql的情况下:
  source  备份文件
2. 在不登录的情况下
  mysql -u用户名 -p密码 库名 < 备份文件

4.10、视图

什么是视图:
    视图是一个虚拟表,其内容由查询定义。同真实的表一样,视图包含一系列带有名称的列和行数据。但是,视图并不在数据库中以存储的数据值集形式存在。行和列数据来自由定义视图的查询所引用的表,并且在引用视图时动态生成。
    视图具有表结构文件,但不存在数据文件。
    对其中所引用的基础表来说,视图的作用类似于筛选。定义视图的筛选可以来自当前或其它数据库的一个或多个表,或者其它视图。通过视图进行查询没有任何限制,通过它们进行数据修改时的限制也很少。
    视图是存储在数据库中的查询的sql语句,它主要出于两种原因:安全原因,视图可以隐藏一些数据,如:社会保险基金表,可以用视图只显示姓名,地址,而不显示社会保险号和工资数等,另一原因是可使复杂的查询易于理解和使用。
-- 创建视图
CREATE [OR REPLACE] [ALGORITHM = {
    UNDEFINED | MERGE | TEMPTABLE}] VIEW view_name [(column_list)] AS select_statement
    - 视图名必须唯一,同时不能与表重名。
    - 视图可以使用select语句查询到的列名,也可以自己指定相应的列名。
    - 可以指定视图执行的算法,通过ALGORITHM指定。
    - column_list如果存在,则数目必须等于SELECT语句检索的列数
-- 查看结构
    SHOW CREATE VIEW view_name
-- 删除视图
    - 删除视图后,数据依然存在。
    - 可同时删除多个视图。
    DROP VIEW [IF EXISTS] view_name ...
-- 修改视图结构
    - 一般不修改视图,因为不是所有的更新视图都会映射到表上。
    ALTER VIEW view_name [(column_list)] AS select_statement
-- 视图作用
    1. 简化业务逻辑
    2. 对客户端隐藏真实的表结构
-- 视图算法(ALGORITHM)
    MERGE       合并
        将视图的查询语句,与外部查询需要先合并再执行!
    TEMPTABLE   临时表
        将视图执行完毕后,形成临时表,再做外层查询!
    UNDEFINED   未定义(默认),指的是MySQL自主去选择相应的算法。

4.11、Select小结


MySQL_第54张图片

5、MySQL函数

官网:http://www.searchdoc.cn/rdbms/mysql/dev.mysql.com/doc/refman/5.7/en/func-op-summary-ref.com.coder114.cn.html

5.1、常用函数

-- =============================== 常用函数 ============================
-- 数学运算
SELECT ABS(-8) -- 绝对值
SELECT CEILING(9.4) -- 向上取整
SELECT FLOOR(9.4) -- 向下取整
SELECT RAND() -- 返回一个0-1之间的随机数
SELECT SIGN(10) -- 判断一数的符号 0-0 负数返回-1 整数返回1
-- 字符串函数
SELECT CHAR_LENGTH('即使再小的帆也能远航') -- 字符串的长度
SELECT CONCAT('我','爱','你们')  -- 拼接字符串
SELECT INSERT('我爱变成helloworld',1,2,'超级热爱') -- 查询,从某个位置开始替换某个长度
SELECT LOWER('KuangShen') -- 小写字母
SELECT UPPER('KuangShen') -- 大写字母
SELECT INSERT('kuangshen','h') -- 返回第一次出现的子串的索引
SELECT REPLACE('狂神说坚持就能成功','坚持','努力') -- 替换出现的指定字符串
SELECT SUBSTR('狂神说坚持就能成功',4,6) -- 返回指定的子字符串(源字符串,截取的位置,截取的长度)
SELECT REVERSE('清晨我上马') -- 反转
-- 查询姓 周的同学,名字,刘
SELECT REPLACE(studentname,'刘','周')FROM student
WHERE studentname LIKE '刘%'

SELECT * FROM student
-- 时间和日期函数(记住)
SELECT CURRENT_DATE() -- 获取当前日期
SELECT CURDATE() -- 获取当前日期
SELECT NOW()  -- 获取当前的时间
SELECT LOCALTIME() -- 本地时间
SELECT SYSDATE() -- 系统时间
SELECT YEAR(NOW())  -- 年
SELECT MONTHNAME(NOW())  -- 月
SELECT DAY(NOW())  -- 日
SELECT HOUR(NOW())  -- 小时
SELECT MINUTE(NOW())  -- 分钟
SELECT SECOND(NOW())  -- 秒

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

5.2、聚合函数(常用)


MySQL_第55张图片

-- =============================== 聚合函数 ============================
-- 都能够统计 表中的数据(想查询一个表中有多少个记录,就使用这个count())
SELECT COUNT(identitycard) FROM student; -- Count(指定列),会忽略所有的null值
SELECT COUNT(*) FROM `subject`; -- Count(*),不会忽略null值,本质,计算行数
SELECT COUNT(1) FROM `subject`; -- 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

-- 查询不同课程的平均分,最高分,最低分
-- 核心:(根据不同的课程分组)
SELECT subjectname, AVG(studentresult) as 平均分,MAX(studentresult) as 最高分,MIN(studentresult) as 最低分
FROM result r
INNER JOIN `subject` sub
ON r.subjectno=sub.subjectno
GROUP BY r.subjectno -- 通过什么字段来分组
HAVING 平均分>80

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

MD5百度百科

MySQL_第56张图片

-- =============================== 测试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,'lisi','123456'),(3,'wangwu','12345')
-- 查询
SELECT * FROM testmd5
-- 加密指定id
UPDATE testmd5 set pwd=MD5(pwd) WHERE id=1
-- 加密全部
UPDATE testmd5 set pwd=MD5(pwd)
-- 插入的时候加密
INSERT INTO testmd5 VALUES (4,'XIAOMING',MD5('123456'))
-- 如何校验:将用户传递进来的密码,进行md5加密,然后对比加密后的值
SELECT * FROM testmd5 WHERE `name`='XIAOMING' AND pwd=MD5('123456')

6、事务

事务是指逻辑上的一组操作,组成这组操作的各个单元,要不全成功要不全失败。
    - 支持连续SQL的集体成功或集体撤销。
    - 事务是数据库在数据完整性方面的一个功能。
    - 需要利用 InnoDBBDB 存储引擎,对自动提交的特性支持完成。
    - InnoDB被称为事务安全型引擎。
-- 事务开启
    START TRANSACTION; 或者 BEGIN;
    开启事务后,所有被执行的SQL语句均被认作当前事务内的SQL语句。
-- 事务提交
    COMMIT;
-- 事务回滚
    ROLLBACK;
    如果部分操作发生问题,映射到事务开启前。
-- 事务的特性
    1. 原子性(Atomicity)
        事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
    2. 一致性(Consistency)
        事务前后数据的完整性必须保持一致。
        - 事务开始和结束时,外部数据一致
        - 在整个事务过程中,操作是连续的
    3. 隔离性(Isolation)
        多个用户并发访问数据库时,一个用户的事务不能被其它用户的事物所干扰,多个并发事务之间的数据要相互隔离。
    4. 持久性(Durability)
        一个事务一旦被提交,它对数据库中的数据改变就是永久性的。
-- 事务的实现
    1. 要求是事务支持的表类型
    2. 执行一组相关的操作前开启事务
    3. 整组操作完成后,都成功,则提交;如果存在失败,选择回滚,则会回到事务开始的备份点。
-- 事务的原理
    利用InnoDB的自动提交(autocommit)特性完成。
    普通的MySQL执行语句后,当前的数据提交操作均可被其他客户端可见。
    而事务是暂时关闭“自动提交”机制,需要commit提交持久化数据操作。
-- 注意
    1. 数据定义语言(DDL)语句不能被回滚,比如创建或取消数据库的语句,和创建、取消或更改表或存储的子程序的语句。
    2. 事务不能被嵌套
-- 保存点
    SAVEPOINT 保存点名称 -- 设置一个事务保存点
    ROLLBACK TO SAVEPOINT 保存点名称 -- 回滚到保存点
    RELEASE SAVEPOINT 保存点名称 -- 删除保存点
-- InnoDB自动提交特性设置
    SET autocommit = 0|1;   0表示关闭自动提交,1表示开启自动提交。
    - 如果关闭了,那普通操作的结果对其他客户端也不可见,需要commit提交后才能持久化数据操作。
    - 也可以关闭自动提交来开启事务。但与START TRANSACTION不同的是,
        SET autocommit是永久改变服务器的设置,直到下次再次修改该设置。(针对当前连接)START TRANSACTION记录开启前的状态,而一旦事务提交或回滚后就需要再次开启事务。(针对当前事务)

6.1、什么是事务

要么都成功,要么都失败

1、SQL执行 A给B转账 A 1000 —》200 B200

2、SQL执行 B收到A的钱 A 800 —-》 B400

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

事务原则:ACID原则

原子性,一致性,隔离性,持久性

事务ACID理解

MySQL_第57张图片

MySQL_第58张图片

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

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

-- 手动处理事务


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

INSERT xx
INSERT xx

-- 提交:持久化(成功!)
COMMIT
-- 回滚:回到原来的样子(失败!)
ROLLBACK

-- 事务结束
SELECT autocommit=1 -- 开启自动提交

-- 了解
SAVEPOINT 保存点名 -- 设置一个事务的保存点
ROLLBACK TO SAVEPOINT 保存点名 -- 回滚到保存点
RELEASE SAVEPOINT 保存点名   -- 撤销保存点

模拟场景

-- ============================= 模拟场景 ====================================
-- 转账
CREATE DATABASE shop_qinjiang CHARACTER SET utf8 COLLATE utf8_general_ci
use shop_qinjiang
CREATE TABLE `account`(
    `id` int(3) not null auto_increMent,
		`name` varchar(30) not null,
		`money` DECIMAL(9,2) not null,
		PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT charset=utf8

INSERT INTO account(`name`,`money`)
VALUES('A',2000.00),('B',10000.00)

SELECT * FROM `account`

-- 模拟转账:事务
SET autocommit =0; -- 关闭自动提交
START TRANSACTION -- 开启一个事务

UPDATE account SET money=money-500 WHERE `name`='A' -- A减500
UPDATE account SET money=money+500 WHERE `name`='B' -- A加500

COMMIT; -- 提交事务,就被持久化了,再回滚也没用了
ROLLBACK; -- 回滚

SET autocommit =1;-- 恢复默认值


MySQL_第59张图片

7、索引

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

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

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

7.1、索引的分类

唯一索引:唯一表示的是字段唯一,比如个人账户不能重复。不允许索引的字段具有相同的索引值。在一个列中避免有重复的数据。

MySQL_第60张图片

基础语法

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

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

-- 增加一个索引(索引名)(列名)
ALTER TABLE school_qinjiang.student  ADD FULLTEXT INDEX studentname(studentname)

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

SELECT * FROM student WHERE MATCH(studentname) AGAINST('刘')

【MySQL优化】——看懂explain

7.2、测试索引

use school_qinjiang
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用户表'

-- 插入一百万条数据
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`='用户99999';
EXPLAIN SELECT * FROM app_user WHERE `name` ='用户99999';
SELECT * FROM student

-- 给表创建普通索引,创建索引之后查询用户时注意对比没有加入索引之前的用时
-- id_表名_字段名
-- CREATE INDEX 索引名 on 表(字段)
CREATE INDEX id_app_user_name ON app_user(`name`);
-- 查询用户
SELECT * FROM app_user WHERE `name`='用户99999';
EXPLAIN SELECT * FROM app_user WHERE `name` ='用户99999';

-- 总结:索引本质其实就是去找对应的ID,没加索引前是遍历
EXPLAIN SELECT * FROM app_user WHERE `name` ='用户99999';
-- 没有加索引前执行代码结果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-onMcHuN2-1615651477819)(D:\笔记\java\狂神说java\MySQL\MySQL.assets\image-20210217171431484.png)]

EXPLAIN SELECT * FROM app_user WHERE `name` ='用户99999';
-- 加索引后执行代码结果如下:

image-20210217171633970

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

7.3、索引原则

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

索引的数据结构

Hash类型的索引

Btree:InnoDB默认数据结构

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

8、权限管理和数据库备份

mysql授予远程连接的权限

8.1、权限管理

MySQL_第61张图片

SQL命令操作

用户表:mysql.user

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

-- 刷新权限
flush privileges;
-- 创建用户   CREATE USER 用户名 IDENTIFIED BY '密码'
CREATE USER kuangshen identified BY '123456'

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

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

-- 重命名  RENAME USER 旧名字 TO 新名字
RENAME USER kuangshen TO kuangshen2


-- 分配权限/添加用户
GRANT 权限列表 ON 表名 TO 用户名 [IDENTIFIED BY [PASSWORD] 'password']
-- 用户授权 ALL PRIVILEGES 全部权限,库,表
-- ALL PRIVILEGES 除了给别人授权,其它都可以
GRANT ALL PRIVILEGES ON *.* TO kuangshen
-- 远程数据库授权连接本地数据库
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%'WITH GRANT OPTION

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

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

-- 撤销权限 REVOKE 哪些权限,在哪个库撤销,给谁撤销
REVOKE 权限列表 ON 表名 FROM 用户名
-- 撤销所有权限
REVOKE ALL PRIVILEGES ON *.* FROM kuangshen

-- 删除用户
DROP USER kuangshen

/* 表维护 */

-- 分析和存储表的关键字分布
ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE 表名 ...
-- 检查一个或多个表是否有错误
CHECK TABLE tbl_name [, tbl_name] ... [option] ...
option = {
    QUICK | FAST | MEDIUM | EXTENDED | CHANGED}
-- 整理数据文件的碎片
OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...

8.2、MYSQL备份

为什么要备份(备份重要性):

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

MySQL数据库备份的方式

  • 直接拷贝物理文件和相关配置文件
  • 在可视化工具中可以手动导出
  • mysqldump 备份工具
-- 导出单个文件
-- mysqldump -h主机 -u用户名 -p密码 数据库 表名 >物理磁盘位置/文件名
 mysqldump -hlocalhost -uroot -p123456 school student >D:/a.sql
 
 -- 导出多个文件
 -- mysqldump -h主机 -u用户名 -p密码 数据库 表1 表2 表3 >物理磁盘位置/文件名
  mysqldump -hlocalhost -uroot -p123456 school student >D:/b.sql
  
  -- 导出数据库(所有表)
   -- mysqldump -h主机 -u用户名 -p密码 数据库>物理磁盘位置/文件名
  mysqldump -hlocalhost -uroot -p123456 school >D:/c.sql
  
  -- 导入
  -- 连接用户
  mysql -uroot -p123456
  -- 使用数据库
  use school
  -- 导入a.sql文件;登录的情况下,切换到指定的数据库
  source d:/a.sql
  -- 没有登录的情况下
  mysql -u用户名 -p密码 库名<备份文件

9、规范数据库设计

9.1、为什么需要设计

当数据库比较复杂的时候,我们就需要设计了

MySQL_第62张图片


MySQL_第63张图片


MySQL_第64张图片

9.2、三大范式

三大范式通俗理解

MySQL_第65张图片


MySQL_第66张图片

10、JDBC(重点)

10.1、数据库驱动


MySQL_第67张图片

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

10.2、JDBC


image-20210218140002208


MySQL_第68张图片

java.sql

javax.sql

还需要导入一个数据库驱动包:mysql-connector-java-5.1.47.jar

数据库驱动包可在maven官网下载:https://mvnrepository.com/

10.3、第一个JDBC程序

创建测试数据库

CREATE DATABASE `jdbcStudy` CHARACTER SET utf8 COLLATE utf8_general_ci;

USE `jdbcStudy`;

CREATE TABLE `users`(
 `id` INT PRIMARY KEY,
 `NAME` VARCHAR(40),
 `PASSWORD` VARCHAR(40),
 `email` VARCHAR(60),
 birthday DATE
);

 INSERT INTO `users`(`id`,`NAME`,`PASSWORD`,`email`,`birthday`)
VALUES(1,'zhangsan','123456','[email protected]','1980-12-04'),
(2,'lisi','123456','[email protected]','1981-12-04'),
(3,'wangwu','123456','[email protected]','1979-12-04')

1、创建一个普通项目

2、导入数据库驱动

3、编写测试代码

package cn.dxj1016.lesson01;

import java.sql.*;

//我的第一个JDBC程序
public class JdbcFirstDemo {
     
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
     
//        1、加载驱动
        Class.forName("com.mysql.jdbc.Driver");//固定写法,加载驱动
//        2、用户信息和url
//        useUnicode=true:中文;characterEncoding=utf8:编码;useSSL=trueuseUnicode=true:SSL连接;
//        jdbc:mysql://localhost:3306/mydb3?serverTimezone=GMT%2B8&useSSL=false
//        jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true
        String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false";
        String username = "root";
        String password = "980413dxj";
//        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("birthday="+resultSet.getObject("birthday"));
            System.out.println("=====================================================");
        }

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

错误:Exception in thread “main” com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

将useSSL=true改为false就可以了。

MySQL_第69张图片


MySQL_第70张图片
MySQL_第71张图片
MySQL_第72张图片
![image-20210218155421072](https://img-blog.csdnimg.cn/img_convert/0ebd9b743364758592d5e3afcc02c193.png
MySQL_第73张图片
MySQL_第74张图片

10.4、statement对象


MySQL_第75张图片
MySQL_第76张图片
MySQL_第77张图片
MySQL_第78张图片

代码实现

1、工具类编写

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
username=root
password=980413dxj
package cn.dxj1016.lesson02.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 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 getConnenction() 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

package cn.dxj1016.lesson02;
import cn.dxj1016.lesson02.utils.JdbcUtils;
import java.sql.*;
//增
public class TestInsert {
     
    public static void main(String[] args) {
     
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
     
            connection = JdbcUtils.getConnenction();//获取数据库连接
            statement = connection.createStatement();//获得SQL的执行对象
            String sql = "INSERT INTO users(id,`NAME`,`PASSWORD`,email,birthday)" +
                    "VALUES (5,'kuagnshen','123456','[email protected]','2020-01-01')";
            int i = statement.executeUpdate(sql);
            if (i > 0) {
     
                System.out.println("插入成功");

            }

        } catch (SQLException e) {
     
            e.printStackTrace();
        }finally {
     
            JdbcUtils.release(connection,statement,resultSet);
        }

    }
}

package cn.dxj1016.lesson02;
import cn.dxj1016.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
//删
public class TestDelect {
     
    public static void main(String[] args) {
     
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
     
            connection = JdbcUtils.getConnenction();//获取数据库连接
            statement = connection.createStatement();//获得SQL的执行对象
            String sql = "DELETE FROM users WHERE id=4;";
            int i = statement.executeUpdate(sql);
            if (i > 0) {
     
                System.out.println("删除成功");

            }

        } catch (SQLException e) {
     
            e.printStackTrace();
        }finally {
     
            JdbcUtils.release(connection,statement,resultSet);
        }

    }
}

package cn.dxj1016.lesson02;
import cn.dxj1016.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
//查
public class TestUpdate {
     
    public static void main(String[] args) {
     
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
     
            connection = JdbcUtils.getConnenction();//获取数据库连接
            statement = connection.createStatement();//获得SQL的执行对象
            String sql = "UPDATE users SET `NAME`='dxj1016' WHERE id=5";
            int i = statement.executeUpdate(sql);
            if (i > 0) {
     
                System.out.println("修改成功");

            }

        } catch (SQLException e) {
     
            e.printStackTrace();
        }finally {
     
            JdbcUtils.release(connection,statement,resultSet);
        }

    }
}

3、查询 executeQuery

package cn.dxj1016.lesson02;

import cn.dxj1016.lesson02.utils.JdbcUtils;

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

public class TestSelect {
     
    public static void main(String[] args) {
     
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
     
            connection = JdbcUtils.getConnenction();//获取数据库连接
            statement = connection.createStatement();//获得SQL的执行对象
            String sql = "SELECT * FROM users ";
            resultSet = statement.executeQuery(sql);
            while (resultSet.next()) {
     
                System.out.println(resultSet.getString("NAME"));
            }

        } catch (SQLException e) {
     
            e.printStackTrace();
        }finally {
     
            JdbcUtils.release(connection,statement,resultSet);
        }
    }
}

10.5、SQL注入

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

sql注入基础原理(超详细

SQL注入百度百科

package cn.dxj1016.lesson02;

import cn.dxj1016.lesson02.utils.JdbcUtils;

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

public class SQL注入 {
     
    public static void main(String[] args) {
     
//        login("dxj1016","123456");
        login(" 'or '1=1"," 'or '1=1");

    }

    //    登录业务
    public static void login(String username, String password) {
     
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
     
            connection = JdbcUtils.getConnenction();//获取数据库连接
            statement = connection.createStatement();//获得SQL的执行对象
            String sql = "SELECT * FROM users WHERE `NAME`='"+username+"' AND `PASSWORD`='"+password+"';";
            resultSet = statement.executeQuery(sql);
            while (resultSet.next()) {
     
                System.out.println(resultSet.getString("NAME"));
                System.out.println(resultSet.getString("PASSWORD"));
                System.out.println("=============================================");
            }

        } catch (SQLException e) {
     
            e.printStackTrace();
        }finally {
     
            JdbcUtils.release(connection,statement,resultSet);
        }
    }
}
/*
执行结果:
zhangsan
123456
=============================================
lisi
123456
=============================================
wangwu
123456
=============================================
dxj1016
123456
=============================================
 */

10.6、PreparedStatement对象

PreparedStatement对象防止数据泄露

  1. 新增

    package cn.dxj1016.lesson03;
    
    import cn.dxj1016.lesson02.utils.JdbcUtils;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.util.Date;
    
    public class TestInsert {
           
        public static void main(String[] args) {
           
            Connection connection = null;
            PreparedStatement preparedStatement = null;
            try {
           
                connection = JdbcUtils.getConnenction();//获取数据库连接
    //            区别
    //            使用?代替占位符参数
                String sql = "INSERT INTO users(id,`NAME`,`PASSWORD`,email,birthday) values (?,?,?,?,?)";
                preparedStatement = connection.prepareStatement(sql);//预编译SQL,先写SQL,然后不执行
    //            手动给参数赋值
                preparedStatement.setInt(1, 4);
                preparedStatement.setString(2, "qinjiang");
                preparedStatement.setString(3, "123456");
                preparedStatement.setString(4, "[email protected]");
    //            注意点:sql.Date 数据库      java.sql.Date()
    //                    util.Date Java     new Date().getTime() 获得时间戳
                preparedStatement.setDate(5,new java.sql.Date(new Date().getTime()));
    //            执行
                int i = preparedStatement.executeUpdate();
                if (i > 0) {
           
                    System.out.println("插入成功");
                }
    
            } catch (Exception e) {
           
                e.printStackTrace();
            }finally {
           
                JdbcUtils.release(connection,preparedStatement,null);
            }
    
        }
    }
    
    
  2. 删除

    package cn.dxj1016.lesson03;
    
    import cn.dxj1016.lesson02.utils.JdbcUtils;
    
    import java.sql.*;
    
    public class TestDelect {
           
        public static void main(String[] args) {
           
            Connection connection = null;
            PreparedStatement preparedStatement = null;
            try {
           
                connection = JdbcUtils.getConnenction();//获取数据库连接
    //            区别
    //            使用?代替占位符参数
                String sql = "DELETE FROM users WHERE id=?;";
                preparedStatement = connection.prepareStatement(sql);//预编译SQL,先写SQL,然后不执行
    //            手动给参数赋值
                preparedStatement.setInt(1, 4);
    //            执行
                int i = preparedStatement.executeUpdate();
                if (i > 0) {
           
                    System.out.println("删除成功");
                }
    
            } catch (Exception e) {
           
                e.printStackTrace();
            }finally {
           
                JdbcUtils.release(connection,preparedStatement,null);
            }
        }
    }
    
    
  3. 更新

    package cn.dxj1016.lesson03;
    
    import cn.dxj1016.lesson02.utils.JdbcUtils;
    
    import java.sql.*;
    
    public class TestUpdate {
           
        public static void main(String[] args) {
           
            Connection connection = null;
            PreparedStatement preparedStatement = null;
            try {
           
                connection = JdbcUtils.getConnenction();//获取数据库连接
    //            区别
    //            使用?代替占位符参数
                String sql = "UPDATE users SET `NAME`=?,`PASSWORD`=? WHERE id=?";
                preparedStatement = connection.prepareStatement(sql);//预编译SQL,先写SQL,然后不执行
    //            手动给参数赋值
    
                preparedStatement.setString(1, "qinjiang");
                preparedStatement.setString(2, "5678807");
                preparedStatement.setInt(3, 5);
    //            执行
                int i = preparedStatement.executeUpdate();
                if (i > 0) {
           
                    System.out.println("修改成功");
                }
    
            } catch (Exception e) {
           
                e.printStackTrace();
            }finally {
           
                JdbcUtils.release(connection,preparedStatement,null);
            }
        }
    }
    
    
  4. 查询

    package cn.dxj1016.lesson03;
    
    import cn.dxj1016.lesson02.utils.JdbcUtils;
    
    import java.sql.*;
    
    public class TestSelect {
           
        public static void main(String[] args) {
           
            Connection connection = null;
            PreparedStatement preparedStatement = null;
            ResultSet resultSet = null;
            try {
           
                connection = JdbcUtils.getConnenction();//获取数据库连接
                String sql = "SELECT * FROM users where id=?";
                preparedStatement = connection.prepareStatement(sql);//获得SQL的执行对象
                preparedStatement.setInt(1,1);
                resultSet = preparedStatement.executeQuery();
                while (resultSet.next()) {
           
                    System.out.println(resultSet.getString("NAME"));
                }
    
            } catch (SQLException e) {
           
                e.printStackTrace();
            }finally {
           
                JdbcUtils.release(connection,preparedStatement,resultSet);
            }
        }
    }
    
    
  5. 防止SQL注入

    package cn.dxj1016.lesson03;
    
    import cn.dxj1016.lesson02.utils.JdbcUtils;
    
    import java.sql.*;
    
    public class SQL注入 {
           
        public static void main(String[] args) {
           
            //login("zhangsan","123456");
            login("'' or 1=1","123456");
    
        }
    
        //    登录业务
        public static void login(String username, String password) {
           
            Connection connection = null;
            PreparedStatement preparedStatement = null;
            ResultSet resultSet = null;
            try {
           
                connection = JdbcUtils.getConnenction();//获取数据库连接
    //            preparedStatement 防止SQL注入的本质,把传递进来的参数当做字符
    //            假设其中存在转义字符,比如说 ' 会被直接转义
                String sql = "SELECT * FROM users WHERE `NAME`=? AND `PASSWORD`=?";//Mybatis
                preparedStatement = connection.prepareStatement(sql);//获得SQL的执行对象
                preparedStatement.setString(1, username);
                preparedStatement.setString(2, password);
                resultSet = preparedStatement.executeQuery();
                while (resultSet.next()) {
           
                    System.out.println(resultSet.getString("NAME"));
                    System.out.println(resultSet.getString("PASSWORD"));
                    System.out.println("=============================================");
                }
    
            } catch (SQLException e) {
           
                e.printStackTrace();
            }finally {
           
                JdbcUtils.release(connection,preparedStatement,resultSet);
            }
        }
    }
    /*
    执行结果:
    
     */
    
    

    10.7使用IDEA连接数据库

    MySQL_第79张图片
    MySQL_第80张图片

    10.8、事务


MySQL_第81张图片
MySQL_第82张图片

package cn.dxj1016.lesson04;

import cn.dxj1016.lesson02.utils.JdbcUtils;

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

public class TestTransaction2 {
     
    public static void main(String[] args) {
     
        Connection connection = null;
        PreparedStatement preparedStatement = null;

        try {
     
            connection = JdbcUtils.getConnenction();
//            关闭自动提交事务
            connection.setAutoCommit(false);
            String sql1 = "UPDATE  account SET money=money-100 WHERE `NAME`='A';";
            preparedStatement = connection.prepareStatement(sql1);
            preparedStatement.executeUpdate();

            int x = 1 / 0;//报错,回滚

            String sql2 = "UPDATE  account SET money=money+100 WHERE `NAME`='B';";
            preparedStatement = connection.prepareStatement(sql2);
            preparedStatement.executeUpdate();
//            业务完毕,提交事务
            connection.commit();
            System.out.println("成功");

        } catch (Exception e) {
     
            try {
     
                connection.rollback();
                System.out.println("捕获到异常,回滚");
            } catch (SQLException ex) {
     
                ex.printStackTrace();
            }
            e.printStackTrace();
        }finally {
     
            JdbcUtils.release(connection,preparedStatement,null);
        }

    }
}
/*
执行结果:
捕获到异常,回滚
java.lang.ArithmeticException: / by zero
	at cn.dxj1016.lesson04.TestTransaction2.main(TestTransaction2.java:22)
 */

10.9、数据库连接池

MySQL_第83张图片

MySQL_第84张图片

MySQL_第85张图片

MySQL_第86张图片

DBCP连接池

#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false
username=root
password=980413dxj

#
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 指定由连接池所创建的连接的只读(read-only)状态。
#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
defaultReadOnly=

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

import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;

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

public class JdbcUtils_DBCP {
     
    public static BasicDataSource basicDataSource = null;

    static{
     
        try {
     
            InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
            Properties properties = new Properties();
            properties.load(in);
//              创建数据源  工厂模式--》创建
            basicDataSource = BasicDataSourceFactory.createDataSource(properties);

        } catch (Exception e) {
     
            e.printStackTrace();
        }
    }
//    获取连接
    public static Connection getConnection() throws SQLException {
     
        return basicDataSource.getConnection();
    }
    //    释放资源连接
    public static void release(Connection conn, Statement st, ResultSet rs) {
     
        if (rs != null) {
     
            try {
     
                rs.close();
            } catch (Exception e) {
     
                e.printStackTrace();
            }
        }
        if (st != null) {
     
            try {
     
                st.close();
            } catch (Exception e) {
     
                e.printStackTrace();
            }
        }
        if (conn != null) {
     
            try {
     
                conn.close();
            } catch (Exception e) {
     
                e.printStackTrace();
            }
        }
    }
}
package cn.dxj1016.lesson05;
import cn.dxj1016.lesson05.utils.JdbcUtils_DBCP;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;

public class TestDBCP {
     
    public static void main(String[] args) {
     
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        try {
     
            connection = JdbcUtils_DBCP.getConnection();//获取数据库连接
//            区别
//            使用?代替占位符参数
            String sql = "INSERT INTO users(id,`NAME`,`PASSWORD`,email,birthday) values (?,?,?,?,?)";
            preparedStatement = connection.prepareStatement(sql);//预编译SQL,先写SQL,然后不执行
//            手动给参数赋值
            preparedStatement.setInt(1, 4);
            preparedStatement.setString(2, "qinjiang");
            preparedStatement.setString(3, "123456");
            preparedStatement.setString(4, "[email protected]");
//            注意点:sql.Date 数据库      java.sql.Date()
//                    util.Date Java     new Date().getTime() 获得时间戳
            preparedStatement.setDate(5,new java.sql.Date(new Date().getTime()));
//            执行
            int i = preparedStatement.executeUpdate();
            if (i > 0) {
     
                System.out.println("插入成功");
            }

        } catch (Exception e) {
     
            e.printStackTrace();
        }finally {
     
             JdbcUtils_DBCP.release(connection, preparedStatement, null);
        }

    }
}
/*
错误:Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class cn.dxj1016.lesson05.utils.JdbcUtils_DBCP
	at cn.dxj1016.lesson05.TestDBCP.main(TestDBCP.java:37)
未解决
*/

11、遇到问题

  • 执行 mysql -u root -p 123456出错:
    提示
    ERROR 2003 (HY000): Can’t connect to MySQL server on ‘localhost’ (10061)
    在计算机管理->服务和应用程序->服务->Mysql 中发现MySQL启动之后总是马上停止
    解决方法:在配置文件my.ini中注释掉 #skip-grant-tables

  • Navicat for MySQL在连接数据库时出现1045-Access denied for user ‘root’@‘localhost’(using password:YES)问题?
    解决方法: https://www.huaweicloud.com/articles/69a429d8789d1c0fcb12263f7e6bc390.html

  • IDEA连接数据库出错解决方法:https://blog.csdn.net/gao_jun1/article/details/108213670

  • JDBC连接数据库时出错:

    1. 使用老版5.1 ,如果报错 ,改成Url后面那里改成useSSL=false;
    2. 使用8.0新版,加载驱动那改成Class.forName(“com.mysql.cj.jdbc.Driver”); ,然后url后面加一串&serverTimezone=Asia/Shanghai

你可能感兴趣的:(java基础阶段,MySQL,mysql,数据库,dbcp,jdbc)