数据库隔离
‘壹’ 什么是信息系统和数据库的物理隔离
数据库的服务器和信息系统的服务器物理上是隔离的,不在同一服务器,同一网段。
‘贰’ 怎么查看数据库隔离级别
修改方法
有两种方法可以对配置了 systemd 的程序进行资源隔离:1. 命令行修改:通过执行systemctl set-property命令实现,形式为systemctl set-propertyname parameter=value;修改默认即时生效。2. 手工修改文件:直接编辑程序的 systemd unit file 文件,完成之后需手工执行systemctldaemon-reload更新配置,并重启服务systemctl restart name.service。
systemd unit file 里支持的资源隔离配置项,如常见的:
CPUQuota=value
该参数表示服务可以获取的最大 CPU 时间,value 为百分数形式,高于 100% 表示可使用1 核以上的CPU。与 cgroup cpu 控制器cpu.cfs_quota_us配置项对应。
MemoryLimit=value
该参数表示服务可以使用的最大内存量,value 可以使用 K, M, G, T 等后缀表示值的大小。与 cgroupmemory 控制器memory.limit_in_bytes配置项对应。
事务的4种隔离级别
READ UNCOMMITTED 未提交读,可以读取未提交的数据。
READ COMMITTED 已提交读,对于锁定读(select with for update 或者 for share)、update 和 delete 语句,InnoDB 仅锁定索引记录,而不锁定它们之间的间隙,因此允许在锁定的记录旁边自由插入新记录。
Gap locking 仅用于外键约束检查和重复键检查。
REPEATABLE READ 可重复读,事务中的一致性读取读取的是事务第一次读取所建立的快照。
SERIALIZABLE 序列化在了解了 4 种隔离级别的需求后,在采用锁控制隔离级别的基础上,我们需要了解加锁的对象(数据本身&间隙),以及了解整个数据范围的全集组成。
数据范围全集组成
sql 语句根据条件判断不需要扫描的数据范围(不加锁);
SQL 语句根据条件扫描到的可能需要加锁的数据范围;
以单个数据范围为例,数据范围全集包含:(数据范围不一定是连续的值,也可能是间隔的值组成)
‘叁’ 数据库事务隔离级别 一般用哪个
术式之后皆为逻辑,一切皆为需求和实现。希望此文能从需求、现状和解决方式的角度帮大家理解隔离级别。
隔离级别的产生
在串型执行的条件下,数据修改的顺序是固定的、可预期的结果,但是并发执行的情况下,数据的修改是不可预期的,也不固定,为了实现数据修改在并发执行的情况下得到一个固定、可预期的结果,由此产生了隔离级别。
所以隔离级别的作用是用来平衡数据库并发访问与数据一致性的方法。
事务的4种隔离级别
READ UNCOMMITTED 未提交读,可以读取未提交的数据。READ COMMITTED 已提交读,对于锁定读(select with for update 或者 for share)、update 和 delete 语句, InnoDB 仅锁定索引记录,而不锁定它们之间的间隙,因此允许在锁定的记录旁边自由插入新记录。 Gap locking 仅用于外键约束检查和重复键检查。REPEATABLE READ 可重复读,事务中的一致性读取读取的是事务第一次读取所建立的快照。SERIALIZABLE 序列化
在了解了 4 种隔离级别的需求后,在采用锁控制隔离级别的基础上,我们需要了解加锁的对象(数据本身&间隙),以及了解整个数据范围的全集组成。
数据范围全集组成
SQL 语句根据条件判断不需要扫描的数据范围(不加锁);
SQL 语句根据条件扫描到的可能需要加锁的数据范围;
以单个数据范围为例,数据范围全集包含:(数据范围不一定是连续的值,也可能是间隔的值组成)
1. 数据已经填充了整个数据范围:(被完全填充的数据范围,不存在数据间隙)
整形,对值具有唯一约束条件的数据范围 1~5 ,
已有数据1、2、3、4、5,此时数据范围已被完全填充;
整形,对值具有唯一约束条件的数据范围 1 和 5 ,
已有数据1、5,此时数据范围已被完全填充;
整形的数据范围 1~5 ,
已有数据 1、2、3、4、5,但是因为没有唯一约束,
所以数据范围可以继续被 1~5 的数据重复填充;
整形,具有唯一约束条件的数据范围 1~5 ,
已有数据 2,5,此时数据范围未被完全填充,还可以填充 1、3、4 ;
整形的数据范围 1~5 ,数据范围内当前没有任何数据。
更新丢失:当多个事务选择了同一行,然后基于最初选定的值更新该行时,
由于每个事物不知道其他事务的存在,最后的更新就会覆盖其他事务所做的更新;
脏读: 一个事务正在对一条记录做修改,这个事务完成并提交前,这条记录就处于不一致状态。
这时,另外一个事务也来读取同一条记录,如果不加控制,
第二个事务读取了这些“脏”数据,并据此做了进一步的处理,就会产生提交的数据依赖关系。
这种现象就叫“脏读”。
不可重复读:一个事务在读取某些数据后的某个时间,再次读取以前读过的数据,
却发现其读出的数据已经发生了改变,或者某些记录已经被删除了。
这种现象就叫“不可重复读”。
幻读:一个事务按相同的查询条件重新读取以前检索过的数据,
却发现其他事务插入了满足其查询条件的新数据,这种现象称为“幻读”。
可以简单的认为满足条件的数据量变化了。
Record Locks
索引记录锁,索引记录锁始终锁定索引记录,即使表中未定义索引,
这种情况下,InnoDB 创建一个隐藏的聚簇索引,并使用该索引进行记录锁定。
Gap Locks
间隙锁是索引记录之间的间隙上的锁,或者对第一条记录之前或者最后一条记录之后的锁。
间隙锁是性能和并发之间权衡的一部分。
对于无间隙的数据范围不需要间隙锁,因为没有间隙。
Next-Key Locks
索引记录上的记录锁和索引记录之前的 gap lock 的组合。
假设索引包含 10、11、13 和 20。
可能的next-key locks包括以下间隔,其中圆括号表示不包含间隔端点,方括号表示包含端点:
(负无穷大, 10] (10, 11] (11, 13] (13, 20] (20, 正无穷大) 对于最后一个间隔,next-key将会锁定索引中最大值的上方,
2. 数据填充了部分数据范围:(未被完全填充的数据范围,是存在数据间隙)
3. 数据范围内没有任何数据(存在间隙)
如下:
在了解了数据全集的组成后,我们再来看看事务并发时,会带来的问题。
无控制的并发所带来的问题
并发事务如果不加以控制的话会带来一些问题,主要包括以下几种情况。
1. 范围内已有数据更改导致的:
2. 范围内数据量发生了变化导致:
因为无控制的并发会带来一系列的问题,这些问题会导致无法满足我们所需要的结果。因此我们需要控制并发,以实现我们所期望的结果(隔离级别)。
MySQL 隔离级别的实现
InnoDB 通过加锁的策略来支持这些隔离级别。
行锁包含:
左右滑动进行查看
"上确界"伪记录的值高于索引中任何实际值。
上确界不是一个真正的索引记录,因此,实际上,这个 next-key 只锁定最大索引值之后的间隙。
基于此,当获取的数据范围中,数据已填充了所有的数据范围,那么此时是不存在间隙的,也就不需要 gap lock。
对于数据范围内存在间隙的,需要根据隔离级别确认是否对间隙加锁。
默认的 REPEATABLE READ 隔离级别,为了保证可重复读,除了对数据本身加锁以外,还需要对数据间隙加锁。
READ COMMITTED 已提交读,不匹配行的记录锁在 MySQL 评估了 where 条件后释放。
对于 update 语句,InnoDB 执行 "semi-consistent" 读取,这样它会将最新提交的版本返回到 MySQL,
以便 MySQL 可以确定该行是否与 update 的 where 条件相匹配。
总结&延展:
唯一索引存在唯一约束,所以变更后的数据若违反了唯一约束的原则,则会失败。
当 where 条件使用二级索引筛选数据时,会对二级索引命中的条目和对应的聚簇索引都加锁;所以其他事务变更命中加锁的聚簇索引时,都会等待锁。
行锁的增加是一行一行增加的,所以可能导致并发情况下死锁的发生。
例如,
在 session A 对符合条件的某聚簇索引加锁时,可能 session B 已持有该聚簇索引的 Record Locks,而 session B 正在等待 session A 已持有的某聚簇索引的 Record Locks。
session A 和 session B 是通过两个不相干的二级索引定位到的聚簇索引。
session A 通过索引 idA,session B通过索引 idB 。
当 where 条件获取的数据无间隙时,无论隔离级别为 rc 或 rr,都不会存在间隙锁。
比如通过唯一索引获取到了已完全填充的数据范围,此时不需要间隙锁。
间隙锁的目的在于阻止数据插入间隙,所以无论是通过 insert 或 update 变更导致的间隙内数据的存在,都会被阻止。
rc 隔离级别模式下,查询和索引扫描将禁用 gap locking,此时 gap locking 仅用于外键约束检查和重复键检查(主要是唯一性检查)。
rr 模式下,为了防止幻读,会加上 Gap Locks。
事务中,SQL 开始则加锁,事务结束才释放锁。
就锁类型而言,应该有优化锁,锁升级等,例如rr模式未使用索引查询的情况下,是否可以直接升级为表锁。
就锁的应用场景而言,在回放场景中,如果确定事务可并发,则可以考虑不加锁,加快回放速度。
锁只是并发控制的一种粒度,只是一个很小的部分:
从不同场景下是否需要控制并发,(已知无交集且有序的数据的变更,MySQL 的 MTS 相同前置事务的多事务并发回放)
并发控制的粒度,(锁是一种逻辑粒度,可能还存在物理层和其他逻辑粒度或方式)
相同粒度下的优化,(锁本身存在优化,如IX、IS类型的优化锁)
粒度加载的安全&性能(如获取行锁前,先获取页锁,页锁在执行获取行锁操作后即释放,无论是否获取成功)等多个层次去思考并发这玩意。
‘肆’ 数据库哪个隔离级别可以实现脏读
对于同时运行的多个事务, 当这些事务访问数据库中相同的数据时, 如果没有采取必要的隔离机制, 就会导致各种并发问题:
• 脏读: 对于两个事物 T1, T2, T1 读取了已经被 T2 更新但还没有被提交的字段. 之后, 若 T2 回滚, T1读取的内容就是临时且无效的.
• 不可重复读: 对于两个事物 T1, T2, T1 读取了一个字段, 然后 T2 更新了该字段. 之后, T1再次读取同一个字段, 值就不同了.
• 幻读: 对于两个事物 T1, T2, T1 从一个表中读取了一个字段, 然后 T2 在该表中插入了一些新的行. 之后, 如果 T1 再次读取同一个表, 就会多出几行.
数据库事务的隔离性: 数据库系统必须具有隔离并发运行各个事务的能力, 使它们不会相互影响, 避免各种并发问题.
一个事务与其他事务隔离的程度称为隔离级别. 数据库规定了多种事务隔离级别, 不同隔离级别对应不同的干扰程度, 隔离级别越高, 数据一致性就越好, 但并发性越弱
数据库提供了4中隔离级别:
隔离级别 描述
READ UNCOMMITTED(读未提交数据) 允许事务读取未被其他事务提交的变更,脏读、不可重复读和幻读的问题都会出现
READ COMMITED(读已提交数据) 只允许事务读取已经被其他事务提交的变更,可以避免脏读,但不可重复读和幻读问题仍然会出现
REPEATABLE READ(可重复读) 确保事务可以多次从一个字段中读取相同的值,在这个事务持续期间,禁止其他事务对这个字段进行更新,可以避免脏读和不可重复读,但幻读的问题依然存在
SERIALIZABLE(串行化) 确保事务可以从一个表中读取相同的行,在这个事务持续期间,禁止其他事务对该表执行插入、更新和删除操作,所有并发问题都可以避免,但性能十分低
Oracle 支持的 2 种事务隔离级别:READ COMMITED, SERIALIZABLE. Oracle 默认的事务隔离级别为: READ COMMITED
Mysql 支持 4 中事务隔离级别. Mysql 默认的事务隔离级别为: REPEATABLE READ
‘伍’ 用sql数据库做个小程序,实现数据隔离,怎么控制
看了你的需求,首页区分下概念,分清哪些是数据库中的设置的,哪些是在程序中设置的。
第一个问题:
连接数据库时的登录名:就是登陆Sql Server的账号(sa为默认的最高权限);在sql中称为登陆名,可以在sql中新建登陆名,该登陆名可以设置sql的登陆权限,在新建登陆名时用户映射中,设置该登陆名可以访问的数据库名。登陆名包含了登陆权限(就是获取数据库权限的用户名)。登陆名下包含了服务器角色(批处理权限的角色)信息,一般有sysadmin(sa)、public(新建的、默认)等。
上述用户是sql中设置的信息,与程序无关。而程序使用的登陆用户名是在sql中新建一个数据库(AA),然后在数据库中在新建一张用户表(User),即你所说的用户表包含了序号(ID)、用户名(UID)、密码(PWD)、身份(LOGIN)4个字段。程序的登陆名只是User表中的一个字段(UID)。
第二个问题:
首要要更正你的观点,既然是程序里面要在登陆时要实现不同的身份查看不同的数据,那么所有的问题都由程序来做,与数据库无关。只不过在数据库AA里建立不同的表,存放不同的数据。因此总体设计如下:
1、建立sql数据库连接登陆名,只需要一个,用默认的sa也可以
2、建立数据库AA
3、建立各数据表。包括User表,User表中的用户名(UID)即程序登陆用户名
程序设计
4、程序建立与sql server的连接(即用1中新建的,sa也可以)
5、制作登陆验证程序。首页验证UID与PWD是否匹配,其次根据不同的LOGIN跳转不同的界面
6、在各自不同的界面调用所需要的数据
希望你能看明白!
‘陆’ Navicat怎样设置数据库隔离级别
1.查看当前会话隔离级别
select @@tx_isolation;
2.查看系统当前隔离级别
select @@global.tx_isolation;
3.设置当前会话隔离级别
set session transaction isolatin level repeatable read;
4.设置系统当前隔离级别
set global transaction isolation level repeatable read;
5.命令行,开始事务时
set autocommit=off 或者 start transaction
关于隔离级别的理解
‘柒’ 数据库的隔离级别
第四步的值为 0 第六步为100 第三步虽然更新了,但是没有提交,还没有写入数据库,所以第三步查询的,仍为数据库的原值。第五步做了一次提交 ,会把值写入数据库,查询出来为更新值。 多线程的话就不一定了,可能出现脏读的现象。既然有提交的话,就得看线程的优先级别了。如果优先级别一样的话,就得看运气咯。 总而言之 如果更新提交后,另外一个线程才执行查询的话,肯定会查处更新后的值。如果只执行到更新,另一个线程执行了查询的话,就会出现脏读
‘捌’ oracle 数据库隔离级别学习
oracle
事务隔离级别
事务不同引发的状况:
脏读(Dirty
reads)
一个事务读取另一个事务尚未提交的修改时,产生脏读
很多数据库允许脏读以避免排它锁的竞争。
不可重复读(Nonrepeatable
reads)
同一查询在同一事务中多次进行,由于其他提交事务所做的修改或删除,每次返回不同的结果集,此时发生非重复读。
幻读(Phantom
reads)
同一查询在同一事务中多次进行,由于其他提交事务所做的插入操作,每次返回不同的结果集,此时发生幻像读。
数据库操作的隔离级别
未提交读(read
uncommitted)
提交读(read
committed)
重复读(repeatable
read)
序列化(serializable)
oracle默认隔离级别read
committed
(statement
level
serialization)
每一个语句,在语句开始时,会获取一个此刻的数据快照。
一个事务有多条语句,如果语句之间存在其它完成的事务,这可能引起不可持续读和幻读。
新建一个测试表books:
name,code,price三个字段
添加两条测试数据
使用pl/sql和java程序模拟并发
不允许脏读测试:
程序段首先查询code是qqq的书的价格
复制代码
代码如下:
//获取连接
省略
pstat
=
conn.prepareStatement("select
price
from
books
where
code='qqq'");
rs
=
pstat.executeQuery();
while(rs.next()){
System.out.println("price:"+rs.getDouble(1));
}
close();
输出结果:price:15.0
然后pl/sql执行更新
复制代码
代码如下:
update
books
set
price=18
where
code='qqq'
!pl/sql设置成手动更新,不自动更新
在执行上面java查询代码
输出仍是price:15.0,说明读不到pl/sql中未提交的执行结果,即不允许脏读
pl/sql
执行
commit;
在执行java查询:
输出结果:price:18.0
会有不可重复读何幻读的现象发生就不用测试了吧,
这两种现象都是针对提交后事物的读引起的,read
commited隔离级别是允许对提交后
的事物进行读的。
隔离级别:重复读(repeatable
read)
这个不允许脏读,不可重复读,但是会有幻读现象。
这个oracle不支持,不好测试。
理解的话就是如果一条查询语句查询的内容有其它事物正在更新的时候,这
查询处于等待状态,直到先前事物提交更新后,才会执行本条查询。也就是
查询的时候也会有锁,需要等待并发的事物释放锁。然后自己获取到锁,执行
自己事物。这样查询也加锁,并发性更低
select
...
for
update
就是这样可以避免不可重复读的发生
隔离级别:serializable
这个就更严格了,事物执行是一个一个的。一个事务中的语句共享同一个数据快照(在事务开始时存在的数据)。
是事物级别的,脏读,不可重复读,幻读根本就没有机会发生。
前面像read
committed都是语句级别的,以语句为单元。
比如
read
committed一个事物A有a(select),b(select),c(update)三条语句
当A事物执行a,b的时候,若有B事物执行更新操作,是有可能的
因为a,b是不加锁的
例子:
复制代码
代码如下:
//获取连接和关闭连接代码
省略
//不自动提交
conn.setAutoCommit(false);
/**
*
a
查询
*/
pstat
=
conn.prepareStatement("select
price
from
books
where
code='qqq'");
rs
=
pstat.executeQuery();
while(rs.next()){
//输出
price:25.0
System.out.println("price:"+rs.getDouble(1));
}
close();
/**
*
暂停一会,用pl/sql执行B事务
*
update
books
set
price=15
where
code='qqq'
*
commit;
*/
Thread.sleep(10000);
/**
*
如果这里再执行a查询的话,和第一次查询结果就不一样,因为中间有B事务的提交更新
*
修改,这也是不可重复读
*/
//b
更新
pstat
=
conn.prepareStatement("update
books
set
price=price+10
where
code='qqq'");
pstat.executeUpdate();
close();
//c
查询
pstat
=
conn.prepareStatement("select
price
from
books
where
code='qqq'");
rs
=
pstat.executeQuery();
while(rs.next()){
//输出
还是price:25.0
,因为B事务的干预
System.out.println("price:"+rs.getDouble(1));
}
close();
//提交事务
conn.commit();
if(conn
!=
null){
conn.close();
}
上面执行的顺序,事务B是在A的执行过程中执行的。
以上通过实例介绍了oracle数据库隔离级别的相关内容,希望对大家有所帮助。
下面是一些补充:
数据库中的事务基本作用是将数据库从一致状态转换到另一种一致状态,那么事务隔离级别就是定义了一个事务对于另外一个事务做出的修改有多“敏感”。也就是不同的隔离级别定义了事务相互影响的程度,下面分别介绍一下几种不同的隔离级别。
1.
READ
UNCOMMITTED
其实,oracle不支持这种隔离级别。这种隔离级别允许脏读(也就是可以读取到用户未提交的数据),支持这种隔离级别的数据库主要是为了支持非阻塞读,但是oracle默认支持非阻塞读,所以oracle里面不支持这种隔离级别。下面举一个例子:
如上图所示,假设某一家银行要统计所有账号总共有多少金额。事务A负责统计,事务A从第一行开始读取。假设读取到100行的时候,事务B从账号123转了400元到账户987(事务B还未提交),支持脏读的数据库当事务A读取到342023行的时候,就会得到500元,从而多加了400元。
2.
READ
COMMITTED
这种隔离级别指的是,事务只能读取已经提交的数据,(但是支持可重复读与幻想读)是oracle数据库默认的隔离模式。其实这种隔离级别在别的数据库里面可能还是会“退化”得像脏读一样。就看前面那个例子,假设在事务A读取到342023行前,事务B提前锁定了这一行,并将金额由100改成了500。那么事务A读取到这一行的时候,发现已经被其他事务锁定了,于是进行等待,直到事务B提交。但是当事务B提交之后,事务A还是读取到了500这一个错误信息,这样就和脏读一样的了,而且还让用户等待这个错误的答案。
3.
REPEATABLE
READ
这种隔离级别不支持脏读,不支持可重复读,支持幻想读。主要是为了得到一致性的答案与防止丢失更新。
a.
得到一致性答案
在oracle里面这个通过多版本机制得到了实现,但是在其他的数据库需要通过加锁机制进行控制,就以上一个例子为例,怎样才能统计出正确的总金额呢,事务A在读取每一行的时候,给每一行加上共享读锁,这样当事务B执行从账号123转400元到账户987的时候。先是操作第一行将账户123的金额由500修改成100,但是第一行已经被事务A锁定,于是等待,这样事务A能够读取到正确的数据。但是如果事务B执行的操作是从账户987转50元到账户123的时候,事务B先操作第342023行,发现没有被锁定,于是锁定将金额由100修改成50,然后操作第一行,发现锁定了于是等待。而事务A读取到342023行的时候,发现这一行已经被事务B锁定于是等待,这样就陷入了死锁。
b.
丢失更新
在采用共享读锁的数据库中,这种隔离级别可以防止丢失更新,比如事务1先读取了第A行然后修改了这一行的C列(其他列也修改了只是值还和以前一样,因为程序员都是整行的更新)。这个时候事务2想也想修改A行的时候会被阻塞,防止事务1的更新被覆盖。
4.
SEAIALIZABLE
不允许脏读,重复读与幻想读,最高的隔离级别。这种隔离级别标明事务A在操作数据库的时候好像就只有事务A在操作,没有其他事务在操作数据库一样。
Oracle
中是这样实现
SERIALIZABLE
事务的:原本通常在语句级得到的读一致性现在可以扩展到事务级。也就是在事务执行的那一刻,将这个事务将要操作的数据拍了一张照片。
从上面的例子我们可以看出,其他数据库采用共享读锁来解决统计总金额问题是没有oracle多版本机制灵活的,其一严重影响了程序的并发性,读阻塞了写。其二可能引起死锁。
‘玖’ 数据库的隔离级别:“可重复读”的误区
第一步:开始事务1,并进行查询
此时d的值还是45d。
证明你的结论1正确
‘拾’ 我们公司一个系统平台,数据库用的Mysql,为保障数据隔离每个客户都是一个数据库
分配数据库的时候 需要制定数据库的 初始空间大小,和之后的增长的比例。Oracle 有表空间的概念,可以通过sql语句查询剩余空间,mysql 复杂些,具体的方法,可以上网搜搜。