参考视频遇见狂神说-mysql
一、初识MySQL
1.命令行
1.进入root账户
mysql -u root -p
2.查看所有的数据库
show databases;
3.切换数据库
use [databases_name]
4.查看数据库中所有表
show tables;
5.显示数据库中所有的表的信息
describe [tables_name];
6.创建一个数据库
create database [databases_name]
7.退出链接
exit;
8.单行注释
--
9.多行注释
/**/
二、操作数据库
2.操作数据库
操作数据库->操作数据库中的表->操作数据库里的数据
1.创建数据库
create database [if not exists] westos;
2.删除数据库
drop database [if exists] westos;
3.使用数据库
use `school`;
4.查看数据库
show databases;
3.数据库的列类型
3.1 数据
tinyint | 十分小的数据 | 1字节 |
smallint | 较小的数据 | 2字节 |
mediumint | 中等大小的数据 | 3字节 |
int | 数据 | 4字节 |
bigint | 较大的数据 | 8字节 |
float | 浮点数 | 4字节 |
double | 浮点数 | 8字节 |
decimal | 字符串形式的浮点数 | 金融计算的时候,一般用decimal |
3.2 字符串
char | 字符串固定大小的 | 0-255 | |
varchar | 可变字符串 | 0-65535 | 常用的 类似于java的String |
tinytext | 微型文本 | 2^8-1 | |
text | 文本串 | 2^16-1 | 保存大文本 |
3.3 时间日期
java.util.Date
-
Date YYYY-MM-DD 日期格式
-
Time HH: mm: ss 时间格式
-
Datetime YYYY-MM-DD HH: MM: ss 最常用的时间格式
-
Timestamp 时间戳 1970.1.1到现在的毫秒数
也较为常用
-
Year 年份表示
3.4 null
- 没有值,未知
- 不要使用null进行运算
4.!数据库的字段属性
4.1 unsighed:
- 无符号的整数
- 声明了该列不能声明为负数
4.2 zerofill:
- 0填充的
- 不足的位数,用0填充,int(3), 5 ... 005
4.3 自增aoto_increment:
- 通常理解为自增,自动在上一条记录的基础上+1
- 通常用来设计唯一主键~index,必须是整数类型
- 可以自定义设计自增的起步值和步长
4.4 非空NUll not null
- 假设设为not null,如果不赋值,就会报错
- Null如果不填写值,默认就是NULL
4.5 默认defaut
- 设置默认的值
- Sex 默认值为男,如果不指定该列的值,则会有默认的值
4.6 拓展
//每一个主键都应该存在一下5个字段
`id` 主键
`version` 乐观锁
`is_delete` 伪删除
`gmt_create` 创建时间
`gmt_update` 修改时间
5.!创建数据库表
5.1 实例
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(20) 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;
5.2 格式
create table [if not exists] `表名`(
`字段名` 列类型 [属性] [索引] [注释],
`字段名` 列类型 [属性] [索引] [注释],
...
`字段名` 列类型 [属性] [索引] [注释],
)[表类型][字符集设置][注释]
5.3 常用命令
SHOW CREATE DATABASE `school`; --查看数据库创建
SHOW CREATE TABLE student; --查看表创建
DESC `student`; --查看表的细节
6.数据表的类型
6.1 MYISAM与INNODB对比
/*
INNODB 默认使用
MYISAM 早些年使用
*/
MYISAM | INNODB | |
---|---|---|
事务支持 | 不支持 | 支持 |
数据行锁定 | 不支持 | 支持 |
外键约束 | 不支持 | 支持 |
全文索引 | 支持 | 不支持 |
表空间的大小 | 较小 | 较大,约为MYISAM的两倍 |
常规使用操作: |
- MYISAM 节约空间,速度较快
- INNODB 安全性高,支持事务处理,多表多用户操作
6.2 在物理空间存在的位置
所有的数据库文件都存在data目录下
本质还是文件的存储
6.3 MySQL引擎在物理文件上的区别
- InnoDB 在数据库表中只有一个*.frm文件,以及上级文件目录的ibdata1文件
- MYISAM对应文件
- *.frm 表结构的定义文件
- *.MYD 数据文件(data)
- *.MYI 索引文件(index)
6.4 设置数据库表的字符集编码
charset=utf8
不设置的话,会是mysql默认的字符集编码latin1(不支持中文)
7.修改删除表
7.1 修改
7.1.1 修改表名
-- alter table [old_table_name] as [new_table_name];
-- 范例:
alter table student as teacher;
7.1.2 增加表的字段
-- alter table [table_name] add [字段名] [列属性];
-- 示例:
alter table teacher add age int(3);
7.1.3 修改表的字段
alter table teacher modify age varchar(11); -- 修改约束
alter table teacher change age age1 int(1); -- 字段重命名 现在也可以修改约束
7.2 删除
7.2.1 删除表的字段
alter table teacher drop age1;
7.2.2 删除表(如果表存在再删除)
drop table if exists teacher1;
所有的创建和删除操作尽量加上判断,以免报错
三、MySQL数据管理
8.外键(了解)
图8.1:
- 将student(若为其他名,省略该步)删除
drop table student;
- 添加如下表:
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;
8.1 添加外键的三种方式
8.1.1 创建表时添加约束
-- 学生表的 gradeId 字段 要去引用年级表的 gradeId
-- 定义外键key
-- 给这个外键添加约束(执行引用) references 引用
-- constraint 限制,约束
-- foreign 涉外的 外国的
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(20) not null default '女' comment '性别',
`birthday` datetime default null comment '生日',
`gradeId` int(10) not null comment '学生的年级',
`address` varchar(100) default null comment '家庭住址',
`email` varchar(50) default null comment '邮箱',
primary key(`id`),
key `FK_gradeId` (gradeId),
constraint `FK_gradeId` foreign key references `grade` (`gradeid`)
)engine=INNODB default charset = utf8;
8.1.2 修改外键关系
alter table `student` add constraint `FK_gradeId` foreign key (`gradeId`) references `grade`(`gradeId`);
alter table [slave-table-name] add constraint `FK_slave-key` foreign key (`slave-key`) references `master-table-name` (`masger-key`)
以上操作都是物理外键,是数据库级别的外键,不建议使用!(避免数据库过多造成困扰)
8.1.3 最佳实践
- 数据库就是单纯的表,只用来存数据,只有行(数据)和列(字段)
- 我们想使用多张表的数据,想使用外键(程序去实现)
9.!DML语言(全部记住)
数据库意义: 数据存储,数据管理
DML语言: 数据操作语言
- Insert
- update
- delete
9.1 添加
-- 插入语句,添加
insert into 表名([字段名1,字段名2,字段3])values(`值1`),(`值2`),(`值3`),(...);
insert into `grade` (`gradeName`) values('大四')
-- 由于主键自增可以省略,如果不写表的字段,就会一一匹配
insert into `grade` values('大四'); -- 发生错误
-- 相当于:
insert into `grade`(`gradeId`,`gradeName`) values('大四',null);
尽量写上字段名
案例:
insert into student(`name`,`pwd`,`sex`) values('zhangshan','aaaaaa','man');
insert into `student`(`name`,`pwd`,`sex`) values('张三','aaaa','男'),
('李四','bbbb','男');
9.2 修改
- 语法1:
update 修改谁 (条件) set 原来的值 = 新值;
案例:
update `student` set name='狂神' where id = 1;
- 语法2:
update 表名 set colnum_name = value,[colnum_name = value,...] where [条件]
-- 修改多个属性
update `student` set `name` = '狂神', email = '24736743@qq.com' where id=1;
条件:where子句 运算符 id等于某个值 大于某个值 再某个区间
操作符会返回布尔值
操作符 | 含义 | 范围 | 结果 |
---|---|---|---|
== | 等于 | 5=6 | false |
<>或!= | 不等于 | 5<>6 | true |
|||
<|||
=|||
<=|||
between ... and ...|[2,5]|在某个范围内|
and|&&||
or|或||
-- 通过多个条件定位数据
update `student` set `name`='长江7号' where name='狂神' and sex=`女`;
注意:
- colnum_name是数据库的列,尽量带上``
- 条件,是筛选的条件,如果没有指定,则会修改所有的列
- value,是一个具体的值,也可以是一个变量,如:
update `student` set `birthday` = current_time where `name`= '长江7号' and `sex` = '女';
9.3 删 除
9.3.1 删除
语法
delete from 表名 [where 条件];
-- 例子
delete from `student` where id = 3;
9.3.2 清空
作用:完全清空一个数据库表,表的结构和索引约束不会变。
truncate 表名;
truncate `student`;
9.3.3 delete和truncate区别
- 相同点: 都能删除数据,都不会删除表结构
- 不同:
- truncate 重新设置自增列 计数器会归零
- truncate 不会影响事务
- delete 不会影响自增
了解:delete删除的问题,重启数据库现象:
- InnoDB 自增列会从1开始(存在内存当中的,断电即失)
- MyISAM 继续从上一个自增量开始(存在文件中的,不会丢失)
四、!!DQL查询数据(最重点)
10.DQL
(Data Query Language:数据查询语言)
- 所有的查询操作都用它 select
- 简单的查询,复杂的查询都能做
- 数据库中最核心的语言,最重要的语句
- 使用频率最高的语句
10.1 select语法
SELECT [ALL | DISTINCT]
{* | table.* | [table.field1[as alias1][,table.field2[as alias2]][,...]]}
FROM table_name [as table_alias]
[left | right | inner join table_name2] #联合查询
[WHERE ...] #指定结果需满足的条件
[GROUP BY ...] #指定结果按照哪几个字段来分组
[HAVING] #过滤分组的记录必须满足的次要条件
[ORDER BY ...] #指定查询记录按一个或多个条件排序
[LIMIT {[offset,]row_count | row_countOFFSET offset}];
# 指定查询的记录从哪条至哪条
注意 : [ ] 括号代表可选的 , { }括号代表必须得
提供素材:
/*
SQLyog Ultimate v10.00 Beta1
MySQL - 5.7.19 : Database - school
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;
/*!40101 SET SQL_MODE=''*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`school` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `school`;
/*Table structure for table `grade` */
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;
/*Data for the table `grade` */
INSERT INTO `grade`(`GradeID`,`GradeName`) VALUES (1,'大一'),(2,'大二'),(3,'大三'),(4,'大四'),(5,'预科班');
/*Table structure for table `result` */
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;
/*Data for the table `result` */
INSERT INTO `result`(`StudentNo`,`SubjectNo`,`ExamDate`,`StudentResult`) VALUES (1000,1,'2013-11-11 16:00:00',94),(1000,2,'2012-11-10 10:00:00',75),(1000,3,'2011-12-19 10:00:00',76),(1000,4,'2010-11-18 11:00:00',93),(1000,5,'2013-11-11 14:00:00',97),(1000,6,'2012-09-13 15:00:00',87),(1000,7,'2011-10-16 16:00:00',79),(1000,8,'2010-11-11 16:00:00',74),(1000,9,'2013-11-21 10:00:00',69),(1000,10,'2012-11-11 12:00:00',78),(1000,11,'2011-11-11 14:00:00',66),(1000,12,'2010-11-11 15:00:00',82),(1000,13,'2013-11-11 14:00:00',94),(1000,14,'2012-11-11 15:00:00',98),(1000,15,'2011-12-11 10:00:00',70),(1000,16,'2010-09-11 10:00:00',74),(1001,1,'2013-11-11 16:00:00',76),(1001,2,'2012-11-10 10:00:00',93),(1001,3,'2011-12-19 10:00:00',65),(1001,4,'2010-11-18 11:00:00',71),(1001,5,'2013-11-11 14:00:00',98),(1001,6,'2012-09-13 15:00:00',74),(1001,7,'2011-10-16 16:00:00',85),(1001,8,'2010-11-11 16:00:00',69),(1001,9,'2013-11-21 10:00:00',63),(1001,10,'2012-11-11 12:00:00',70),(1001,11,'2011-11-11 14:00:00',62),(1001,12,'2010-11-11 15:00:00',90),(1001,13,'2013-11-11 14:00:00',97),(1001,14,'2012-11-11 15:00:00',89),(1001,15,'2011-12-11 10:00:00',72),(1001,16,'2010-09-11 10:00:00',90),(1002,1,'2013-11-11 16:00:00',61),(1002,2,'2012-11-10 10:00:00',80),(1002,3,'2011-12-19 10:00:00',89),(1002,4,'2010-11-18 11:00:00',88),(1002,5,'2013-11-11 14:00:00',82),(1002,6,'2012-09-13 15:00:00',91),(1002,7,'2011-10-16 16:00:00',63),(1002,8,'2010-11-11 16:00:00',84),(1002,9,'2013-11-21 10:00:00',60),(1002,10,'2012-11-11 12:00:00',71),(1002,11,'2011-11-11 14:00:00',93),(1002,12,'2010-11-11 15:00:00',96),(1002,13,'2013-11-11 14:00:00',83),(1002,14,'2012-11-11 15:00:00',69),(1002,15,'2011-12-11 10:00:00',89),(1002,16,'2010-09-11 10:00:00',83),(1003,1,'2013-11-11 16:00:00',91),(1003,2,'2012-11-10 10:00:00',75),(1003,3,'2011-12-19 10:00:00',65),(1003,4,'2010-11-18 11:00:00',63),(1003,5,'2013-11-11 14:00:00',90),(1003,6,'2012-09-13 15:00:00',96),(1003,7,'2011-10-16 16:00:00',97),(1003,8,'2010-11-11 16:00:00',77),(1003,9,'2013-11-21 10:00:00',62),(1003,10,'2012-11-11 12:00:00',81),(1003,11,'2011-11-11 14:00:00',76),(1003,12,'2010-11-11 15:00:00',61),(1003,13,'2013-11-11 14:00:00',93),(1003,14,'2012-11-11 15:00:00',79),(1003,15,'2011-12-11 10:00:00',78),(1003,16,'2010-09-11 10:00:00',96),(1004,1,'2013-11-11 16:00:00',84),(1004,2,'2012-11-10 10:00:00',79),(1004,3,'2011-12-19 10:00:00',76),(1004,4,'2010-11-18 11:00:00',78),(1004,5,'2013-11-11 14:00:00',81),(1004,6,'2012-09-13 15:00:00',90),(1004,7,'2011-10-16 16:00:00',63),(1004,8,'2010-11-11 16:00:00',89),(1004,9,'2013-11-21 10:00:00',67),(1004,10,'2012-11-11 12:00:00',100),(1004,11,'2011-11-11 14:00:00',94),(1004,12,'2010-11-11 15:00:00',65),(1004,13,'2013-11-11 14:00:00',86),(1004,14,'2012-11-11 15:00:00',77),(1004,15,'2011-12-11 10:00:00',82),(1004,16,'2010-09-11 10:00:00',87),(1005,1,'2013-11-11 16:00:00',82),(1005,2,'2012-11-10 10:00:00',92),(1005,3,'2011-12-19 10:00:00',80),(1005,4,'2010-11-18 11:00:00',92),(1005,5,'2013-11-11 14:00:00',97),(1005,6,'2012-09-13 15:00:00',72),(1005,7,'2011-10-16 16:00:00',84),(1005,8,'2010-11-11 16:00:00',79),(1005,9,'2013-11-21 10:00:00',76),(1005,10,'2012-11-11 12:00:00',87),(1005,11,'2011-11-11 14:00:00',65),(1005,12,'2010-11-11 15:00:00',67),(1005,13,'2013-11-11 14:00:00',63),(1005,14,'2012-11-11 15:00:00',64),(1005,15,'2011-12-11 10:00:00',99),(1005,16,'2010-09-11 10:00:00',97),(1006,1,'2013-11-11 16:00:00',82),(1006,2,'2012-11-10 10:00:00',73),(1006,3,'2011-12-19 10:00:00',79),(1006,4,'2010-11-18 11:00:00',63),(1006,5,'2013-11-11 14:00:00',97),(1006,6,'2012-09-13 15:00:00',83),(1006,7,'2011-10-16 16:00:00',78),(1006,8,'2010-11-11 16:00:00',88),(1006,9,'2013-11-21 10:00:00',89),(1006,10,'2012-11-11 12:00:00',82),(1006,11,'2011-11-11 14:00:00',70),(1006,12,'2010-11-11 15:00:00',69),(1006,13,'2013-11-11 14:00:00',64),(1006,14,'2012-11-11 15:00:00',80),(1006,15,'2011-12-11 10:00:00',90),(1006,16,'2010-09-11 10:00:00',85),(1007,1,'2013-11-11 16:00:00',87),(1007,2,'2012-11-10 10:00:00',63),(1007,3,'2011-12-19 10:00:00',70),(1007,4,'2010-11-18 11:00:00',74),(1007,5,'2013-11-11 14:00:00',79),(1007,6,'2012-09-13 15:00:00',83),(1007,7,'2011-10-16 16:00:00',86),(1007,8,'2010-11-11 16:00:00',76),(1007,9,'2013-11-21 10:00:00',65),(1007,10,'2012-11-11 12:00:00',87),(1007,11,'2011-11-11 14:00:00',69),(1007,12,'2010-11-11 15:00:00',69),(1007,13,'2013-11-11 14:00:00',90),(1007,14,'2012-11-11 15:00:00',84),(1007,15,'2011-12-11 10:00:00',95),(1007,16,'2010-09-11 10:00:00',92),(1008,1,'2013-11-11 16:00:00',96),(1008,2,'2012-11-10 10:00:00',62),(1008,3,'2011-12-19 10:00:00',97),(1008,4,'2010-11-18 11:00:00',84),(1008,5,'2013-11-11 14:00:00',86),(1008,6,'2012-09-13 15:00:00',72),(1008,7,'2011-10-16 16:00:00',67),(1008,8,'2010-11-11 16:00:00',83),(1008,9,'2013-11-21 10:00:00',86),(1008,10,'2012-11-11 12:00:00',60),(1008,11,'2011-11-11 14:00:00',61),(1008,12,'2010-11-11 15:00:00',68),(1008,13,'2013-11-11 14:00:00',99),(1008,14,'2012-11-11 15:00:00',77),(1008,15,'2011-12-11 10:00:00',73),(1008,16,'2010-09-11 10:00:00',78),(1009,1,'2013-11-11 16:00:00',67),(1009,2,'2012-11-10 10:00:00',70),(1009,3,'2011-12-19 10:00:00',75),(1009,4,'2010-11-18 11:00:00',92),(1009,5,'2013-11-11 14:00:00',76),(1009,6,'2012-09-13 15:00:00',90),(1009,7,'2011-10-16 16:00:00',62),(1009,8,'2010-11-11 16:00:00',68),(1009,9,'2013-11-21 10:00:00',70),(1009,10,'2012-11-11 12:00:00',83),(1009,11,'2011-11-11 14:00:00',88),(1009,12,'2010-11-11 15:00:00',65),(1009,13,'2013-11-11 14:00:00',91),(1009,14,'2012-11-11 15:00:00',99),(1009,15,'2011-12-11 10:00:00',65),(1009,16,'2010-09-11 10:00:00',83),(1010,1,'2013-11-11 16:00:00',83),(1010,2,'2012-11-10 10:00:00',87),(1010,3,'2011-12-19 10:00:00',89),(1010,4,'2010-11-18 11:00:00',99),(1010,5,'2013-11-11 14:00:00',91),(1010,6,'2012-09-13 15:00:00',96),(1010,7,'2011-10-16 16:00:00',72),(1010,8,'2010-11-11 16:00:00',72),(1010,9,'2013-11-21 10:00:00',98),(1010,10,'2012-11-11 12:00:00',73),(1010,11,'2011-11-11 14:00:00',68),(1010,12,'2010-11-11 15:00:00',62),(1010,13,'2013-11-11 14:00:00',67),(1010,14,'2012-11-11 15:00:00',69),(1010,15,'2011-12-11 10:00:00',71),(1010,16,'2010-09-11 10:00:00',66),(1011,1,'2013-11-11 16:00:00',62),(1011,2,'2012-11-10 10:00:00',72),(1011,3,'2011-12-19 10:00:00',96),(1011,4,'2010-11-18 11:00:00',64),(1011,5,'2013-11-11 14:00:00',89),(1011,6,'2012-09-13 15:00:00',91),(1011,7,'2011-10-16 16:00:00',95),(1011,8,'2010-11-11 16:00:00',96),(1011,9,'2013-11-21 10:00:00',89),(1011,10,'2012-11-11 12:00:00',73),(1011,11,'2011-11-11 14:00:00',82),(1011,12,'2010-11-11 15:00:00',98),(1011,13,'2013-11-11 14:00:00',66),(1011,14,'2012-11-11 15:00:00',69),(1011,15,'2011-12-11 10:00:00',91),(1011,16,'2010-09-11 10:00:00',69),(1012,1,'2013-11-11 16:00:00',86),(1012,2,'2012-11-10 10:00:00',66),(1012,3,'2011-12-19 10:00:00',97),(1012,4,'2010-11-18 11:00:00',69),(1012,5,'2013-11-11 14:00:00',70),(1012,6,'2012-09-13 15:00:00',74),(1012,7,'2011-10-16 16:00:00',91),(1012,8,'2010-11-11 16:00:00',97),(1012,9,'2013-11-21 10:00:00',84),(1012,10,'2012-11-11 12:00:00',82),(1012,11,'2011-11-11 14:00:00',90),(1012,12,'2010-11-11 15:00:00',91),(1012,13,'2013-11-11 14:00:00',91),(1012,14,'2012-11-11 15:00:00',97),(1012,15,'2011-12-11 10:00:00',85),(1012,16,'2010-09-11 10:00:00',90),(1013,1,'2013-11-11 16:00:00',73),(1013,2,'2012-11-10 10:00:00',69),(1013,3,'2011-12-19 10:00:00',91),(1013,4,'2010-11-18 11:00:00',72),(1013,5,'2013-11-11 14:00:00',76),(1013,6,'2012-09-13 15:00:00',87),(1013,7,'2011-10-16 16:00:00',61),(1013,8,'2010-11-11 16:00:00',77),(1013,9,'2013-11-21 10:00:00',83),(1013,10,'2012-11-11 12:00:00',99),(1013,11,'2011-11-11 14:00:00',91),(1013,12,'2010-11-11 15:00:00',84),(1013,13,'2013-11-11 14:00:00',98),(1013,14,'2012-11-11 15:00:00',74),(1013,15,'2011-12-11 10:00:00',92),(1013,16,'2010-09-11 10:00:00',90),(1014,1,'2013-11-11 16:00:00',64),(1014,2,'2012-11-10 10:00:00',81),(1014,3,'2011-12-19 10:00:00',79),(1014,4,'2010-11-18 11:00:00',74),(1014,5,'2013-11-11 14:00:00',65),(1014,6,'2012-09-13 15:00:00',88),(1014,7,'2011-10-16 16:00:00',86),(1014,8,'2010-11-11 16:00:00',77),(1014,9,'2013-11-21 10:00:00',86),(1014,10,'2012-11-11 12:00:00',85),(1014,11,'2011-11-11 14:00:00',86),(1014,12,'2010-11-11 15:00:00',75),(1014,13,'2013-11-11 14:00:00',89),(1014,14,'2012-11-11 15:00:00',79),(1014,15,'2011-12-11 10:00:00',73),(1014,16,'2010-09-11 10:00:00',68),(1015,1,'2013-11-11 16:00:00',99),(1015,2,'2012-11-10 10:00:00',60),(1015,3,'2011-12-19 10:00:00',60),(1015,4,'2010-11-18 11:00:00',75),(1015,5,'2013-11-11 14:00:00',78),(1015,6,'2012-09-13 15:00:00',78),(1015,7,'2011-10-16 16:00:00',84),(1015,8,'2010-11-11 16:00:00',95),(1015,9,'2013-11-21 10:00:00',93),(1015,10,'2012-11-11 12:00:00',79),(1015,11,'2011-11-11 14:00:00',74),(1015,12,'2010-11-11 15:00:00',65),(1015,13,'2013-11-11 14:00:00',63),(1015,14,'2012-11-11 15:00:00',74),(1015,15,'2011-12-11 10:00:00',67),(1015,16,'2010-09-11 10:00:00',65),(1016,1,'2013-11-11 16:00:00',97),(1016,2,'2012-11-10 10:00:00',90),(1016,3,'2011-12-19 10:00:00',77),(1016,4,'2010-11-18 11:00:00',75),(1016,5,'2013-11-11 14:00:00',75),(1016,6,'2012-09-13 15:00:00',97),(1016,7,'2011-10-16 16:00:00',96),(1016,8,'2010-11-11 16:00:00',92),(1016,9,'2013-11-21 10:00:00',62),(1016,10,'2012-11-11 12:00:00',83),(1016,11,'2011-11-11 14:00:00',98),(1016,12,'2010-11-11 15:00:00',94),(1016,13,'2013-11-11 14:00:00',62),(1016,14,'2012-11-11 15:00:00',97),(1016,15,'2011-12-11 10:00:00',76),(1016,16,'2010-09-11 10:00:00',82),(1017,1,'2013-11-11 16:00:00',100),(1017,2,'2012-11-10 10:00:00',88),(1017,3,'2011-12-19 10:00:00',86),(1017,4,'2010-11-18 11:00:00',73),(1017,5,'2013-11-11 14:00:00',96),(1017,6,'2012-09-13 15:00:00',64),(1017,7,'2011-10-16 16:00:00',81),(1017,8,'2010-11-11 16:00:00',66),(1017,9,'2013-11-21 10:00:00',76),(1017,10,'2012-11-11 12:00:00',95),(1017,11,'2011-11-11 14:00:00',73),(1017,12,'2010-11-11 15:00:00',82),(1017,13,'2013-11-11 14:00:00',85),(1017,14,'2012-11-11 15:00:00',68),(1017,15,'2011-12-11 10:00:00',99),(1017,16,'2010-09-11 10:00:00',76);
/*Table structure for table `student` */
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;
/*Data for the table `student` */
INSERT INTO `student`(`StudentNo`,`LoginPwd`,`StudentName`,`Sex`,`GradeId`,`Phone`,`Address`,`BornDate`,`Email`,`IdentityCard`) VALUES (1000,'111111','郭靖',1,1,'13500000001','北京海淀区中关村大街1号','1986-12-11 00:00:00','test1@bdqn.cn','450323198612111234'),(1001,'123456','李文才',1,2,'13500000002','河南洛阳','1981-12-31 00:00:00','test1@bdqn.cn','450323198112311234'),(1002,'111111','李斯文',1,1,'13500000003','天津市和平区','1986-11-30 00:00:00','test1@bdqn.cn','450323198611301234'),(1003,'123456','武松',1,3,'13500000004','上海卢湾区','1986-12-31 00:00:00','test1@bdqn.cn','450323198612314234'),(1004,'123456','张三',1,4,'13500000005','北京市通州','1989-12-31 00:00:00','test1@bdqn.cn','450323198612311244'),(1005,'123456','张秋丽 ',2,1,'13500000006','广西桂林市灵川','1986-12-31 00:00:00','test1@bdqn.cn','450323198612311214'),(1006,'123456','肖梅',2,4,'13500000007','地址不详','1986-12-31 00:00:00','test1@bdqn.cn','450323198612311134'),(1007,'111111','欧阳峻峰',1,1,'13500000008','北京东城区','1986-12-31 00:00:00','test1@bdqn.cn','450323198612311133'),(1008,'111111','梅超风',1,1,'13500000009','河南洛阳','1986-12-31 00:00:00','test1@bdqn.cn','450323198612311221'),(1009,'123456','刘毅',1,2,'13500000011','安徽','1986-12-31 00:00:00','test1@bdqn.cn','450323198612311231'),(1010,'111111','大凡',1,1,'13500000012','河南洛阳','1986-12-31 00:00:00','test1@bdqn.cn','450323198612311044'),(1011,'111111','奥丹斯',1,1,'13500000013','北京海淀区中关村大街*号','1984-12-31 00:00:00','test1@bdqn.cn','450323198412311234'),(1012,'123456','多伦',2,3,'13500000014','广西南宁中央大街','1986-12-31 00:00:00','test1@bdqn.cn','450323198612311334'),(1013,'123456','李梅',2,1,'13500000015','上海卢湾区','1986-12-31 00:00:00','test1@bdqn.cn','450323198612311534'),(1014,'123456','张得',2,4,'13500000016','北京海淀区中关村大街*号','1986-12-31 00:00:00','test1@bdqn.cn','450323198612311264'),(1015,'123456','李东方',1,4,'13500000017','广西桂林市灵川','1976-12-31 00:00:00','test1@bdqn.cn','450323197612311234'),(1016,'111111','刘奋斗',1,1,'13500000018','上海卢湾区','1986-12-31 00:00:00','test1@bdqn.cn','450323198612311251'),(1017,'123456','可可',2,3,'13500000019','北京长安街1号','1981-09-10 00:00:00','test1@bdqn.cn','450323198109108311'),(10066,'','Tom',1,1,'13500000000','','0000-00-00 00:00:00','email@22.com','33123123123123123');
/*Table structure for table `subject` */
DROP TABLE IF EXISTS `subject`;
CREATE TABLE `subject` (
`SubjectNo` INT(11) NOT NULL AUTO_INCREMENT COMMENT '课程编号',
`SubjectName` VARCHAR(50) DEFAULT NULL COMMENT '课程名称',
`ClassHour` INT(4) DEFAULT NULL COMMENT '学时',
`GradeID` INT(4) DEFAULT NULL COMMENT '年级编号',
PRIMARY KEY (`SubjectNo`)
) ENGINE=INNODB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8;
/*Data for the table `subject` */
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第一学年',110,1),(10,'JAVA第二学年',110,2),(11,'JAVA第三学年',100,3),(12,'JAVA第四学年',130,4),(13,'数据库结构-1',110,1),(14,'数据库结构-2',110,2),(15,'数据库结构-3',100,3),(16,'数据库结构-4',130,4),(17,'C#基础',130,1);
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
10.2 指定查询字段
10.2.1 查询全部
语法:
select 字段, ... from 表
有时候,列名字不是那么见名知意,就起别名 AS
字段名 as 别名
表名 as 别名
案例:
-- 查询全波的学生 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;
10.2.2 去重
查询全部的考试成绩:
select * from result;
查询有哪些同学参加了考试:
SELECT `StudentNo` FROM result;
发现重复数据,去重distinct:
SELECT DISTINCT `StudentNo` FROM result;
作用:去除select查询出来的结果中重复的数据,重复的数据只显示一条
使用数据库可以做的一些事情:
select version();-- 查询版本系统(函数)
select 100+3-2 as 计算结果; -- 用来计算(表达式)
select @@auto_increment_increment --查询自增的步长(变量) v8.0不可用
-- 学员考试成绩+1分查看
select `StudentNo`,`StudentResult` + 1 as `提分后` from result;
数据库中的表达式: 文本值,列,null,函数,计算表达式,系统变量……
select 表达式 from 表;
10.3 where条件子句
作用:检索数据中符合条件的值
where输入一个布尔值
运算符 | 语法 | 描述 |
---|---|---|
and && | a and b a && b | 逻辑与 |
or || | a or b a||b | 逻辑或 |
Not ! | not a !a | 逻辑非 |
尽量使用英文符号 |
10.3.1 !模糊查询
运算符 | 语法 | 描述 |
---|---|---|
is null | a is null | 如果操作符为NULL,结果为真 |
is not null | a is not null | 如果操作符部位null,结果为真 |
between | a between b and c | 若a在b和c之间,则结果为真 |
like | a like b | SQL匹配,如果a匹配b,则结果为真 |
in | a in (a1,a2,...) | 假设a在a1,或者a2...其中的某一个值中,结果为真 |
- 案例 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 '安徽';
- 查询1001,1002,1003号学员
- 案例null not null
- 查询地址为空的学生 null
select StudentNo,StudentName from student where `Address` = '' or is null;
- 查询有出生日期的同学
select StudentNo,StudentName from student where Borndate is not null;
- 查询地址为空的学生 null
10.4 联表查询
10.4.1 join
初学比较复杂,推荐链接SQL的各种连接Join详解
10.4.2 自连接
自己的表和自己的表连接,核心:
一张表拆为两张一样的表即可
父类:
categoryid | categoryName |
---|---|
2 | 信息技术 |
3 | 信息开发 |
5 | 美术开发 |
子类:
pid | categoryid | categoryName |
---|---|---|
3 | 4 | 数据库 |
2 | 8 | 办公信息 |
3 | 6 | web开发 |
5 | 7 | ps技术 |
操作:查询父类对应的子类关系
父类 | 子类 |
---|---|
信息技术 | 办公信息 |
软件开发 | 数据库 |
软件开发 | web开发 |
美术设计 | ps技术 |
附上表:
CREATE TABLE `category`(
`categoryid` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主题id',
`pid` INT(10) NOT NULL COMMENT '父id',
`categoryName` VARCHAR(50) NOT NULL COMMENT '主题名字',
PRIMARY KEY(`categoryid`)
)ENGINE=INNODB AUTO_INCREMENT=9 DEFAULT CHARSET = utf8;
INSERT INTO `category`(`categoryid`,`pid`,`categoryName`)
VALUES('2','1','信息技术'),
('3','1','软件开发'),
('4','3','数据库'),
('5','1','美术设计'),
('6','3','web开发'),
('7','5','ps技术'),
('8','2','办公信息');
查询:
SELECT a.`categoryName` AS '父栏目',
b.`categoryName` AS '子栏目'
FROM `category` AS a, `category` AS b
WHERE a.`pid` = b.`categoryid`;
10.5 分页和排序
分页 limit
语法 limit 起始值,页面的大小
排序 order by
升序 asc
降序 desc
/*============== 分页 ================
语法 : SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset
好处 : (用户体验,网络传输,查询压力)
推导:
第一页 : limit 0,5
第二页 : limit 5,5
第三页 : limit 10,5
......
第N页 : limit (pageNo-1)*pageSzie,pageSzie
[pageNo:页码,pageSize:单页面显示条数]
*/
-- 每页显示5条数据
SELECT s.studentno,studentname,subjectname,StudentResult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON r.subjectno = sub.subjectno
WHERE subjectname='数据库结构-1'
ORDER BY StudentResult DESC , studentno
LIMIT 0,5
#查询 JAVA第一学年 课程成绩前10名并且分数大于80的学生信息(学号,姓名,课程名,分数)
SELECT s.studentno,studentname,subjectname,StudentResult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON r.subjectno = sub.subjectno
WHERE subjectname='JAVA第一学年'
ORDER BY StudentResult DESC
LIMIT 0,10
10.6 子查询
where(这个值是计算出来的)
本质: 在where语句中嵌套一个子查询语句
SELECT studentNo,subjectNo,studentResult
FROM result r
WHERE `SubjectNo` = (
SELECT subjectNo FROM `subject`
WHERE `SubjectName` = '数据库结构-1'
)
ORDER BY studentResult DESC
LIMIT 0,10
SELECT DISTINCT s.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'
)
SELECT studentNo,studentName FROM student WHERE studentNo IN (
SELECT studentNo FROM result WHERE StudentResult>80 AND subjectNo = (
SELECT subjectNo FROM `subject` WHERE `subjectName` = '高等数学-2'
)
)
10.7 分组
group by
-- 查询不同课程的大于80的科目的平均分
-- 核心: 根据不同的课程分组
SELECT subjectName,AVG(studentResult) AS 平均分,
MAX(studentResult) AS 最高分,MIN(studentResult) AS 最低分
FROM result AS r
INNER JOIN `subject` sub
ON r.`SubjectNo` = sub.`SubjectNo`
GROUP BY r.subjectNo
HAVING 平均分 >= 80
五、MySQL函数
官网:https://dev.mysql.com/doc/refman/8.0/en/func-op-summary-ref.html
11.常用函数
-- 数学运算
SELECT ABS(-8)
SELECT CEILING(9.4) -- 向上取整
SELECT FLOOR(9.4) -- 向下取整
SELECT RAND() -- 返回一个0~1之间的随机数
SELECT SIGN(-09) -- 判断一个数的符号 0-0 负数返回-1 正数返回1
-- 字符串
SELECT CHAR_LENGTH('即使再小的帆也能远航') -- 字符串长度
SELECT CONCAT('我','爱','你') -- 拼接字符串
SELECT INSERT('我爱helloworld',1,2,'超级热爱') -- 插入,替换 [a,b],从1开始
-- 会被换成‘超级热爱helloworld’
-- 可以把此处2换成100之类会将所有删除换成‘超级热爱’
SELECT LOWER('LKJsdfa') -- 小写字母
SELECT UPPER('jdsflkLL') -- 大写字母
SELECT INSTR('asdfsdaf','s') -- 返回第一次出现的字串的索引
SELECT REPLACE('坚持就能成功','坚持','努力') -- 替换出现的指定字符串
SELECT SUBSTR('努力就能成功',4) -- 返回指定的子字符串(源字符串,截取位置 [,截取长度])
SELECT REVERSE('努力就能成功') -- 反转
-- 查询姓李的的同学
SELECT * FROM student
WHERE studentName LIKE '李%'
-- 时间和日期函数(记住)
SELECT CURRENT_DATE() -- 当前日期
SELECT CURDATE() -- 获取当期日期
SELECT NOW() -- 获取当前的时间
SELECT LOCALTIME() -- 本地时间
SELECT SYSDATE() -- 系统时间
SELECT YEAR(NOW())
SELECT MINUTE(NOW())
-- 系统
SELECT SYSTEM_USER()
SELECT USER()
SELECT VERSION()
12.聚合函数(常用)
函数名称 | 描述 |
---|---|
count() | 计数 |
sum() | 求和 |
avg() | 平均值 |
max() | 最大值 |
min() | 最小值 |
... | ... |
-- 查询不同课程的大于80的科目的平均分
-- 核心: 根据不同的课程分组
SELECT subjectName,AVG(studentResult) AS 平均分,
MAX(studentResult) AS 最高分,MIN(studentResult) AS 最低分
FROM result AS r
INNER JOIN `subject` sub
ON r.`SubjectNo` = sub.`SubjectNo`
GROUP BY r.subjectNo
HAVING 平均分 >= 80
13.数据库级别的MD5加密(扩展)
md5不可逆,具体的值的md5值是一样的
CREATE TABLE testmd5(
id INT(4) NOT NULL,
`name` VARCHAR(100) NOT NULL,
pwd VARCHAR(100) NOT NULL,
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET = utf8
-- 明文密码
INSERT INTO testmd5 VALUES(1,'zhangsan','123456'),(2,'lisi','123456'),(3,'wangwu','123456')
-- 加密
UPDATE testmd5 SET pwd = MD5(pwd) WHERE id = 1
-- 插入时候加密
insert into testmd5 values(4,'xiaoming',md5('123456'))
-- 如何检校:将用户传递进来的密码,进行md5加密,然后对比加密后的值
select * from testmd5 where `name`='小明' and pwd=md5('123456')
六、事务
要么都成功,要么都失败
——————
1、SQL执行 A给B转账 A1000 --> 200 B 200
2、SQL执行 B收到A的钱 A800 --> B 400
——————
将一组SQL放在一个批次中去执行~
事务原则:ACID原则 原子性 一致性 隔离性 持久性 (脏读、幻读、……)
https://blog.csdn.net/dengjili/article/details/82468576
原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。一致性(Consistency)
事务前后数据的完整性必须保持一致。隔离性(Isolation)
事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响
mysql是默认开启事务自动提交的
set autocommit = 0 -- 关闭
set autocommit = 1 -- 开启(默认)
/* 使用set语句来改变自动提交模式 */
SET autocommit = 0; /*关闭*/
SET autocommit = 1; /*开启*/
/* 注意
1.MySQL中默认是自动提交
2.使用事务时应先关闭自动提交
*/
/*开始一个事务,标记事务的起始点*/
START TRANSACTION
/*提交一个事务给数据库*/
COMMIT
/*将事务回滚,数据回到本次事务的初始状态*/
ROLLBACK
/*还原MySQL数据库的自动提交*/
SET autocommit =1;
-- 保存点
SAVEPOINT 保存点名称 -- 设置一个事务保存点
ROLLBACK TO SAVEPOINT 保存点名称 -- 回滚到保存点
RELEASE SAVEPOINT 保存点名称 -- 删除保存点
模拟场景
SET autocommit = 0;
-- 转账
CREATE DATABASE shop CHARACTER SET utf8 COLLATE utf8_general_ci
USE shop
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.0);
-- 模拟转账:事务
SET autocommit = 0; -- 关闭自动提交
START TRANSACTION; -- 开启一个事务(一组事务)
UPDATE account SET money = money-500 WHERE `name` = 'a'; -- a减500
UPDATE account SET money = money+500 WHERE `name` = 'b'; -- b加500
COMMIT; -- 提交事务,就被持久化了!
ROLLBACK; -- 回滚
SET autocommit = 1; --恢复默认值
七、索引
索引是帮助mysql高效获取数据的数据结构
作用 :
- 提高查询速度
- 确保数据的唯一性
- 可以加速表和表之间的连接 , 实现表与表之间的参照完整性
- 使用分组和排序子句进行数据检索时 , 可以显著减少分组和排序的时间
- 全文检索字段进行搜索优化.
分类 :
-
主键索引 (Primary Key)
- 唯一标识,主键不可重复,只能有一个列作为主键
-
唯一索引 (Unique)
- 不允许具有索引值相同的行,唯一索引可以重复,多个列都可表示为唯一索引
-
常规索引 (Index)
- 默认的,index / key关键字来设置
-
全文索引 (FullText)
- 在特定的数据库引擎下才有,MyISAM,现在很多都有了
- 快速定位数据
1.主键索引
主键 : 某一个属性组能唯一标识一条记录
特点 :
- 最常见的索引类型
- 确保数据记录的唯一性
- 确定特定数据记录在数据库中的位置
2.唯一索引
作用 : 避免同一个表中某数据列中的值重复
与主键索引的区别
-
主键索引只能有一个
-
唯一索引可能有多个
3.常规索引
作用 : 快速定位特定数据
注意 :
-
index 和 key 关键字都可以设置常规索引
-
应加在查询找条件的字段
-
不宜添加太多常规索引,影响数据的插入,删除和修改操作
4.全文索引
作用 : 快速定位特定数据
注意 :
- 只能用于MyISAM类型的数据表
- 只能用于CHAR , VARCHAR , TEXT数据列类型
- 适合大型数据集
5.开始学习索引
创建表:
CREATE TABLE `app_user`(
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) DEFAULT '' COMMENT '用户昵称',
`email` VARCHAR(50) NOT NULL COMMENT '用户邮箱',
`phone` VARCHAR(20) DEFAULT '' COMMENT '手机号',
`gender` TINYINT(4) UNSIGNED DEFAULT '0' COMMENT '性别(0:男;1:女)',
`password` VARCHAR(100) NOT NULL COMMENT '密码',
`age` TINYINT(4) DEFAULT '0' COMMENT '年龄',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
`update_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY(`id`)
)ENGINE INNODB DEFAULT CHARSET=utf8mb4 COMMENT='app用户表';
创建一个函数:
SET GLOBAL log_bin_trust_function_creators=TRUE;
-- 插入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`)
VALUES(
CONCAT('用户',i),
CONCAT(i,'@qq.com'),
CONCAT('18',FLOOR(RAND()*999999999-100000000)),
FLOOR(RAND()*2),
UUID(),
FLOOR(RAND()*2)
);
-- 在上方插入语句
SET i = i + 1;
END WHILE;
RETURN i;
END;
运行:
SELECT mock_data();
可在增加索引前看看没加索引的时候查询速度:
SELECT * FROM app_user WHERE `name`='用户9999'
EXPLAIN SELECT * FROM app_user WHERE `name`='用户9999'
增加索引
-- id_表名_字段名
CREATE INDEX 索引名 ON 表(字段);
CREATE INDEX id_app_user_name ON app_user(`name`);
再看看增加索引后的查询速度:
SELECT * FROM app_user WHERE `name`='用户9999'
EXPLAIN SELECT * FROM app_user WHERE `name`='用户9999'
/*
#方法一:创建表时
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';
/*使用全文索引*/
EXPLAIN SELECT *FROM student WHERE MATCH(studentname) AGAINST('love');
6.索引原则
- 索引不是越多越好
- 不要对进程变动数据加索引
- 小数据量的表不需要加索引
- 索引一般加再常用来查询的字段上!
索引的数据结构
八、权限管理和备份
1.用户管理
可视化界面
sql命令操作
用户表:mysql.user
本质:对这张表增删改查
-- 创建用户
CREATE USER 用户名 IDENTIFIED BY '密码';
CREATE USER test IDENTIFIED BY '123456' ;
-- 修改密码
SET PASSWORD = PASSWORD('111111');
/*注:在mysql8.0以上版本,
update mysql.user set password='newpassword' where user='root';
和
update mysql.user set password=PASSWORD('newpassword') where User='root';
这两条命令已经不起作用了。*/
ALTER USER test IDENTIFIED WITH MYSQL_NATIVE_PASSWORD BY '111111';
-- 重命名
RENAME USER 原来名字 TO 新名字;
RENAME USER test TO test2;
-- 用户授权 all privileges 全部的权限,库.表
-- all privileges 除了给别人授权,其他都能干
GRANT ALL PRIVILEGES ON *.* TO test2;
-- 查看权限
SHOW GRANTS FOR test2;
SHOW GRANTS FOR root@localhost;
-- 撤销权限 revoke 哪些权限,在哪个库撤销,给谁撤销
REVOKE ALL PRIVILEGES ON *.* FROM test2;
-- 删除用户
DROP USER test2;
2.MySQL备份
- 保证重要的数据不丢失
- 数据转移 A------>B
MySQL数据库备份的方式:
-
直接拷贝
-
使用类似与SQLyog这种可视化工具中手动导出
-
在想要导出的表或者库中,右键,选择备份或导出:
-
-
使用命令行导出 mysqldump
-
# mysqldump -h 主机 -u 用户名 -p 密码 数据库 表1 表2 表3 > 物理磁盘位置/文件名 mysqldump -h localhost -u root -p qq123456 school student >D:/a.sql #在MySQL8中 mysqldump -h localhost -u root -p school student >D:/a.sql #回车后会请求输入密码,之后再执行
-
-
用命令行导入
-
在登录的情况下
source d:/a.sql
-
注意,要使用符合数据要求的数据库
show databases;查看数据库 #如果 mydb 不存在,先创建 mydb create database mydb; #再选中 mydb use mydb;
-
或者:
mysql -u 用户名 -p 库名< 备份文件
-
九、规范数据库设计
1.为什么需要设计
当数据库比较复杂的时候,我们就需要设计了
糟糕的数据库设计:
- 数据冗余,浪费空间
- 数据库插入和删除都会麻烦、异常【屏蔽使用物理外键】
- 程序的性能差
良好的数据库设计:
- 节省内存空间
- 保证数据库的完整性
- 方便开发系统
软件开发中,关于数据库的设计
- 分析需求:分析业务和需要处理的数据库的需求
- 概要设计:设计关系图E-R图
设计数据库的步骤:(比如个人博客)
- 收集信息,分析需求
- 用户表(用户登陆注销,用户个人信息,写博客,//创建分类)
- 分类表(文章分类,谁创建的)
- 文章表(文章的信息)
- 评论表
- 友链表(友链信息)
- //自定义表(系统信息,某个关键的字,或者一些主字段)key:value
- 标识实体之间的关系(把需求落地到每个字段)
- 写博客:user-->blog
- 创建分类:user-->category
- 关注:user-->user
- 友链:links
- 评论:user-user-blog
2.三大范式
为什么需要数据规范化:
- 信息重复
- 更新异常
- 插入异常
- 无法正常显示信息
- 删除异常
- 丢失有效信息
三大范式
目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。
第一范式(1NF)
原子性:保证每一列不可再分
第二范式(2NF)
前提:满足第一范式
每张表只描述一件事情
第三范式(3NF)
前提:满足第一范式和第二范式
第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。
(规范数据库的设计)
规范性和性能的问题
关联查询的表不得超过三张表
- 考虑商业化的需求和目标(成本,用户体验!)数据库的性能更加重要
- 在规范性能的问题的时候,适当考虑一下规范性
- 故意给某些表增加一些冗余的字段(从多表查询中变为单表查询)
- 故意增加一些计算列(从大数据量降低为小数据量的查询:索引)
十、!JDBC(重点)
1.数据库驱动
驱动:比如声卡、显卡,数据库也要驱动
程序会通过数据库驱动和数据库打交道
2.JDBC
sun公司为了简化开发人员对数据库的统一操作,提供了一个java操作数据库的规范,俗称JDBC
规范的实现由具体厂商操作
对于开发人员来说,只需要掌握JDBC的接口的操作即可
没有什么是加一层是解决不了的,如果有,再加一层
java.sql
javax.sql
还需要导入一个数据库驱动包
3.第一个JDBC程序
创建测试数据库:
CREATE DATABASE jdbcStudy CHARACTER SET utf8 COLLATE utf8_general_ci;
USE jdbcStudy;
CREATE TABLE users(
id INT PRIMARY KEY,
`name` VARCHAR(40),
`password` VARCHAR(40),
email VARCHAR(60),
birthday DATE
);
INSERT INTO users (id,`name`,`password`,email,birthday)
VALUES(1,'zhangsan','123456','zs@sina.com','1980-12-04'),
(2,'lisi','123456','lisi@sina.com','1981-12-04'),
(3,'wangwu','123456','wangwu@sina.com','1979-12-04');
-
创建一个Maven项目
-
导入数据库驱动依赖
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.17</version> </dependency>
-
编写测试代码
mysql错误:java.sql.SQLException: The server time zone value '�й���ʱ��' is unrecognized or represents
package com.huangdekai.javaWebLearn; // 第一个JDBC程序 import java.sql.*; public class jdbcFirstDemo { public static void main(String[] args) throws ClassNotFoundException, SQLException { //1.加载驱动 Class.forName("com.mysql.jdbc.Driver"); //2.用户信息和url //教程中只有useUnicode=true&characterEncoding=utf8&useSSL=true //出现了上述连接的mysql错误,在url里添加了serverTimezone=UTC String url="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC"; String username = "root"; String password = "qq123456"; //3.连接成功,数据库对象 Connection代表数据库 Connection connection = DriverManager.getConnection(url, username, password); //4.执行SQL的对象 Statement statement = connection.createStatement(); //5.执行SQL的对象去执行SQL,可能存在结果,查看返回结果 String sql = "SELECT * FROM users"; //返回的结果集,结果封装了我们全部的查询出来的结果 ResultSet resultSet = statement.executeQuery(sql); while (resultSet.next()){ System.out.println("id="+resultSet.getObject("id")); System.out.println("name="+resultSet.getObject("name")); System.out.println("password="+resultSet.getObject("password")); System.out.println("email="+resultSet.getObject("email")); System.out.println("birthday="+resultSet.getObject("birthday")); } //6.释放连接 resultSet.close(); statement.close(); connection.close(); } }
步骤总结:
-
加载驱动
Class.forname("com.mysql.jdbc.Driver");
现在似乎推荐用
Class.forname("com.mysql.cj.jdbc.Driver");
上述程序可互换
-
连接数据库DriverManager
-
获得执行sql的对象 Statement
-
获得返回的结果集
-
释放连接
DriverManager
//DriverManager.registerDriver(new com.sql.jdbc.Driver());
Class.forName("com.sql.jdbc.Driver");//固定写法,加载驱动
Connection connection = DriverManager.getConnection(url,username,password);
// connection 代表数据库
// 数据库设置自动提交
// 事务提交
// 事务回滚
connection.rollback();
connection.commit();
connection.setAutoCommit();
URL
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC";
// mysql ---- 3306
/*
jdbc:mysql://主机地址:端口号/数据库名?参数1&参数2&参数3
协议://主机端口:端口号
*/
// oralce ---- 1521
/*
jdbc:oracle:thin@localhost:1521:sid
*/
Statment 执行SQL的对象
prepareStatement执行SQL的对象
String sql = "select * from users";//编写SQL
statement.executeQuery();//查询操作返回ResultSet
statement.execute(); //执行任何SQL,因此效率慢点
statement.executeUpdate();//更新、插入、删除,都是用这个,返回受影响的行数
ResultSet 查询的结果集:封装了所有的查询结果
获得指定的数据类型
resultSet.getObject();//在不知道列类型的情况下使用
resultSet.getString();
resultSet.getInt();
resultSet.getFloat();
resultSet.getDate();
...
遍历,指针
resultSet.beforeFirst();//移动到最前面
resultSet.afterLast();//移动到最后面
resultSet.next();//移动到下一个数据
resultSet.previous();//移动到前一行
resultSet.absolute(row);//移动到指定行
释放资源
resultSet.close();
statement.close();
connection.close();
4.statement对象
jdbc中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。
statement对象的executeUpdate方法,用于向数据库发送增、删、改的sql语句,executeUpdate执行完后,将会返回一个整数(即增删改语句导致了数据库几行数据发生了变化)
Statement.executeQuery方法用于向数据库发送查询语句,executeQuery方法返回代表查询结果的ResultSet对象
CRUD操作-create
使用executeUpdate(String sql)方法完成数据添加操作,示例操作:
Statement st = conn.createStatement();
String sql = "insert into user(...) values(...)";
int num = st.excuteUpdate(sql);
if(num>0){
System.out.println("插入成功");
}
CRUD操作-delete
使用executeUpdate(String sql)方法完成数据删除操作,示例操作:
Statement st = conn.createStatement();
String sql = "delete from user where id=1";
int num = st.excuteUpdate(sql);
if(num>0){
System.out.println("修改成功");
}
CRUD操作-update
Statement st = conn.createStatement();
String sql = "update user set `name`='' where `name`=''";
int num = st.excuteUpdate(sql);
if(num>0){
System.out.println("删除成功");
}
CRUD操作-read
使用executeQuery(String sql)方法完成数值查询操作,示例操作:
Statement st = conn.createStatement();
String sql = "select * from user where id = 1";
ResultSet rs = st.excuteQuery(sql);
while(rs.next()){
//根据获取列的数据类型,分别调用rs的相应方法映射到java对象中
}
代码实现
-
准备
-
路径
-
db.properties内容
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC username = root password = qq123456
-
-
提取工具类
package com.huangdekai.javaWebLearn.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 in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties"); Properties properties = new Properties(); properties.load(in); driver = properties.getProperty("driver"); url = properties.getProperty("url"); username = properties.getProperty("username"); password = properties.getProperty("password"); //1.驱动只用加载一次 Class.forName(driver); } catch (Exception e) { e.printStackTrace(); } } //获取连接 public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url,username,password); } //释放连接资源 public static void release(Connection connection, Statement statement, ResultSet resultSet){ if (resultSet != null){ try { resultSet.close(); } catch (SQLException e) { e.printStackTrace(); } } if (statement != null){ try { statement.close(); } catch (SQLException e) { e.printStackTrace(); } } if (connection != null){ try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
-
编写增删改的方法
executeUpdate
package com.huangdekai.javaWebLearn;
import static org.junit.Assert.assertTrue;
import com.huangdekai.javaWebLearn.utils.JdbcUtils;
import org.junit.Test;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* Unit test for simple App.
*/
public class AppTest
{
@Test
public void TestInsert(){
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection();
statement = connection.createStatement();
String sql = "insert into users(`id`,`name`,`password`,`email`,`birthday`) " +
"values " +
"(4,'bilibili','123122','bilibili@qq.com','1970-01-01')," +
"(5,'danlidanli','122342','danlidanlli@qq.com','1970-01-01')" ;
int i = statement.executeUpdate(sql);
if (i>0){
System.out.println("插入成功");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection,statement,resultSet);
}
}
@Test
public void TestDelete(){
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection();
statement = connection.createStatement();
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);
}
}
@Test
public void TestUpdate(){
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection();
statement = connection.createStatement();
String sql = "update users set `name`='duzhuan2' where `id` = 2" ;
int i = statement.executeUpdate(sql);
if (i>0){
System.out.println("更新成功");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection,statement,resultSet);
}
}
}
- 查询
executeQurey
package com.huangdekai.javaWebLearn;
import com.huangdekai.javaWebLearn.utils.JdbcUtils;
import org.junit.Test;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestExecuteQurey {
@Test
public void testExecuteQurey(){
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection();
statement = connection.createStatement();
String sql = "select * from users";
resultSet = statement.executeQuery(sql);
while (resultSet.next()){
System.out.println("id=" + resultSet.getInt("id"));
System.out.println("name=" + resultSet.getString("name"));
System.out.println("password=" + resultSet.getString("password"));
System.out.println("email=" + resultSet.getString("email"));
System.out.println("birthday="+resultSet.getDate("birthday"));
System.out.println();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.release(connection,statement,resultSet);
}
}
}
sql注入的问题
sql存在漏洞,会被攻击,导致数据泄露,SQL会被拼接 or
package com.huangdekai.javaWebLearn;
import com.huangdekai.javaWebLearn.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class SQLDI {
public static void main(String[] args) {
//login("duzhuan","123456");//正常输入
login(" 'or '1=1","' or'1=1");
// select * from users where `name` = '' or '1=1' and `password` =''or'1=1'
}
// 登陆业务
public static void login(String username,String password){
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection();
statement = connection.createStatement();
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"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.release(connection,statement,resultSet);
}
}
}
5.PreparedStatement对象
PreparedStatement 可以防止SQL注入,效率更好
目录结构
增删改
package com.huangdekai.javaWebLearn;
import com.huangdekai.javaWebLearn.utils.JdbcUtils;
import org.junit.Test;
import javax.swing.text.Utilities;
import java.sql.*;
import java.util.Date;
public class TestPreparedStatment {
@Test
public void testInsert(){
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection();
//区别
//使用?占位符
String sql = "insert into " +
"users(`id`,`name`,`password`,`email`,`birthday`) " +
"value(?,?,?,?,?)";//占位符
preparedStatement = connection.prepareStatement(sql);//预编译SQL,先写SQL,然后不执行
//手动给参数赋值
preparedStatement.setInt(1,4); //id赋值
preparedStatement.setString(2,"杜撰");
preparedStatement.setString(3,"aa123456");
preparedStatement.setString(4,"123123@qq.com");
//注意:sql.Date java java.sal.Date()
// util.Date 数据库 new Date().getTime()获得时间戳
preparedStatement.setDate(5, new java.sql.Date(new Date().getTime()));
//执行
int i = preparedStatement.executeUpdate();
if (i>0){
System.out.println("插入成功");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.release(connection,preparedStatement,resultSet);
}
}
@Test
public void testDelete(){
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection();
//区别
//使用?占位符
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 (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.release(connection,preparedStatement,resultSet);
}
}
@Test
public void testUpdate(){
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection();
//区别
//使用?占位符
String sql = "update users set `id` = 0 where id = ?";//占位符
preparedStatement = connection.prepareStatement(sql);//预编译SQL,先写SQL,然后不执行
//手动给参数赋值
preparedStatement.setInt(1,4);
//执行
int i = preparedStatement.executeUpdate();
if (i>0){
System.out.println("修改成功");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.release(connection,preparedStatement,resultSet);
}
}
}
查
package com.huangdekai.javaWebLearn;
import com.huangdekai.javaWebLearn.utils.JdbcUtils;
import org.junit.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestPreparedStatementQuery {
@Test
public void testPrepareStatementQuery() throws SQLException {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection();
String sql = "select * from users where id = ?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1,0);//传递参数
resultSet = preparedStatement.executeQuery();
if (resultSet.next()){
System.out.println("name = "+resultSet.getString("name"));
}
}catch (Exception e){
e.printStackTrace();
}
}
}
防止SQL注入
package com.huangdekai.javaWebLearn;
import com.huangdekai.javaWebLearn.utils.JdbcUtils;
import java.sql.*;
public class SQLDIPreparedStatement {
public static void main(String[] args) {
//login("duzhuan","123456");//正常输入
login("'' or 1=1","'' or 1=1");
// select * from users where `name` = '' or '1=1' and `password` =''or'1=1'
}
// 登陆业务
public static void login(String username,String password){
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection();
//PreparedStatement防止SQL注入的本质,把传递进来的参数当作字符
//假设其中存在转义字符,引号会被直接转义
String sql = "select * from users where `name`= ? and `password`= ?";
statement = connection.prepareStatement(sql);
statement.setString(1,username);
statement.setString(2,password);
resultSet = statement.executeQuery();
while (resultSet.next()){
System.out.println(resultSet.getString("name"));
System.out.println(resultSet.getString("password"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.release(connection,statement,resultSet);
}
}
}
6.使用IDEA连接数据库
可能出现的问题的解决方法链接:
连接成功后可以选择数据库:
7.事务
要么都成功,要么都失败
ACID原则
原子性:要么都成功,要么都失败
一致性:总数不变
隔离性:多个进程互不干扰
持久性:一旦提交不可逆,持久化到数据库中
隔离性的问题:
脏读:一个事务读取到另一个没有提交的事务
不可重复读:在同一个事务内,重复读取表中的数据,表数据发生了改变
虚读(幻读):在一个事务内,读取到了别人插入的数据,导致前后读出来结果不一致
代码实现
- 开启事务
connection.setAutoCOmmit(false)
- 一组业务执行完毕,提交事务
- 可以在catch语句中显式定义回滚语句,但是默认失败就会回滚
package com.huangdekai.javaWebLearn;
import com.huangdekai.javaWebLearn.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 connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection();
//关闭数据库的自动提交,自动会开启事务
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 (SQLException e) {
//如果不写,也默认回滚
try {
connection.rollback();//如果失败,就回滚
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
} finally {
JdbcUtils.release(connection,preparedStatement,resultSet);
}
}
}
8.数据库连接池
池化技术----执行完毕----释放
连接 -- 释放 十分浪费系统资源
池化技术:准备一些预先的资源,过来就连接预先准备好的
常用连接数:假设10个
最小连接数:5、10、100 按常用连接数来 按以上假设,假设设10个
假设还有5个资源
最大连接数:业务最高承载上线,按照以上假设,是15个
设有100个,排队等待
等待超时:100ms
编写连接池,实现一个接口 DataSource
开源数据源实现
DBCP
C3P0
Druid:阿里巴巴
使用了这些数据库连接池之后,我们在项目开发中就不需要连接数据库的代码了
DBCP
pom.xml添加依赖
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
dbcpconfig.properties
#连接设置 这里的名字,是DBCP数据源中定义好的
driverClassName = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC
username = root
password = qq123456
#下面的东西可以默认不设置
#初始化连接
initialSize = 10
#最大连接数量
maxActive = 50
#最大空闲连接
maxIdle = 20
#最小连接数量
minIdle = 5
#超时等待时间以毫秒为单位 60000ms/10000 = 60s
maxWait = 60000
#JDBC驱动建立连接时附带的连接属性的格式必须为【属性名=property;】
#注意:"user"与"password"两个属性会被明显传递,因此这里不需要包含他们
connectionProperties=useUnicode=true;characterEncoding=UTF8;serverTimezone=UTC
#指定由连接池所创建的连接的自动提交(auto-commit)状态
defaultAutoCommit=true
# driver default指定由连接池所创建的连接的只读(read-only)状态
# 如果没有设置该值,则"setReadOnly"方法将不被调用,(某些驱动不支持只读模式,如:Informix)
defaultReadOnly =
# driver default指定由连接池所创建的连接的事务级别(TransactionIsolation)
# 可用值为下列之一:(详情见javadoc)NONE,READ_UNCOMMITTED,REPEATABLE_READ,SERIALIZABLF...
defaultTransactionIsolation=READ_UNCOMMITTED
工具类JdbcUtils_DBCP
package com.huangdekai.javaWebLearn.utils;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils_DBCP {
private static DataSource dataSource = null;
static{
try {
InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
Properties properties = new Properties();
properties.load(in);
//创建数据源 工厂模式 --》 创建对象
dataSource = BasicDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();//从数据源中获取连接
}
//释放连接资源
public static void release(Connection connection, Statement statement, ResultSet resultSet){
if (resultSet != null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement != null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
测试:
package com.huangdekai.javaWebLearn;
import com.huangdekai.javaWebLearn.utils.JdbcUtils;
import com.huangdekai.javaWebLearn.utils.JdbcUtils_DBCP;
import org.junit.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestDBCP {
@Test
public void testPrepareStatementQuery() throws SQLException {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils_DBCP.getConnection();
String sql = "select * from users where id = ?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1,0);//传递参数
resultSet = preparedStatement.executeQuery();
if (resultSet.next()){
System.out.println("name = "+resultSet.getString("name"));
}
} catch (Exception e){
e.printStackTrace();
} finally {
JdbcUtils_DBCP.release(connection,preparedStatement,null);
}
}
}
C3P0
依赖:
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
.....
结论
无论使用什么数据源,本质是一样的,DataSource接口不会变,方法就不会变