一、基础术语
DML(data manipulation language):
如SELECT、UPDATE、INSERT、DELETE,主要用来对数据库里的数据进行操作的语言
DDL(data definition language):
主要的命令有CREATE、ALTER、DROP等,DDL主要是用在定义或改变表(TABLE)的结构,数据类型,表之间的链接和约束等初始化工作上,大多在建立表时使用。
DCL(Data Control Language):
数据库控制功能。是用来设置或更改数据库用户或角色权限的语句,包括(grant,deny,revoke等)语句。默认情况下,只有sysadmin,dbcreator,db_owner或db_securityadmin等人员才有权力执行DCL
二、数据库三范式
关系型数据库设计表时为了减小冗余,增强数据的有效性和存储效率,需要遵循一定的规范,这些规范按照严格程度来区分可以分为第一范式(1NF),第二范式(2NF),第三范式(3NF),BC范式(BCNF),第四范式(4NF),第五范式(5NF)等。
数据库范式是数据库设计中必不可少的理论依据,不理解数据库范式就无法设计出搞笑优雅的数据库,甚至依赖混乱,操作经常出错。实际应用中常用的范式有第一范式(1NF),第二范式(2NF)和第三范式(3NF),后面三个范式则用的比较少,这是因为适当的冗余可以增加数据库的查询效率。
第一范式(1NF):属性不可分
第一范式要求数据库表中所有字段都是不可分的原子值。不满足第一范式的数据库,不是关系数据库!
第二范式(2NF):非主属性完全依赖于码
第二范式是在第一范式的基础上更进一步,要求数据库要有主键,其他非主属性完全依赖于主键,而不能只依赖主键中的一部分。即联合主键的情况,如果某一个非主属性只依赖于联合主键中的一个或者部分属性,则不符合第二范式。第二范式隐式要求数据库一张表只保存一种数据,尽量不要把多种数据保存到一张表中。
第三范式(3NF):非主属性之间不存在传递依赖
第三范式是在第二范式的基础上更进一步,要求属性不能依赖于表中的非主属性。第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。
三、事务:
事务(Transaction)是并发控制的基本单位。所谓事务,即一系列操作的集合,这些操作要么都不执行,要么全部执行,不允许执行其中一部分,即把一系列操作作为一个整体进行控制。比如银行转账,简化下来至少需要两步操作,1:要从A账户扣除100元,2:给B账户增加100元,这两步操作必须作为一个整体进行控制,假如从A账户扣款成功,给B账户增加金额失败,则事务必须回滚(roolback),即把A账户的扣款返回给A账户。
事务具有四个基本特征(ACID):
Atomic(原子性):
事务中包含的操作被看做一个逻辑单元,这个逻辑单元中的操作要么全部成功,要么全部失败。
Consistency(一致性):
只有合法的数据可以被写入数据库,否则事务应该将其回滚到最初状态。
Isolation(隔离性):
事务允许多个用户对同一个数据进行并发访问,而不破坏数据的正确性和完整性。同时,并行事务的修改必须与其他并行事务的修改相互独立。这表明事务必须是独立的,不应该以任何方式以来于或影响其他事务。
Durability(持久性):
事务结束后,事务处理的结果必须能够得到固化。事务完成之后,它对于系统的影响是永久的,该修改即使出现系统故障也将一直保留,真实的修改了数据库。
如果多个事务同时影响同一条或者同一些数据,将会导致数据混乱或者事务执行失败,因此需要对事务的并发进行控制。隔离级别就是对对事务并发控制的等级。SQL-92标准中定义了四个隔离级别,串行化(SERIALIZABLE)、可重复读(REPEATABLE READ)、读已提交(READ COMMITED)、读未提交(READ UNCOMMITED):
√ 表示可能发生,× 表示不会发生
脏读 |
不可重复读 |
幻读 |
|
Read uncommitted |
√ |
√ |
√ |
Read committed |
× |
√ |
√ |
Repeatable read |
× |
× |
√ |
Serializable |
× |
× |
× |
假如有两个事务A和B都在对同一个数据库进行操作:
1、如果数据库隔离级别设为Read uncommitted,事务A先操作数据库,修改了一条数据,但未提交事务,此时事务B读数据库,则会读取到事务A未提交的脏数据,即为脏读;
2、如果数据库隔离级别设为Read committed,事务A先操作数据库,读取数据data_a,然后事务B讲数据库中对应的数据修改为data_b并提交事务,此时事务A再去读同一条数据,则数据 变为data_b,即不可重复读;
3、如果数据库隔离级别设为Repeatable read,事务A先读取某一条件下的一些数据,然后事务B插入一条数据并提交,而这条数据又恰好满足事务A的select条件,此时事务A再去数据库查询该条件下的数据,发现比上一次多了一条,好像出现幻觉一般,称为幻读;
4、如果数据库隔离级别设为Serializable,则所有事务都是排着队一条一条执行的,只有上一条事务执行完毕才会开始下一条事务,因而脏读、不可重复读、幻读这些情况都不可能出现。
不可重复读与幻读的区别是,不可重复读是因为修改了数据而造成的数据不一致,幻读是因为插入数据造成的数据不一致。
SQL Server 和Oracle默认的隔离级别是Read committed,MySQL数据库默认的隔离级别是Repeatable read
四、数据库锁
数据库系统本身的锁机制 :
1、共享锁(Shared Lock) S锁允许多个事务同时对同一数据进行读操作,但是不允许修改数据(与X锁冲突)。
2、更新锁(Update Lock) 更新所也称修改锁,事务在更新某一项数据时需要加U锁,读取该数据项,此时允许其他事务在该项上加S锁,待事务读出并修改后,将U锁升级为X锁,然后写入修改后的数据。
3、排他锁(Exclusive Lock):排他锁是独占锁,一般修改数据时使用,select...for update
4、意向锁(Intent Lock):意向锁是表级锁,说明在资源底层获得共享锁或独占锁的意向。例如,当读取表里的页面时,在请求页共享锁(S锁)之前,事务在表级请求共享意向锁。这样可以防止其他事务随后在表上获取排他锁(X锁),修改整个表格。意向锁可以提高性能,因为数据库引擎仅在表级检查意向锁,确定事务是否能安全地获取该表上的锁,而不需要检查表中的每行或每页上的锁以确定事务是否可以锁定整个表。意向锁有两种用途:防止其他事务以会使较低级别的锁无效的方式修改较高级别资源;提高数据库引擎在较高的粒度级别检测锁冲突的效率。
意向共享锁(IS):表示事务准备给数据行加入共享锁,也就是说一个数据行加共享锁前必须先取得该表的IS锁
意向排他锁(IX):类似上面,表示事务准备给数据行加入排他锁,说明事务在一个数据行加排他锁前必须先取得该表的IX锁。
各种锁的兼容性如下:
意向共享(IS) |
共享(S) |
更新(U) |
意向排他(IX) |
排他(X) |
|
意向共享(IS) |
是 |
是 |
是 |
是 |
否 |
共享(S) |
是 |
是 |
是 |
否 |
否 |
更新(U) |
是 |
是 |
否 |
否 |
否 |
意向排他(IX) |
是 |
否 |
否 |
是 |
否 |
排他(X) |
否 |
否 |
否 |
否 |
否 |
5、模式锁(Schema Lock):Altert table,改变表结构时使用
6、批量更新锁(Bulk Update Lock):数据库备份恢复
业务级别上的锁机制,hibernate支持有以下两种类型的锁
悲观锁:
对数据被外界修改持保守态度,即认为经常会发生不止一个事务修改同一条数据的情况,因此所有事务对数据修改前都要获取一把锁,用来排斥其他事务对该数据的操作。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能 真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系 统不会修改数据)。如 select * form user where id=#{id} for update;语句,就会使数据库系统锁定该条记录。
乐观锁:
乐观锁认为多个事务并发修改数据库同一条记录这样的情况是不经常发生的,对事务操作加锁也是非必须的,即对此事持乐观态度。但是同样要保证数据的一致性,乐观锁要使用一个标志位来标示是否存在其他事务同时在操作该条数据,这样的标志位大多是基于数据版本(Version)记录机制实现的。
锁的分类(oracle)
1、按操作划分,可分为DML锁、DDL锁
2、按锁的粒度划分,可分为表级锁、行级锁、页级锁(mysql)
3、按锁级别划分,可分为共享锁、排他锁
4、按加锁方式划分,可分为自动锁、显示锁
5、按使用方式划分,可分为乐观锁、悲观锁
五、其他
视图(View)
数据库视图是一张虚表,逻辑上的表,有时为了区别视图和表,也称表为基本表——Base Table。视图所对应的数据不进行实际存储,不占用物理空间。视图掩码数据库的复杂性,视图把数据库设计的复杂性与用户屏蔽分开,也能起到用户程序与实际数据库表结构解耦的作用。
存储过程
存储过程是 SQL 语句和可选控制流语句的预编译集合,以一个名称存储并作为一个单元处理。存储过程存储在数据库内,可由应用程序通过一个调用执行,而且允许用户声明变量、有条件执行以及其它强大的编程功能。
存储过程与函数的区别:
1.一般情况下,函数实现的功能针对性比较强而存储过程实现的功能要复杂一点。
2..存储过程来说可以返回参数,而函数只能返回值或者表对象。
3.一般将存储过程作为一个独立的部分来执行,而把函数作为查询语句的一个部分来调用,由于函数可以返回一个表对象,因此它可以出现在查询语句FROM关键字的后面。
触发器
触发器和存储过程一样,也是一段sql程序。不同的是存储过程通过名字直接调用,而触发器则相当于事件监听器,在某个特定的事件发生时由数据库系统自动调用的。
触发器语法:
create trigger 触发器的名字 on 操作表 befor|after instead of update|insert|delete as SQL语句
在mysql的innoDB引擎下(该引擎下表为事务表),触发器和引起触发器执行的Sql语句具有事务性,如果before类型的触发器执行失败则sql语句不执行,如果sql语句执行失败则after触发器不执行,如果after触发器执行失败则引起触发器执行的sql语句回滚。
游标
游标是一个数据缓冲器,也就是一个内存区域,用来暂时存放受SQL语句影响到的数据。即受影响的数据暂时存放在一张虚表中,这个虚表就是游标。
Orale中游标的类型:
1,隐式游标:在 PL/SQL 程序中执行DML SQL 语句时自动创建隐式游标,名字固定叫sql。数据库中的事物可以回滚,而游标在其中起着非常重要的作用,由于对数据库的操作我们会暂时放在游标中,只要不提交,我们就可以根据游标中内容进行回滚,在一定意义有利于数据库的安全。
2,显式游标:用于从表中取出多行数据,并将多行数据一行一行的单独进行处理.
declare --1,声明游标 cursor cur is select * from user; begin --2,直接使用,Oracle会自动打开和关闭等操作。 for v_user in cur loop dbms_output.put_line(v_user.userName); end loop end;