[Crazy God Talks about Java] Mysql detailed notes (full)

1. First introduction to MySQL

JavaEE: Enterprise-level Java development Web
front-end (page: display: data)
background (connection point: connecting to the database JDBC, connecting to the front-end (controlling the view jump, passing data to the front-end))
database (storing data, Txt, Excel, Word)

I can only write code, learn database well, and basically make a living:

Operating systems, data structures and algorithms! Be a good programmer!

Discrete mathematics, digital circuits, architecture, compilation principles. + Practical experience, excellent programmer

1.1 Why learn database

1. Job requirements
2. In today’s world, in the era of big data, those who get the data win the world
3. Forced demand: store data
4. The database is the core existence of DBA in all software systems

1.2 What is a database

Database: (DB, DataBase)
concept: data warehouse, software, installed on one of the operating systems (windows, Linux, mac)! SQL can store a large amount of data (more than 5 million needs to be optimized)!
Function: store data, manage data Excel

1.3 Database classification

Relational database: (SQL)

  • MySQL, Oracle, sql Server, DB2, SQLite
  • Data is stored through relationships between tables and between rows and columns.

Non-relational database: (NoSQL) Not Only SQL

  • Redis, MongDB
  • Non-relational databases and object storage are determined by the properties of the object itself.

DBMS (database management system)

  • Database management software scientifically and effectively manages, maintains and obtains our data
  • MySQL, data management system!

1.4 Introduction to MySQL

MySQL is a relational database management system
. Previous life: Swedish MySQL AB company
. Current life: A product of Oracle
. MySQL is one of the best RDBMS (Relational Database Management System) application software.
Open source database software
is small in size, fast in speed, low in total cost of ownership, and relatively low in recruitment costs.
Small and medium-sized websites, or large websites, clusters
official website:

1.5 Connect to database

Command line connection!

mysql -u root -p --连接数据库
输入密码

#设置管理员密码的
update mysql.user set authentication_string=password('root') where user='root' and Host='localhost';  --修改密码

flush privileges;--刷新权限
--------------------------------------------------
--所有语句使用;结尾--

show databases;--查看所有的数据库
use school--切换数据库, use 数据库名
--
show tables;--查看数据库中所有的表
describe student;--显示数据库中所有的表的信息
create database westos;--创建一个数据库
exit;--退出连接

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

image.png
image.png

2. Operation database

Operate the database》Operate the tables in the database》Operate the data of the tables in
the databaseMySQL is not case-sensitive

2.1 Operation database

Create database

CREATE DATABASE IF NOT EXISTS student;

Delete database

DROP DATABASE student;

Use database

USE student;

View database

SHOW DATABASES;

2.2 Database column types

numerical value

  • tinyint very small data 1 byte
  • smallint smaller data 2 bytes
  • mediumint medium size 3 bytes
  • int standard integer 4 bytes (commonly used)
  • bigint larger data 8 bytes
  • float floating point number 4 bytes
  • double floating point number 8 bytes (precision issue)
  • decimal is a floating point number in the form of a string, generally used in financial calculations.

string

  • char string fixed size 0-255
  • varchar variable string 0-65535 (commonly used)
  • tinytext tiny text 2^8-1
  • text text string 2^16-1 (save large text)

time date

java.util.Date

  • date YYYY-MM-DD, date
  • time HH:mm:ss time format
  • datetime YYYY-MM-DD HH:mm:ss the most commonly used time format
  • timestamp The number of milliseconds from timestamp 1970.1.1 to now
  • year represents the year

null

  • No value, unknown
  • Note, do not use null for operation , the result will be null

2.3 Database field types (key points)

unsigened:

  • unsigned integer
  • Declare that the column cannot declare negative numbers

zerofill:

  • 0 padded
  • The length of 10 is 1 – 0000000001. The missing digits are filled with 0s.

Self-increment:

  • Usually understood as auto-increment, it automatically adds +1 to the previous record.
  • Usually used to design a unique primary key index, which must be an integer type
  • You can customize the starting value and step size of the primary key auto-increment

not Null not Null

  • Assuming it is set to not null, if you do not assign a value to it, an error will be reported.
  • NULL If not filled in, the default is NULL

default:

  • Set default value!

Extensions:

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

2.4 Create database table

--目标:创建一个schoo1数据库
--创建学生表(列,字段)使用SQL 创建
--学号int   登录密码varchar(20)   姓名,性别varchar(2)  出生日期(datatime)  家庭住址,emai1
--注意点使用英文(),表的名称和字段尽量使用括起来

-- AUTO_ INCREMENT 自增
-- COMMENT 属性注释
-- DEFAULT 默认值
-- NUT NULL 必须不为空
-- 字符串使用单引号括起来!
-- ENGINE=INNODB 设置引擎
-- 所有的语句后面加,(英文的),最后一个不用加

-- PRIMARY KEY 主键,一般一个表只有一个唯一的主键!
CREATE DATABASE school
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


SHOW CREATE DATABASE school -- 查看建立数据库的语句
SHOW CREATE TABLES student -- 查看建立数据表的语句

DESC student --显示表的结构

2.5 Type of data table (database engine)

MYISAM INNODB
Transaction support not support support
Data row lock not support support
foreign key constraints not support support
Full text index support not support
table space size smaller Larger, about twice that of MYISAM

General usage operations:

  • MYISAM saves space and is faster.
  • INNODB has high security, transaction processing, and multi-table and multi-user operations.

location in physical space

All database files are stored in the data directory, and one folder corresponds to one database. The
essence is still the storage of files.
The difference between the physical files of the MySQL engine

  • InnoDB has only one *.frm file in the database table, and the ibdata1 file in the upper-level directory
  • MYISAM corresponding files
    • *.frm - definition file of table structure
    • *.MYD - data file
    • *.MYI - index file

Set database character set encoding

If not set, it will be the default character set encoding of mysql - (Chinese is not supported)
You can configure the default encoding in my.ini (not recommended)character-set-server=utf8

2.6 Modify and delete table

Revise

-- 修改表名 ALTER TABLE 旧表面 AS 新表名
ALTER TABLE student RENAME AS student1
-- 增加表的字段 ALTER TABLE 表名 ADD 字段名 列属性
ALTER TABLE student1 ADD age INT(11)
-- 修改表的字段(重命名,修改约束)
ALTER TABLE student1 MODIFY age VARCHAR(11)  -- 修改约束
ALTER TABLE student1 CHANGE age age1 INT(1)  -- 字段重命名,也可修改约束

-- 删除表的字段
ALTER TABLE student1 DROP age1

Delete table

DROP TABLE IF EXISTS `student1`

All creation and deletion operations should be judged as much as possible to avoid errors
. Note:

  • `` field name, use this package
  • Comment – ​​/**/
  • SQL keywords are not case sensitive, it is recommended to write them in lowercase
  • All symbols are in English

3. MySQL data management

3.1 Foreign keys (understanding)

Method 1: Add constraints when creating a table (troublesome, more complicated)

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

image.png

When deleting a table with a foreign key relationship, you must first delete the referenced table (slave table), and then delete the referenced table (master table). Method 2: Add the
foreign key after successfully creating the table.

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

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

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

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

The above operations are all physical foreign keys, database-level foreign keys, and are not recommended. (Avoiding trouble caused by too many databases)
Best Practices

  • A database is a simple table, only used to store data, with only rows (data) and columns (fields)
  • We want to use data from multiple tables and use foreign keys (implemented by program)

3.2 DML language (remember all)

Database meaning : data storage, data management
DML language : data manipulation language

  • insert
  • update
  • delete

3.3 Insert

insert

-- 插入语句(添加)
-- insert into 表名([字段一], [字段二])values('值1','值2')

INSERT INTO `grade` (`gradename`) VALUES('大四')

-- 一般写插入语句,我们一定要数据和字段一一对应。(不写字段默认全部字段)
-- 插入多行,针对一个字段,每行一个括号
INSERT INTO `grade`(`gradename`) VALUES ('大二'),('大一');
--gradeid无默认值 要插入这个数据
INSERT INTO `student`(`id`,`name`,`pwd`,`sex`,`gradeid`) VALUES (1,'张三','aaaaa','男',1)

Grammar:-- insert into 表名([字段一], [字段二])values('值1','值2')
Notes:

  1. Separate fields with commas
  2. Fields can be omitted, but subsequent values ​​must correspond one-to-one
  3. Multiple pieces of data can be inserted at the same time. The values ​​after VALUES need to be used. They can be separated by values('value 1'), ('value 2')

3.4 Modification

update

-- 修改学员名字
UPDATE `student` SET `name`='aaa' WHERE id =1;
-- 不指定条件的情况下,会改动所有表
UPDATE `student` SET `name`='bbb'
-- 语法;
-- UPDATE 表名 set column_name = value,[column_name = value,...] where [条件]

Condition: where clause operator id is equal to a certain value, is greater than a certain value, and is modified within a certain range.
The operator returns a Boolean value
image.png
. Note:

  • column_name is the column of the database, with ``
  • Condition is the filtering condition. If not specified, all columns will be modified.
  • value is a specific value or a variable
  • Use commas to separate multiple set attributes.
UPDATE `student` SET `birthday`=CURRENT_TIME where `name`='bbb' AND SEX = '男'

3.5 Delete

delete
Syntax: delete from table name [where condition]

-- 删除数据 (避免这样写)
DELETE FROM `student`
-- 删除指定
DELETE FROM `student` where id= 1

TRUNCATE
Function: Completely clear a database, the structure and index of the table will not change.
Similarity: Both can delete data, but the table structure will not be deleted
. Difference:

  • TRUNCATE resets the auto-increment column counter to zero
  • TRUNCATE does not affect transactions
-- 测试delete 和 truncate 区别
CREATE TABLE `test`(
   `id` INT(4) NOT NULL AUTO_INCREMENT,
   `coll` VARCHAR(20) NOT NULL,
   PRIMARY KEY (`id`)
 )

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

DELETE FROM `test` -- 删除后不会影响自增

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

4. DQL query data (most important)

4.1DQL

( Data Query Language ): Data query language.
It is used for all query operations. Select
It can do simple queries and complex queries. It is
the core language in the database and the most
frequently used language
. Note: [ ] Parentheses represent optional, { } Brackets represent required selections

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;

-- 创建年级表
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;

-- 创建科目表
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;

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

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

-- 插入成绩数据  这里仅插入了一组,其余自行添加
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);

-- 插入年级数据
insert into `grade` (`gradeid`,`gradename`) values(1,'大一'),(2,'大二'),(3,'大三'),(4,'大四'),(5,'预科班');
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);

4.2 Specify query fields

-- 查询所有学生
select * from student;

-- 查询指定字段
select `studentno`, `studentname` from student;

-- 给结果取名字 字段或表名
select `studentno` as '学号', `studentname` as '名字' from student as s;

-- 函数 Concat(a, b)
select concat('姓名:', studentname) as 新名字 from student;

image.png
image.png
Syntax: SELECT field... FROM table
Sometimes, column names are not so obvious. We alias AS, field name AS, alias table name AS, alias
distinctto remove duplicates
image.png
image.png

-- 查询所有学生
select * from student;

-- 查询指定字段
select `studentno`, `studentname` from student;

-- 给结果取名字 字段或表名
select `studentno` as '学号', `studentname` as '名字' from student as s;

-- 函数 Concat(a, b)
select concat('姓名:', studentname) as 新名字 from student;

-- 查询同学
select * from result;

select `studentno` from result;

-- 去重
select distinct `studentno` from result;

select version(); -- 版本

select 100*3 as 计算结果;

select @@auto_increment_increment;  --步长

-- 学院考试成绩 + 1
SELECT `studentno` , `studentresult` + 1 as '提分后' from result;

Expressions in the database: text values, columns, Null, functions, calculated expressions, system variables...
select expression from table

4.3 where conditional clause

Function: Retrieve qualified values ​​in the data, the result is a Boolean
logical operator

operator grammar result
and && a and b a && b logical AND
or || a or b a ||b logical or
not ! not a !a logical negation
-- 查询成绩在95~100之间
select studentno,studentresult from result 
where studentresult >= 95 && studentresult <= 100;

select studentno,studentresult from result 
where studentresult >= 95 and studentresult <= 100;

-- 模糊查询 (区间)
select studentno,studentresult from result 
where studentresult between 95 and 100;

select studentno,studentresult from result 
where studentno != 1000;

select studentno,studentresult from result 
where not studentno = 1000;

Fuzzy query: comparison operators

operator grammar describe
is null a is null a is null, the result is true
is not null a is not null a is not null, the result is true
between a between b and c a is between b and c, the result is true
like a like b SQL matching, if a matches b, the result is true
in a in (a1, a2, a3…) If a is between (a1, a2, a3...), the result is true
-- like

-- 模糊查询 %(代表0到任意个字符) _一个字符 不能用等号 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 ('%深圳%','北京');

select studentno, studentname from student 
where borndate is not null;

4.4 Joint table query

join comparison
image.png
image.png

operate describe
inner join If there is at least one match in the table, return the row
left join Returns all values ​​from the left table even if there is no match in the left table
right join Returns all values ​​from the right table even if there is no match in the right table
-- 联表查询

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

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

-- join on(条件判断) 连接查询   on在取表之前判断
-- where 等值查询              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

-- 查询缺考的同学
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

-- 查询学员所属的年级(学号,姓名,年级)
select studentno,studentname,gradename
from student s
inner join grade g
on s.gradeid = g.gradeid

-- 查询参加c语言-2考试的同学信息 学号 姓名 科目名 分数
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 sub.subjectname = 'C语言-2'

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

-- from a left join b   左为准
-- from a right join b	右为准

self-connection

CREATE TABLE `category`(
  `categoryid` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主题id',
  `pid` INT(10) NOT NULL COMMENT '父id',
  `categoryname` VARCHAR(50) NOT NULL COMMENT '主题名字',
  PRIMARY KEY (`categoryid`) 
) ENGINE=INNODB  AUTO_INCREMENT=9 DEFAULT CHARSET=utf8; 

INSERT INTO `category` (`categoryid`, `pid`, `categoryname`) 
VALUES ('2','1','信息技术'),
('3','1','软件开发'),
('5','1','美术设计'),
('4','3','数据库'),
('8','2','办公信息'),
('6','3','web开发'),
('7','5','ps技术');

image.png
Connect your own table to your own table. The core: split one table into two identical tables.
Parent class

categoryid categoryname
2 information Technology
3 software development
5 art design

Subclass

pid categoryid categoryname
3 4 database
2 8 Office information
3 6 web development
5 7 art design

Operation: Query the relationship between parent class and subclass

father Subclass
information Technology Office information
software development database
software development web development
art design ps technology
-- 查询父子信息 子类的pid等于父类的id
select a.categoryname as '父栏目',b.categoryname as '子栏目'
from category as a, category as b
where a.categoryid = b.pid

4.5 Paging and sorting

sort

--  排序 升序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 sub.subjectname = 'C语言-2'
order by studentresult asc

Pagination

-- 为什么要分页
-- 缓解数据库压力,给人的体验更好
-- 分页,每页显示五条数据

-- 语法: limit 起始页,页面的大小
-- limit 0,5 -- 1-5
-- limit 1,5 -- 2-6
-- limit 6,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 0,5

-- 第一页 limit 0,5
-- 第二页 limit 5,5
-- 第三页 limit 10,5
-- 第N页 limit pagesize*(n-1),pagesize
-- [pagesize*(n-1),pagesize]
-- pagesize 页面大小
-- n 当前页
-- 【数据总数/页面大小=总页数】

Syntax limit (query starting subscript, pagesize)

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' and studentresult >= 80
order by studentresult desc
limit 0,10

4.6 Subquery

Where (this value is calculated)
essence: nest a subquery statement in the where statement

/*============== 子查询 ================
什么是子查询?
在查询语句中的WHERE条件子句中,又嵌套了另一个查询语句
嵌套查询可由多个子查询组成,求解的方式是由里及外;
子查询返回的结果一般都是集合,故而建议使用IN关键字;
*/

-- 查询 数据库结构-1 的所有考试结果(学号,科目编号,成绩),并且成绩降序排列
-- 方法一:使用连接查询
SELECT studentno,r.subjectno,StudentResult
FROM result r
INNER JOIN `subject` sub
ON r.`SubjectNo`=sub.`SubjectNo`
WHERE subjectname = '数据库结构-1'
ORDER BY studentresult DESC;

-- 方法二:使用子查询(执行顺序:由里及外)
SELECT studentno,subjectno,StudentResult
FROM result
WHERE subjectno=(
   SELECT subjectno FROM `subject`
   WHERE subjectname = '数据库结构-1'
 )
ORDER BY studentresult DESC;

-- 查询课程为 高等数学-2 且分数不小于80分的学生的学号和姓名
-- 方法一:使用连接查询
SELECT s.studentno,studentname
FROM student s
INNER JOIN result r
ON s.`StudentNo` = r.`StudentNo`
INNER JOIN `subject` sub
ON sub.`SubjectNo` = r.`SubjectNo`
WHERE subjectname = '高等数学-2' AND StudentResult>=80

-- 方法二:使用连接查询+子查询
-- 分数不小于80分的学生的学号和姓名
SELECT r.studentno,studentname 
FROM student s
INNER JOIN result r 
ON s.`StudentNo`=r.`StudentNo`
WHERE StudentResult>=80

-- 在上面SQL基础上,添加需求:课程为 高等数学-2
SELECT r.studentno,studentname 
FROM student s
INNER JOIN result r 
ON s.`StudentNo`=r.`StudentNo`
WHERE StudentResult>=80 AND subjectno=(
   SELECT subjectno FROM `subject`
   WHERE subjectname = '高等数学-2'
 )

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

4.7 Grouping and filtering

-- 查询不同课程的平均分,最高分,最低分
-- 前提:根据不同的课程进行分组

SELECT subjectname,AVG(studentresult) AS 平均分,MAX(StudentResult) AS 最高分,MIN(StudentResult) AS 最低分
FROM result AS r
INNER JOIN `subject` AS s
ON r.subjectno = s.subjectno
GROUP BY r.subjectno
HAVING 平均分>80;

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

4.8 select summary

SELECT syntax

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

5. MySQL functions

Official website: https://dev.mysql.com/doc/refman/8.0/en/built-in-function-reference.html

5.1 Commonly used functions

-- 数学运算

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('2323232') -- 返回字符串长度
SELECT CONCAT('我','233') -- 拼接字符串
SELECT INSERT('java',1,2,'cccc') -- 从某个位置开始替换某个长度 (str,pos,len,newstr) -->ccccva
SELECT INSTR('kuangshen','h') --返回首次出现的位置7
SELECT UPPER('abc') 
SELECT LOWER('ABC')
SELECT SUBSTR('123456',4,6) -- 返回从4开始的长度为6的字符串

SELECT REPLACE('坚持就能成功','坚持','努力')
-- 查询姓 周 的同学 ,改成邹
SELECT REPLACE(studentname,'周','邹') FROM student WHERE studentname LIKE '周%'

-- 时间跟日期函数(记住)
SELECT CURRENT_DATE() -- 获取当前日期
SELECT CURDATE() -- 获取当前日期
SELECT NOW() -- 获取当前日期
SELECT LOCATIME()  -- 本地时间
SELECT SYSDATE()  -- 系统时间

SELECT YEAR(NOW())
SELECT MONTH(NOW())
SELECT DAY(NOW())
SELECT HOUR(NOW())
SELECT MINUTE(NOW())
SELECT SECOND(NOW())

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

5.2 Aggregation functions (commonly used)

function name describe
COUNT() count
SUM() Sum
AVG() average value
MAX() maximum value
MIN() minimum value
-- 聚合函数
/*COUNT:非空的*/
SELECT COUNT(studentname) FROM student; -- 会忽略null
SELECT COUNT(*) FROM student;  -- 不会忽略null
SELECT COUNT(1) FROM student;  /*推荐*/ -- 会忽略null

-- 从含义上讲,count(1) 与 count(*) 都表示对全部数据行的查询。
-- count(字段) 会统计该字段在表中出现的次数,忽略字段为null 的情况。即不统计字段null 的记录。
-- count(*) 包括了所有的列,相当于行数,在统计结果的时候,包含字段为null 的记录;
-- count(1) 用1代表代码行,在统计结果的时候,包含字段为null 的记录 。
/*
很多人认为count(1)执行的效率会比count(*)高,原因是count(*)会存在全表扫描,
而count(1)可以针对一个字段进行查询。其实不然,count(1)和count(*)都会对全表进行扫描,
统计所有记录的条数,包括那些为null的记录,因此,它们的效率可以说是相差无几。而
count(字段)则与前两者不同,它会统计该字段不为null的记录条数。

下面它们之间的一些对比:

1)在表没有主键时,count(1)比count(*)快
2)有主键时,主键作为计算条件,count(主键)效率最高;
3)若表格只有一个字段,则count(*)效率较高。
*/

SELECT SUM(StudentResult) AS 总和 FROM result;
SELECT AVG(StudentResult) AS 平均分 FROM result;
SELECT MAX(StudentResult) AS 最高分 FROM result;
SELECT MIN(StudentResult) AS 最低分 FROM result;

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

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

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,'kuangshen','123456'),(2,'qinjiang','456789')

-- 如果我们要对pwd这一列数据进行加密,语法是:
update testmd5 set pwd = md5(pwd);

-- 如果单独对某个用户(如kuangshen)的密码加密:
INSERT INTO testmd5 VALUES(3,'kuangshen2','123456')
update testmd5 set pwd = md5(pwd) where name = 'kuangshen2';

-- 插入新的数据自动加密
INSERT INTO testmd5 VALUES(4,'kuangshen3',md5('123456'));

-- 查询登录用户信息(md5对比使用,查看用户输入加密后的密码进行比对)
SELECT * FROM testmd5 WHERE `name`='kuangshen' AND pwd=MD5('123456');

5.4 小结

-- ================ 内置函数 ================
-- 数值函数
abs(x)            -- 绝对值 abs(-10.9) = 10
format(x, d)    -- 格式化千分位数值 format(1234567.456, 2) = 1,234,567.46
ceil(x)            -- 向上取整 ceil(10.1) = 11
floor(x)        -- 向下取整 floor (10.1) = 10
round(x)        -- 四舍五入去整
mod(m, n)        -- m%n m mod n 求余 10%3=1
pi()            -- 获得圆周率
pow(m, n)        -- m^n
sqrt(x)            -- 算术平方根
rand()            -- 随机数
truncate(x, d)    -- 截取d位小数

-- 时间日期函数
now(), current_timestamp();     -- 当前日期时间
current_date();                    -- 当前日期
current_time();                    -- 当前时间
date('yyyy-mm-dd hh:ii:ss');    -- 获取日期部分
time('yyyy-mm-dd hh:ii:ss');    -- 获取时间部分
date_format('yyyy-mm-dd hh:ii:ss', '%d %y %a %d %m %b %j');    -- 格式化时间
unix_timestamp();                -- 获得unix时间戳
from_unixtime();                -- 从时间戳获得时间

-- 字符串函数
length(string)            -- string长度,字节
char_length(string)        -- string的字符个数
substring(str, position [,length])        -- 从str的position开始,取length个字符
replace(str ,search_str ,replace_str)    -- 在str中用replace_str替换search_str
instr(string ,substring)    -- 返回substring首次在string中出现的位置
concat(string [,...])    -- 连接字串
charset(str)            -- 返回字串字符集
lcase(string)            -- 转换成小写
left(string, length)    -- 从string2中的左边起取length个字符
load_file(file_name)    -- 从文件读取内容
locate(substring, string [,start_position])    -- 同instr,但可指定开始位置
lpad(string, length, pad)    -- 重复用pad加在string开头,直到字串长度为length
ltrim(string)            -- 去除前端空格
repeat(string, count)    -- 重复count次
rpad(string, length, pad)    --在str后用pad补充,直到长度为length
rtrim(string)            -- 去除后端空格
strcmp(string1 ,string2)    -- 逐字符比较两字串大小

-- 聚合函数
count()
sum();
max();
min();
avg();
group_concat()

-- 其他常用函数
md5();
default();

6. 事务

6.1 什么是事务

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

SQL执行, A给B转账 A 1000–> 200 B 200
SQL 执行, B收到A的钱 A 800 — B 400
将一组SQL放在一个批次中执行


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

原子性(Atomicity)
要么都成功,要么都失败,不能只发生一个
一致性(Consistency)
事务前后的数据完整性要保持一致(ab互相赚钱,钱不会到因为到银行而流失,AB的总价值一直不变)
持久性(Durability)
事务没有提交,恢复到原状(宕机),事务一旦提交就不可逆转,被持久化到数据库中
隔离性(Isolation)
事务产生多并发时,互不干扰

隔离产生的问题

脏读:
指一个事务读取了另外一个事务未提交的数据。
不可重复读:
在一个事务内读取表中的某一行数据,多次读取结果不同。(这个不一定是错误,只是某些场合不对)
虚读(幻读)
是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。
(一般是行影响,多了一行)

6.2 执行事务

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

-- 手动处理事务
SET autocommit =0 -- 关闭自动提交

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

-- sql
INSERT XX
INSERT XX

-- 提交 : 持久化(成功)
COMMIT 
-- 回滚:  回到原来的样子(失败)
ROLLBACK
-- 事务结束(提交,回滚)
SET autocommit = 1 -- 开启自动提交

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

image.png
测试

/*
课堂测试题目

A在线买一款价格为500元商品,网上银行转账.
A的银行卡余额为2000,然后给商家B支付500.
商家B一开始的银行卡余额为10000

创建数据库shop和创建表account并插入2条数据
*/

CREATE DATABASE `shop`CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `shop`;

CREATE TABLE `account` (
   `id` INT(11) NOT NULL AUTO_INCREMENT,
   `name` VARCHAR(32) NOT NULL,
   `cash` DECIMAL(9,2) NOT NULL,
   PRIMARY KEY (`id`)
 ) ENGINE=INNODB DEFAULT CHARSET=utf8

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

-- 转账实现
SET autocommit = 0; -- 关闭自动提交
START TRANSACTION;  -- 开始一个事务,标记事务的起始点
UPDATE account SET cash=cash-500 WHERE `name`='A';
UPDATE account SET cash=cash+500 WHERE `name`='B';
COMMIT; -- 提交事务,就被持久了,不能回滚了
rollback; --回滚
SET autocommit = 1; -- 恢复自动提交

7. 索引

MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度。
索引的作用

  • 提高查询速度
  • 确保数据的唯一性
  • 可以加速表和表之间的连接 , 实现表与表之间的参照完整性
  • 使用分组和排序子句进行数据检索时 , 可以显著减少分组和排序的时间
  • 全文检索字段进行搜索优化.

7.1 索引的分类

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

  • 主键索引 (PRIMARY KEY)
    • 唯一的标识,主键不可重复,只能有一个列作为主键
  • 唯一索引 (UNIQUE KEY)
    • 避免重复的列出现,唯一索引可以重复,多个列都可以标识唯一索引
  • 常规索引(KEY/INDEX)
    • 默认的,index,key关键字来设置
  • 全文索引(FULLTEXT)
    • 在特点的数据库引擎下才有,MyISAM
    • 快速定位数据
#方法一:创建表时
CREATE TABLE 表名 (
字段名1 数据类型 [完整性约束条件…],
字段名2 数据类型 [完整性约束条件…],
[UNIQUE | FULLTEXT | SPATIAL ]   INDEX | KEY
[索引名] (字段名[(长度)] [ASC |DESC])
);


-- 方法二:CREATE在已存在的表上创建索引
CREATE [UNIQUE | FULLTEXT | SPATIAL ] INDEX 索引名
ON 表名 (字段名[(长度)] [ASC |DESC]) ;


#方法三:ALTER TABLE在已存在的表上创建索引
ALTER TABLE 表名 ADD [UNIQUE | FULLTEXT | SPATIAL ] INDEX
索引名 (字段名[(长度)] [ASC |DESC]) ;


#删除索引:DROP INDEX 索引名 ON 表名字;
#删除主键索引: ALTER TABLE 表名 DROP PRIMARY KEY;
#显示索引信息: SHOW INDEX FROM student;

/*增加全文索引*/
ALTER TABLE `school`.`student` ADD FULLTEXT INDEX `studentname` (`StudentName`);

/*EXPLAIN : 分析SQL语句执行性能*/
EXPLAIN SELECT * FROM student WHERE studentno='1000';

/*使用全文索引*/
-- 全文搜索通过 MATCH() 函数完成。
-- 搜索字符串作为 against() 的参数被给定。搜索以忽略字母大小写的方式执行。对于表中的每个记录行,MATCH() 返回一个相关性值。即,在搜索字符串与记录行在 MATCH() 列表中指定的列的文本之间的相似性尺度。
EXPLAIN SELECT * FROM student WHERE MATCH(studentname) AGAINST('love');

/*
开始之前,先说一下全文索引的版本、存储引擎、数据类型的支持情况

MySQL 5.6 以前的版本,只有 MyISAM 存储引擎支持全文索引;
MySQL 5.6 及以后的版本,MyISAM 和 InnoDB 存储引擎均支持全文索引;
只有字段的数据类型为 char、varchar、text 及其系列才可以建全文索引。
测试或使用全文索引时,要先看一下自己的 MySQL 版本、存储引擎和数据类型是否支持全文索引。
*/

7.3 测试索引

CREATE TABLE `app_user` (
  `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(50) DEFAULT '',
  `email` VARCHAR(50) NOT NULL,
  `phone` VARCHAR(20) DEFAULT '',
  `gender` TINYINT(4) UNSIGNED DEFAULT '0',
  `password` VARCHAR(100) NOT NULL DEFAULT '',
  `age` TINYINT(4) DEFAULT NULL,
  `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

-- 插入100万数据
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`)
    VALUE(CONCAT('用户',i),'[email protected]',CONCAT('18',FLOOR(RAND()*9999999)),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' -- 接近1秒
--分析一下上一条语句,发现查询了99999条数据
EXPLAIN SELECT * FROM app_user WHERE `name`='用户9999'  -- 查询99999条记录

-- 索引名 id_表名_字段名
-- create index 索引名 on 表名(字段)
CREATE INDEX id_app_user_name ON app_user(`name`); 
EXPLAIN SELECT * FROM app_user WHERE `name`='用户9999'  -- 0.001 s

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

7.3 索引原则

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

8. 权限管理和备份

8.1 用户管理

Navicat可视化管理
SQL命令操作
用户表:mysql.user
本质:对这张表进行,增删改查

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

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


-- 修改密码(修改指定用户密码)

SET PASSWORD FOR sanjin = PASSWORD('111111')


-- 重命名  rename user 原名字 to 新名字
RENAME USER sanjin TO sanjin2

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

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


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

-- 删除用户
DROP USER sanjin2

8.2 MySQL备份

为什么备份:

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

MySQL数据库备份的方式

  • 直接拷贝物理文件
  • 数据库管理工具- 在想要导出的表或者库中,右键选择备份和导出
  • 直接拷贝数据库文件和相关配置文件

mysqldump客户端
作用 :

  • 转储数据库
  • 搜集数据库进行备份
  • 将数据转移到另一个SQL服务器,不一定是MySQL服务器
-- 导出
1. 导出一张表 -- mysqldump -uroot -p123456 school student >D:/a.sql
mysqldump -u用户名 -p密码 库名 表名 > 文件名(D:/a.sql)
2. 导出多张表 -- mysqldump -uroot -p123456 school student result >D:/a.sql
mysqldump -u用户名 -p密码 库名 表123 > 文件名(D:/a.sql)
3. 导出所有表 -- mysqldump -uroot -p123456 school >D:/a.sql
mysqldump -u用户名 -p密码 库名 > 文件名(D:/a.sql)
4. 导出一个库 -- mysqldump -uroot -p123456 -B school >D:/a.sql
mysqldump -u用户名 -p密码 -B 库名 > 文件名(D:/a.sql)

可以-w携带备份条件

-- 导入
1. 在登录mysql的情况下:-- source D:/a.sql
source 备份文件
2. 在不登录的情况下
mysql -u用户名 -p密码 库名 < 备份文件

9. 规范数据库设计

9.1 为什么需要数据库设计

当数据库比较复杂时我们需要设计数据库
糟糕的数据库设计 :

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

良好的数据库设计 :

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

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

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

设计数据库步骤

  • 收集信息
  • 与该系统有关人员进行交流 , 座谈 , 充分了解用户需求 , 理解数据库需要完成的任务.
  • 标识实体[Entity]–>把需求落地到每个字段
  • 标识数据库要管理的关键对象或实体,实体一般是名词
  • 标识每个实体需要存储的详细信息[Attribute]
  • 标识实体之间的关系[Relationship]

9.2 三大范式

问题 : 为什么需要数据规范化?
不合规范的表设计会导致的问题:

  • 信息重复
  • 更新异常
  • 插入异常
    • 无法正确表示信息
  • 删除异常
    • 丢失有效信息

三大范式
第一范式 (1st NF)
第一范式的目标是确保每列的原子性,如果每列都是不可再分的最小数据单元,则满足第一范式
第二范式(2nd NF)
第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。
第二范式要求每个表只描述一件事情
第三范式(3rd NF)
如果一个关系满足第二范式,并且除了主键以外的其他列都不传递依赖于主键列,则满足第三范式.
第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关

规范化和性能的关系
阿里开发手册:关联查询不得超过三张表

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

10. JDBC(重点)

10.1 数据库驱动

驱动:声卡,显卡,数据库
image.png
我们的程序会通过数据库驱动,和数据库打交道!

10.2 JDBC

SUN 公司为了简化开发人员的(对数据库的统一)操作,提供了一个(Java操作数据库的)规范,JDBC
这些规范的实现由具体的厂商去做
对于开发人员来说,我们只需要掌握JDBC的接口操作即可
image.png
java.sql
javax.sql
除了这两个默认就有的,还需要导入数据库驱动包

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,'zhansan','123456','[email protected]','1980-12-04'),
(2,'lisi','123456','[email protected]','1981-12-04'),
(3,'wangwu','123456','[email protected]','1979-12-04')
  • 1.创建一个普通项目或maven项目
  • 2.导入数据库驱动
    • 普通项目
      file->Project Structure -> Libraries

image.png

image.png
pom.xml中配置

<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.28</version>
    </dependency>
  • 3 测试
package Deom01;

import java.sql.*;

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

        // 2.用户信息和URL
        // useUnicode=true&characterEncoding=utf8&useSSL=true"
        String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
        String username = "root";
        String password = "root";

        // 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("id=" + resultSet.getObject("NAME"));
            System.out.println("id=" + resultSet.getObject("PASSWORD"));
            System.out.println("id=" + resultSet.getObject("email"));
            System.out.println("id=" + resultSet.getObject("birthday"));
        }

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

步骤总结:

  • 1.加载驱动
  • 2.连接数据库 DriverManager
  • 3.获取执行SQL的对象 Statement
  • 4.获得返回的结果集
  • 5.释放连接

DriverManager

//DriverManager.registerDriver(new com.mysql.jdbc.Driver()); //(推荐使用下面的方式)
Class.forName("com.mysql.jdbc.Driver");//固定写法,加载驱动
Connection connection= DriverManager.getConnection(url,name,password);

// connection代表数据库
connection.rollback();// 事务回滚
connection.commit();// 事务提交
connection.setAutoCommit();// 数据库设置自动提交

URL

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

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

// Oracle   1521
// jdbc:oralce:thin:@localhost:1521:sid

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

Statement statement = connection.createStatement();
String sql="SELECT * FROM users";//编写Sql

statement.executeQuery(); //查询操作,返回ResultSet
statement.execute();      //执行任何sql,效率低
statement.executeUpdate();//更新,插入,删除,返回一个受影响的行数

ResultSet 查询的结果集,封装了所有的查询结果
获得指定的数据类型

ResultSet resultSet = statement.executeQuery(sql);//返回的结果集,结果集中封装了我们全部查询的结果
resultSet.getObject();//在不知道列类型下使用
resultSet.getString();//如果知道则指定使用
resultSet.getInt();  
...

遍历,指针

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

释放内存

//6. 释放连接  否则耗资源
resultSet.close();
statement.close();
connection.close();

10.4 statement对象

JDBC中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要
通过这个对象向数据库发送增删改查语句即可。
Statement对象的executeUpdate方法,用于向数据库发送增、删、改的sq|语句,
executeUpdate执行完后, 将会返回一个整数(即增删改语句导致了数据库几行数据发生了
变化)。
Statement.executeQuery方法用于向数据库发生查询语句,executeQuery方法返回代表查询
结果的ResultSet对象。
CRUD操作-create
使用executeUpdate(String sql)方法完成数据添加操作,示例操作:

Statement statement = connection.createStatement();
String sql = "insert into user(...) values(...)";
int num = statement.executeUpdate(sql);
if(num>0){
    
    
System.out.println("插入成功");

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

Statement statement = connection.createStatement();
String sql = "delete from user where id =1";
int num = statement.executeUpdate(sql);
if(num>0){
    
    
    System.out.println("删除成功");
}

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

Statement statement = connection.createStatement();
String sql = "update user set name ='' where name = ''";
int num = statement.executeUpdate(sql);
if(num>0){
    
    
    System.out.println("修改成功");
}

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

Statement statement = connection.createStatement();
String sql = "select * from  user where id =1";
ResultSet rs= statement.executeQuery(sql);
if(rs.next()){
    
    
    System.out.println("");
}

代码实现
1.提取工具类

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

package Demo02.utils;

import java.io.IOException;
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 is = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
            Properties properties = new Properties();
            properties.load(is);
            driver = properties.getProperty("driver");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");

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

        } catch (ClassNotFoundException ex) {
    
    
            throw new RuntimeException(ex);
        } catch (IOException e) {
    
    
            throw new RuntimeException(e);
        }
    }

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

    // 释放资源
    public static void release(Connection connection, Statement statement, ResultSet resultSet){
    
    
        if (resultSet !=null){
    
    
            try {
    
    
                resultSet.close();
            } catch (SQLException e) {
    
    
                throw new RuntimeException(e);
            }
        }
        if (statement!=null){
    
    
            try {
    
    
                statement.close();
            } catch (SQLException e) {
    
    
                throw new RuntimeException(e);
            }
        }
        if (connection!=null){
    
    
            try {
    
    
                connection.close();
            } catch (SQLException e) {
    
    
                throw new RuntimeException(e);
            }
        }
    }
}

package Demo02.utils;

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

public class TestJdbcUtils {
    
    
    public static void main(String[] args) {
    
    
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;

        try {
    
    
            connection = JdbcUtils.getConnection();
            System.out.println(1);
            statement = connection.createStatement();

            // 插入
            String sql = "INSERT INTO users(`name`,`password`,`email`,`birthday`)"+
                    "VALUES('name','123456','email','2022-01-17')";
            if (statement.executeUpdate(sql)>0){
    
    
                System.out.println("插入成功");
            }

            // 查
            sql = "SELECT * FROM `users`";
            resultSet = statement.executeQuery(sql);
            while (resultSet.next()){
    
    
                System.out.println(resultSet.getInt("id"));
            }

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

SQL注入问题
SQL注入是比较常见的网络攻击方式之一,它不是利用操作系统的BUG来实现攻击,而是针
对程序员编写时的疏忽,通过SQL语句,实现无账号登录,甚至篡改数据库。sql存在漏洞,
会被攻击导致数据泄露 .SQL会被拼接 or

package com.kuang.lesson02.utils;

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

import static com.kuang.lesson02.utils.JdbcUtils.getConnection;

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

        Connection conn =null;
        Statement st = null;
        ResultSet rs =null;

        try {
    
    
            conn = getConnection();//获取连接
            st = conn.createStatement();//获取SQL执行对象
            String sql = "select * from users where `NAME`='"+ name +"'  AND `PASSWORD`='"+ password +"'" ;
            rs=st.executeQuery(sql);//查询完毕返回结果集

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

10.5 PreparedStatement对象

PreparedStatement can prevent SQL injection and is more efficient. (Escape special characters such as quotation marks?)

  1. New
  2. delete
  3. Inquire
package lesson03;

import Demo02.utils.JdbcUtils;

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

public class TestPrepareStatement {
    
    
    public static void main(String[] args) {
    
    
        Connection connection = null;
        PreparedStatement pstm = null;
        try {
    
    

            connection = JdbcUtils.getConnection();
            //区别
            //使用问号占位符代替参数
            String sql = "insert into users(id,`NAME`) values(?,?)";
            pstm = connection.prepareStatement(sql);//预编译sql,先写sql然后不执行
            //手动赋值
            pstm.setInt(1, 8);
            pstm.setString(2, "SANJIN");

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

summary:

  • statement().executeQuery(sql) //Direct execution
  • prepareStatement(sql).executeQuert(sql) //Precompile

10.6 IDEA connects to database

The premise is that the lib directory is imported?
image.png

10.7 JDBC operation transactions

Either all succeed or both fail
ACID principle

  • Atomicity: either all is completed or none is completed
  • Consistency: The total number of results does not change
  • Isolation: multiple processes do not interfere with each other
  • Persistence: Once submitted, it is irreversible and persisted to the database.

Isolation issues:

  • Dirty read: A transaction reads another uncommitted transaction
  • Non-repeatable read: within the same transaction, the data in the table is read repeatedly, and the table changes
  • Virtual reading (phantom reading): In a transaction, data inserted by others is read, resulting in inconsistent reading results.

Code

  1. Open transaction conn.setAutoCommit(false);
  2. After a set of business execution is completed, the transaction is submitted
  3. Rollback can be defined explicitly in the catch statement, but it will rollback by default if it fails.
package Demo04;

import Demo02.utils.JdbcUtils;

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

public class TestTransaction1 {
    
    
    public static void main(String[] args) {
    
    
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        try {
    
    
            conn = JdbcUtils.getConnection();
            //关闭数据库的自动提交,自动开启事务
            conn.setAutoCommit(false); //开启事务

            String sql1 = "update account set money = money-100 where name = 'A'";
            ps = conn.prepareStatement(sql1);
            ps.executeUpdate();

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

            String sql2 = "update account set money = money+100 where name = 'B'";
            ps = conn.prepareStatement(sql2);
            ps.executeUpdate();

            // 业务完毕,开启事务
            conn.commit();

        } catch (SQLException e) {
    
    
            // 回滚语句,显示定义,不定义也行,系统默认调用
            try {
    
    
                conn.rollback();
            } catch (SQLException ex) {
    
    
                throw new RuntimeException(ex);
            }
            throw new RuntimeException(e);
        }finally {
    
    
            // 这里不能写开启自动提交,否则会提交报错之前的内容,导致回滚失败,
            // 回滚失败应该是 继续 从conn.setAutoCommit(false); 这个状态开始
            JdbcUtils.release(conn,ps,rs);
        }
    }
}

10.8 Database connection pool

Database connection—Complete execution—Release connection—Release is a waste of system resource
pooling technology: Prepare some resources in advance, and then connect to the pre-prepared resources.

Write a connection pool and implement an interface. DataSource
I can’t understand it later.

Guess you like

Origin blog.csdn.net/qq_53517370/article/details/128861112