什么是数据库
- DB,DataBase - 存储数据、管理数据
数据库分类
关系型数据库 (SQL)
-
MySQL、Oracle、 Sql Server 、DB2、 SQLIite
通过表之间,行和列之间的关系进行数据的存储
非关系型数据库 (NoSOL)
- Redis 、MongDB
- 非关系型数据库、对象存储、通过对象的自身的属性来决定
MySQL
-
MySQL 是最流行的关系型数据库管理系统之一
-
MySQL是一个关系型数据库管理系统
-
MySQL是一种关系型数据库管理系统
-
关系数据库将数据保存在不同的表中
-
而不是将所有数据放在一个大仓库内
-
这样就增加了速度并提高了灵活性。
-
MySQL所使用的 SQL 语言是用于访问数据库的最常用标准化语言
-
其体积小、速度快、总体拥有成本低,开放源码
命令行连接(常用命令)
mysql -uroot -p123456 --连接数据库 update mysql.user set authentication_string=password('123456') where user='root' and Host = 'localhost'; -- 修改用户密码 flush privileges; --刷新权限 ------------------- -- 所有语句都使用 ; 结尾 show databass; --查看所有的数据库 mysql> use school -- 切换数据库 Database changed show tables; --查看数据库中所有的表 describe xxtable; --显示数据库中所有的表的信息 creat database xxname; --创建一个数据库 -- 单行注释 /* * *多行注释 * * * */
数据库xxx语言 (CRUD)
-
DDL 定义
-
DML 操作
-
DQL 查询
-
DCL 控制
操作数据库
操作数据库 - -> 操作数据库中的表操 – > 作数据库中表的数据
关键字不区分大小写
操作数据库
1创建数据库
CREATE DATABASE IF NOT EXISTS XXNAME
2 删除数据库
DROP DATABASE IF EXISTS XXNAME
3查看数据库
SHOW DATABASE --查看数据库
数据库的列类型
数值
-
tinyint 很小的数据 1个字节
-
smallint 较小的数据 2个字节
-
mediumint 中等大小的数据 3个字节
-
int 标准的整数 4个字节
-
bigint 较大的数据 8个字节
-
float 浮点数 4个字节
-
double 浮点数 8个字节
-
decimal 字符串形式的浮点数 金融计算 ,一般使用decimal
-
-
字符串
- char 字符串固定大小的 0-255
- varchar 可变字符串 0-65536 常用的 String
- tinytext 微型文本 2^8 -1
- text 文本串 2^16 -1 保存大文本
时间日期
-
data YYYY-MM–DD, 日期格式
-
time HH:mm:ss 时间格式
-
datatime YYYY-MM-DD HH:mm:ss 最常用的时间格式
-
timestamp 时间戳 1970.1.1 到现在的毫秒数
-
year 年份表示
null
zerofill:
- 0填充的
- 不足的位数,使用0来填充,
自增:
- 自动在上一条记录的基础上 +1
- 通常用来设计唯一的主键 index 必须是整数类
- 可以自定义设计主键自增的起始值和步长
非空 NULL not null
-
假设设置为 not null,如果不给它赋值,就会报错
-
NULL,如果不填写值,就默认为null
默认:
-
默认设置值
-
如果不指定该列的值
创建表
-- 目标:创建一个school数据库 -- 创建学生表(列,字段)使用SQL创建 -- 学号int 登录密码varchar(20)姓名,性别varchar(2),出生日期(datatime),家庭住址 -- 注意点,使用英文() 表的名称 和字段 尽量用 `` 括起来 -- AUTO_INCREMENT 自增 -- 字符串使用 单引号括起来 -- 所有的语句后面加, (英文的),最后一个不用加 -- PRIMARY KEY 主键,一般一个表只有一个唯一的主键 CREATE TABLE IF NOT EXISTS `student` ( `id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号', `name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名', `pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密码', `sex` VARCHAR(2) NOT NULL DEFAULT '女' COMMENT '性别', `birthday` DATETIME DEFAULT NULL COMMENT '出生日期', `address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址', `email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱', PRIMARY KEY(`id`) )ENGINE=INNODB DEFAULT CHARSET=uft8
公式
-
CREATE TABLE [IF NOT EXISTS] `表名`(
`字段` 列类型[属性] [索引] [注释],
`字段` 列类型[属性] [索引] [注释],
`字段` 列类型[属性] [索引] [注释],
....
`字段` 列类型[属性] [索引] [注释],
)[表引擎] [字符类型] [注释]
SHOW CREATE DATABASE school -- 查看创建的数据库的语句 `字段` 列类型[属性] [索引] [注释],
SHOW CREATE TABLE student1 -- 查看student数据表的定义语句
DESC student -- 显示表的结构
关于数据库的引擎
/*
*INNODB 默认使用~
*
*MYISAM 早些年使用的
*/
INNODB | MYISAM | |
---|---|---|
事物支持 | 不支持 | 支持 |
数据行锁定 | 不支持 | 支持 |
外键约束 | 不支持 | 支持 |
全文索引 | 支持 | 不支持 |
表空间的大小 | 较小 | 较大,约为2倍 |
常规使用操作:
-
MYISAM 节约空间,速度较快
-
INNODB 安全性高,事务的处理,多表多用户操作
在物理空间存在的位置
所有的数据库文件都存在data目录下
本质还是文件的存储!
MySQL引擎在物理文件上的区别
- InnoDB在数据库表中只有一个*.frm文件,以及上级目录下的ibdata1文件
- MYISAM对应文件
- *.frm -表结构的定义文件
- *.MYD 数据文件(data)
- *.MYI 索引文件(index)
设置数据库表的字符集编码
CHARSET=UTF8
不设置的话,会mysql默认的字符集编码~ (不支持中文)
MySQL的默认编码Latin1,不支持中文
在my.ini中配置默认的编码
character-set-server=utf8
修改表
-- 修改表 原表名 新表名
ALTER TABLE student1 RENAME AS teacher
-- 增加字段 表名 字段名 列属性
ALTER TABLE student ADD sex VARCHAR(2)
-- 修改约束 用 modify
ALTER TABLE student MODIFY sex INT(9)
-- 重命名 用 change 新名 列属性
ALTER TABLE student CHANGE sex human VARCHAR(2)
-- 删除字段 表名 字段名
ALTER TABLE student DROP human
*modify能修改字段类型和约束,而chenge不能
*change用来字段重命名,不能修改字段类型和约束
*modify不能用来字段重命名,只能修改字段类型和约束
删除表
-- 删除表 如果存在就删除
DROP TABLE IF EXISTS student
** 所有创建和删除尽量加上判断,以防报错*
MySQL数据库管理
外键(了解)
CREATE TABLE IF NOT EXISTS `grade`(
`gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT'年纪ID',
`gradename` VARCHAR(50) NOT NULL COMMENT'年纪名称',
PRIMARY KEY(`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
DROP TABLE IF EXISTS teacher
-- 学生表的gradeid 字段 要去引用年纪表 gradeid
-- 定义外键 key
-- 给这个外键添加约束(执行引用) references 引用
CREATE TABLE IF NOT EXISTS `student` (
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
`name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密码',
`sex` VARCHAR(2) NOT NULL DEFAULT '女' COMMENT '性别',
`birthday` DATETIME DEFAULT NULL COMMENT '出生日期',
`gradeid` INT(10) NOT NULL COMMENT'年纪的年纪',
`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',
`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY(`id`),
KEY `FK_gradeid` (`gradeid`),
CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade` (`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
*删除有外键的表,先删除主表,在删除从表
– 创表后添加约束 --外键
CREATE TABLE IF NOT EXISTS `grade`(
`gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT'年纪ID',
`gradename` VARCHAR(50) NOT NULL COMMENT'年纪名称',
PRIMARY KEY(`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
DROP TABLE IF EXISTS teacher
-- 学生表的gradeid 字段 要去引用年纪表 gradeid
-- 定义外键 key
-- 给这个外键添加约束(执行引用) references 引用
CREATE TABLE IF NOT EXISTS `student` (
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
`name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密码',
`sex` VARCHAR(2) NOT NULL DEFAULT '女' COMMENT '性别',
`birthday` DATETIME DEFAULT NULL COMMENT '出生日期',
`gradeid` INT(10) NOT NULL COMMENT'年纪的年纪',
`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',
`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
-- ALTER TABLE 表 ADD CONSTRAINT 约束名 FOREGIN KEY(作为外键的列) REFRENCES (表字段)
ALTER TABLE `student`
ADD CONSTRAINT `FK_gradeid` FOREIGN KEY(`gradeid`) REFERENCES `grade`(`gradeid`);
-
以上操作是物理外键,数据库级别的外键,(避免数据库过多造成困扰)
= 数据库只来存取数据,行(数据),列(字段)
DML语言(强记)
增加
insert
-- 插入语句(添加)
-- insert into 表名([字段1,字段2,字段3,]) values('值1'),('值2'),('值3')
INSERT INTO `grade`(`gradename`) VALUES('大四')
-- 由于主键自增可以省略(如果不写表字段,他就会一一匹配)
INSERT INTO `grade` VALUES('大三')
-- 一般插入语句,要数据和字段对应
-- 插入多个字段
INSERT INTO `grade`(`gradename`)
VALUES('大二'),('大三')
INSERT INTO `student`(`name`) VALUES ('李四')
INSERT INTO `student` (`name`,`pwd`,`sex`)
VALUES('王五','77777','女')
INSERT INTO `student` (`name`,`pwd`,`sex`)
VALUES('王五','77777','女'),('小七','77777','女')
修改
update
-- 修改学员名字
UPDATE `student` SET `name`='佐助' WHERE id = 2 ;
-- 不指定条件的情况下,会该动所有表
UPDATE `student` SET `name`='玛卡巴卡';
-- 修改多个属性,逗号隔开
UPDATE `student` SET `name`='小草',`sex`='男' WHERE id=3;
条件:where子句 运算符
操作符 | 含义 | 范围 | 结果 |
---|---|---|---|
= | 等于 | 5=6 | false |
<>或 != | 不能等于 | 5<>6 | true |
> | |||
< | |||
>= | |||
<= | |||
BETWEEN … AND… | 在某个范围 | [2,5] | |
AND | && 与 | 5>1 and 1>2 | false |
OR | || 或 | 5>1 or 1>2 | true |
-- 通过多个条件定位数据
UPDATE `student` SET `name`='羊驼' WHERE `name`='小草' AND `sex`='男'
删除
delete
语法:deleted from 表名 [where 条件]
-- 删除数据(勿用)
DELETE FROM `student`
-- 删除指定数据
DELETE FROM `student` WHERE id=1;
TRUNCATE
作用:清空表内的数据,不改变表结构和索引约束
-- 清空 student 表
TRUNCATE `student`
delete 与 TRUNCATE 区别
- 相同点 : 都能删除数据,都不会改变表结构
- 不同:
-
TRUNCATE 会使自增置零
-
TRUNCATE 不会影响事物
```sql
-
– 测试 delete 和 TRUNCATE 区别
CREATE TABLE test
(
id
INT(10) NOT NULL AUTO_INCREMENT,
col
VARCHAR(20) NOT NULL,
PRIMARY KEY(id
)
)ENGINE=INNODB DEFAULT CHARSET=uft8
INSERT INTO test
(col
) values (‘1’),(‘2’)(‘3’)
DELETE FROM test
– 不会影响自增
TRUNRCATE TABLE test
– 自增归零
```
— DELETE 删除的问题 ,重启数据库
- INNODB 自增列会重1开始 (存在内存中的,断电既消失)
- MyISAM 继续从上一个自增量开始 (存在文件中,不会丢失)
DQL查询数据(最重点)
DQL:Data QueryLanguage 数据查询语言
- 所有查询操作都用它 Select
- 简单复杂皆可查
- 数据库最核心语言,最重要的语句
标准语法:
SELECTselect_list
[ INTOnew_table ]
FROMtable_source
[ WHEREsearch_condition ]
[ GROUPBY group_by_expression ]
[ HAVINGsearch_condition ]
[ ORDERBY order_expression [ ASC | DESC ] ]
DQL:数据库查询语言。关键字:SELECT … FROM … WHERE。
DDL :数据库模式定义语言。关键字:CREATE,DROP,ALTER。
DML:数据操纵语言。关键字:INSERT、UPDATE、DELETE。
DCL:数据控制语言 。关键字:GRANT、REVOKE。
TCL:事务控制语言。关键字:COMMIT、ROLLBACK、SAVEPOINT。
DDL,DML,DCL,DQL,TCL共同组成数据库的完整语言。
-- 查询全部 的学生 select 字段 from 表
select * from student
-- 查询指定字段
select `StudentNo`, `StudentName` from student
-- 给结果重命名 use AS 也可以给字段起名 ,也可以给表起名
select `StudentNo` AS 学号,`StudentName` AS 学生姓名 from student AS teacher
-- CONCAT (a,b)
select CONCAT('姓名:',Student) AS 新名字 from student
去重 distinct
-
去除select查询出来的结果中重复的数据,重复的数据只显示一条
-- 查询一下有哪些同学参加了考试, SELECT * FROM result -- 查询全部的考试成绩 SELECT `StudentNo` FROM result -- 查询有那些同学参加了考试 SELECT DISTINCT `Student` FROM result -- 去掉重复数据
select vesion() -- 查询版本
select 100*3-1 AS 计算结果 -- 用来计算
select @@auto_increment_increment --查询自增步长
-- 学员考试加分 +1分查看
SELECT `StudentNO`,`StudentResult`+1 AS '提分后' FROM student
数据库中表达式:文本,列,null,函数,计算表达式,系统变量。…
where 条件子具
- 检索数据中符合条件的值
逻辑运算符
运算符 | 语法 | 描述 |
---|---|---|
AND && | A AND B A && B | |
OR || | A OR B A ||B | |
NOT ! | NOT A ! A |
模糊查询:比较运算符
运算符 | 语法 | 描述 |
---|---|---|
IS NULL | a is null | 如果操作符为NULL,则为真 |
IS NOT NULL | a is not null | 如果操作符不为NULL,则为真 |
BETWEEN | a between | 若a在b和c之间,则为真 |
Like | a like b | SQL匹配,如果a匹配b,则为真 |
In | a in(a1,a2,a3) | 假设a在其中,则为真 |
-- like结合 %(代表任意个字符) _(代表一个字符)
SELECT `StudentNo`,`StudentName` FROM `student`
where StudentName Like '刘%' -- 姓刘后面有任意字
SELECT `StudentNo`,`StudentName` FROM `student`
where StudentName Like '刘_' -- 姓刘两个字
— IN (具体的一个或多个值)
-- 查询学号为101,102,103的学员
select `StudentNo`,`StudentName` From `student`
where StudentNo in(102,101,103);
select `StudentNo`,`StudentName` From `student`
where `Adress` in('四川','北京','陕西西安');
– null not null–
-- 查询地址为空的学生
select `StudentNo` `StudentName` from `student`
where address='' or addres is null
– 查询学生成绩为空的学生
select `StudentNo` `StudentName` from `student`
where 'result' is null --
where 'result' is not null -- 成绩不为空
–联表查询 jion
select s.studentNo,studentName,SubjectNo,StudentResult
from student as s
inner join result as r
on s.studentNo =r.studentNo
– Right join
select s.studentNo,stduentName,SubjectNo,StudentResult
from student s
right join result r
on s.studentNo = r.studentNo
– left join
select s.studentNo,stduentName,SubjectNo,StudentResult
from student s
left join result r
on s.studentNo = r.studentNo
– 查询缺考学生
select s.studentNo,stduentName,SubjectNo,StudentResult
from student s
left join result r
on s.studentNo = r.studentNo
where StudentResult is null
— where 等值查询
— on 连接查询
操作 | 描述 |
---|---|
inner join | 如果表中至少有一个匹配,就返回行 |
left join | 会从左表中返回所有的值,即使右表中没有匹配 |
right join | 会从右表中返回所有的值,即使右表中没有匹配 |
–自连接
自己的表和自己的表连接,核心:一张表拆为两张表即可
categoryid | pid | categoryName |
---|---|---|
3 | 1 | 信息技术 |
5 | 1 | 软件开发 |
4 | 3 | 数据库 |
8 | 1 | 美术设计 |
2 | 3 | web开发 |
6 | 5 | ps技术 |
7 | 2 | 办公信息 |
父类表
categoryid | categoryName |
---|---|
2 | 信息技术 |
3 | 软件开发 |
5 | 美术设计 |
子类表
pid | categoryid | categoryName |
---|---|---|
3 | 4 | 数据库 |
2 | 8 | 办公信息 |
3 | 6 | web开发 |
5 | 7 | ps技术 |
查询父类对应的子类关系
父类 | 子类 |
---|---|
信息技术 | 办公信息 |
软件开发 | 数据库 |
软件开发 | web开发 |
美术设计 | ps技术 |
select a.`categoryName` as'父栏目' ,b.`categoryName`as'子栏目'
from `category` as a,`category` as b
where a.`categoryid`= b.`pid`
分页(limit)排序(order by)–
排序 :升序 ASC , 降序 DESC
ORDER BY studentResult asc -- (升序)
limit 5,5
--[pagesize:]
--[(n-1)*pagsize: 起始值]
-- [n: 第几页]
--[数据总数/页面大小=总页数]
— 子查询
select `StudentNo`,r.`StudentNo`,`StudentResult`
from `result` r
inner join `subject` sub
on r.SubjectNo =sub.SubjectNo
where SubjectName = '数据结构'
order by StudentResult Desc
-- 子查询(由里及外)
select `StudentNo`,`SubjectNo`,`StudentResult`
from `result`
where SubjectNo = (
select SubjectNo from `subject`
where SubjectName = '数据结构'
)
– 分组过滤
-- 查询不同课程的平均分,最高分,最低分,品均分》80
select SubjectName,AVG(StudentResult) as 平均分,MaX(StudentResult) as 最高分,MIn(StudentResult) as 最低分
from result r
inner join `subject` sub
on r.`SubjectNo` = sub.`SubjectNo`
group by r.SubjectNo -- 通过什么字段分组
having 平均分>80 --having 过滤条件
常用函数
select ABS(-10) --绝对值
select ceiling(9.4) -- 向上取 整在 10
select floor(9.4) -- 向下取去整 9
select rand() --0-1 的随机数
select sign(10) --判断一个数的符号 0-0 负数 -1 正数 1
-- 时间和日期
select current_date() --获取当前时间
select now()
select localtime()
select sysdate() --系统时间
-- 系统
select user()
聚合函数
函数名称 | 描述 |
---|---|
COUNT() | 计数 |
SUM() | 求和 |
AVG() | 平均值 |
MAX() | 最大值 |
MIN() | 最小值 |
select count('字段') from table ;--count(字段 ) 会忽略所有null值
select count(*) ... --count(*),不会忽略null值
select count(1).. -- count(1) 不会忽略null 效率高
update testmd5 set pwd=md5(pwd) where id=1
insert into testmd5 values(4,'xxx',md5('1345'))
--校验
select * from testmd5 where `name`=`xiaoming` and pwd=md5('123456')
事务-
:在关系数据库中,一个事务可以是一条SQL语句,一组SQL语句或整个程序。
原则:ACID 原则 原子性,一致性,隔离性,持久性 (脏读,幻读)
原子性(atomicity)。一个事务是一个不可分割的工作单位,事务中包括的操作要么都做,要么都不做。
一致性(consistency)。事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
隔离性(isolation)。一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
持久性(durability)。持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。
手动事务
手动事务允许显式处理若干过程,这些过程包括:开始事务、控制事务边界内的每个连接和资源登记、确定事务结果(提交或中止)以及结束事务。尽管此模型提供了对事务的标准控制,但它缺少一些内置于自动事务模型的简化操作。例如,在手动事务中数据存储区之间没有自动登记和协调。此外,与自动事务不同,手动事务中事务不在对象间流动。
如果选择手动控制分布式事务,则必须管理恢复、并发、安全性和完整性。也就是说,必须应用维护与事务处理关联的 ACID 属性所需的所有编程方法。
自动事务
.NET 页、XML Web services方法或 .NET Framework 类一旦被标记为参与事务,它们将自动在事务范围内执行。您可以通过在页、XML Web services 方法或类中设置一个事务属性值来控制对象的事务行为。特性值反过来确定实例化对象的事务性行为。因此,根据声明特性值的不同,对象将自动参与现有事务或正在进行的事务,成为新事务的根或者根本不参与事务。声明事务属性的语法在 .NET Framework 类、.NET 页和 XML Web services 方法中稍有不同。
声明性事务特性指定对象如何参与事务,如何以编程方式被配置。尽管此声明性级别表示事务的逻辑,但它是一个已从物理事务中移除的步骤。物理事务在事务性对象访问数据库或消息队列这样的数据资源时发生。与对象关联的事务自动流向合适的资源管理器,诸如 OLE DB、开放式数据库连接 (ODBC) 或 ActiveX 数据对象 (ADO) 的关联驱动程序在对象的上下文中查找事务,并通过分布式事务处理协调器 (DTC) 在此事务中登记。整个物理事务自动发生。
- 原子性:针对同一个事务
- 一致性:针对一个事务操作前与操作后的状态一致
- 持久性:事务一旦提交不可逆,被持久化到数据库中 (宕机或断电👇)
- 事务没提交:恢复原状
- 事务已提交:持久化到数据库
- 隔离性:事务的隔离是多个用户并发访问数据时,数据为每一个用户开启的事务,不能被其他事务的操作所干扰事务之间要相互隔离
事务隔离级别
***脏读***:一个事务读取了另一个事务未提交的数据
**不可重复度:**在一个事务内读取表的某一行数据,多次读取结果不同
**幻读:**一个事务内读取到了别的事物插入数据库,导致前后读取不一致
— mysql是默认开启事务自动提交的
set autocommit = 0 --/关闭/
set autocommit = 1--/开启(默认的/
--手动处理事务
set autocommit = 0 --关闭自动提交
-- 事务开启
start transaction --标记一个事务的开始,此后sql都在同一个事务内
insert xx
insert xx
-- 提交:持久化(成功)
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
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'
UPDATE account SET money = money +500 WHERE `name`='B'
COMMIT; -- 提交事务(就被持久化
ROLLBACK ; -- 回滚
SET autocommit = 1; -- 恢复默认值
索引
MySQL:索引帮助MySQL高效获取数据的数据结构
- 提取句子主干,就可以得到索引的本质:索引是数据机构
索引分类
- 主键索引 (PRIMARY KEY)
- 一种特殊的唯一索引
- 一个表只能有一个主键且不允许有空值
- 索引列只能出现一次且必须唯一。
- 唯一索引 (UNICODE KEY)
- 种索引,不允许具有索引值相同的行,从而禁止重复的索引或键值
- 唯一索引可以重复(多个列都可以标识 唯一索引)
- 避免重复列出现
- 常规索引 (KEY / INDEX)
- 默认的,index,key关键字来设置
- 全文索引 (FullText)
- 在特定的数据库引擎下才有,MyISMA
- 快速定位数据
-- 索引使用
-- 在创建表的时候给字段增加索引
-- 创建完毕后,增加索引
-- 显示所有的索引信息
show index from xxtable
-- 增家一个全文
alter table shool.student add fulltext index `studentName`(`stdentName`)
-- explian 分析sql执行状况
explian select * from student;
expian selct * from student where match(studentName) AGAINST ('XX')
-- ID -- 表名 -- ———— 字段名
-- create index 索引 on 表(字段)
create index id_app_user_name on app_user(`name`);
– 索引在小数据量的时候,用处不大,在大数据时候,区别十分明显
索引原则–
-
确定针对该表的操作是大量的查询操作还是大量的增删改操作。
-
尝试建立索引来帮助特定的查询。检查自己的sql语句,为那些频繁在where子句中出现的字段建立索引。
-
尝试建立复合索引来进一步提高系统性能。修改复合索引将消耗更长时间,同时,复合索引也占磁盘空间。
-
对于小型的表,建立索引可能会影响性能
-
应该避免对具有较少值的字段进行索引。
-
避免选择大型数据类型的列作为索引。
用户管理 和备份
-- 创建用户 create user 用户名 identified by '密码 '
create user xxxx identifide by '123456'
--修改密码
set password = password('111111')
-- 修改指定用户密码
set password for xxxx = password('1111111')
--用户重命名 rename user 原来名字 to 新的名字
rename user xxx to 新xxx
-- 不可授权 除了 root
-- 用户授权 all privileges 全部权限 *.*==所有库,所有表 (库,表)
grant all privileges on *.* to xxx
-- 查询 权限
show grants for xxxuser
-- 撤销权限 revoke 那些权限 那个库撤销, xxuser
revoke all privileges on *.* from xxuser
-- 删除用户
drop user xxuser
数据库备份
-
保证数据不丢失
-
数据转移
MySQL数据库备份方式
- copy物理物件
- sqlyog可视化 工具手动导出
- 使用命令行导出 mysqldump 命令行使用
# mysqldump -h主机 -u 用户名 -p 密码 数据库 表名 > 物理磁盘位置、文件名
mysqldump -hlocalhost -uroot -p123456 school student >D:/xxx.xxx
# mysqldump -h主机 -u 用户名 -p 密码 数据库 表名 表名 表名 > 物理磁盘位置、文件名
mysqldump -hlocalhost -uroot -p123456 school student xx表名 xx表名 >D:/xxx.xxx
# mysqldump -h主机 -u 用户名 -p 密码 数据库 > 物理磁盘位置、文件名
mysqldump -hlocalhost -uroot -p123456 school student >D:/xxx.xxx
#导入
#登录情况下,切换到指定的数据库
source d:/a.sql
数据库的设计
- 好的数据库
节省空间
保证数据的完整性
方便系统开发
- 差的数据库
数据冗余,浪费空间
数据库插入删除麻烦,异常[屏蔽使用物理外键]
程序性能差
软件开发,关于数据库设计
- 分析需求:分析业务和需要处理的数据库的需求
- 概要设计:设计关系图E-R图
设计数据库步骤(个人博客)
-
收集信息,分析需求
- 用户表 (用户登录注销,用户个人信息,写博客,创建分类)
- 分类表(文章分类)
- 文章表(文章的信息
- 品论表
- 友链表(友链信息)
- 自定义表(系统信息,某个关键字,或者一些主字段) key: value
-
标识实体(需求落实)
-
标识实体之间的关系
- 写博客:user->blog
- 创建分类:user->category
- 关注:user->user
- 友链:links
- 评论:user->user->blog
三大范式
-
数据库规范化避免
-
信息重复
-
更新异常
-
插入异常
-
无法正常显示信息
删除异常
- 丢失有效的信息
-
-
第一范式:每个列都不可以再拆分。
第二范式:在第一范式的基础上,非主键列完全依赖于主键,而不能是依赖于主键的一部分。
第三范式:在第二范式的基础上,非主键列只依赖于主键,不依赖于其他非主键。
在设计数据库结构的时候,要尽量遵守三范式,如果不遵守,必须有足够的理由。比如性能。事实上我们经常会为了性能而妥协数据库的设计。
规范性和性能问题
关联查询表不得超过三张表
- 考虑商业化需求和目标 数据库性能更加重要
- 在规范性能的问题时候,需要适当考虑 规范性
- 故要增加冗余字段(从多表查询变为单表查询)
- 故意增加计算列(从大数据降为小数据查询:索引)
JDBC
***JDBC***一般指Java数据库连接
是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法
主要用途
与数据库建立连接
发送 SQL 语句
处理结果
CREATE DATABASE jdbcStudy CHARACTER SET utf8 COLLATE utf8_general_ci;
USE jdbcStudy
CREATE TABLE users(
id INT PRIMARY KEY,
NAME VARCHAR(40),
PASSWORD VARCHAR(40),
email VARCHAR(60),
birthday DATE
);
INSERT INTO users(id,NAME,PASSWORD,email,birthday)
VALUES (1,'zhansan','123456','zs@sina.com','1980-12-04'),
(2,'lisi','123456','lisi@sina.com','1981-12-04'),
(3,'wangwu','123456','wangwu@sina.com','1919-12-04');
==============================================
public class JdbcFirstDemo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//加载驱动
Class.forName("com.mysql.jdbc.Driver"); //固定写法
//用户信息和url
//useUnicode=tree&characterEncoding=utf8&&useSSL=true
String url ="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&&useSSL=true";
String username= "root";
String password = "123456";
//连接成功,数据库对象 connection 代表数据库
Connection connection=DriverManager.getConnection(url,username,password);
//执行sql对象 statement 执行sql对象
Statement statement= connection.createStatement();
//执行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("pwd= "+resultSet.getObject("PASSWORD"));
System.out.println("email= "+resultSet.getObject("email"));
System.out.println("birthday= "+resultSet.getObject("birthday"));
}
//释放连接
resultSet.close();
statement.close();
connection.close();
}
}
- 步骤
- 加载驱动
- 连接数据库DriverManager
- 获取执行sql的对象Statement
- 获取返回结果集
- 释放连接
DriverManager
//DriverManager.registerDriver(new com.jdbc.Driver());
Class.forName("com.sql.jdbc.Driver");
Connection connection=DriverManager.getConnection(url,username,password);
//connection 代表数据库
//数据库设计自动提交 connection.setAutocommit()
//事务回滚connection.rollback();
//事务提交 connection.commit();
URL
String url ="jdbc:mysql://localhos:3306/jdvcstudy?
useUnicode=true&charcterEncoding=utf8&&useSSL=true";
//oralce --1521
//jdbc:mysql://主机地址:端口号/数据库名?参数1&参数2&参数3
Statement 执行SQL的对象 PrepareStatement 执行SQL的对象
statement.executeQuery();//查询操作返回ResultSet
statement.execute(); //执行任何SQL
statement.executeUpdate(); //更新、插入、删除、都是用这个,返回一个受影响的行数
ResultSet 查询结果集:封装了所有的查询结果
获得指定的数据类型
resultSet.getObject();//在不知列类型情况使用
//指定类型
resultSet.getString();
resultSet.getInt();
resultSet.getFloat();
resultSet.getDouble();
... .... ....
释放资源
resultSet.close();
statement.close();
connection.close();
Statement 对象
jdbc中的statement对象用于向数据库发送SQL语句,完成对数据库的增删该查,只需通过此对象向数据库发送增删改查语句即可。
Statement对象的excuteUpdate方法,用于数据库发送增,删、改的sql语句,executeUpdate执行完后,返回一个整数(增删改语句导致数据库几行发生编号)
Statement.excuteQuery方法用于数据库发送查询语句,excuteQuery方法返回代表查询结果ResultSet对象。
CRUD操作 - create
使用excuteUpdate(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
使用excuteUpdate(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
使用excuteUpdate(String sql) 修改操作
Statement st = conn.createStatement();
String sql="update from user where name=''";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println("修改成功")
}
CRUD操作 -read
使用excuteUpdate(String sql) 查询操作
Statement st = conn.createStatement()
String sql="select from user where id=1";
ResultSet rs = st.executeQuery(sql);
if(rs.next()){
//根据获取的数据类型,分别调用rs的对应方法映射到java对象中
}
—增删改查
driver= com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true
username=root
password=123456
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");
//驱动只需加载一次
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,username,password);
}
//释放资源
public static void release(Connection conn, Statement st,ResultSet rs){
if (rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(st!=null){
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestInsert {
public static void main(String[] args) {
Connection conn=null;
Statement st=null;
ResultSet rs=null;
try {
conn= JdbcUtils.getConnection();//获取数据库连接
st=conn.createStatement();//获得SQl的执行对象
String sql ="INSERT INTO users(id,`NAME`,`PASSWORD`,`email`,`birthday`)" +
"VALUES(4,'kakaxi','123456','24736743@qq.com','2020-01-01')";
int i = st.executeUpdate(sql);
if(i>0){
System.out.println("插入成功");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
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 conn=null;
Statement st=null;
ResultSet rs=null;
try {
conn= JdbcUtils.getConnection();//获取数据库连接
st=conn.createStatement();//获得SQl的执行对象
String sql ="DELETE FROM users WHERE id=4;";
int i = st.executeUpdate(sql);
if(i>0){
System.out.println("删除成功");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
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 conn=null;
Statement st=null;
ResultSet rs=null;
try {
conn= JdbcUtils.getConnection();//获取数据库连接
st=conn.createStatement();//获得SQl的执行对象
String sql ="UPDATE users SET `NAME`='kakaxi',`email`='1445162998@qq.com' WHERE id=1;";
int i = st.executeUpdate(sql);
if(i>0){
System.out.println("更新成功");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
查询 > executeQuery
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 conn=null;
Statement st=null;
ResultSet rs=null;
try {
conn=JdbcUtils.getConnection();
st= conn.createStatement();
//SQL
String sql="select * from users where id=1";
rs= st.executeQuery(sql);//查询完毕返回一个结果集
while(rs.next()){
System.out.println( rs.getString("NAME"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
SQL注入问题
sql存在漏洞,会被攻击导致数据泄露
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class SQLInjectionAttack {
public static void main(String[] args) {
//正常登录 login("kakaxi","123456");
login(" 'or '1=1","123456");
}
//登录业务
public static void login(String username,String password){
Connection conn=null;
Statement st=null;
ResultSet rs=null;
try {
conn=JdbcUtils.getConnection();
st= conn.createStatement();
//SQL
String sql="select * from users where `NAME`='"+username+"'AND `password`='"+password+"'";
rs= st.executeQuery(sql);//查询完毕返回一个结果集
while(rs.next()){
System.out.println( rs.getString("NAME"));
System.out.println( rs.getString("password"));
System.out.println("-------------------");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
PreparedStatement 对象
-
防止SQL注入,效率更高
import com.kakaxi.lesson2.utils.JdbcUtils; import java.util.Date; import java.sql.*; public class TestInsert { public static void main(String[] args) { Connection conn=null; PreparedStatement st=null; ResultSet rs=null; try { conn= JdbcUtils.getConnection(); //区别 占位符代替参数 String sql="insert into users(id,`NAME`,`PASSWORD`,`email`,`birthday`) values(?,?,?,?,?)"; st=conn.prepareStatement(sql);//预编译,先写sql,然后不执行 //手动给参数赋值 st.setInt(1,4);//id st.setString(2,"huahua"); st.setString(3,"123456"); st.setString(4,"123456@qq.com"); //注意点:sql.Date 数据库 //util.Date java new Date().getTime() 获得时间戳 st.setDate(5,new java.sql.Date(new Date().getTime())); //执行 int i=st.executeUpdate(); if(i>0){ System.out.println("插入成功!"); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(conn,st,rs); } } }
import com.kakaxi.lesson2.utils.JdbcUtils; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Date; public class TestDelete { public static void main(String[] args) { Connection conn=null; PreparedStatement st=null; ResultSet rs=null; try { conn= JdbcUtils.getConnection(); //区别 占位符代替参数 String sql="delete from users where id=?"; st=conn.prepareStatement(sql);//预编译,先写sql,然后不执行 //手动给参数赋值 st.setInt(1,4); //执行 int i=st.executeUpdate(); if(i>0){ System.out.println("删除成功!"); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(conn,st,rs); } } }
import com.kakaxi.lesson2.utils.JdbcUtils; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Date; public class TestUpdate { public static void main(String[] args) { Connection conn=null; PreparedStatement st=null; ResultSet rs=null; try { conn= JdbcUtils.getConnection(); //区别 占位符代替参数 String sql="update users set `NAME`=? WHERE id=?"; st=conn.prepareStatement(sql);//预编译,先写sql,然后不执行 //手动给参数赋值 st.setString(1,"卡卡西"); st.setInt(2,1); //执行 int i=st.executeUpdate(); if(i>0){ System.out.println("更新成功!"); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(conn,st,rs); } } }
–查询
import com.kakaxi.lesson2.utils.JdbcUtils; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class TestSelect { public static void main(String[] args) { Connection conn=null; PreparedStatement st=null; ResultSet rs=null; try { conn=JdbcUtils.getConnection(); String sql="select * from users where id=?"; st=conn.prepareStatement(sql); //传参 st.setInt(1,2); //执行 rs= st.executeQuery(); if(rs.next()){ System.out.println(rs.getString("NAME")); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(conn,st,rs); } } }
//PreparedStatement 防止SQLz注入的本质,把传递进来的参数当作字符
-
假设其中存在转义字符,” ’ “ 会被直接转义
import com.kakaxi.lesson2.utils.JdbcUtils; import java.sql.*; public class SQLInjectionAttack { public static void main(String[] args) { // login("lisi","123456"); login("''or '1=1","123456"); } //登录业务 public static void login(String username,String password){ Connection conn=null; PreparedStatement st=null; ResultSet rs=null; try { conn=JdbcUtils.getConnection(); //SQL String sql="select * from users where `NAME`=? and `PASSWORD`=?"; st= conn.prepareStatement(sql); st.setString(1,username); st.setString(2,password); rs= st.executeQuery();//查询完毕返回一个结果集 while(rs.next()){ System.out.println( rs.getString("NAME")); System.out.println( rs.getString("password")); System.out.println("-------------------"); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(conn,st,rs); } } }
事务
import com.kakaxi.lesson2.utils.JdbcUtils; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class TestTransaction { public static void main(String[] args) { Connection conn=null; PreparedStatement st=null; ResultSet rs=null; try { conn=JdbcUtils.getConnection(); //关闭数据自动提交功能,自动开启事务 conn.setAutoCommit(false); String sql1="update account set money =money -500 where name='A'"; st=conn.prepareStatement(sql1); st.executeUpdate(); String sql2="update account set money =money +500 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); } } }
-
SQL
create table account(
id int primary key auto_increment,
name varchar(40),
money float
);
insert into account(name,money) values('A',1000);
insert into account(name,money) values('B',1000);
insert into account(name,money)values('C',1000);
数据库连接池
**池化技术:**池化技术 (Pool) 是一种很常见的编程技巧,在请求量大时能明显优化应用性能,降低系统频繁建连的资源开销
import com.kakaxi.lesson2.utils.JdbcUtils;
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.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 conn, Statement st, ResultSet rs){
if (rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(st!=null){
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
import com.kakaxi.lesson2.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
public class TestDBCP {
public static void main(String[] args) {
Connection conn=null;
PreparedStatement st=null;
ResultSet rs=null;
try {
conn= JdbcUtils_DBCP.getConnection();
//区别 占位符代替参数
String sql="insert into users(id,`NAME`,`PASSWORD`,`email`,`birthday`) values(?,?,?,?,?)";
st=conn.prepareStatement(sql);//预编译,先写sql,然后不执行
//手动给参数赋值
st.setInt(1,4);//id
st.setString(2,"huahua");
st.setString(3,"123456");
st.setString(4,"123456@qq.com");
//注意点:sql.Date 数据库
//util.Date java new Date().getTime() 获得时间戳
st.setDate(5,new java.sql.Date(new Date().getTime()));
//执行
int i=st.executeUpdate();
if(i>0){
System.out.println("插入成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils_DBCP.release(conn,st,rs);
}
}
}
#设置连接
driverClassName= com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true
username=root
password=123456
#<!--初始化连接-->
initialSize=10
#最大连接数量
maxActive=50
#<!--最大空闲连接-->
maxIdle=20
#<!--最空闲连接-->
minIdle=5
#<!--超时等待时间以毫秒为单位6000毫秒/1000等于60秒-->
maxWait=6000
#JDBC驱动建立连接时附带的连接属性的格式必须:[属性明=property;]
# "user" 与 "password"两个属性会被明确传递,这不需要包含他们
connectionProperties=useUnicode=true;characterEncoding=UTF8
#指定由连接池所创建的连接的自动提交(auto-commit)状态
defaultAutoCommit=true
#driver default 指定由连接池所创建的连接的只读(read-only)状态
#如果没有设置该值,则"setReadOnly"方法不被调用。(某些驱动不支持只读模式)
defaultReadOnly=
#diver default 指定由连接池所创建的连续的事务级别(TransactionIsolation)
#可用值为下列
defaultTransactionIsolation=READ_UNCOMMITTED