MySQL
1、初始MySQL
javaEE: 企业级开发 web
前端(页面渲染,展示 数据)
后台(连接点: 连接数据库 jdbc mybatis 连接前端(控制视图的跳转,给前端传递数据))
数据库(存取数据)
1.1为什么学习数据库
1.岗位需求
2.现在的世界,大数据时代—mysql集群,得数据者得天下,没有隐私
3.被迫需求:存数据 去IOE 不用国外的
4.数据库是所有软件体系中最核心的存在DBA(数据库管理员)
1.2什么是数据库
数据库(DataBase)
概念: 数据仓库, 存储数据 软件, 安装在操作系统之上的 sql 可以存储大量的数据
作用: 存数据,管理数据
1.3数据库分类
关系型数据库: Excle(SQL)
- Mysql、oracle、 sql server、DB2、SQLLite
- 通过表和表之间,行和列之间的关系进行数据的存储,学院信息表 考勤表
非关系型数据库: json (key : value)(NoSQL 不仅仅是sql)
- redis、mongdb
- 非关系型数据库, 对象存储,通过对象的自身的属性来决定
DBMS(数据库管理系统)
- 数据库管理软件,科学有效的管理我们的数据,维护和获取数据;
- MySQL,本质是一个数据库管理系统!
1.4MySQL简介
MySQL是一个**关系型数据库管理系统****,**由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件之一。
MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。
MySQL所使用的 SQL 语言是用于访问数据库的最常用标准化语言。MySQL 软件采用了双授权政策,分为社区版和商业版,由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,一般中小型网站的开发都选择 MySQL 作为网站数据库。也可以用于大型网站
前世:由瑞典MySQL AB 公司开发
今生:属于 Oracle 旗下产品
MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件之一,开源的数据库软件
5.7 版本稳定 8.0也可以
官网:https://www.mysql.com/
官网下载地址:https://dev.mysql.com/downloads/mysql/
安装建议 :
- 尽量不要使用.exe文件
- 尽可能使用安装包安装
1.5安装MySQL
1.解压安装包
2.配置环境变量 新加path就行
3.新建mysql配置文件ini, 把文件的扩展名打开
my.ini
[mysqld]
# 设置3306端口
port=3306
# 设置mysql的安装目录
basedir=D:\\mysql\mysql-8.0.18-winx64
# 切记此处一定要用双斜杠\\,单斜杠这里会出错。
# 设置mysql数据库的数据的存放目录
datadir=D:\\mysql\mysql-8.0.18-winx64\\Data
# 此处同上
# 允许最大连接数
max_connections=200
# 允许连接失败的次数。这是为了防止有人从该主机试图攻击数据库系统
max_connect_errors=10
# 服务端使用的字符集默认为UTF8
character-set-server=utf8
# 创建新表时将使用的默认存储引擎
default-storage-engine=INNODB
# 默认使用“mysql_native_password”插件认证
default_authentication_plugin=mysql_native_password
[mysql]
# 设置mysql客户端默认字符集
default-character-set=utf8
[client]
# 设置mysql客户端连接服务端时默认使用的端口
port=3306
default-character-set=utf8
4.管理员模式,打开所有的东西
5.进入bin目录下
# 安装mysql服务
mysqld -install
# 初始化数据问价
mysqld --initialize-insecure --user=mysql
# 启动mysql 服务
net start mysql # 会显示mysql启动成功
6.进入mysql修改密码update user set password=password("123456") where user="root"; flush privileges;
注释跳过密码
7.重启服务,然后进行登录mysql -uroot -p123456
sql后面一定要加上分号
8.sc delete mysql
清空服务
1.6无脑安装sqlyog
一些简单的操作
创建数据库
1.7连接数据库
命令行连接
mysql -uroot -p123456 --连接数据库
update mysql.user set authentication_string=password('123456') where user='root' and Host = 'localhost'; -- 修改用户的密码
flush privileges;` -- 刷新权限
-- 所有的语句都用分号结尾
-------------------------
show databases; -- 查询所有的数据库
mysql> use `school`; -- 切换数据库
Database changed
show tables; --查看数据库中所以的表
describe student; -- 显示表中所有的字段的信息
-------------------------
create database mytest; -- 创建一个数据库
exit; -- 退出连接
# 是sqlyog 的注释 -- 是sql的注释
/**/ 是多行注释
-- 单行注释
数据库xxx语言增删改查 cv程序员 api程序员 crud业务程序员
DDL: 数据库定义语言
DML: 数据库操作语言
DQL: 数据库查询语言(核心一般是查询语言)
DCL:数据库控制语言
2.操作数据库
mysql的关键字不区分大小写
操作数据库>操作数据库中的表>操作数据库表中的数据
2.1操作数据库(了解,操作一遍就可以了)
1.创建数据库
CREATE DATABASE IF NOT EXISTS mytest;
2.删除数据库
DROP DATABASE IF EXISTS mytest;
3.使用数据库
USE school;
注意: 如果是使用关键词来表示数据库,那么需要加一个`来进行转移义
4.查看数据库
SHOW DATABASES; -- 展示所有的数据库
对比sqlyog的可视化操作
学习思路: 不会的操作对比sqlyog操作
2.2数据库的数据列类型
数值
tinyint | 十分小的类型 | 1个字节 |
---|---|---|
smallint | 比较小的类型 | 2个字节 |
mediumint | 中等大小的数据 | 3个字节 |
int | 标准的整数 | 4个字节后面的括号里面的数字表示的是最大的显示的宽度 |
bigint | 较大的数据 | 8个字节 |
float | 单精度浮点数 | 4个字节 |
double | 双精度浮点数 | 8个字节 |
decimal | 字符串的浮点数 | (金融计算的时候一般使用这个类型) |
字符串
char | 字符串固定大小 | 0-255 |
---|---|---|
varchar | 字符串可变长度 | 0-65535(String) |
tinytext | 微型文本 | 2^8-1 |
text | 文本串 | 2^16-1(大文本) |
时间和日期
date | YYYY-MM-DD | 日期 |
---|---|---|
time | HH:mm:ss | 时间格式 |
datetime | YYYY-MM-DD HH:mm:ss | 最常用的时间格式 |
timestamp | 时间戳 | 1970-1-1到现在的毫秒数 |
year | 年份表示 |
null
没有值,未知,不要使用null进行运算,结果为null
2.3数据库的字段属性(重点)
Unsigned | 无符号证书整数 | 声明了该列不能为负数 |
---|---|---|
Zerofill? | 0填充的 | 不足的位数,用0来进行填充 |
自增 | 通常理解为自增,自动在上一条记录的基础上加一 | 通常用来设置唯一的主键,必须是证书类型,可以自定义设置起始值 |
非空 Null notnull | 假设设置为not null,如果不给他赋值,就会报错 | null如果不填充,就是null |
设置默认值 | 如果不指定该列的值,它会是默认的值 |
/*每一个表都必须存在以下五个字段,表示每个记录存在的意义*/
id 主键
`version` 乐观锁
is_delete 伪删除
gmt_create 创建时间
gmt_update 修改时间
2.4创建数据库表
/*
使用英文的括号
后面要加,
字符串使用单引号
*/
CREATE TABLE IF NOT EXISTS `student`(
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
`name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密码',
`sex` VARCHAR(2) NOT NULL DEFAULT '女' COMMENT '性别',
`birthday` DATETIME DEFAULT NULL COMMENT '出生日期',
`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',
`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
格式
CREATE TABLE [IF NOT EXISTS] `表名`(
`字段名` 列类型 [属性] [索引][注释],
`字段名` 列类型 [属性] [索引][注释],
`字段名` 列类型 [属性] [索引][注释],
....
)[表类型][字符集设置][注释]
-- 查看创建数据库school的语句
SHOW CREATE DATABASE school;
-- 查看创建表student的语句
SHOW CREATE TABLE student;
-- 查看表的基本结构
DESC student;
2.5数据表的类型
-- 关于数据库的引擎
/*
INNODB 默认使用
MYISAM 早些年使用
*/
MYISAM | INNODB | |
---|---|---|
事务支持 | 不支持 | 支持 |
数据行锁定 | 不支持 | 支持 |
外键约束 | 不支持 | 支持 |
全文索引 | 支持 | 不支持 |
较小 | 较大约为前者的两倍 |
常规的使用操作:
- MYISAM 节约空间,速度较快
- INNODB 安全性高,支持事务的处理,多表多用户操作
在物理空间存在的位置
所有的数据库文件都存在data目录下一个文件夹就对应一个数据库
本质还是文件存储
MySQL引擎在物理文件上的区别:
- INNODB在数据库表中只有一个*.frm文件,以及上级目录下的ibdata文件
- MYISAM对应文件
- *.frm — 表结构的定义文件
- *.MYD 数据文件(Data)
- *.MYI 索引文件
设置数据库字符集的编码
CHARSET=utf8
-- 不设置的话是mysql的默认的字符集编码(不支持中文) 最好在创建表的时候去设置
-- 1.创建表的时候就修改
-- 2.在my.ini添加字符集
2.6修改和删除表
修改
-- 修改表
--ALTER TABLE 旧的表名 RENAME `新的表名`;
ALTER TABLE `teacher` RENAME `teacher1`;
--ALTER TABLE `表名` ADD 字段 数据类型;
ALTER TABLE `teacher1` ADD age INT(3);
-- 修改表的字段 (重命名修改约束)
-- 修改表的约束
-- ALTER TABLE `表名` MODIFY 字段名字 类型;
ALTER TABLE `teacher1` MODIFY age VARCHAR(11);
-- 重命名表的字段的名字
-- ALTER TABLE `表名` CHANGE 旧的字段名 新的字段名 新的字段名的类型;
ALTER TABLE `teacher1` CHANGE age age1 INT(2);
-- 删除表的字段
ALTER TABLE `teacher1` DROP age1;
删除
注意: 所有的删除尽量加上是否存在,以免报错
-- 删除表(如果表存在)
--DROP TABLE IF EXISTS `表名`;
DROP TABLE IF EXISTS `teacher1`;
注意点:
- ``的引用,所有的字段名使用这个符号
- 注释是 – 或者是/**/
- sql关键字的大小写是不敏感的,建议写小写
- 所有的符号全部用英文的
3.MySQL的数据管理
3.1外键(了解即可)
方式一: 在创建表的时候给表添加约束
-- 创建年级表
CREATE TABLE `grade`(
`gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT '年级id',
`gradename` VARCHAR(50) NOT NULL COMMENT '年级名称',
PRIMARY KEY(`gradeid`)
)ENGINE=INNODB CHARSET=utf8
-- 创建学生表
-- 学生表的gradeid 要引用年级表的gradeid
-- 1.定义外键
-- 2.给这个外键添加约束
CREATE TABLE IF NOT EXISTS `student`(
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
`name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密码',
`sex` VARCHAR(2) NOT NULL DEFAULT '女' COMMENT '性别',
`birthday` DATETIME DEFAULT NULL COMMENT '出生日期',
`gradeid` INT(10) NOT NULL COMMENT '学生的年级',
`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',
`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY(`id`),
KEY `FK_gradeid` (gradeid) ,
CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade`(`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
删除表的时候,要删除引用的表(从表),之后再删除被引用的表(主表)
方式二: 创建表成功后添加外键约束
-- 创建年级表
CREATE TABLE `grade`(
`gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT '年级id',
`gradename` VARCHAR(50) NOT NULL COMMENT '年级名称',
PRIMARY KEY(`gradeid`)
)ENGINE=INNODB CHARSET=utf8
-- 创建学生表
-- 学生表的gradeid 要引用年级表的gradeid
-- 1.定义外键
-- 2.给这个外键添加约束
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 `表名`
-- ADD CONSTRAINT `FK_gradeid` FOREIGN KEY (`作为外键的列`) REFERENCES `引用的表`(`引用的表的字段`);
ALTER TABLE `student`
ADD CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade`(`gradeid`);
注意: 以上的操作都物理外键,不建议使用(避免数据库过多造成困扰,这里了解即可)
最佳实践: 数据库就是单存的表,只用来存储行和列,我们要使用外键,使用程序去解决
在企业中有要求,不得使用外键,一切外键概念必须在应用层解决(在删除和更新的时候比较方便)
3.2DML语言(全部记住)
数据库的意义: 数据存储和数据管理
DML 数据操作语言:
- insert
- update
- delete
3.3添加(insert)
-- 插入语句(添加) 如果不写表的字段,就会一一匹配
-- INSERT INTO `表名`(`字段名`) VALUES('值');
INSERT INTO `grade`(`gradename`) VALUES('大二');
-- 一般写插入语句,一定要数据和字段一一对应
INSERT INTO `grade`(`gradename`) VALUES('大二');
-- 插入多个字段
-- INSERT INTO `grade`(`gradename`) VALUES('大三'),('大四');
INSERT INTO `grade`(`gradename`) VALUES('大三'),('大四');
INSERT INTO `student`(`name`,`pwd`,`sex`) VALUES('李四','aaaaaa','男'),
('王五','aaaaaa','男'),
('孙子','aaaaaa','男');
注意事项
1.字段和字段之间使用英文逗号隔开
2.字段可以省略,但是里面的值要一一对应
3.可以同时插入多条数据,values后面的值,需要使用逗号隔开
3.4修改(update)
-- 修改数据 修改谁 也就是条件
-- 修改学院的名字
-- 指定条件的修改
UPDATE `student` SET `name`='陈留红' WHERE id = 1;
-- 不指定条件的修改
UPDATE `student` SET `name`='陈留红';
-- 修改多个属性的时候,一样需要使用逗号隔开
条件: where 子语句 运算符 id = 某个值或者是其他的判断条件
操作符 | 含义 | 范围 | 结果 |
---|---|---|---|
= | 等于 | 5=6 | false |
<>或者是!= | 不等于 | 5<>6 | true |
> | |||
< | |||
>= | |||
<= | |||
between…and… | 在某个范围内 | [2,5] | |
and | 我和你 && | 5>1 and 1>2 | false |
or | 我或你 || | 5>1 or 1>2 | true |
-- 通过多个条件修改数据,没有上限
SELECT * FROM student;
UPDATE `student` SET `name`='孙子' WHERE `name`='陈留红' AND id=1;
注意事项: 列名不能随便写,尽量带上`,条件是筛选的条件,如果没有指定,则会修改所有的列,value,是一个具体的值,也可以是一个变量,多个设置的属性使用英文隔开trim 把多余的符号干掉
-- 通过多个条件修改数据,没有上限 设置变量值 , 一般只有时间会用
SELECT * FROM student;
UPDATE `student` SET `birthday`=CURRENT_TIME WHERE `name`='孙子';
3.5删除(delete)
-- 删除全部的数据
DELETE FROM `student`;
-- 删除数据
DELETE FROM `student` WHERE id=1;
TRUNCATE
作用: 完全清空一个数据库表,表的结构和索引约束不会变
-- 清空student表
TRUNCATE `student`;
DELETE和TRUNCATE的区别
相同点: 都能够删除数据,都不会删除表结构
不同点:
- TRUNCATE 重新设置 自增列 计数器会归零
- TRUNCATE 不会影响事务
-- 清空student表
TRUNCATE `student`;
-- 测试 DELETE 和TRUNCATE 的区别
CREATE TABLE `test`(
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` VARCHAR(30) NOT NULL,
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO `test`(`name`) VALUES('zs'),('ls'),('ww');
DELETE FROM `test`; -- 不会影响自增
TRUNCATE TABLE `test`;
了解即可: delete删除的问题
,重启数据库,现象:
- INNODB 自增列会从1开始(存储在内存当中的,断电及失)
- MYISAM 继续从上一个自增量开始(存在文件之中,不会丢失)
4.DQL查询数据(最重点)
select 语法
SELECT [ALL | DISTINCT]
{* | table.* | [table.field1[as alias1][,table.field2[as alias2]][,...]]}
FROM table_name [as table_alias]
[left | right | inner join table_name] --联合查询
[WHERE ...] -- 指定结果需满足条件
[GROUP BY ...] -- 指定结果按照那几个字段来分组
[HAVING ...] -- 过滤分组的条件满足的次要条件
[ORDER BY ... ] -- 指定查询记录按一个或者是多个条件排序
[LIMIT {[offset,]row_count | row_countOFFSET offset}];
-- 指定查询的记录从那条开始至那条
4.1DQL
(Data Query Language : 数据查询语言)
- 所有的查询操作都用select
- 简单的查询,复杂的查询都能做
- 数据库的核心语言,最终要的语句
- 使用频率最高的语句
测试数据
/*
SQLyog Ultimate v12.08 (64 bit)
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@qq.com','450323198612111234'),(1001,'123456','周颖',1,2,'13500000002','河南洛阳','1981-12-31 00:00:00','test1@qq.com','450323198112311234'),(1002,'111111','杨文瑞',1,1,'13500000003','天津市和平区','1986-11-30 00:00:00','test1@qq.com','450323198611301234'),(1003,'123456','韩萌',1,3,'13500000004','上海卢湾区','1986-12-31 00:00:00','test1@qq.com','450323198612314234'),(1004,'123456','刘丽侠',1,4,'13500000005','北京市通州','1989-12-31 00:00:00','test1@qq.com','450323198612311244'),(1005,'123456','姜嘉航',2,1,'13500000006','广西桂林市灵川','1986-12-31 00:00:00','test1@qq.com','450323198612311214'),(1006,'123456','郑嘉祥',2,4,'13500000007','地址不详','1986-12-31 00:00:00','test1@qq.com','450323198612311134'),(1007,'111111','刘洋',1,1,'13500000008','北京东城区','1986-12-31 00:00:00','test1@qq.com','450323198612311133'),(1008,'111111','刘洋洋',1,1,'13500000009','河南洛阳','1986-12-31 00:00:00','test1@qq.com','450323198612311221'),(1009,'123456','刘毅',1,2,'13500000011','安徽','1986-12-31 00:00:00','test1@qq.com','450323198612311231'),(1010,'111111','赵杰',1,1,'13500000012','河南洛阳','1986-12-31 00:00:00','test1@qq.com','450323198612311044'),(1011,'111111','赵成',1,1,'13500000013','北京海淀区中关村大街*号','1984-12-31 00:00:00','test1@qq.com','450323198412311234'),(1012,'123456','刘恒',2,3,'13500000014','广西南宁中央大街','1986-12-31 00:00:00','test1@qq.com','450323198612311334'),(1013,'123456','张伟奇',2,1,'13500000015','上海卢湾区','1986-12-31 00:00:00','test1@qq.com','450323198612311534'),(1014,'123456','牛恩来',2,4,'13500000016','北京海淀区中关村大街*号','1986-12-31 00:00:00','test1@qq.com','450323198612311264'),(1015,'123456','马辉',1,4,'13500000017','广西桂林市灵川','1976-12-31 00:00:00','test1@qq.com','450323197612311234'),(1016,'111111','陈勉',1,1,'13500000018','上海卢湾区','1986-12-31 00:00:00','test1@qq.com','450323198612311251'),(1017,'123456','赵宇航',2,3,'13500000019','北京长安街1号','1981-09-10 00:00:00','test1@qq.com','450323198109108311');
/*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 */;
4.2 指定查询字段
-- 查询指定字段
-- 查询全部的学生
SELECT * FROM `student`;
-- 查询全部的成绩
SELECT * FROM `result`;
-- 查询指定字段
SELECT `StudentNo`,`StudentName` FROM `student`;
-- 别名 , 给结果起一个名字 AS 可以给字段起别名,也可以给表起别名
SELECT `StudentNo` AS '学号',`StudentName` AS '学员姓名' FROM `student` AS s;
-- 函数 Concat(a,b)
SELECT CONCAT('姓名:',`studentname`) AS 新名字 FROM student;
语法:select 字段 ... from 表
注意: 有的时候,列的名字不是见名知意,可以起别名来进行
-- 去重复 distinct
-- 查询有哪些同学参加了考试
SELECT * FROM `result`; -- 查询全部的成绩
-- 查询哪些同学参加了考试
SELECT `studentno` FROM result;
-- 发现重复数据,我们可以去重
SELECT DISTINCT `studentno` FROM `result`;
数据库的列:
-- 查看系统的版本(函数)
SELECT VERSION();
SELECT 100*3-1 AS 计算结果 -- 用来计算(计算表达式)
SELECT @@auto_increment_increment; -- 查询自增的步长(变量)
-- 学院考试成绩加一分查看
SELECT `StudentNo`,`StudentResult`+1 AS '提分后' FROM `result`;
数据库中的表达式: 文本的值,列,Null,函数,计算表达式,系统变量
select 表达式
from 表
4.3where条件子句
作用: 检索数据中符合条件
的值
逻辑运算符
搜索的条件由一个或者是多个表达式组成! 结果为布尔值
运算符 | 语法 | 描述 |
---|---|---|
and && | a and b a&&b | 逻辑与,两个都为真,结果为真 |
or || | a or b a||b | 逻辑或,两个都为假,结果为假 |
Not ! | not a !a | 逻辑非,真为假,假为真 |
尽量使用英文符号
-- =========where=============
SELECT `studentno`,`studentresult` FROM `result`;
-- 查询成绩在95 到 100 分之间的学生
SELECT `studentno`,`studentresult` FROM `result`
WHERE `studentresult`>95 AND `studentresult`<100;
-- 模糊查询(区间范围)
SELECT `studentno`,`studentresult` FROM `result`
WHERE `studentresult` BETWEEN 95 AND 100;
-- 除了1000号学生之外的信息
SELECT `studentno`,`studentresult` FROM `result`
WHERE `studentno` != 1000; -- not `studentno`=1000
模糊查询: 本质是比较运算符
运算符 | 语法 | 描述 |
---|---|---|
IS NULL | a is null | 如果操作符为null,则结果为真 |
IS NOT NULL | a is not null | 如果操作符为null,则结果为假 |
BETWEEN | A BETWEEN B AND C | 若a在b和c之间,则结果为真 |
Like | a like b | 如果a 能匹配到b,则结果为真 |
in | a in (a1,a2,a3,…) | 如果a在a1和。。。中的一个,那么就为真 |
小红like红
-- =============模糊查询=================
-- 查询名字姓刘的同学
-- like结合%(代表0到任意个字符) ——(一个字符)
SELECT `studentno`,`studentname` FROM `student`
WHERE `studentname` LIKE '刘%';
-- 查询名字姓刘的同学,名字后面只有一个字的
SELECT `studentno`,`studentname` FROM `student`
WHERE `studentname` LIKE '刘_';
-- 查询名字姓刘的同学,名字后面只有两个字的
SELECT `studentno`,`studentname` FROM `student`
WHERE `studentname` LIKE '刘__';
-- 查询名字中间有嘉字的同学_%嘉%_
SELECT `studentno`,`studentname` FROM `student`
WHERE `studentname` LIKE '_%嘉%_';
-- ================in==============
-- 查询1001,1002,1003的学生
SELECT `studentno`,`studentname` FROM `student`
WHERE `studentno` IN (1001,1002,1003);
-- 查询在安徽的学生 in 是具体的一个或者是多个值
SELECT `studentno`,`studentname` FROM `student`
WHERE `address` IN ('安徽','河南','洛阳');
-- ==========null 和 not null================
-- 插叙地址为null ''的同学
SELECT `studentno`,`studentname` FROM `student`
WHERE `address`='' OR `address` IS NULL;
-- 查询有出生日期的同学
SELECT `studentno`,`studentname` FROM `student`
WHERE `BornDate` IS NOT NULL;
-- 查询没有出生日期的同学
SELECT `studentno`,`studentname` FROM `student`
WHERE `BornDate` IS NULL;
注意: 在是不是null 的时候要用is,不是等于
4.4联表查询
JOIN对比
-- ============联表查询Join=================
-- 查询参加考试的同学(学号,姓名,科目编号,分数)
/*
分析需求: 分析需求的字段来自那些表
确定使用哪种连接查询
确定一个交叉点(这两个表中那个数据是相同的)
判断的条件: 学生表中的`studentno` == 成绩表中的 `studentno`
*/
-- join(连接的表) on(判断的条件) 连接查询
-- where 等值查询
-- inner join as 可以省略
SELECT s.`studentno`,`studentname`,`subjectno`,`studentresult`
FROM student AS `s`
INNER JOIN result AS `r`
WHERE r.`StudentNo`=s.`StudentNo`;
-- right join
SELECT `s`.`studentno`,`s`.`studentname`,`r`.`subjectno`,`r`.`studentresult`
FROM student AS `s`
RIGHT JOIN result AS `r`
-- WHERE r.`StudentNo`=s.`StudentNo`;
ON `r`.`StudentNo`=`s`.`StudentNo`;
-- left join
SELECT `s`.`studentno`,`s`.`studentname`,`r`.`subjectno`,`r`.`studentresult`
FROM student AS `s`
LEFT JOIN result AS `r`
-- WHERE r.`StudentNo`=s.`StudentNo`;
ON `r`.`StudentNo`=`s`.`StudentNo`;
-- 查询缺考的同学
SELECT `s`.`studentno`,`s`.`studentname`,`r`.`subjectno`,`r`.`studentresult`
FROM student AS `s`
LEFT JOIN result AS `r`
-- WHERE r.`StudentNo`=s.`StudentNo`;
ON `r`.`StudentNo`=`s`.`StudentNo`
WHERE `r`.`studentresult` IS NULL;
-- 查询了参加了考试的同学的信息(学号,姓名,科目名称,分数)
/*
分析需求: 分析需求的字段来自那些表 student result subject
确定使用哪种连接查询
确定一个交叉点(这两个表中那个数据是相同的)
判断的条件: 学生表中的`studentno` == 成绩表中的 `studentno`
*/
SELECT `s`.`studentno` AS '学号',`studentname` AS '姓名',
`subjectname` AS '科目名称',`studentresult` AS '成绩'
FROM `student` AS `s` RIGHT JOIN `result` AS `r`
ON `s`.`studentno` = `r`.`studentno`
INNER JOIN `subject` AS `sub`
ON `sub`.`subjectno` = `r`.`subjectno`;
-- 我要查那些数据 select ....
-- 从那几个表中查询 from 表 xxxx join 连接的表 on 交叉的条件
-- 假设存在多张表查询,慢慢来,先查询两张表,然后再慢慢查询
-- from a left join b
-- from a right join b
操作 | 描述 |
---|---|
inner join | 如果表中至少有一个匹配,就返回行 |
left join | 即使右表中没有匹配,也会从左表中返回所有的值 |
right join | 会从右表中返回所有的值,即使左表中没有匹配 |
自连接
自己的表和自己的表连接, 核心: 一张表拆为两张一样的表即可
父类:
categoryid | categoryname |
---|---|
2 | 信息技术 |
3 | 软件开发 |
5 | 美术设计 |
子类
pid | categoryid | categoryname |
---|---|---|
3 | 4 | 数据库 |
2 | 8 | 办公信息 |
3 | 6 | web开发 |
5 | 7 | 美术设计 |
操作: 查询父类对用子类关系
父类 | 子类 |
---|---|
信息技术 | 办公信息 |
软件开发 | 数据库 |
软件开发 | web开发 |
美术设计 | ps技术 |
-- =============自连接====================
CREATE TABLE `category`(
`categoryid` INT(10) 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 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`.`categoryid` = `b`.`pid`;
4.5分页和排序
排序
-- =================分页和排序 order by===================
-- 排序 : 升序ASC 和降序 DESC
-- order by 通过那个字段进行排序,怎么拍
-- 查询了参加了数据库结构-1考试的同学的信息(学号,姓名,科目名称,分数) 根据成绩排序
SELECT `s`.`studentno`,`studentname`,`subjectname`,`studentresult`
FROM `student` AS `s` INNER JOIN `result` AS `r`
ON `s`.`studentno` = `r`.`studentno`
INNER JOIN `subject` AS `sub`
ON `r`.`subjectno` = `sub`.`subjectno`
WHERE `sub`.`subjectname` = '数据库结构-1'
ORDER BY `studentresult` ASC;
分页
-- 100万
-- 分页
-- 环境: 数据库压力 给人的体验更好 瀑布流(图片)
-- 分页, 每页只显示五条数据
-- 网页: 当前页 总的页数 页面大小
-- limit 当前页 页面的大小
-- LIMIT 1,5; -- 2到6调数据
-- limit 0,5;-- 1到5调数据
SELECT `s`.`studentno`,`studentname`,`subjectname`,`studentresult`
FROM `student` AS `s` INNER JOIN `result` AS `r`
ON `s`.`studentno` = `r`.`studentno`
INNER JOIN `subject` AS `sub`
ON `r`.`subjectno` = `sub`.`subjectno`
WHERE `sub`.`subjectname` = '数据库结构-1'
ORDER BY `studentresult` ASC
LIMIT 1,5; -- 1到5调数据
-- 第一页 limit 0,5 (i-1)*5
-- 第二页 limit 5,5 (i-1)*5
-- 第三页 limit 10,5
-- 第二页 limit 0,5 (n-1)*pagesize,pagesize
-- pagesize 页面的大小 (n-1)*pagesize起始值 n代表当前页
-- 总数 [n代表当前页]
-- 总页数=总数/页面的大小
语法:limit(查询起始下标 , pagesize)
小练习:
-- 查询java第一学年 课程成绩排名前十的学生 并且分数大于80的学生的信息
-- (学号,姓名,课程名称,分数)
SELECT `s`.`studentno`,`studentname`,`subjectname`,`studentresult`
FROM `student` AS `s` INNER JOIN `result` AS `r`
ON `s`.`studentno` = `r`.`studentno`
INNER JOIN `subject` AS `sub`
ON `sub`.`subjectno` = `r`.`subjectno`
WHERE `subjectname` = 'JAVA第一学年' AND `studentresult` > 80
ORDER BY `studentresult` DESC
LIMIT 0,10;
4.6子查询
where(值是固定的 , 这个值是计算出来的)
本质:在where语句中嵌套一个子查询语句
where (select * from …)
-- =============where============
-- 查询数据库结构-1的所有考试结果(学号 , 科目编号 , 成绩) ,降序排列
-- 方式一
SELECT `studentno`,`sub`.`subjectno`,`studentresult`
FROM `result` AS r
INNER JOIN `subject` AS `sub`
ON `sub`.`subjectno` = `r`.`subjectno`
WHERE `sub`.`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;
-- 分数不小于80分的学生的学号和姓名
SELECT DISTINCT `s`.`studentno`,`studentname`
FROM `student` AS `s` INNER JOIN
`result` AS `r`
ON `s`.`studentno` = `r`.`studentno`
WHERE `studentresult` > 80;
-- 在这个基础上增加一个高等数学-2 查询高等数学-2的编号
SELECT DISTINCT `s`.`studentno`,`studentname`
FROM `student` AS `s` INNER JOIN
`result` AS `r`
ON `s`.`studentno` = `r`.`studentno`
WHERE `studentresult` > 80
AND `subjectno` = (
SELECT `subjectno`
FROM `subject`
WHERE `subjectname` = '高等数学-2'
);
-- 查询课程为高等数学-2 且分数不小于80分的同学的学号和姓名
SELECT `s`.`studentno`,`studentname`
FROM `student` AS `s`
INNER JOIN `result` AS `r`
ON `s`.`studentno` = `r`.`studentno`
INNER JOIN `subject` AS `sub`
ON `sub`.`subjectno` = `r`.`subjectno`
WHERE `studentresult` > 80
AND `sub`.`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')
);
-- 查询c语言-1 前五名同学的成绩信息(学号 姓名 分数)
-- 使用子查询
SELECT `s`.`studentno`,`studentname`,`studentresult`
FROM `student` AS `s`
INNER JOIN `result` AS `r`
WHERE`s`.`studentno` = `r`.`studentno`
AND `subjectno` = (
SELECT `subjectno`
FROM `subject`
WHERE `subjectname` = 'c语言-1'
)
ORDER BY `studentresult` DESC
LIMIT 0,5;
注意where子查询是比较快的,因为它不负责连接
4.7分组和过滤
-- 查询不同课程的平均分 最高分 最低分 平均分大于80分
-- 核心: 分组进行查询
SELECT `subjectname` , AVG(`studentresult`) AS '平均分',
MAX(`studentresult`) AS '最高分',MIN(`studentresult`) AS '最低分'
FROM `result` AS `r` INNER JOIN `subject` AS `sub`
ON `r`.`SubjectNo` = `sub`.`SubjectNo`
GROUP BY `r`.`SubjectNo`
HAVING 平均分 >= 80; -- 通过什么字段进行分组
4.8select小结
淘宝每个人登录的时候的首页都是不同的
5.MySQL函数
官网 :https://dev.mysql.com/doc/refman/5.7/en/sql-function-reference.html
5.1常用函数(并不常用)
-- ===========常用函数==================
-- 数学函数
SELECT ABS(-8); -- 绝对值
SELECT CEILING(9.4); -- 向上取整
SELECT FLOOR(9.4); -- 向下取整
SELECT RAND(); -- 0到1之间的随机数
SELECT SIGN(-8); -- 判断一个数的符号 负数返回负一 正数返回1 0 返回0
-- 字符串函数
SELECT CHAR_LENGTH('即使再小的帆也能远航'); -- 字符长长度
SELECT CONCAT('我','爱','你们'); -- 拼接字符串
-- 查询,替换 从某个位置开始替换某个长度
SELECT INSERT('我爱编程helloworld',1,2,'超级热爱');
-- 转大写或者是小写字母
SELECT LOWER('Kuangshen');
SELECT UPPER('Kuangshen');
-- 查看是第几个字符
SELECT INSTR('kuangshen','h');
-- 替换指定的字符串
SELECT REPLACE('坚持就能成功','坚持','努力');
-- 截取指定的字符串(原字符串,截取的位置,截取的长度)
SELECT SUBSTR('狂神坚持就能成功',4);
-- 反转字符串
SELECT REVERSE('狂神坚持就能成功');
-- 查询姓周的同学, 名字周改为邹
SELECT REPLACE(`studentname`,'周','邹') FROM `student`
WHERE `studentname` LIKE '周%';
-- 时间和日期函数(记住)
-- 获取当前日期
SELECT CURRENT_DATE();
SELECT CURDATE();
-- 获取当前的时间
SELECT NOW();
-- 获取本地时间
SELECT LOCALTIME();
-- 系统时间
SELECT SYSDATE();
SELECT YEAR(NOW());
SELECT MONTH(NOW());
SELECT DAY(NOW());
SELECT HOUR(NOW());
SELECT MINUTE(NOW());
SELECT SECOND(NOW());
-- 系统当前的用户
SELECT SYSTEM_USER();
SELECT USER();
SELECT VERSION();
5.2聚合函数
函数名称 | 描述 |
---|---|
COUNT() | 计数 |
SUM() | 求和 |
AVG() | 平均数 |
MAX() | 最大值 |
MIN() | 最小值 |
… | … |
-- ==========聚合函数============
-- count(指定列) 会忽略所有的null值
-- count(*) 包括了所有的列,相当于行数,在统计结果的时候,不会忽略值为null
-- count(1) 包括了忽略所有列,用1代表代码行,不会忽略列值为null
-- 列为主键 count(列名) 比count(1)快
-- 想查询一个表中有多少记录count()
SELECT COUNT(`studentname`) FROM `student`;
SELECT COUNT(*) FROM `student`; -- 本质: 计算行数
SELECT COUNT(1) FROM `student`;
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不可逆,具体的值的MD5是一样的
- MD5破解网站的原理,背后有一个字典,MD5加密后的值 加密的前值
-- ============测试MD5加密========
CREATE TABLE `testmd5`(
`id` INT(4) NOT NULL,
`name` VARCHAR(20) NOT NULL,
`pwd` VARCHAR(50) NOT NULL,
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
-- 明文密码
INSERT INTO `testmd5` VALUES
(1,'张三','123456'),
(2,'李四','123456'),
(3,'王五','123456'),
(4,'陈留红','123456'),
(5,'孙子','123456');
-- 加密
UPDATE `testmd5` SET pwd=MD5(pwd) WHERE id=1;
-- 加密全部的密码
UPDATE `testmd5` SET pwd=MD5(pwd);
-- 插入的时候加密
INSERT INTO `testmd5` VALUES(6,'杜志明',MD5('123456'));
-- 如何校验 : 将用户传递进来的密码进行md5加密,然后比对加密的值
SELECT * FROM `testmd5` WHERE `name`='陈留红' AND pwd=MD5('123456');
6.事务
6.1什么是事务
要么都成功,要么都失败
一一一一一一一一一一一一一一一一
1.sql执行 a给b转账 a 1000 ----》 200 b
2.sql执行 b收到a的钱 a 800 ----》 b 400
一一一一一一一一一一一一一一一一
将一组sql放在一个批次中去执行
innodb,在最新版的myisam也是支持的
事务原则: ACID 原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性 (Transaction) (脏读,幻读 …)
原子性 Atomicity
要么都成功,要么都失败
一致性 Consistency
事务前后的数据完整性要保持一致
持久性 Transaction
事务一旦提交则不可逆转,被持久化到数据库中
隔离性 Isolation
事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他的操作数据干扰,事务之间要互相隔离
隔离所导致的一些问题:
-
脏读: 指一个是务读取了另一个事务未提交的数据
-
不可重复读: 在一个事务内读取表中的某一行数据,多次读的结果不同(这个不一定是错误,只是某些场合不对)
-
幻读: 是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致
事务
-- =========事务========
-- mysql是默认开启事务自动提交的
SET autocommit = 0; -- 关闭
-- 手动处理事务
-- 事务开启
-- 标志事务的开始,从这个之后的sql都在同一个事务内
START TRANSACTION;
-- 提交 持久化
COMMIT;
-- 回滚 回到原来的样子
ROLLBACK;
-- 事务结束
SET autocommit = 1; -- 开启
SAVEPOINT 保存点名; -- 保存点名 设置一个事务的保存点
ROLLBACK TO SAVEPOINT 保存点名; -- 回滚到保存点位置
RELEASE SAVEPOINT 保存点名; -- 删除保存点
事务流程图
模拟场景
-- 转账
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
SELECT * FROM `account`;
INSERT INTO `account`(`name`,`money`)
VALUES('A',2000.00),('B',10000.00);
-- 模拟转账
SET autocommit = 0; -- 关闭自动提交
START TRANSACTION; -- 开启事务
UPDATE `account` SET `money` = `money`-500 WHERE `name`='A'; --A减500
UPDATE `account` SET `money` = `money`+500 WHERE `name`='B'; --B加500
COMMIT; -- 提交事务
ROLLBACK; -- 回滚
SET autocommit=1; -- 恢复默认值
注意: 这里是手动点的,在java中使用的是try catch,在执行失败的时候自己会回滚
7.索引
MySQL官方对索引的定义为:索引(Index) 是帮助MySQL高效获取数据的数据结构。
提取句子主干,就可以得到索引的本质;索引是数据结构
7.1索引的分类
在一个表中,主键索引只能有一个,唯一索引可以有多个
- 主键索引 PRIMARY KEY
- 唯一的标识,主键不可重复,只能有一个主键索引
- 唯一索引 UNIQUE KEY
- 避免重读的列出现,唯一索引可以重复, 多个列都可以标识唯一索引
- 常规索引 KEY/index
- 默认的,index关键字或者是key关键字设置
- 全文索引 FUllText
- 在特定的数据库引擎下才有 myisam
- 快速定位数据
基础语法
-- 索引的使用
-- 在创建表的时候给字段增加索引
-- 创建完毕后增加索引
-- 显示所有的索引信息
USE `school`;
SHOW INDEX FROM `student`;
-- 增加一个索引
-- ALTER TABLE 数据库的表 ADD FULLTEXT INDEX `索引名`(`索引的列`);
ALTER TABLE `school`.`student` ADD FULLTEXT INDEX `studentname`(`studentname`);
-- EXPLAIN 分析sql执行的状况
EXPLAIN SELECT * FROM `student`; -- 非全文索引
EXPLAIN SELECT * FROM `student` WHERE MATCH(`studentname`) AGAINST('刘');
7.2测试索引
CREATE TABLE `app_user`(
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '用户的id',
`name` VARCHAR(20) DEFAULT '' COMMENT '用户的名字',
`email` VARCHAR(50) NOT NULL COMMENT '用户邮箱',
`phone` VARCHAR(20) DEFAULT '' COMMENT '手机号',
`gender` TINYINT(4) UNSIGNED DEFAULT '0' COMMENT '性别(0为男,1为女)',
`password` VARCHAR(100) NOT NULL COMMENT '密码',
`age` TINYINT(4) DEFAULT '0' COMMENT '年龄',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
`update_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COMMENT 'app用户表';
-- 插入100万条数据 49.011秒插入1000000调数据
-- 必须写,当做标志
DELIMITER $$
CREATE FUNCTION mock_data()
RETURNS INT DETERMINISTIC
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),'1844736251@qq.com',CONCAT('18',FLOOR(RAND()*((999999999-100000000)+100000000))),FLOOR(RAND()*2),UUID(),FLOOR(RAND()*100));
SET i = i+1;
END WHILE;
RETURN i;
END;
SELECT mock_data();
-- 耗时 0.607秒
SELECT * FROM `app_user` WHERE `name` = '用户9999';
-- 耗时0秒
SELECT * FROM `student`;
EXPLAIN SELECT * FROM `app_user` WHERE `name` = '用户9999';
-- 创建索引相当与是使用了树 没加索引相当于是遍历,创建索引相当于是定位
-- id_表名_字段名
-- CREATE INDEX 索引名 ON `表名`(`字段名`);
CREATE INDEX id_app_user_name ON `app_user`(`name`);
注意: 索引在小数据量的时候用处不大,但是在大数据的时候,区别十分明显
7.3索引原则
- 索引不是越多越好
- 不要对经常变动的数据加索引
- 小数据量的表不需要加索引
- 索引一般加在常用来查询的字段上
索引的数据结构
Hash类型的索引,默认的是BTREE(INNODB的默认的底层的数据结构)
阅读: http://blog.codinglabs.org/articles/theory-of-mysql-index.html
8.权限管理和数据库备份
8.1用户权限
SQL yog 可视化管理
SQL命令操作
用户表: mysql.user
本质: 对这张表进行增删改查
-- 用户
-- 创建用户 CREATE USER 用户名 IDENTIFIED BY '密码';
CREATE USER timous IDENTIFIED BY '123456';
-- 修改指定用户密码
SET PASSWORD = PASSWORD('123456'); -- 8版本的不行
SET PASSWORD FOR timous = PASSWORD('123456');
-- 重命名 RENAME USER 原来的名字 TO 新的名字;
RENAME USER timous TO timous2;
-- 授予全部的权限 用户授权 除了给别人授权,其他的都能干
-- GRANT ALL PRIVILEGES ON 库.表 TO 用户;
GRANT ALL PRIVILEGES ON *.* TO timous2;
-- 查询权限
-- 查看指定用户的权限
SHOW GRANTS FOR timous2;
-- root 用户的权限 防止你删库跑路
SHOW GRANTS FOR root@localhost;
-- 撤销权限
-- REVOKE ALL PRIVILEGES ON 库.表 FROM 用户;
REVOKE ALL PRIVILEGES ON *.* FROM timous2;
-- 删除用户
CREATE USER kuangshen;
DROP USER kuangshen;
8.2数据库备份
- 保证重要的数据不丢失
- 数据转移
MySQL数据库备份的方式:
- 直接拷贝物理文件
- 使用sqlyog可视化工具中备份导出
- 命令行导出 mysqldump 命令行使用 是在cmd里面
C:\Users\Administrator>mysqldump -hlocalhost -uroot -p123456 school student >D:/a.sql
mysqldump: [Warning] Using a password on the command line interface can be insecure.
mysqldump -h主机 -u用户名 -p密码 数据库名 表名1 表2 表3 >磁盘位置:/文件名
mysqldump -h主机 -u用户名 -p密码 数据库名 >磁盘位置:/文件名
mysql -uroot -p123456 # 登录
source d:/a.sql就可以了
# 导入
登录的情况下直接source就可以了(导入数据库不需要切换)
mysql -uroot -p密码 库名< 备份文件
假设你要备份数据库,防止数据丢失,把数据库给朋友,sql文件给别人即可!
9.规范数据库设计
9.1为什么需要设计数据库
当数据库比较复杂的时候,我们就需要设计数据库了
糟糕的数据库设计
- 数据冗余,浪费空间
- 数据库插入和删除都会麻烦,异常[屏蔽使用物理外键]
- 程序的性能差
良好的数据库设计
- 节省内存空间
- 保证数据库的完整性
- 方便我们开发系统
软件开发中,关于数据库的设计
- 需求分析: 分析业务和需要处理的数据库的需求
- 概要设计: 设计关系图 ER图
设计数据库的步骤(个人博客)
- 收集信息,分析需求
- 用户表(用户登录注销,用户的个人信息,写博客,创建分类)
- 分类表(文章分类,谁创建的)
- 文章表(文章的信息)
- 友链表(友链信息)
- 自定义表(系统信息,某个关键的字,或者一些主字段) key value
- 评论表
- 说说表(发表心情 id content create_time update_time)
- 标识实体(把需求落实到每个字段)
- 标识实体之间的关系
- 写博客 user—》blog
- 创建分类user----》 category
- 关注user---->user
- 友链; link
- 评论: user—user----blog
9.2三大范式
为什么需要数据规范化:
- 信息重复
- 更新异常
- 插入异常
- 无法正常显示信息
- 删除异常
- 丢失有效的信息
三大范式
目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)
第一范式(1NF):要求数据库表的每一列都是不可分割的原子数据项。
原子性: 每一列不可再分
第二范式(2NF):在1NF的基础上,非码属性必须完全依赖于候选码(在1NF基础上消除非主属性对主码的部分函数依赖)
前提: 满足第一范式
每张表只描述一件事
第三范式(3NF):在2NF基础上,任何非主属性不依赖于其它非主属性(在2NF基础上消除传递依赖)
前提: 满足第二范式的条件下消除依赖
规范数据库的设计
规范性和性能问题:
阿里的规范: 关联的表不能超过三张
- 考虑商业化的需求和目标(成本和用户的体验) 数据库的性能更加重要
- 在规范性能问题的时候,适当的去考虑一下规范性
- 故意给某些表增加一些冗余字段
- 订单: 商品id—查询商品 可以直接放商品的信息
- 故意增加一些计算列(每次增加的时候直接增加列加一,从大数据量降低为小数据量的查询: 添加索引)
10.jdbc
10.1数据库驱动
驱动: 声卡,显卡、数据库
我们的程序会通过数据库驱动,和数据库打交道
10.2JDBC
sun公司为了假话开发人员(对数据库同一)的操作,提供了一个(java操作数据库的)规范,俗称JDBC这些规范的实现由具体的厂商去做
对开发人员来说,我们只需要掌握JDBC的接口的操作即可
java.sql
javax.sql
还需要导入数据库驱动包mysql-connector-java-8.0.11.jar
10.3第一个JDBC程序
创建测试数据库
CREATE DATABASE `jdbcstudy` CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `jdbcstudy`;
CREATE TABLE `users`(
`id` INT,
`name`VARCHAR(40),
`password` VARCHAR(40),
`email` VARCHAR(60),
`birthday` DATE,
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO `users`(id,`name`,`password`,`email`,`birthday`)
VALUES(1,'zhangsan','123456','zs@sina.com','1980-12-04'),
(2,'lisi','123456','lisi@sina.com','1980-12-04'),
(3,'wangwu','123456','wangwu@sina.com','1980-12-04');
SELECT * FROM `users`;
1.创建一个普通项目
2.导入数据库驱动
3.编写测试代码
package com.tmous.test01;
import java.sql.*;
//我的第一个jdbc程序
public class JdbcFirstDemo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1.加载驱动
Class.forName("com.mysql.cj.jdbc.Driver"); // 固定写法,加载驱动
//2.用户信息和url
String url = "jdbc:mysql://127.0.0.1:3306/jdbcstudy?serverTimezone=UTC&&useSSL=false";
String username = "root";
String password = "123456";
//3.连接成功
Connection connection = DriverManager.getConnection(url,username,password);
//4.执行sql的对象
Statement statement = connection.createStatement();
//5.执行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();
}
}
步骤总结:
- 加载驱动
- 连接数据库DriverManager
- 获得执行sql的对象Statement
- 获得返回的结果集
- 释放连接
DriverManager
//1.加载驱动
// 不推荐使用 DriverManager.registerDriver(new Driver()); 本身里面已经注册过来了
Class.forName("com.mysql.cj.jdbc.Driver"); // 固定写法,加载驱动
Connection connection = DriverManager.getConnection(url,username,password);
//代表数据库
// 可以提交或者是回滚等
//数据库设置自动提交
// 事务提交
// 事务回滚
connection.commit();
connection.rollback();
connection.setAutoCommit();
URL
//2.用户信息和url
String url = "jdbc:mysql://127.0.0.1:3306/jdbcstudy?serverTimezone=UTC&&useSSL=false";
// mysql默认是3306 orcle默认是1521 orcle的表就是一个库 sqlserver 1433
String username = "root";
String password = "123456";
Statement 执行sql的类 PreparedStatement
String sql = "SELECT * FROM `users`;"; //编写sql
Statement statement = connection.createStatement();
statement.executeQuery(); // 查询条件返回结果集
statement.execute(); //执行任何操作
statement.executeUpdate();// 更新、插入、删除,都是用这个,返回一个受影响的行数
statement.executeBatch();//执行多个sql
Result 查询的结果集 : 封装了所有的查询结果
获得指定的数据类型
ResultSet resultSet = statement.executeQuery(sql);//结果集中封装了对应的结果
resultSet.getObject(); // 在不知道列类型的时候使用 知道的话直接使用
resultSet.getString();
resultSet.
遍历,指针
//获取结果集
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"));
}
resultSet.beforeFirst(); //移动到最前面一行
resultSet.afterLast();//移动到最后面一行
resultSet.next();//移动到下一个
resultset.previous();//移动到前一行
resultset.absolute(row);//移动到指定行
释放资源
//6、释放连接
resultSet.close();
statement.close();
connection.close();
10.4Statement对象
Jdbc中的statement对象用于向数据库发送sql语句,想完成数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。
Statement对象的executeUpdate方法,用于向数据库发送增删改的sql语句,executeUpdate执行完后,将会返回一个整数(即增删改语句导致了数据库几行数据发生了变化)
Statement.executeQuery方法返回代表查询结果的ResultSet对象
CRUD操作-create
使用executeUpdate(String sql)方法完成数据添加操作,示例操作:
Statement st = conn.createStatement();
String sql = "insert into user() values();";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println("插入成功!!!");
}
CRUD操作-delete
使用executeUpdate(String sql)方法完成数据删除操作,示例操作:
Statement st = conn.createStatement();
String sql = "delete from user where id=1;";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println("删除成功!!!");
}
CRUD操作-update
使用executeUpdate(String sql)方法完成数据删除操作,示例操作:
Statement st = conn.createStatement();
String sql = "update user set name='' where name='';";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println("更新成功!!!");
}
CRUD操作-read
使用executeQuery(String sql)方法完成数据删除操作,示例操作:
Statement st = conn.createStatement();
String sql = "select * from user where id=1;";
ResultSet resultset = st.executeQuery(sql);
while(resultset.next()){
//根据获取列的数据类型,分别调用rs的响应方法映射到java中
}
代码实现
1.提取工具类
package com.tmous.utils;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils {
private static String driver = null;
private static String url = null;
private static String username = null;
private static String password = null;
static{
try {
InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
Properties properties = new Properties();
properties.load(in);
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
//1.驱动只需要加载一次
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接
public static Connection 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();
}
}
}
}
// db.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/jdbcstudy?serverTimezone=UTC&&useSSL=false
username=root
password=123456
2.编写增删改的代码
//增
package com.tmous.test01;
import com.tmous.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestInsert {
public static void main(String[] args) {
Connection 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,'chenliuhong','123456','chenliuhong@sina.com','1980-12-05');";
int i = statement.executeUpdate(sql);
if(i>0){
System.out.println("插入成功!");
}else{
System.out.println("插入失败!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection , statement , resultSet);
}
}
}
//删
package com.tmous.test01;
import com.tmous.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestDelete {
public static void main(String[] args) {
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("删出成功!");
}else{
System.out.println("删出失败!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection , statement , resultSet);
}
}
}
//改
package com.tmous.test01;
import com.tmous.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestUpdate {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection(); //获取数据库连接
statement = connection.createStatement();
String sql = "UPDATE `users` SET `name`='陈留红' WHERE `id` = 1;";
int i = statement.executeUpdate(sql);
if(i>0){
System.out.println("修改成功!");
}else{
System.out.println("修改失败!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection , statement , resultSet);
}
}
}
3.查询的代码
package com.tmous.test01;
import com.tmous.utils.JdbcUtils;
import javax.swing.plaf.nimbus.State;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestSelect {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet rs = null;
//获取连接
try {
connection = JdbcUtils.getConnection();
statement = connection.createStatement();
String sql = "SELECT * FROM `users`;\n";
rs = statement.executeQuery(sql);
while(rs.next()){
System.out.println("id="+rs.getObject("id"));
System.out.println("name="+rs.getObject("name"));
System.out.println("password="+rs.getObject("password"));
System.out.println("email="+rs.getObject("email"));
System.out.println("birthday="+rs.getObject("birthday"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection , statement , rs);
}
}
}
sql注入的问题
sql存在漏洞,会被攻击,导致泄漏 SQL会被拼接
package com.tmous.test01;
import com.tmous.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class SqlProblem {
public static void main(String[] args) {
//login("陈留红","123456"); // 正常登录
login("'or '1=1" , "123456");// 有技巧的输入
}
//登录业务
public static void login(String username , String password){
Connection connection = null;
Statement statement = null;
ResultSet rs = null;
//获取连接
try {
connection = JdbcUtils.getConnection();
statement = connection.createStatement();
String sql = "SELECT * FROM `users` where name = '"+username+"'and password = '"+password+"';";
rs = statement.executeQuery(sql);
while(rs.next()){
System.out.println("name="+rs.getObject("name"));
System.out.println("password="+rs.getObject("password"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection , statement , rs);
}
}
}
10.5PreparedStatement
PreparedStatement可以防止sql注入,并且效率更好。
增删改代码
// 增
package com.tmous.test01;
import com.tmous.utils.JdbcUtils;
import java.sql.*;
public class TestInserts {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
connection = JdbcUtils.getConnection();
//区别 : 使用问号占位符代替参数
String sql = "INSERT INTO `users`(`id`,`name`,`password`,`email`,`birthday`) VALUES (?,?,?,?,?);";
st = connection.prepareStatement(sql); //预编译的sql
//手动给参数赋值
st.setInt(1,4);
st.setString(2,"老狗");
st.setString(3,"123456");
st.setString(4,"1844736@qq.com");
st.setDate(5, new java.sql.Date(new java.util.Date().getTime()));
int i = st.executeUpdate();
if(i>0){
System.out.println("插入成功!");
}else{
System.out.println("插入失败!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection , st , null);
}
}
}
//删
package com.tmous.test01;
import com.tmous.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
//测试
public class TestDeletes {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
connection = JdbcUtils.getConnection();
//区别 : 使用问号占位符代替参数
String sql = "delete from `users` where id=?";
st = connection.prepareStatement(sql); //预编译的sql
//手动给参数赋值
st.setInt(1,4);
int i = st.executeUpdate();
if(i>0){
System.out.println("删出成功!");
}else{
System.out.println("删出失败!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection , st , null);
}
}
}
//改
package com.tmous.test01;
import com.tmous.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestUpdates {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
connection = JdbcUtils.getConnection();
//区别 : 使用问号占位符代替参数
String sql = "update `users` set `name` = ? where id = ?";
st = connection.prepareStatement(sql); //预编译的sql
//手动给参数赋值
st.setString(1,"小明");
st.setInt(2,1);
int i = st.executeUpdate();
if(i>0){
System.out.println("更新成功!");
}else{
System.out.println("更新失败!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection , st , null);
}
}
}
防止sql注入
package com.tmous.test01;
import com.tmous.utils.JdbcUtils;
import java.sql.*;
public class SqlProblems {
public static void main(String[] args) {
//login("lisi","123456"); // 正常登录
login("'or '1=1" , "123456");// 有技巧的输入
}
//登录业务
public static void login(String username , String password){
Connection connection = null;
PreparedStatement st = null;
ResultSet rs = null;
//获取连接
try {
connection = JdbcUtils.getConnection();
String sql = "SELECT * FROM `users` where `name` = ? and `password` = ?;";
st = connection.prepareStatement(sql);
st.setString(1,username);
st.setString(2,password);
rs = st.executeQuery();
while(rs.next()){
System.out.println("name="+rs.getObject("name"));
System.out.println("password="+rs.getObject("password"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection , st , rs);
}
}
}
PreparedStatement防止sql注入的本质,把传递进来的参数当做字符,假设其中存在转义字符,就直接忽略,`会被直接转义。
10.7 使用IDEA连接数据库
选择数据库
更新数据
如果mysql连接失败,下面的可能能帮助:
10.8事务
要么都成功要么都失败ACID
原子性: 要么全部完成,要么全部失败
一致性: 总数不变
隔离性: 多个进程互不干扰
持久性: 一旦提交不可逆,持久化到数据库了
隔离性的问题:
脏读: 一个事务读取了另一个没有提交的事务
不可重复读: 在同一个事务内重复读取表中的数据,表数据发生了改变
虚读(幻读) : 在一个事务内,读取到了别人插入的数据,导致前后读出来的数据不一致
代码实现
1.开启事务conn.setAutoCommit(false);
2.一组业务执行完毕提交事务
3.可以在catch语句中显示的定义回滚语句,默认也是失败就会回滚的
package Transaction;
import com.tmous.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestTransaction2 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
//关闭数据库的自动提交,自动会开启事务
conn.setAutoCommit(false);//开启事务
String sql1 = "update `account` set `money` = `money` - 100 where `name` = 'A'";
st = conn.prepareStatement(sql1);
st.executeUpdate();
int x = 1/0; // 报错 ,失败,自动回滚
String sql2 = "update `account` set `money` = `money` + 100 where `name` = 'B'";
st = conn.prepareStatement(sql2);
st.executeUpdate();
//业务完毕,提交业务
conn.commit();
System.out.println("操作成功!!!");
} catch (SQLException e) {
//如果失败,则默认回滚
try {
conn.rollback(); // 如果失败,回滚事务
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
}finally {
JdbcUtils.release(conn , st , rs);
}
}
}
10.9数据库连接池
数据库连接----执行完毕-----释放 连接-----释放是十分浪费系统资源的
池化技术:准备一些预先的资源,过来就连接预先准备好的
10 SQL 5个连接 直接拿到conn 不需要连接 用完释放
最小连接数: 5 10 100 按照需求
最大连接数: 10 业务最高承载上限超过的就排队等待
编写连接池需要 实现一个接口datasource
开源数据源实现
DBCP
C3P0
Druid: 阿里巴巴的
使用了这些数据库连接池之后,我们在项目开发的时候就不需要写数据库连接的代码了。
DBCP
需要用到的jar包commons-dbcp-1.4
commons-pool-1.6
dbcpconfig.properties
#<!-- 连接设置 -->
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/jdbcstudy?serverTimezone=UTC&&useSSL=false
username=root
password=123456
#<!--初始化连接 -->
initialSize=10
#<!--最大连接数量 -->
maxActive=50
#<!--最大空闲连接 -->
maxIdle=20
#<!--最小空闲连接-->
minIdle=5
#<!--超时等待时间以毫秒为单位-->
maxWait=60000
#JDBC驱动建立时附带的连接属性的格式必须为 属性名=properties
connectionProperties=useUnicode=true;characterEncoding=UTF8
# 指定由连接池所创建的连接的自动提交状态
defaultAutoCommit=true
#driver default 指定由连接池所创建的连接的只读状态
# 如果没有设置该值 则setReadOnly 方法将不被调用
defaultReadOnly=
# driver default 指定由连接池所创建的连接的事务的级别
defaultTransactionIsolation=READ_UNCOMMITTED
DBCP帮助类
package com.tmous.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();
}
}
}
}
测试DBCP
package TestPool;
import com.tmous.utils.JdbcUtils;
import com.tmous.utils.JdbcUtils_DBCP;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestDbcp {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
connection = JdbcUtils_DBCP.getConnection();
//区别 : 使用问号占位符代替参数
String sql = "INSERT INTO `users`(`id`,`name`,`password`,`email`,`birthday`) VALUES (?,?,?,?,?);";
st = connection.prepareStatement(sql); //预编译的sql
//手动给参数赋值
st.setInt(1,4);
st.setString(2,"老狗");
st.setString(3,"123456");
st.setString(4,"1844736@qq.com");
st.setDate(5, new java.sql.Date(new java.util.Date().getTime()));
int i = st.executeUpdate();
if(i>0){
System.out.println("插入成功!");
}else{
System.out.println("插入失败!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils_DBCP.release(connection , st , null);
}
}
}
c3p0
c3p0-0.9.5.5
,mchange-commons-java-0.2.15
导入依赖的jar就行
帮助类:
package com.tmous.utils;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class JdbcUtils_C3P0 {
private static ComboPooledDataSource dataSource = null;
static{
try {
dataSource = new ComboPooledDataSource("MySQL"); // 配置文件写法
//代码版配置
// dataSource = new ComboPooledDataSource();
// dataSource.setDriverClass();
// dataSource.setUser();
// dataSource.setPassword();
// dataSource.setJdbcUrl();
// dataSource.setMaxPoolSize();
// dataSource.setMinPoolSize();
} 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();
}
}
}
}
c3po配置文件:c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?useSSL=false&serverTimezone=UTC</property>
<property name="user">root</property>
<property name="password">123456</property>
<property name="acquireIncrement">5</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property>
</default-config>
<named-config name="MySQL">
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?useSSL=false&serverTimezone=UTC</property>
<property name="user">root</property>
<property name="password">123456</property>
<property name="acquireIncrement">5</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property>
</named-config>
<!-- 可以配置多套数据源 -->
</c3p0-config>
测试类:
package TestPool;
import com.tmous.utils.JdbcUtils_C3P0;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestC3P0 {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
connection = JdbcUtils_C3P0.getConnection();
//区别 : 使用问号占位符代替参数
String sql = "INSERT INTO `users`(`id`,`name`,`password`,`email`,`birthday`) VALUES (?,?,?,?,?);";
st = connection.prepareStatement(sql); //预编译的sql
//手动给参数赋值
st.setInt(1,5);
st.setString(2,"老狗");
st.setString(3,"123456");
st.setString(4,"1844736@qq.com");
st.setDate(5, new java.sql.Date(new java.util.Date().getTime()));
int i = st.executeUpdate();
if(i>0){
System.out.println("插入成功!");
}else{
System.out.println("插入失败!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils_C3P0.release(connection , st , null);
}
}
}
结论
无论是使用什么数据源,本质还是一样的,接口都是没变的(DataSource),方法就不会变,也就是测试类的代码基本都不会变
Druid: 阿里的数据源,比较高级的
----业务级别的MySQL学习
有兴趣的人
-----运维级别MySQL