事务
什么是数据库事务?
数据库的事务(Transaction)包含了一组数据库操作命令。事务把所有的命令作为一个整体一起向系统提交或撤销操作请求,即这一组数据库命令要么都执行,要么都不执行,因此事务是一个不可分割的工作逻辑单元。
在数据库系统上执行并发操作时,事务是作为最小的控制单元来使用的,特别适用于多用户同时操作的数据库系统。例如,航空公司的订票系统、银行、保险公司以及证券交易系统等。
事务最经典例子就是转账了
假如小明要给小红转账1000元,这个转账会涉及到两个关键操作就是:将小明的余额减少1000元,将小红的余额增加1000元。万一在这两个操作之间突然出现错误比如银行系统崩溃,导致小明余额减少而小红的余额没有增加,这样就不对了。应该是出错误了就回滚到之前的状态,那小明就应该是没有减少余额,事务就是保证这两个关键操作要么都成功,要么都要失败。
事物的四大特性(ACID)介绍一下?
关系性数据库需要遵循ACID规则,具体内容如下:
原子性: 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
一致性: 执行事务前后,数据完整性保持一致
隔离性: 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;
持久性: 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
MySQL(InnoDB)事务隔离级别有哪些?
Read Uncommitted(未提交读) >> 在该隔离级别,事务可以读取到其它事务未提交的数据。本隔离级别很少用于实际应用。可能导致脏读(读取未提交的数据,也被称之为脏读)、不可重复读和幻读
Read Committed(提交读) >> 也叫不可重复读,事务所做的修改只有在提交过后才能对其它事务可见。也是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。这种隔离级别可能出现不可重复读和幻读。(事务A读取了两次数据资源,在这两次读取的过程中事务B修改了数据,导致事务A在这两次读取出来的数据不一致。这种在同一个事务中,前后两次读取的数据不一致的现象就是不可重复读)
Repeatable Read(可重读) >>是MySQL的默认事务隔离级别,一个事务中连续执行2次或多次相同的查询,查询的结果集总是一致的。可能会出现幻读,InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control 间隙锁)机制解决了该问题。注:其实多版本只是解决不可重复读问题,而加上间隙锁(也就是它这里所谓的并发控制)才解决了幻读问题。(幻读是指一个事务中连续执行相同的查询,得到的结果集可能不一致(其他事务对数据进行了操作),对比两次的结果集,数据就好像是凭空出现亦或凭空消失)
Serializable(可串行化) >> 这是最高的隔离级别,各种问题(脏读、不可重复读、幻读)都不会发生,通过加锁实现(读锁和写锁)。
什么是脏读?幻读?不可重复读?
1、脏读
读取到另一个事务未提交的数据可能会导致脏读(Dirty Read),脏读也就是读取了错误的数据,不准确的数据来使用
常见的脏读情况如下
- 在事务A执行过程中,事务A对数据资源进行了修改,事务B读取了事务A修改后的数据。由于某些原因,事务A并没有完成提交,发生了RollBack操作,则事务B读取的数据就是脏数据。
2、不可重复读
前后两次读取的数据的值不一致的现象就是不可重复读,例如事务A读取了两次数据资源,在这两次读取的过程中事务B修改了数据,导致事务A在这两次读取出来的数据不一致。
3、幻读
简单说就是同样的条件, 第1次和第2次读出来的记录数不一样,例如假设下面的事务A第一次读10条数据,然后其中没有骚戴这条数据,但是事务B在事务执行的时候插入了一条“骚戴”的数据,事务A同样的查询条件再去读的时候发现读出11条数据,其中有“骚戴”这条数据,这就是幻读,这种情况的出现必须要多个事务并发执行才会发生
例子2
我的理解:幻读就是事务A查询某条数据的时候不存在,然后在准备添加这条数据的之前又有一个事务B插入了这条数据并提交了事务,所以当事务A添加这条数据添加不成功,因为数据库中已经有了,这就导致事务A查询也查询不到这条数据,添加也添加不了这条数据,最后事务A又查询了一次这条数据,惊奇的发现这条数据最后又的确出现在数据库里,从事务A的角度来看就像出现了幻觉,莫名其妙多了一条数据
不可重复读和幻读的区别
- 不可重复读的重点是修改;同样的条件,第1次和第2次读取的值不一样。幻读的重点在于新增或者删除;同样的条件, 第1次和第2次读出来的记录数不一样。
- 从控制角度来看,不可重复读只需要锁住满足条件的记录,幻读要锁住满足条件及其相近的记录。
锁
隔离级别与锁的关系
读未提交
事务读,不阻塞其他事务读和写,事务写,阻塞其他事务写但不阻塞读。
可以通过写操作加“持续-X锁”实现。
读已提交
事务读,不会阻塞其他事务读和写,事务写,会阻塞其他事务读和写。
可以通过写操作加“持续-X”锁,读操作加“临时-S锁”实现。
可重复读
事务读,会阻塞其他事务事务写但不阻塞读,事务写,会阻塞其他事务读和写。
可以通过写操作加“持续-X”锁,读操作加“持续-S锁”实现。
串行化
“行级锁”做不到(X锁和S锁是行级锁),需使用“表级锁”。
区分事务隔离级别是为了解决脏读、不可重复读和幻读三个问题的。
从锁的类别上分MySQL都有哪些锁呢?
按锁的类别来分,锁可以分为共享锁和排它锁,共享锁和排它锁都只是概念,不是具体的锁,共享锁和排他锁在MySQL中具体的实现就是读锁和写锁:
1、读锁(共享锁)
Shared Locks(S锁),针对同一份数据,多个读操作可以同时进行而不会互相影响,但是不能写。
2、写锁(排它锁)
Exclusive Locks(X锁),当前写操作没有完成前,它会阻断其他写锁和读锁
3、IS锁
意向共享锁、Intention Shared Lock。当事务准备在某条记录上加S锁时,需要先在表级别加一个IS锁。
4、IX锁
意向排他锁、Intention Exclusive Lock。当事务准备在某条记录上加X锁时,需要先在表级别加一个IX锁。
IS、IX锁是表级锁,它们的提出仅仅为了快速判断表中的记录是否被上行锁,如果没有这个意向锁那就只能用遍历的方式来查看表中有没有上锁的记录。IS锁和IX锁就避免了判断表中行有没有加锁时对每一行的遍历。直接查看表有没有意向锁就可以知道表中有没有行锁。
注意:如果一个表中有多个行锁,他们都会给表加上意向锁,意向锁和意向锁之间是不会冲突的。
锁的粒度取决于具体的存储引擎,InnoDB实现了行级锁,页级锁,表级锁。他们的加锁开销从大到小,并发能力也是从大到小。
MySQL中InnoDB引擎的行锁是怎么实现的?
答:InnoDB是基于索引来完成行锁
例 : select * from tab_with_index where id = 1 for update;
for update 可以根据条件来完成行锁锁定,并且 id 是有索引键的列,如果 id 不是索引键那么InnoDB将完成表锁,并发将无从谈起
InnoDB存储引擎的行锁的算法?
InnoDB存储引擎有3种行锁的算法,其分别是
- Record Lock:锁定单个行记录
- Gap Lock:间隙锁,锁定一个范围,但不包含记录本身
- Next-Key Lock:Gap Lock + Record Lock,锁定一个范围,并且锁定记录本身
Record Lock总是会锁住索引记录,如果InnoDB存储引擎建立的时候没有设置任何一个索引,这时InnoDB存储引擎会使用隐式的主键来进行锁定。
Next-Key Lock是结合了Gap Lock和Record Lock的一种锁定算法,innodb对于行的查询都是采用Next-Key Lock算法。
什么是死锁?怎么解决?怎么降低死锁?
什么是死锁?
死锁是指两个或者两个以上的事务在执行过程中,因争夺锁资源而造成的一种互相等待的现象。
虽然不能完全避免死锁,但可以使死锁的数量减至最少。将死锁减至最少可以增加事务的吞吐量并减少系统开销,因为只有很少的事务回滚,而回滚会取消事务执行的所有工作。由于死锁时回滚而由应用程序重新提交。
怎么解决?
解决死锁最有用最简单的方法是不要有等待,将任何等待都转化为回滚,并且事务重新开始。但是有可能影响并发性能。
1:超时回滚,即当两个事务互相等待时,当一个等待时间超过设置的某一阀值的时候,其中一个事务进行回滚,另一个事务就能继续进行。在InnoDB引擎中,参数innodb_lock_wait_time用来设置超时的时间。
2:wait-for-graph方法:跟超时回滚比起来,这是一种更加主动的死锁检测方式。InnoDB引擎也采用这种方式。这种方式一般要求数据库保存一下两种信息:锁的信息链表和事务等待链表。
通过这两条链表可以构造出一张图,而在这个图中若存在回路,就代表存在死锁,因此资源间互相发生等待。
在wait-for graph中,事务为图中的节点。而在图中,事务T1指向T2边的定义为:
事务T1等待事务T2所占用的资源
事务T1最终等待T2所占用的资源,也就是事务之间在等待相同的资源,而事务T1发送在事务T2的后面。
从wait-for graph图中我们可以发现存在回路(t1,t2),因此存在死锁。
怎么降低死锁?
下列方法有助于最大限度地降低死锁:
(1)按同一顺序访问对象。
(2)避免事务中的用户交互。
(3)保持事务简短并在一个批处理中。
(4)使用低隔离级别。
按同一顺序访问对象
如果所有并发事务按同一顺序访问对象,则发生死锁的可能性会降低。例如,如果两个并发事务获得 Supplier 表上的锁,然后获得 Part 表上的锁,则在其中一个事务完成之前,另一个事务被阻塞在 Supplier 表上。第一个事务提交或回滚后,第二个事务继续进行。不发生死锁。将存储过程用于所有的数据修改可以标准化访问对象的顺序。
避免事务中的用户交互
避免编写包含用户交互的事务,因为运行没有用户交互的批处理的速度要远远快于用户手动响应查询的速度,例如答复应用程序请求参数的提示。例如,如果事务正在等待用户输入,而用户去吃午餐了或者甚至回家过周末了,则用户将此事务挂起使之不能完成。这样将降低系统的吞吐量,因为事务持有的任何锁只有在事务提交或回滚时才会释放。即使不出现死锁的情况,访问同一资源的其它事务也会被阻塞,等待该事务完成。
保持事务简短并在一个批处理中
在同一数据库中并发执行多个需要长时间运行的事务时通常发生死锁。事务运行时间越长,其持有排它锁或更新锁的时间也就越长,从而堵塞了其它活动并可能导致死锁。
保持事务在一个批处理中,可以最小化事务的网络通信往返量,减少完成事务可能的延迟并释放锁。
使用低隔离级别
确定事务是否能在更低的隔离级别上运行。执行提交读允许事务读取另一个事务已读取(未修改)的数据,而不必等待第一个事务完成。使用较低的隔离级别(例如提交读)而不使用较高的隔离级别(例如可串行读)可以缩短持有共享锁的时间,从而降低了锁定争夺。
mysql里面的乐观锁和悲观锁熟悉吗?
1、乐观锁
顾名思义,就是对数据的处理持乐观态度,乐观的认为数据一般情况下不会发生冲突,只有提交数据更新时,才会对数据是否冲突进行检测。
常规的方式,都是在数据行上加一个版本号或者时间戳等字段
乐观锁的实现原理:
事务A在读取数据时,将对应的版本号字段读取出来,假设此时的版本号是1。
事务B同时也执行的读取操作(注意这个时候事务A和事务B读取的版本号都是1)。当事务A执行完操作后提交事务时,对版本号执行+1(也也就是修改版本号),此时该数据行的版本号就是2。
事务B执行修改操作时,默认增加一个版本号作为where条件(这个版本号还是1,但实际上事务A提交事务后版本号已经变成了2)。此时修改语句中的版本号字段是不满足where条件,该事务执行失败。通过这种方式来达到锁的功能。
乐观锁是基于程序实现的,所以不存在死锁的情况,适用于读多的应用场景。如果经常发生冲突,上层应用不断的让用户进行重新操作,这反而降低了性能,这种情况下悲观锁就比较适用。
2、悲观锁
顾名思义,就是对于数据的处理持悲观态度,总认为会发生并发冲突,获取和修改数据时,别人会修改数据。所以在整个数据处理过程中,需要将数据锁定。
悲观锁的实现,通常依靠数据库提供的锁机制实现,比如mysql的排他锁,select .... for update来实现悲观锁。
注:要使用悲观锁,我们必须关闭mysql数据库的自动提交属性,因为MySQL默认使用autocommit模式,也就是说,当你执行一个更新操作后,MySQL会立刻将结果进行提交。FOR UPDATE必须在事务中才有效,查询和更新必须在同一个事务中!!!
我们可以使用命令设置MySQL为非autocommit模式:
set autocommit=0;
设置完autocommit后,我们就可以执行我们的正常业务了。具体如下:
//0.开始事务 begin;/begin work;/start transaction; (三者选一就可以) //1.查询出商品信息 select status from t_goods where id=1 for update; //2.根据商品信息生成订单 insert into t_orders (id,goods_id) values (null,1); //3.修改商品status为2 update t_goods set status=2; //4.提交事务 commit;/commit work;
注:上面的begin/commit为事务的开始和结束,因为在前一步我们关闭了mysql的autocommit,所以需要手动控制事务的提交。
上面的第一步我们执行了一次查询操作:select status from t_goods where id=1 for update;
与普通查询不一样的是,我们使用了select…for update的方式,这样就通过数据库实现了悲观锁。此时在t_goods表中,id为1的 那条数据就被我们锁定了,其它的事务必须等本次事务提交之后才能执行。这样我们可以保证当前的数据不会被其它事务修改。
注:需要注意的是,在事务中,只有SELECT ... FOR UPDATE 或LOCK IN SHARE MODE 同一笔数据时会等待其它事务结束后才执行,一般SELECT ... 则不受此影响。
拿上面的实例来说,当我执行select status from t_goods where id=1 for update;后。我在另外的事务中如果再次执行select status from t_goods where id=1 for update;则第二个事务会一直等待第一个事务的提交,此时第二个查询处于阻塞的状态,但是如果我是在第二个事务中执行select status from t_goods where id=1;则能正常查询出数据,不会受第一个事务的影响。
3、总结
读取频繁使用乐观锁,写入频繁使用悲观锁。
乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行retry,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适,之所以用悲观锁就是因为两个用户更新同一条数据的概率高,也就是冲突比较严重的情况下,所以才用悲观锁。
悲观锁比较适合强一致性的场景,但效率比较低,特别是读的并发低。乐观锁则适用于读多写少,并发冲突多的场景。
mysql有哪些锁?
i、按照锁粒度来分
当数据库有并发事务的时候,可能会产生数据的不一致,这时候需要锁机制来保证访问的次序
MyISAM和MEMORY采用表级锁(table-level locking)
BDB采用页面锁(page-level locking)或表级锁,默认为页面锁
InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁
1、行级锁
(1) 描述
行级锁是mysql中锁定粒度最细的一种锁。表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突,其加锁粒度最小,但加锁的开销也最大。行级锁分为共享锁和排他锁
(2) 特点
开销大,加锁慢,会出现死锁。发生锁冲突的概率最低,并发度也最高。
(3) InnoDB有三种行锁的算法
Record Lock(记录锁):单个行记录上的锁。这个也是我们日常认为的行锁。
Gap Lock(间隙锁):间隙锁,锁定一个范围,但不包括记录本身(只不过它的锁粒度比记录锁的锁整行更大一些,他是锁住了某个范围内的多个行【这里主要指的是范围,不是记录本身】,包括根本不存在的数据)。GAP锁的目的,是为了防止同一事务的两次当前读,出现幻读的情况。该锁只会在隔离级别是RR或者以上的级别内存在。间隙锁的目的是为了让其他事务无法在间隙中新增数据。
Next-Key Lock(临键锁):它是记录锁和间隙锁的结合,锁定一个范围,并且锁定记录本身。对于行的查询,都是采用该方法,主要目的是解决幻读的问题。next-key锁是InnoDB默认的锁
上面这三种锁都是排它锁(X锁)
2、表级锁
(1) 描述
表级锁是mysql中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分mysql引擎支持。最常使用的MyISAM与InnoDB都支持表级锁定。表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁)
(2) 特点
开销小,加锁快,不会出现死锁。发生锁冲突的概率最高,并发度也最低。
(3)两种表级锁
LOCK TABLE my_table_name READ; 用读锁锁表,会阻塞其他事务修改表数据。
LOCK TABLE my_table_name WRITE; 用写锁锁表,会阻塞其他事务读和写。
MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁,这个过程并不需要用户干预,因此,用户一般不需要直接用LOCK TABLE命令给MyISAM表显式加锁。
但是在InnoDB中如果需要表锁就需要显式地声明了。
3 、页级锁
(1) 描述
页级锁是 MySQL 中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。因此,采取了折中的页级锁,一次锁定相邻的一组记录。BDB 支持页级锁。
(2) 特点
开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
ii、按照锁的共享策略(锁的类别)来分
共享锁和排他锁是概念,在MySQL中具体的实现就是读锁和写锁:
1、读锁(共享锁)
Shared Locks(S锁),针对同一份数据,多个读操作可以同时进行而不会互相影响,但是不能写。
2、写锁(排它锁)
Exclusive Locks(X锁),当前写操作没有完成前,它会阻断其他写锁和读锁
3、IS锁
意向共享锁、Intention Shared Lock。当事务准备在某条记录上加S锁时,需要先在表级别加一个IS锁。
4、IX锁
意向排他锁、Intention Exclusive Lock。当事务准备在某条记录上加X锁时,需要先在表级别加一个IX锁。
为什么要IS和IX锁?
IS、IX锁是表级锁,它们的提出仅仅为了快速判断表中的记录是否被上行锁,如果没有这个意向锁那就只能用遍历的方式来查看表中有没有上锁的记录。IS锁和IX锁就避免了判断表中行有没有加锁时对每一行的遍历。直接查看表有没有意向锁就可以知道表中有没有行锁。
注意:如果一个表中有多个行锁,他们都会给表加上意向锁,意向锁和意向锁之间是不会冲突的。
iii、从加锁策略上分
1、悲观锁
总是假设最坏的情况,悲观锁认为对于同一个数据的并发操作,一定是会发生修改的(或者增删改多,查少),哪怕没有修改,也会认为修改。因此对于同一个数据的并发操作,悲观锁采取加锁的形式,悲观的认为,不加锁的并发操作一定会出问题。
2、乐观锁
乐观锁则认为对于同一个数据的并发操作,是不会发生修改的(或者增删改少,查多)。在更新数据的时候,会采用不断尝试更新的方式来修改数据。也就是先不管资源有没有被别的线程占用,直接取申请操作,如果没有产生冲突,那就操作成功,如果产生冲突,有其他线程已经在使用了,那么就不断地轮询。乐观的认为,不加锁的并发操作是没有事情的。就是通过记录一个数据历史记录的多个版本,如果修改完之后发现有冲突再将版本返回到没修改的样子,乐观锁就是不加锁。好处就是减少上下文切换,坏处是浪费CPU时间。
iv、自增锁(AUTO-INC锁)
自增锁是一种特殊的表级锁,主要用于事务中插入自增字段,也就是我们最常用的自增主键id。通过innodb_autoinc_lock_mode参数可以设置自增主键的生成策略。防止并发插入数据的时候自增id出现异常。
当一张表的某个字段是自增列时,innodb存储引擎会在该索引的末位加一个排它锁。为了访问这个自增的数值,需要加一个表级锁,不过这个表级锁的持续时间只有当前sql,而不是整个事务,即当前sql执行完,该表级锁就释放了。其他session无法在这个表级锁持有时插入任何记录。
select for update是表锁还是行锁?
如果查询条件用了索引/主键,那么select … for update就会进行行锁。
如果查询条件是普通字段(没有索引/主键),那么select … for update就会进行锁表。
好文参考:select......for update会锁表还是锁行。_油锅里的猪的博客-CSDN博客
注意上面的文章里有个没有提交的案例,这跟提不提交没有关系
视图
什么是视图?
MySQL 视图(View)是一种虚拟存在的表,同真实表一样,视图也由列和行构成,但视图并不实际存在于数据库中。视图的数据来源于定义视图查询所引用的真实表中。使用视图查询数据时,数据库会从真实表中取出对应的数据。因此,视图中的数据是依赖于真实表中的数据的。一旦真实表中的数据发生改变,显示在视图中的数据也会发生改变。所以视图是在使用视图时动态生成的
视图可以从原有的表上选取对用户有用的信息,那些对用户没用,或者用户没有权限了解的信息,都可以直接屏蔽掉,作用类似于筛选。这样做既使应用简单化,也保证了系统的安全。
为什么要使用视图/优缺点?
1) 定制用户数据,聚焦特定的数据
在实际的应用过程中,不同的用户可能对不同的数据有不同的要求。
例如,当数据库同时存在时,如学生基本信息表、课程表和教师信息表等多种表同时存在时,可以根据需求让不同的用户使用各自的数据。学生查看修改自己基本信息的视图,安排课程人员查看修改课程表和教师信息的视图,教师查看学生信息和课程信息表的视图。
2) 简化数据操作
在使用查询时,很多时候要使用聚合函数,同时还要显示其他字段的信息,可能还需要关联到其他表,语句可能会很长,如果这个动作频繁发生的话,可以创建视图来简化操作。
3) 提高数据的安全性
视图是虚拟的,物理上是不存在的。可以只授予用户视图的权限,而不具体指定使用表的权限,来保护基础数据的安全。
4) 共享所需数据
通过使用视图,每个用户不必都定义和存储自己所需的数据,可以共享数据库中的数据,同样的数据只需要存储一次。
5) 更改数据格式
通过使用视图,可以重新格式化检索出的数据,并组织输出到其他应用程序中。
6) 重用 SQL 语句
视图提供的是对查询操作的封装,本身不包含数据,所呈现的数据是根据视图定义从基础表中检索出来的,如果基础表的数据新增或删除,视图呈现的也是更新后的数据。视图定义后,编写完所需的查询,可以方便地重用该视图。
视图的缺点?
性能。数据库必须把视图的查询转化成对基本表的查询,如果这个视图是由一个复杂的多表查询所定义,那么,即使是视图的一个简单查询,数据库也把它变成一个复杂的结合体,需要花费一定的时间。
修改限制。当用户试图修改视图的某些行时,数据库必须把它转化为对基本表的某些行的修改。事实上,当从视图中插入或者删除时,情况也是这样。对于简单视图来说,这是很方便的,但是,对于比较复杂的视图, 可能是不可修改的
视图有哪些特点(视图和数据表的区别)?
视图不是数据库中真实的表,而是一张虚拟表,列数据和行数据来自于视图查询所引用的实际表,引用视图时动态生成这些数据。
视图没有实际的物理记录,不是以数据集的形式存储在数据库中的,它所对应的数据实际上是存储在视图所引用的真实表中的。
视图是查看数据表的一种方法,可以查询数据表中某些字段构成的数据,只是一些 SQL 语句的集合。从安全的角度来看,视图的数据安全性更高,使用视图的用户不接触数据表,不知道表结构。
视图的建立和删除只影响视图本身,不影响对应的基本表
总结:视图是数据的窗口,而表是内容。表是实际数据的存放单位,而视图只是以不同的显示方式展示数据,其数据来源还是实际表。
视图的用途和使用场景有哪些?
视图的用途?
视图根本用途在我看来就一个:简化sql查询,提高开发效率。如果说还有另外一个用途那就是兼容老的表结构。
视图的使用场景?
1)计算列的需要
数据库设计范式要求我们减少冗余字段,因此现在很多数据表都没有计算列字段,如采购单:有价格、数量、税率、含税金额,多半没有不含税金额、税额,而这些字段在很多报表中有都会用到,所以我们可以创建一个含有计算列字段的视图来解决这个问题。
2)不同表字段聚合和信息重组
如:经销商通常有业务员,业务员通常有上下级关系(客户经理、区域经理、大区经理等),因此查看经销商业务员时我们需要看到直管业务员是谁?该业务员对应的区域经理、大区经理是谁(可能NULL)?因此我们可以联合经销商表、业务员信息表、业务员上下级关系表定义一个经销商视图。
3)安全性需要
主要是早期遗留系统集成需要,如:需要xx系统数据,又没接口,怎么办?直接操作数据库,这时就涉及数据安全性,合理利用视图则可以减少很多授权工作和保证数据安全性。当下新构建的系统几乎都是暴露api接口,因此数据安全性更多关注在接口的身份认证和数据粒度方面。
4)兼容老的数据表
曾经碰到过这么个问题。 公司自主研发的进销存管理系统,一开始自用的,后来合作伙伴企业也要用,所以打算Saas化,当初做了一个最大的变动就是几乎所有表增加了一个使用单位(co_id)字段。悲催的是另外一个外购系统用到了采购单表,该系统已经停止维护、又继续在用。于是就创建了一个co_id=自有公司的视图,命名为原采购单表,而原采购单表改成新表名。这样一来外购系统可以继续使用,而且数据也没问题。
能否向Mysql视图中插入/更新/删除数据?
要通过视图更新基本表数据,必须保证视图是可更新视图,即可以在INSET、UPDATE或DELETE等语句当中使用它们。对于可更新的视图,在视图中的行和基表中的行之间必须具有一对一的关系。还有一些特定的其他结构,这类结构会使得视图不可更新。
如果视图包含下述结构中的任何一种,那么它就是不可更新的
(1)聚合函数;
(2)DISTINCT关键字;
(3)GROUP BY子句;
(4)ORDER BY子句;
(5)HAVING子句;
(6)UNION运算符;
(7)位于选择列表中的子查询;
(8)FROM子句中包含多个表;
(9)SELECT语句中引用了不可更新视图;
(10)WHERE子句中的子查询,引用FROM子句中的表;
(11)ALGORITHM 选项指定为TEMPTABLE(使用临时表总会使视图成为不可更新的)。
常用SQL语句
SQL语句主要分为哪几类
结构化查询语言(Structured Query Language)简称SQL,是一种数据库查询语言。
作用:用于存取数据、查询、更新和管理关系数据库系统。
如大家所知 sql语句被分为四大类
- 数据定义语言DDL
- 数据查询语言DQL
- 数据操纵语言DML
- 数据控制功能DCL