数据库知识点总结

一、 left join, right join, inner join区别?

  • left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录
  • right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录
  • inner join(等值连接) 只返回两个表中联结字段相等的行

注意:在某些数据库中left join等同于left outer join

举个例子:
表A记录如下

aID aNum
1 a20050111
2 a20050112
3 a20050113
4 a20050114
5 a20050115

表B记录如下

bID bName
1 2006032401
2 2006032402
3 2006032403
4 2006032404
8 2006032408



1、sql语句如下:

select * from A
left join B
on A.aID = B.bID

结果如下:

aID aNum bID bName
1 a20050111 1 2006032401
2 a20050112 2 2006032402
3 a20050113 3 2006032403
4 a20050114 4 2006032404
5 a20050115 NULL NULL

(所影响的行数为5行)
结果说明:
left join是以A表的记录为基础的,A可以看成左表,B可以看成右表,left join是以左表为准的。换句话说,左表(A)的记录将会全部表示出来,而右表(B)只会显示符合搜索条件的记录(例子中为:A.aID = B.bID)。B表记录不足的地方均为NULL。

2、sql语句如下:

select * from A
right join B
on A.aID =B.bID

结果如下:

aID aNum bID bName
1 a20050111 1 2006032401
2 a20050112 2 2006032402
3 a20050113 3 2006032403
4 a20050114 4 2006032404
NULL NULL 8 2006032408

(所影响的行数为5行)
结果说明
仔细观察一下,就会发现,和left join的结果刚好相反,这次是以右表(B)为基础的,A表不足的地方用NULL填充。

3、sql语句如下:

select * from A
inner join B
on A.aID = B.bID

结果如下:

aID aNum bID bName
1 a20050111 1 2006032401
2 a20050112 2 2006032402
3 a20050113 3 2006032403
4 a20050114 4 2006032404

结果说明:
很明显,这里只显示出了A.aID = B.bID的记录,这说明inner join并不以谁为基础,它只显示符合条件的记录。

二、 存储引擎MyIsam和Innodb区别?

(1)MyIsam类型不支持事务处理等高级处理,而Innodb类型支持
事务处理是指原子性操作。例如,支持事务处理的Innodb表中,你发了一个帖子执行insert语句,来插入帖子内容,插入后要执行一个update语句来增加你的积分。假设一种特殊情况突然发生,insert成功了,update操作却没有被执行。也就是说你发了帖子却没有增加相应的积分。这就会造成用户不满。如果使用了事务处理,insert和update都放入到事务中去执行,这个时候,只有当insert和update两条语句都执行生成的时候才会将数据更新、写入到表中。如果其中任何一条语句失败,那么就会回滚为初始状态,不执行写入。这样就保证了insert和update肯定是一同执行的。

(2)MyIsam表不支持外键。innodb支持外键

(3)在执行数据写入的操作(insert,update,delete)的时候,MyIsam表会锁表,而innodb表会锁行。
通俗的讲,就是你执行一个update语句,那么MyIsam表会将整个表都锁住,其他的insert和delete、update都会被拒之门外,等到这个update语句执行完成后才会被依次执行。而锁行,就是说,你执行update语句时,只会将这一条记录进行锁定,只有针对这条记录的其他写入、更新操作会被阻塞并等待这条update语句执行完毕后再执行,针对其他记录的写入操作不会有影响。但是innodb表的行锁也不是绝对的,如果在执行一个sql语句时,mysql不能确定要扫描的范围,innodb表同样会锁全表,例如update table set num =1 where name like “%aaa%”

(4)表的具体行数
select count(*) from table , MyIsam只要简单的读出保存好的行数,注意的是,当count(*)语句包含where条件时,两种表的操作是一样的。
innodb中不保存表的具体行数,也就是说,执行select count(*) from table时,innodb要扫描一遍整个表来计算有多少行。

总结
因此,当你的数据库有大量的写入、更新操作而查询比较少或者数据完整性要求比较高的时候就选择innodb表。当你的数据库主要以查询为主,相比较而言更新和写入比较少,并且业务方面数据完整性要求不那么严格,就选择myisam表。因为MyIsam表的查询操作效率和速度都比innodb要快。

InnoDB的设计目标是处理大容量数据库系统,它的CPU利用率是其它基于磁盘的关系数据库引擎所不能比的。

我觉得使用InnoDB可以应对更为复杂的情况,特别是对并发的处理要比MyISAM高效。同时结合memcache也可以缓存SELECT来减少SELECT查询,从而提高整体性能。

使用以下mysql sql语句,可以给表设定数据库引擎:

ALTER TABLE `wp_posts` ENGINE = MyISAM;

查看当前数据库的引擎,可看出默认是InnoDB类型。

三、 mysql的优化手段有哪些?

MYSQL数据库优化的八种方式:
(1)选取最适用的字段属性
MYSQL可以很好的支持大数据量的存取,但是一般来说,数据库中的表越小,在它上面执行的查询也就会越快。因此,在创建表的时候,为了获得更好的性能,我们可以将表中字段的宽度设得尽可能小。
例如,在定义邮政编码这个字段时,如果将其设置为CHAR(255),显然给数据库增加了不必要的空间,甚至使用VARCHAR这种类型也是多余的,因为CHAR(6)就可以很好的完成任务了。同样的,如果可以的话,我们应该使用MEDIUMINT而不是BIGINT来定义整型字段。
另外一个提高效率的方法是在可能的情况下,应该尽量把字段设置为NOT NULL,这样在将来执行查询的时候,数据库不用去比较NULL值。
对于某些文本字段,例如“省份”或者“性别”,我们可以将它们定义为ENUM类型。因为在MYSQL中,ENUM类型被当做数值型数据来处理,而数值型数据被处理起来的速度要比文本类型快得多。这样,我们又可以提高数据库的性能。

(2)使用连接(JOIN)来代替子查询(Sub-Queries)
例如:我们要将客户基本信息表中没有任何订单的客户删除掉,就可以利用子查询先从销售信息表中将所有发出订单的客户ID取出来,然后将结果传递给主查询,如下所示:

SELECT* FROM customerinfo
WHERE customerID NOT in (SELECT customerid FROM salesinfo)

如果使用连接(JOIN)来完成这个查询工作,速度将会快很多。尤其是当salesinfo表中对CustomerID建有索引的话,性能将会更好。查询如下:
SELECT * FROM customerinfo
LEFT JOIN salesinfo ON customerinfo.customerid = salesinfo.customerif
Where salesinfo.customerid is NULL

连接(JOIN)之所以更有效率一些,是因为MYSQL不需要在内存中创建临时表来完成这个逻辑上的需要两个步骤的查询工作。

(3)使用联合(UNION)来代替手动创建的临时表
UNION查询可以把需要使用临时表的两条或更多的select查询合并在一个查询中。在客户端的查询会话结束的时候,临时表会被自动删除,从而保证数据库整齐、高效。使用union来创建查询的时候,我们只需要用union作为关键字把多个select语句连接起来就可以了,要注意的是所有select语句中的字段数目要相同。
例子:

Select name, phone from client union
Select name, birthdate from author union
Select name, supplier from product

(4)事务
尽管我们可以使用子查询、连接(join)和联合(union)来创建各种各样的查询,但不是所有的数据库操作都可以只用一条或少数几条sql语句就可以完成的。更多的时候是需要用到一系列的语句来完成某种工作。但是如果这个语句块中的某一条语句运行出错的时候,整个语句块的操作就会变得不确定起来。因此要尽量使用事务,它的作用:要么语句块中每条语句都操作成功,要么都失败。换句话说,就是可以保持数据库中数据的一致性和完整性。事务以BEGIN关键字开始,COMMIT关键字结束。在这之间的一条SQL操作失败,那么,rollback命令就可以把数据库恢复到BEGIN开始之前的状态。
例子:

BEGIN:
    INSERT INTO  salesinfo SET customerid = 14;
    UPDATE inventory SET quantity = 11 WHERE item=‘book’;
COMMIT;

事务的另一个重要作用是当多个用户同时使用相同的数据源时,它可以利用锁定数据库的方法来为用户提供一种安全的访问方式,这样可以保证用户的操作不被其他的用户所干扰。

(5)锁定表
通过锁定表来防止其他的访问对我们正在操作的表进行插入、更新或者删除的操作。
例子:

LOCK TABLE inventory WRITE SELECT quantity FROM inventory WHERE item=‘book’;
…
UPDATE inventory SET Quantity=11 WHERE Item=‘book’; UNLOCKTABLES

这里,我们用一个select语句取出初始数据,通过一些计算,用update语句将新值更新到表中。包含有WRITE关键字的LOCKTABLE语句可以保证在UNLOCKTABLES命令被执行之前,不会有其他的访问来对inventory进行插入、更新或者删除的操作。

(6)使用外键
锁定表的方法可以维护数据的完整性,但是它却不能保证数据的关联性。这个时候我们就可以使用外键。

(7)使用索引
索引是提高数据库性能的常用方法,它可以令数据库服务器以比没有索引快得多的速度检索特定的行,尤其是在查询语句当中包含有MAX(),MIN()和ORDERBY这些命令的时候,性能提高更为明显。
对哪些字段建立索引?
索引应建立在那些将用于JOIN,WHERE判断和ORDERBY排序的字段上。
全文索引在MYSQL中是一个FULLTEXT类型索引,但仅能用于MYISAM类型的表。对于一个大的数据库,将数据装载到一个没有FULLTEXT索引的表中,然后再使用ALTERTABLE或CREATEINDEX创建索引,将是非常快的。但如果将数据装载到一个已经有FULLTEXT索引的表中,执行过程将会非常慢。

(8)优化查询语句
1、最好在相同类型的字段间进行比较的操作
2、在建有索引的字段上尽量不要使用函数进行操作。
例如,在一个DATE类型的字段上使用YEAR()函数时,将会使索引不能发挥应有的作用。所以下面的两个查询虽然返回的结果一样,但后者要比前者快的多。
3、在搜索字符型字段时,我们有时会使用LIKE关键字和通配符,这种做法虽然简单,但却也是以牺牲系统性能为代价的。
例如下面的查询将会比较表中的每一条记录

SELECT * FROM books WHERE name like “MYSQL%”

但是如果换用下面的查询,返回的结果一样,但速度就要快上很多

SELECT * FROM books WEHRE name>=“MYSQL” and name < “MYSQM”

最后,应该注意避免在查询中让MYSQL进行自动类型转换,因为转换过程也会使索引变得不起作用。

四、 如何查看Mysql执行计划?

mysql的查看执行计划的语句:explain+你要执行的sql语句
例如:


id是一组数字,表示查询中执行select子句或操作表的顺序。id如果相同,则可以认为是一组,从上往下顺序执行,所有组中,id越高,优先级越高,越容易执行。
select_type有simple,primary,subquery,derived(衍生),union,unionresult.
simple表示查询中不包含子查询或者union。
当查询中包含任何复杂的子部分,最外层的查询被标记成primary。在select或where列表中包含了子查询,则子查询被标记成subquery。在from的列表中包含的子查询被标记成derived。....省略
参考网址:
http://www.cnblogs.com/ggjucheng/archive/2012/11/11/2765237.html

mysql执行计划的局限

  1. explain不会告诉你关于触发器、存储过程的信息或用户自定义函数对查询的影响情况。
  2. explain不考虑各种cache
  3. explain不能显示mysql在执行查询时所做的优化工作
  4. 部分统计信息是估算的,并非精确值
  5. explain只能解释select操作,其他操作要重写为select后查看执行计划。

五、 索引是什么? 有什么用? 如何建立? 索引的底层实现是什么? 什么情况下适合建立索引, 什么情况下不适合建立索引?

(1)什么索引?
数据库索引,是帮助数据库系统高效获取数据的数据结构,以协助快速查询、更新数据库表中数据。

(2)建立索引的目的?
在数据库系统中建立索引主要有以下作用:

  1. 大大加快数据的检索速度(最主要原因,)
  2. 保证数据记录的唯一性(通过建立唯一性索引,可以保证数据库中每一行数据的唯一性)
  3. 可以加速表和表之间的连接,实现表与表之间的参照完整性
  4. 在使用order by、group by子句(分组和排序子句)进行数据检索时,利用索引可以显著减少分组和排序的时间。

(3)缺点

  1. 索引需要占物理内存
  2. 当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,降低了数据的维护速度

(4)mysql是使用B+树实现其索引结构

(5)创建索引的办法:

  1. 直接创建索引
    例如使用create index语句或者使用创建索引向导
  2. 间接创建索引
    例如在表中定义主键约束或者唯一性键约束时,同时也创建了索引。

当在表中定义主键或者唯一性键约束时,如果表中已经有了使用create index语句创建的标准索引时,那么主键约束或者唯一性键约束创建的索引覆盖以前创建的标准索引。也就是说,主键约束或者唯一性键约束创建的索引的优先级高于使用create index语句创建的索引。

(6)几种索引类型的比较
聚集索引:物理存储按照索引排序(表中行的物理顺序与键值的索引顺序相同),叶子结点即存储了真实的数据行。
非聚集索引:物理存储位置不按照索引排序,叶子结点包含索引字段值及指向数据页数据行的逻辑指针。

一张表中只能创建一个聚集索引,但表中的每一列都可以有自己的非聚集索引。

唯一性索引:这一列数据不重复,只能一个为NULL
主键索引:主键索引是唯一索引的特定类型。不重复,不允许为空。主键只能有一个。
普通索引:create index等建立的索引,alter tablename add index ...

(7) 外键约束的要求:

  1. 父表和子表必须使用相同的存储引擎,而且禁止使用临时表。
  2. 数据表的存储引擎只能为InnoDB。
  3. 外键列和参照列必须具有相似的数据类型。其中数字的长度或是否有符号位必须相同;而字符的长度则可以不同。
  4. 外键列和参照列必须创建索引。如果外键列不存在索引的话,MySQL将自动创建索引。

六、 什么是存储过程?有什么好处?

(1)什么是存储过程?
存储过程是一个被定义并保存在数据库服务器中的sql语句集,是一种介于应用程序和数据库间的编程接口,也是封装重复性工作的一种有效方法,它支持用户变量、条件执行及其它的编程功能。

(2)存储过程的语法

CREATE PROCEDURE procedure_name([paramters[,...]])[attributes]
BEGIN
    body_statement
END;

注:
procedure_name:存储过程的名字
paramters:存储过程的过程参数,包含:IN、OUT及INOUT。IN代表输入或传入值,在存储过程中被修改,但不返回;OUT代表输出或传出值,在存储过程中被修改,并返回;INOUT代表输入输出,在存储过程中被修改,并返回;body_statement:存储过程体,这里可以放入sql集,也可以内嵌存储过程。

好处:
相对于直接使用sql语句,在应用程序中直接调用存储过程有以下好处:
(1)减少网络通信量。调用一个行数不多的存储过程与直接调用sql语句的网络通信量可能不会有很大的差别,可是如果存储过程包含上百行sql语句,那么其性能绝对比一条一条的调用sql语句要高的多。
(2)执行速度更快。有两个原因:首先,在存储过程创建的时候,数据库已经对其进行了一次解析和优化。其次,存储过程一旦执行,在内存中就会保留一份这个存储过程,这样下次再执行同样的存储过程时,可以从内存中直接调用。
(3)更强的适应性:由于存储过程对数据库的访问时通过存储过程来进行的,因此数据库开发人员可以在不改动存储过程接口的情况下对数据库进行任何改动,而这些改动不会对应用程序造成影响。
(4)布式工作:应用程序和数据库的编码工作可以分别独立进行,而不会相互压制。

七、 乐观锁和悲观锁是什么?

乐观锁和悲观锁是两种并发控制机制。
首先了解一下为什么需要锁(并发控制)?
在多用户环境中,在同一时间可能会有多个用户更新相同的记录,这会产生冲突。这就是著名的并发性问题

典型的冲突有
(1)丢失更新:一个事务的更新覆盖了其他事务的更新结果,这就是所谓的更新丢失。例如:用户A把值从6改为2,用户B把值从2改为6,则用户A丢失了他的更新。
(2)脏读:当一个事务读取其它完成一半事务的记录时,就会发生脏读取。例如:用户A,B看到的值都是6,用户B把值改为2,用户A读到的值仍为6.
为了解决这些并发带来的问题,我们需要引入并发控制机制。

并发控制机制
最常用的处理多用户并发访问的方法是加锁。当一个用户锁住数据库中的某个对象时,其他用户就不能再访问该对象。加锁对并发访问的影响体现在锁的粒度上。比如,放在一个表上的锁限制对整个表的并发访问;放在数据页上的锁限制了对整个数据页的访问;放在行上的锁只限制对该行的并发访问。可见行锁粒度最小,并发访问最好,页锁粒度最大,表锁介于两者之间。

悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作
悲观锁假定其他用户企图访问或者改变你正在访问、更改的对象的概率是很高的,因此在悲观锁的环境中,在你开始改变此对象之前就将该对象锁住,并且直到你提交了所作的更改之后才释放锁。悲观的缺陷是不论是页锁还是行锁,加锁的时间可能会很长,这样可能会长时间的限制其他用户的访问,也就是说悲观锁的并发访问性不好。

乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性
乐观锁不能解决脏读的问题。乐观锁则认为其他用户企图改变你正在更改的对象的概率是很小的,因此乐观锁直到你准备提交所作的更改时才将对象锁住,当你读取以及改变该对象时并不加锁。可见乐观锁加锁的时间要比悲观锁短,乐观锁可以用较大的锁粒度获得较好的并发访问性能。但是如果第二个用户恰好在第一个用户提交更改之前读取了该对象,那么当他完成了自己的更改进行提交时,数据库就会发现该对象已经变化了,这样,第二个用户不得不重新读取该对象并作出更改。这说明在乐观锁环境中,会增加并发用户读取对象的次数。

乐观锁的应用
(1)使用自增长的整数表示数据版本号。更新时检查版本号是否一致,比如数据库中数据版本为6,更新提交时version=6+1,使用该version值(=7)与数据库version+1(=7)作比较,如果相等,则可以更新,如果不等则有可能其他程序已更新该记录,所以返回错误。
(2)使用时间戳来实现。

悲观锁应用
需要使用数据库的锁机制,比如SQL server的TABLOCKX(排它表锁)此选项被选中时,SQL server将在整个表上置排它锁直至该命令或事务结束。这将防止其他进程读取或修改表中的数据。

总结
在实际生产环境里边,如果并发量不大且不允许脏读,可以使用悲观锁解决并发问题;但如果系统的并发非常大的话,悲观锁定会带来非常大的性能问题,所以我们就要选择乐观锁定的方法。

八、 表锁、页锁、行锁的区别?

行级锁是mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但加锁的开销也最大。行级锁分为共享锁和排他锁。
特点:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

表级锁是mysql中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分Mysql引擎支持。最常使用的myisam和innodb都支持表级锁定。表级锁定分为表共享读锁(共享锁)和表独占写锁(排他锁)。
特点:开销小,加锁快;不会出现死锁;锁定粒度大,发出锁冲突的概率最高,并发度最低。

页级锁是mysql钟锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。所以取了折中的页级,一次锁定相邻的一组记录。BDB支持页级表。
特点:开销和加锁时间介于表锁和行锁之间;会出现死锁;锁定粒度介于表锁和行锁之间,并发度一般。

上述三种锁的特性可大致归纳如下:
1) 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
2) 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
3) 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

九、 having和where的区别?

where语句在group by语句之前,sql会在分组之前计算where语句。
having语句在group by语句之后,sql会在分组之后计算having语句。

where是一个约束声明,使用where约束来自数据库的数据,where是在结果返回之前起作用的,where中不能使用聚合函数。having是一个过滤声明,是在查询返回结果集以后对查询结果进行的过滤操作,在having中可以使用聚合函数。
在查询过程中聚合语句(sum,min,max,avg,count)要比having子句优先执行。而where子句在查询过程中执行优先级高于聚合语句。

例一:要查找平均工资大于3000的部门,则sql语句应为:

select department, avg(salary) as average from salary_info
group by department having average>3000

此时只能使用having,而不能使用where。一来,我们要使用聚合语句avg;二来,我们要对聚合后的结果进行筛选(average>3000),因此使用where会被告知sql有误。

例二:要查询每个部门工资大于3000的员工个数

select department, count(*) as c from salary_info
where salary>3000 group by department.

此处的where不可用having进行替换,因为是直接对库中的数据进行筛选,而非对结果集进行筛选。

where和having的执行级别不同
在查询过程中聚合语句(sum,min,max,avg,count)要比having子句优先执行.而where子句在查询过程中执行优先级别优先于聚合语句(sum,min,max,avg,count)。
having就是来弥补where在分组数据判断时的不足。因为where执行优先级别要快于聚合语句。

十、 事务的隔离级别?

隔离级别 脏读 不可重复读 幻读
未提交读 可能 可能 可能
已提交读 不可能 可能 可能
可重复读 不可能 不可能 可能
可串行化 不可能 不可能 不可能



未提交读:允许脏读,也就是可能读取到其他会话中未提交事务修改的数据。
已提交读:只能读取到已经提交的数据。Oracle等多数数据库默认是该级别(不重复读)。
可重复读:在同一个事务内的查询都是事务开始时刻一致的,innodb默认级别。在sql标准中,该隔离级别消除了不可重复读,但是还存在幻象读。
串行读:完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞。

四个级别逐渐增强,每个级别解决一个问题。事务级别越高,性能越差

脏读:是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。

不可重复读:是指在一个事务中,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。

可重复读:第一个事务两次读到的数据是一样的。

幻读:第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改了这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好像发生了幻觉一样。
本事务中第一次读取出一行,做了一次更新后,另一个事务里提交的数据就出现了。也可以看做是一种幻读。

一道笔试题:
小桔A在事务1中第一次读取年龄20岁的员工总数为1000人,之后小桔B在事务2中增加了100名年龄20岁的新员工,之后小桔A在事务1中再次读取年龄20岁的员工数发现总数变为1100人,属于()?
A、脏读
B、不可重复读
C、幻读
选C
幻读的重点在于新增或者删除
同样的条件,第一次和第二次读出来的记录数不一样
例子:
目前工资为1000的员工有10人
事务1,读取所有工资为1000的员工,共读取10条记录。
这时另一个事务向employee表插入了一条员工记录。
事务1再次读取所有工资为1000的员工共读取到了11条记录,这就产生了幻像读

不可重复读的重点是修改
同样的条件,你读取过的数据,再次读取出来发现值不一样了
例如:
在事务1中,Mary读取了自己的工资为1000,操作并没有完成。
在事务2中,这时财务人员修改了Mary的工资为2000,并提交了事务。
在事务1中,Mary再次读取自己的工资时,工资变味了2000。

脏读:
脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。

十一、 事务的特点有哪些?

ACID含义:
原子性(Atomicity):一个事务要么发生,要么不发生。
例如故障发生在write(A)和read(B)之间,则将有可能造成账户A的余额已经减少50元钱,而账户B的余额却没有改变,凭空就少了50元钱。
一致性(Consistency):数据库中数据的完整性,保证他们的正确性。
隔离性(Isolation):多个事务并发(同时)执行,互相不影响
持久性(Durability):每个事务成功执行后对数据库的修改是永久的。即使系统出现故障也不受影响。

十二、 触发器是什么?

触发器是SQL server提供给程序员和数据分析员来保证数据完整性的一种方法,它是与表事件相关的特殊存储过程,它的执行不是由程序调用,也不是手工启动,而是由事件触发。比如当对一个表进行操作(insert,delete,update)时就会激活它执行。触发器经常用于加强数据的完整性约束和业务规则等。

在mysql中,创建触发器语法如下:

Create trigger trigger_name trigger_time trigger_event on tbl_name for each row trigger_stmt

其中:
Trigger_name:标识触发器名称,用户自行指定
trigger_time:标识触发时机,取值为before或after
Trigger_event:标识触发事件,取值为insert,update或delete
Tbl_name:标识建立触发器的表名,即在哪张表上建立触发器
Trigger_stmt:触发器程序体,可以是一句sql语句,或者用begin和end包含的多条语句。

由此可见,可以建立6种触发器,即:before insert、before update、before delete、after insert、after update、after delete。
注意:不能同时在一个表上建立2个相同类型的触发器,因此在一个表上最多建立6个触发器。

SQL Server包括三种常规类型的触发器:DML触发器、DDL触发器和登录触发器

DML触发器
当数据库中表中的数据发生变化时,包括insert,update,delete任意操作,如果我们对该表写了对应的DML触发器,那么该触发器自动执行。DML触发器的主要作用在于强制执行业务规则,以及扩展sql server约束,默认值等。因为我们知道约束只能约束同一个表中的数据,而触发器中则可以执行任意sql命令。

DDL触发器
主要用于审核与规范对数据库中表,触发器,视图等结构上的操作。比如在修改表,修改列,新增表,新增列等。它在数据库结构发生变化时执行,我们主要用它来记录数据库的修改过程,以及限制程序员对数据库的修改,比如不允许删除某些指定表等。

登录触发器
登录触发器将为响应LOGIN事件而激发存储过程。与SQL server实例建立用户会话时将引发此事件。登陆触发器将在登录的身份验证阶段完成之后且用户会话实际建立之前激发。因此,来自触发器内部且通常将到达用户的所有消息会传送到SQL Server错误日志。如果身份验证失败,将不激发登录触发器。

触发器的作用:
1、可在写入数据表前,强制检验或转换数据
2、触发器发生错误时,异动的结果会被撤销
3、部分数据库管理系统可以针对数据定义语言(DDL)使用触发器,称为DDL触发器
4、可依照特定的情况,替换异动的指令(INSTEAD OF)

DML触发器又可分为After触发器和Instead Of触发器
(1)After触发器:这类触发器是在记录已经改变完之后(after),才会被激活执行,它主要是用于记录变更后的处理或检查,一旦发现错误,也可以用Rollback Transaction语句来回滚本次的操作。
(2)Instead of触发器:这类触发器一般是用来取代原本的操作,在记录变更之前发生的,它并不去执行原来SQL语句里的操作(insert、update、delete),而去执行触发器本身所定义的操作。
在SQL Server里,每个DML触发器都分配有两个特殊的表,一个是Inserted表,一个是Deleted表。它们两个存在于数据库服务器的内存中,是由系统管理的逻辑表,是两个临时表,而不是真正存储在数据库中的物理表。用户对这两个表只有读取的权限,没有修改的权限。
这两个表的结构(主外键、字段、数据类型等)与触发器所在数据表的结构是完全一致的,当触发器的工作完成之后,这两个表也将会从内存中删除。

Inserted和Deleted两个表的作用:
Inserted:对于插入记录操作来说,插入表里存放的是要插入的数据;对于更新记录操作来说,插入表里存放的是要更新的记录。
Deleted:对于更新记录操作来说,删除表里存放的是被更新记录;对于删除记录操作来说,删除表里存入的是被删除的旧记录。

激活触发器的操作 Inserted表 Deleted表
Insert 存放要插入到表中的数据
Update 存放要更新到表中的数据 存放被更新的记录
Delete 存放要删除的记录



网上找的一张图,可以帮助理解一下过程。

注意事项:
(1)只有表才可以支持触发器,视图和临时表都不支持触发器
(2)每个表的每个事件只支持一个触发器,因此每个表最多支持6个触发器(触发器应该相应的行动insert,delete,update,触发器何时执行before,after,2*3=6种)
(3)单一触发器不能与多个操作相关
(4)触发器不能更新和覆盖,如果想更新一个触发器必须先删除,再创建。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • MySQL技术内幕:InnoDB存储引擎(第2版) 姜承尧 第1章 MySQL体系结构和存储引擎 >> 在上述例子...
    沉默剑士阅读 7,388评论 0 16
  • 实体-联系模型 基本概念 实体和属性 实体是客观存在并且可以相互区分的任何事物属性是实体所代表事物具有的某种特性每...
    我家有个小太阳阅读 6,718评论 1 8
  • 索引的实现方式 1、B+树我们经常听到B+树就是这个概念,用这个树的目的和红黑树差不多,也是为了尽量保持树的平衡,...
    大黄大黄大黄阅读 2,365评论 1 14
  • 前些年的一天,与老姑聊天我问:为什么我们家里人都怕被夸呢? 老姑说:怎么可能呢?谁都喜欢好听的话,谁还不愿意被人夸...
    子兴阅读 665评论 2 8
  • 幸福邦,帮天下! 周末的早晨,打开手机,微信里收到一段语音,一位朋友哭着向我倾诉:我分手了,好痛苦,失眠睡不着,虽...
    幸福帮阅读 376评论 0 0