# 数据库

# DBMS

DataBase Management System

  • 数据是数据库存储的基本对象
  • 数据库是存放数据的仓库
  • 数据库管理系统是位于用户与操作系统之间的一层数据管理软件。数据库管理系统与操作系统一样,是计算机的基础软件。

主要功能:

  • DDl 数据定义语言
  • DML 数据操纵 (Manipulation) 语言

DBS:数据库系统是由数据库,数据库管理系统、应用程序和数据库管理员组成的存储、管理、处理和维护数据的系统。

数据库系统与文件系统的本质区别:数据库系统实现整体数据的结构化

模式:也称逻辑模式,是数据库中全体数据的逻辑结构和特征的描述,是所有用户的公共数据视图。

外模式:数据库的全局逻辑结构,所有用户公共的数据视图

内模式:也称存储模式,是数据物理结构和存储方式的描述,是数据在数据库内部的组织方式。

数据库设计的步骤:

  1. 需求分析
  2. 概念结构设计
  3. 逻辑结构设计
  4. 物理结构设计
  5. 数据库实施
  6. 数据库的运行和维护

需求分析:进行数据库设计首先必须准确了解与分析用户需求。需求分析是整个设计过程的基础

概念结构设计:通过对用户需求进行综合、归纳与抽象形成一个独立于具体 DBMS 的概念模型。

逻辑结构设计:将概念结构转化为某个数据库管理系统所支持的数据模型,并对其进行优化

物理结构设计阶段:为逻辑数据模型选取一个最适合应用环境的物理结构(包括存储结构和存取方法

# 事务

事务是用户定义的一个数据库操作序列

事务与程序是两个概念

  • 一个事务可以是一条 SQL 语句,一组 SQl 语句或整个程序
  • 一个应用程序包含多个事务

事务是并发控制和恢复的基本单位

定义事务:

1
2
3
begin transaction
if() rollback
commit

若用户未显式定义事务,DBMS 按默认设置划分

事务特性

  • 原子性 Atomic:事务是数据库操作的逻辑单位
  • 一致性 Consistency:事务的执行结果是数据库从一个一致性状态到另一个一致性状态
  • 隔离性 Isolation:并发执行的事务之间不能互相干扰
  • 持久性 Durability:一个事务一旦提交对数据库中数据的改变是永久的

#

基本锁类型:

  • 排它锁或写锁
  • 共享锁或读锁

并发事务调度正确性的唯一准则:可串行化

几个事务并行执行时正确的当且仅当其结果与某一次序串行执行的结果相同

保证并发调度正确性的方法:两段锁协议:

  1. 事务对任何数据进行读写操作之前,首先要获得对改数据的封锁
  2. 事务一旦开始释放锁,不允许其再获得其他锁

事务执行分为了两个阶段

  1. 加锁,扩展阶段
  2. 解锁,收缩阶段

对一个数据库节点加意向锁表示最它下一个节点加 X/S 锁

image-20221222093028992

锁的强度:X 》SIX 》S/IX 》IS

申请封锁:自上而下

释放封锁:自下而上

# 数据库恢复技术

故障是不可避免的:

  • 计算机硬件故障
  • 系统软件和硬件故障
  • 操作员的失误
  • 程序 BUG
  • 恶意的破坏、病毒

故障种类:

  • 事务故障

    常见原因:

    • 输入数据有误
    • 运算溢出
    • 违反了某些完整性限制
    • 应用程序出错
    • 并行事务发生死锁

    恢复:

    • 强行回滚
  • 系统故障

    • 整个系统正常运行突然被破坏
    • 所有正在运行的事务都非正常停止
    • 内存中数据库缓冲区的信息全部丢失
    • 外存上的数据未受影响

    常见原因:

    • 操作系统或 DBMS 代码错误
    • 操作员失误
    • 特定的硬件错误
    • 突然停电

    恢复:

    • Rollback 回滚所有未完成事务(UNDO

    • Commited 已提交的事务可能有未来得及写入磁盘的内容 REDO

  • 介质故障

    • 存储在外存中的数据部分或全部丢失
      • 磁盘损坏
      • 磁头碰撞
      • 瞬时强电磁场
      • 操作系统某种潜在错误
        • 装入 数据库发生介质故障前某个时刻的数据副本
        • 重做滋此时所有成功事务,讲这些事务已提交的结果重新计入数据

# 恢复的实现技术

  • 数据转储:静态转储 / 动态转储 海量转储 / 增量转储
  • 登记日志文件

静态转储:

  • 在系统中无运行事务时进行转储
  • 转储开始时数据库处于一致性状态
  • 转储期间不允许对数据库的任何存取、修改

优点:实现简单

缺点:降低了数据库的可用性

转储必须等待事务结束,新的事务必须等待转储结束

动态转储

转储操作与事务并发进行,转储时允许对数据库进行存取、修改

优点:不用等待正在运行的事务结束,不会影响事务的运行

缺点:不能保证副本中的数据全部正确有效

海量转储:每次转储全部数据库

增量转储:只转储上次转储后更新过的数据

比较:

  • 从恢复的角度看,海量转储得到的后备副本往往更方便恢复
  • 如果数据库很大,事务十分频繁,增量转储的方式更实用有效

# 日志文件

日志:记录事务对数据库更新操作的文件

日志文件的格式:

  • 以记录为单位的日志文件
  • 以数据块为单位的日志文件

日志文件内容:每个事务开始 / 结束,每个事务的更新操作

  • 事务开始 start / 事务结束 commit
  • 记录每一个更新操作:
    • 事务标识
    • 操作类型
    • 数据对象
    • 更新前的旧值
    • 更新后的值

登记日志文件必须遵守两条原则:

  • 登记的次序严格按照事务的执行时间次序
  • 必须先写日志文件,后写数据库

# 恢复策略

  • 事务故障的恢复:事务在运行在正常终止点前被终止

    由恢复子系统应利用日志文件撤销此事务已对数据库进行的修改

  • 系统故障的恢复:系统重启时自动完成

    UNDO 故障发生时未提交的事务

    REDO 故障发生时已提交的事务

  • 介质故障的恢复

    重装数据库备份,使数据库恢复到一致性状态

    REDO 已完成的事务

无日志、使用静态转储副本进行恢复:

正常运行:Ta = 静态转储 => Tb = 运行事务 => Tf

恢复:重装后备副本 ==》重新运行事务

# 程序设计

增: insert into 表名 values(); 或者 insert into 表名(列名...) values();

删: delete from 表名 where……;

改: update 表名 set 列名 = …… where ……;

查: select */列名 from 表名 / where;

视图create view name as select……;

# 触发器

create after referencing for begin ……

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
DROP TRIGGER if EXISTS testi; -- 如果存在testi触发器则删除

CREATE TRIGGER testi
AFTER INSERT ON table
FOR EACH ROW
BEGIN
INSERT INTO bysj_dt VALUES (new.id,new.et_name);
END

create trigger test
after delete on Student
referencing old row as orow
FOR EACH ROW
begin
DELETE FROM SC WHERE SC.Sno = orow.Sno;
end

# 存储过程

1
2
3
4
5
6
7
8
9
10
11
12
create procedure countByDept(in deptName varchar(20), out cnt integer)
begin
select count(*) into cnt
from student
where student.Sdept = deptName;
end


# 调用存储过程
call countByDept('CS',@cnt)
select @cnt

# 函数

1
2
3
4
5
6
7
8
9
10
11
12
create function countByDept(deptName varchar(20))
returns integer
begin
declare cnt integer;
select count(*) into cnt
from student
where student.Stept = deptName;
return cnt;
end;

# 调用函数
select countByDept("CS")

# JDBC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.sql.*;

public class testjdbc{
public static void main(String[] args){
try{
Class.forName("org.mariadb.jdbc.Driver").newInstance();
System.out.println("pass forName");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/StuCou","root","");
Statement stmt = conn.createStatement();
String query = "select * from Student";
ResultSet rs = stmt.excuteQuery(query);
while(rs.next()){
sout……
}
conn.close();
}catch(SQLException e){
sout(e.getSQLState());
sout(e.getErrorCode());
}catch(Exception e){
e.printStackTrace();
}
}
}

更新于 阅读次数 本文阅读量:

请我喝[茶]~( ̄▽ ̄)~*

Windlinxy 微信支付

微信支付

Windlinxy 支付宝

支付宝