想要知道如何处理数据并发,自然需要先了解数据并发。
什么是数据并发 *** 作呢?
就是同一时间内,不同的线程同时对一条数据进行读写 *** 作。
在互联网时代,一个系统常常有很多人在使用,因此就可能出现高并发的现象,也就是不同的用户同时对一条数据进行 *** 作,如果没有有效的处理,自然就会出现数据的异常。而最常见的一种数据并发的场景就是电商中的秒杀,成千上万个用户对在极端的时间内,抢购一个商品。针对这种场景,商品的库存就是一个需要控制的数据,而多个用户对在同一时间对库存进行重写,一个不小心就可能出现超卖的情况。
针对这种情况,我们如何有效的处理数据并发呢?
第一种方案、数据库锁
从锁的基本属性来说,可以分为两种:一种是共享锁(S),一种是排它锁(X)。在MySQL的数据库中,是有四种隔离级别的,会在读写的时候,自动的使用这两种锁,防止数据出现混乱。
这四种隔离级别分别是:
读未提交(Read Uncommitted)
读提交(Read Committed)
可重复读(Repeated Read)
串行化(Serializable)
当然,不同的隔离级别,效率也是不同的,对于数据的一致性保证也就有不同的结果。而这些可能出现的又有哪些呢?
脏读(dirty read)
当事务与事务之间没有任何隔离的时候,就可能会出现脏读。例如:商家想看看所有的订单有哪些,这时,用户A提交了一个订单,但事务还没提交,商家却看到了这个订单。而这时就会出现一种问题,当商家去 *** 作这个订单时,可能用户A的订单由于部分问题,导致数据回滚,事务没有提交,这时商家的 *** 作就会失去目标。
不可重复读(unrepeatable read)
一个事务中,两次读 *** 作出来的同一条数据值不同,就是不可重复读。
例如:我们有一个事务A,需要去查询一下商品库存,然后做扣减,这时,事务B *** 作了这个商品,扣减了一部分库存,当事务A再次去查询商品库存的时候,发现这一次的结果和上次不同了,这就是不可重复读。
幻读(phantom problem)
一个事务中,两次读 *** 作出来的结果集不同,就是幻读。
例如:一个事务A,去查询现在已经支付的订单有哪些,得到了一个结果集。这时,事务B新提交了一个订单,当事务A再次去查询时,就会出现,两次得到的结果集不同的情况,也就是幻读了。
那针对这些结果,不同的隔离级别可以干什么呢?
“读未提(Read Uncommitted)”能预防啥?啥都预防不了。
“读提交(Read Committed)”能预防啥?使用“快照读(Snapshot Read)”方式,避免“脏读”,但是可能出现“不可重复读”和“幻读”。
“可重复读(Repeated Red)”能预防啥?使用“快照读(Snapshot Read)”方式,锁住被读取记录,避免出现“脏读”、“不可重复读”,但是可能出现“幻读”。
“串行化(Serializable)”能预防啥?有效避免“脏读”、“不可重复读”、“幻读”,不过运行效率奇差。
好了,锁说完了,但是,我们的数据库锁,并不能有效的解决并发的问题,只是尽可能保证数据的一致性,当并发量特别大时,数据库还是容易扛不住。那解决数据并发的另一个手段就是,尽可能的提高处理的速度。
因为数据的IO要提升难度比较大,那么通过其他的方式,对数据进行处理,减少数据库的IO,就是提高并发能力的有效手段了。
最有效的一种方式就是:缓存
想要减少并发出现的概率,那么读写的效率越高,读写的执行时间越短,自然数据并发的可能性就变小了,并发性能也有提高了。
还是用刚才的秒杀举例,我们为的就是保证库存的数据不出错,卖出一个商品,减一个库存,那么,我们就可以将库存放在内存中进行处理。这样,就能够保证库存有序的及时扣减,并且不出现问题。这样,我们的数据库的写 *** 作也变少了,执行效率也就大大提高了。
当然,常用的分布式缓存方式有:Redis和Memcache,Redis可以持久化到硬盘,而Memcache不行,应该怎么选择,就看具体的使用场景了。
当然,缓存毕竟使用的范围有限,很多的数据我们还是必须持久化到硬盘中,那我们就需要提高数据库的IO能力,这样避免一个线程执行时间太长,造成线程的阻塞。
那么,读写分离就是另一种有效的方式了
当我们的写成为了瓶颈的时候,读写分离就是一种可以选择的方式了。
我们的读库就只需要执行读,写库就只需要执行写,把读的压力从主库中分离出去,让主库的资源只是用来保证写的效率,从而提高写 *** 作的性能。
数据库一致性(Database Consistency)是指事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。保证数据库一致性是指当事务完成时,必须使所有数据都具有一致的状态。在关系型数据库中,所有的规则必须应用到事务的修改上,以便维护所有数据的完整性。
保证数据库的一致性是数据库管理系统的一项功能比如有两个表(员工\职位),员工表中有员工代码、姓名、职位代码等属性,职位表中有职位代码、职位名称、职位等级等属性。你在其中员工表中进行了插入 *** 作,你插入了一个新员工的信息,而这个新员工的职位是公司新创建的一个职位。如果没有一致性的保证,就会出现有这么一个员工,但是不知道他到底担当什么职责!这个只是它的一个小小方面。
读一致性也是数据库一致性的一个重要方面,在实际中,我们会遇到这种情况:我们对一个表中的某些数据进行了更新 *** 作,,但是还没有进行提交,这时另外一个用户读取表中数据这个时候就出现了读一致性的问题:到底是读什么时候的数据呢是更新前的还是更新后的在DBMS中设有临时表,它用来保存修改前的值,在没有进行提交前读取数据,会读取临时表中的数据,这样一来就保证了数据是一致的(当前用户看到的是更新后的值)
但是还有一种情况:用户user1对表进行了更新 *** 作,用户user2在user1还没有进行提交前读表中数据,而且是大批量的读取(打个比方:耗时3分钟)而在这3分钟内user1进行了提交 *** 作,那又会产生什么影响呢这个时候怎么保证读写一致性呢这个时候DBMS就要保证有足够大的临时表来存放修改前的数值,以保证user2读取的数据是修改前的一致数据然后下次再读取时候就是更新后的数据了。
补充楼主:
其实我没什么经验,只不过是了解一些基础的东西罢了。
一楼的 一朵瘩红花 实际经验很丰富,你可以向她咨询一下。
你问的问题挺好得。三个概念紧密联系在一起。
这样说吧:并发的几个事务同时发生,不加锁控制的话数据就会乱套了,而加了锁后,又是并发访问会出现死锁,所以就会出现避免死锁的一些措施。
首先谈并发:理论指的是在一段时间同时对某件事进行 *** 作。 注意精度问题,修改数据库是在一段时间内 *** 作,不是在某个时刻,而日志则会从 时刻 开始记录你的 *** 作。
造成死锁的原因是为了防止 不同的用户同时间(不是时刻)都对某个数据修改,造成访问不一致的问题。
比如你读了数据库的一个数据然后把它修改了并存回去,是需要时间的(假如是student表中的有个grade属性,你改了一条记录的一个值)在这个过程当中,有人又访问了数据库并且恰恰访问的是存回去之前的数据,然后他要进行 *** 作,过了一段时间,此时你已经存回去了数据。会发现原来的数据被改动了。这时数据就乱套了。(专业术语叫读脏数据,其实还有很多其他类似这种导致前后数据不一致的问题)所以为了限定这种 *** 作,数据库设计了-----锁---来锁定这种 *** 作。就是你正在 *** 作某个数据的时候----通常之前会先锁定这个数据,这样别人就不能对此数据 *** 作了(严格来说就是只能读,不能改),必须等你 *** 作完才能对此数据修改等 *** 作,这就在一定程度上避免了前后 *** 作数据不一致的问题。
但是有了锁后,新问题出现了,就是死锁:
简单解释死锁:进程A等待进程B释放他的资源,B又等待A释放他的资源,这样就互相等待就形成死锁
官方解释死锁
死锁,根本原因在于对共享存储区的访问。在数据库中也一样,如果需要“修改”一条数据,首先数据库管理系统会在上面加锁,以保证在同一时间只有一个事务能进行修改 *** 作。锁有多种实现方式,比如意向锁,共享-排他锁,锁表,树形协议,时间戳协议等等。锁还有多种粒度,比如可以在表上加锁,也可以在记录上加锁。
在并发控制中,锁是非常重要的。
至于在Oracle还是别的数据库管理系统中,死锁产生的原因没有不同,不同的顶多是锁的实现或者死锁的恢复等罢了
再来说说事务:
事务简单来说就是 一系列的对数据库的 *** 作揉在一起,要么同时完成,要么就都不完成。
比如---你要取钱的过程就可以当成是一个小的事务: 插卡,输入取钱金额,取走钱,拿出来卡。此过程缺一不可。把所有这些过程细节封装起来就成为一个事务。
以oracle数据库为例:
一个事务(你可以认为是一系列业务的 *** 作)起始于dml语句(insert、update、delete)
即一条dml语句就做为一个事务的起始,然后根据业务需要,进行其他的dml *** 作都算是事务的一部分。
最后碰到commit。或者rollback,或者其他意外什么的都算作一个事务的结束。
整个过程就是一个事务。
事务的理论解释就是那四个什么特性:什么原子性、一致性、隔离性和持久性
简称ACID
剩下的:数据库是建立在 *** 作系统之上的一个层次。
你问的是数据库的存储机制??工作机制??还是什么的??
数据库就是存数据的。数据库管理系统是 对存的数据进行高效率的管理
大的结构分物理数据跟逻辑数据。
物理数据就是数据在存储设备上的存储方式,什么物理联系,物理结构,物理记录等 术语。
逻辑数据就是程序员和用户看到的数据形式。什么逻辑联系,逻辑结构==同上
数据库管理类系统就是把这些逻辑跟物理相互转换。 好比你输入的叫逻辑数据存储在磁盘上叫物理数据。等等。
废话了一堆,也不知道回答对你的问题没~~
oracle数据库 锁表和死锁的区别
死锁指的是a,b两个事务对同一对象进行dml或ddl *** 作(即修改表结构或者增删改数据),出现了相互等待被锁定的对象的情况,即类似于红绿灯十字路口红灯方向堵住路口,绿灯方向却红灯车辆挡在路口不能过去,这样无论红绿灯如何变化都无法通行。一般像oracle这样的dbms是有死锁检测的,然后把锁定对象抛出来按照预定规则处理或者让程序处理。 锁等待指的是a事务锁定了 *** 作对象,而b事务也要对其进行dml或ddl *** 作(即修改表结构或者增删改数据)时,需要等待a事务完成。这个和死锁不同,只要a事务完成后,b事务就可以正常进行了。类似于正常的红绿灯十字路口通行状态:红灯方向就是等待锁释放的b事务,绿灯方向就是锁定路口的a事务。待红绿灯互换,则a事务执行完毕,b事务也就可以正常执行啦。
MySQL锁表是什么意思?有什么用?什么情况下用?好处?缺点?
白话解说如下:
简单说,就是lock table,不让别人动
锁分共享锁和排它锁。
共享锁时,别人能读,不能改变量表数据
排它锁时,别人既不能读,也不能改表数据
根据以上特点,应该就知道何时使用锁了。不想让别人变更数据,对自己产生影响,就加锁。一定要在不用之后,进行锁释放,不然,应用系统会一直因为读取数据而报错。
好处就是,保证数据的原子性,完整性,一致性。 只有加锁者释放了锁,别人才能改变数据。
缺点就是,增加了系统开销,有可能产生锁等待,造成数据库运行异常。这都是不正常的使用锁带来的问题。
什么情况下造成数据库锁表? 如何解决?
zhidaobaidu/question/180766896
两个SQL的锁表问题
不同的数据库,多版本的实现机制不同,上述语句执行情况也就不一样,下面以oracle为例说明:
1insert/delete语句可以并发执行,不会锁等待
2并发insert不会锁等待
3并发update,如果不是 *** 作同一条记录,不会锁等待
=================================================
对真实存在的数据进行并发 *** 作才有可能发生写冲突,所以楼主供要把握住这点就可以判断是否会冲突了。
建议楼主构造简单数据,开两个客户端,在不同的隔离级下去模拟并发 *** 作,理论和实践相结合,你会理解的更透彻。
oracle 数据库 为什么锁表
简单地说,锁是为了保证数据的一致性,锁不止存在于oracle,其他数据库一样有,只不过机制上可能大相径庭。 至于什么样的 *** 作会锁表,其实锁的种类很多,你所说的锁表大概说的是行级锁——也就是事务锁吧
如何将数据库中被锁表解锁
在 *** 作数据库的时候,有时候会由于 *** 作不当引起数据库表被锁定,这么我们经常不知所措,不知怎么给这些表解锁,在pl/sql Developer工具的的菜单“tools”里面的“sessions”可以查询现在存在的会话,但是我们很难找到那个会话被锁定了,想找到所以被锁的会话就更难了,下面这叫查询语句可以查询出所以被锁的会话。如下:
SELECT snusername, mSID,snSERIAL#, mTYPE,
DECODE (mlmode,
0, 'None',
1, 'Null',
2, 'Row Share',
3, 'Row Excl',
4, 'Share',
5, 'S/Row Excl',
6, 'Exclusive',
lmode, LTRIM (TO_CHAR (lmode, '990'))
) lmode,
DECODE (mrequest,
0, 'None',
1, 'Null',
2, 'Row Share',
3, 'Row Excl',
4, 'Share',
5, 'S/Row Excl',
6, 'Exclusive',
request, LTRIM (TO_CHAR (mrequest, '990'))
) request,
mid1, mid2
FROM v$session sn, v$lock m
WHERE (snSID = mSID AND mrequest != 0) --存在锁请求,即被阻塞
OR ( snSID = mSID --不存在锁请求,但是锁定的对象被其他会话请求锁定
AND mrequest = 0
AND lmode != 4
AND (id1, id2) IN (
SELECT sid1, sid2
FROM v$lock s
WHERE request != 0 AND sid1 = mid1
AND sid2 = mid2)
)
ORDER BY id1, id2, mrequest;
通过以上查询知道了sid和 SERIAL#就可以开杀了
alter system kill session 'sid,SERIAL#';
怎么知道数据库表已经锁表了
通过查询结果中的object_id,可以查询到具体被锁的对象再给你看看我查到的一些关于锁的资料:锁有以下几种模式: 0:none 1:null 空 2:Row-S 行共享(RS):共享表锁 3:Row-X 行专用(RX):用于行的修改 4:Share 共享锁(S):阻止其他DML *** 作 5:S/Row-X 共享行专用(SRX):阻止其他事务 *** 作 6:exclusive 专用(X):独立访问使用数字越大锁级别越高, 影响的 *** 作越多。一般的查询语句如select from ;是小于2的锁, 有时会在v$locked_object出现。 select from for update; 是2的锁。当对话使用for update子串打开一个游标时,所有返回集中的数据行都将处于行级(Row-X)独占式锁定,其他对象只能查询这些数据行,不能进行update、delete或selectfor update *** 作。 insert / update / delete ; 是3的锁。没有mit之前插入同样的一条记录会没有反应, 因为后一个3的锁会一直等待上一个3的锁, 我们必须释放掉上一个才能继续工作。创建索引的时候也会产生3,4级别的锁。 locked_mode为2,3,4不影响DML(insert,delete,update,select) *** 作, 但DDL(alter,drop等) *** 作会提示ora-00054错误。有主外键约束时 update / delete ; 可能会产生4,5的锁。 DDL语句时是6的锁。以DBA角色, 查看当前数据库里锁的情况可以用如下SQL语句: select object_id,session_id,locked_mode from v$locked_object; select t2username,t2sid,t2serial#,t2logon_time from v$locked_object t1,v$session t2 where t1session_id=t2sid order by t2logon_time; 如果有长期出现的一列,可能是没有释放的锁。我们可以用下面SQL语句杀掉长期没有释放非正常的锁: alter system kill session 'sid,serial#'; 如果出现了锁的问题, 某个DML *** 作可能等待很久没有反应。当你采用的是直接连接数据库的方式,也不要用OS系统命令 $kill process_num 或者 $kill -9 process_num来终止用户连接,因为一个用户进程可能产生一个以上的锁, 杀OS进程并不能彻底清除锁的问题。
如何实现数据库锁表及解锁
锁表:
LOCK TABLES tablename WRITE;LOCK TABLES tablename READ;解锁
UNLOCK TABLES;
数据库中如何释锁表进程
锁表查询的代码有以下的形式:
select count() from v$locked_object;
select from v$locked_object;
查看哪个表被锁
select bowner,bobject_name,asession_id,alocked_mode from v$locked_object a,dba_objects b where bobject_id = aobject_id;查看是哪个session引起的
select busername,bsid,bserial#,logon_time from v$locked_object a,v$session b where asession_id = bsid order by blogon_time;杀掉对应进程
执行命令:alter system kill session'1025,41';
其中1025为sid,41为serial#
怎么知道数据库表已经锁表了
先回答你的问题:
select from v$locked_object;
可以获得被锁的对象的object_id及产生锁的会话sid。
通过查询结果中的object_id,可以查询到具体被锁的对象
再给你看看我查到的一些关于锁的资料:
锁有以下几种模式:
0:none
1:null 空
2:Row-S 行共享(RS):共享表锁
3:Row-X 行专用(RX):用于行的修改
4:Share 共享锁(S):阻止其他DML *** 作
5:S/Row-X 共享行专用(SRX):阻止其他事务 *** 作
6:exclusive 专用(X):独立访问使用
数字越大锁级别越高, 影响的 *** 作越多。
一般的查询语句如select from ;是小于2的锁, 有时会在v$locked_object出现。
select from for update; 是2的锁。
当对话使用for update子串打开一个游标时,
所有返回集中的数据行都将处于行级(Row-X)独占式锁定,
其他对象只能查询这些数据行,不能进行update、delete或selectfor update *** 作。
insert / update / delete ; 是3的锁。
没有mit之前插入同样的一条记录会没有反应,
因为后一个3的锁会一直等待上一个3的锁, 我们必须释放掉上一个才能继续工作。
创建索引的时候也会产生3,4级别的锁。
locked_mode为2,3,4不影响DML(insert,delete,update,select) *** 作,
但DDL(alter,drop等) *** 作会提示ora-00054错误。
有主外键约束时 update / delete ; 可能会产生4,5的锁。
DDL语句时是6的锁。
以DBA角色, 查看当前数据库里锁的情况可以用如下SQL语句:
select object_id,session_id,locked_mode from v$locked_object;
select t2username,t2sid,t2serial#,t2logon_time
from v$locked_object t1,v$session t2
where t1session_id=t2sid order by t2logon_time;
如果有长期出现的一列,可能是没有释放的锁。
我们可以用下面SQL语句杀掉长期没有释放非正常的锁:
alter system kill session 'sid,serial#';
如果出现了锁的问题, 某个DML *** 作可能等待很久没有反应。
当你采用的是直接连接数据库的方式,
也不要用OS系统命令 $kill process_num 或者 $kill -9 process_num来终止用户连接,
因为一个用户进程可能产生一个以上的锁, 杀OS进程并不能彻底清除锁的问题。
记得在数据库级别用alter system kill session 'sid,serial#';杀掉不正常的锁。
这里还讲了一些:
>>
sql运行问题?
数据库运行过程中常见的故障有3类:事物故障、系统故障、介质故障。
恢复策略:
1、事物故障:
发生事务故障时,被迫中断的事务可能已对数据库进行丁修改,为了消除该事务对数据库的影响,要利用日志文件中所记载的信息,强行回滚该事务,将数据库恢复到修改前的初始状态。
为此,要检查日志文件中由这些事务所引起的发生变化的记录,取消这些没有完成的事务所做的一切改变,这类恢复 *** 作称为事务撤销。
2、系统故障:
系统故障的恢复要完成两方面的工作,既要撤销所有末完成的事务,还要重做所有已提交的事务,这样才能将数据库真正恢复到一致的状态。
3、介质故障:
介质故障比事务故障和系统故障发生的可能性要小,但这是最严重的一种故障,破坏性很大,磁盘上的物理数据和日志文件可能被破坏,这需要装入发生介质故障前最新的后备数据库副本,然后利用日志文件重做该副本后所运行的所有事务。
“数据故障恢复”和“完整性约束”、“并e799bee5baa6e4b893e5b19e31333431353364发控制”一样,都是数据库数据保护机制中的一种完整性控制。所有的系统都免不了会发生故障,有可能是硬件失灵,有可能是软件系统崩溃,也有可能是其他外界的原因,比如断电等等。
数据库运行的突然中断会使数据库处在一个错误的状态,而且故障排除后没有办法让系统精确地从断点继续执行下去。这就要求DBMS要有一套故障后的数据恢复机构,保证数据库能够回复到一致的、正确地状态去。
SQL Server 的内存管理机制是:
有可用内存, 则为新需求分配内存
无可用内存时, 释放内存来处理新需求
这是SQL Server 缓冲池的预期行为。
默认情况下,在启动 SQL Server之后,SQL Server会根据 *** 作系统报告的物理内存数来动态增大或缩小高速缓冲存储器的容量。
只要可用物理内存大小保持在4MB到10MB之间,SQL Server 缓冲池就会继续增大(保留可用物理内存在4MB到10MB之间是为了
避免 *** 作系统因为缺少内存而频繁地换页)。如果物理可用内存变得较少的时候,则SQL Server会将一些内存释放给 *** 作系统。
解决方案:
1给 *** 作系统、sql server打最新补丁
2确保不是病毒原因(可能性比较小)
3sql server设计时的要求就是最大可能的减少磁盘的I/O,磁盘I/O是比较消耗资源的,这个磁盘I/O包括了读取数据库文件
还有和虚拟内存的页交换。如果还有足够的可用内存它都会毫不吝啬的使用的(没有设置上限),它会根据需要动态获取和
释放内存的。你要分析的是这占用的内存开销主要用做了什么?是不是有大型的查询或事务 *** 作。
4如果服务器是专职的数据库服务器,不建议设置最大内存上限。如果还有其它重要的服务在机器上运行,就要考虑它的内存
使用是否会影响其它服务的正常的运行和性能。如果你的服务器除了sql服务, 还有其他服务需求, 则需要设置sql server的最大内存限制
以上就是关于如何处理数据库并发问题全部的内容,包括:如何处理数据库并发问题、数据库的一致性是什么有什么作用、数据库死锁,并发问题等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)