① java 脏读脏写 怎么产生的
产生脏数烂唯据,是弊历棚因为多线程的原因,当某一个正租则在写数据时,另一个线程读取的数据是不准确的,需要进行同步处理。
② ThreadLocal本质及脏数据、内存泄漏问题
ThreadLocal作为WeakReference的referent,只要ThreadLocal对象引用被置为null,Entry的key(referent)就会在下一次YGC时被回收。在使用ThreadLocal的get()和set()时,会卜猛将失效的Entry(key == null)的value置为null,使value能够被GC回收,避免内存泄漏。
ThreadLocal对象常作为私有静态变量使用,其生命周期不会随着线程结束而结束。
ThreadLocal本质属性:线程间共享。
调用该init的有8个Thread构造器:
这8个构造器的inheritThreadLocals为true。
只有下面的构造器inheritThreadLocals为false:
在init中:
InheritableThreadLocal用来给子线程从父线程继承thread-local值。
InheritableThreadLocal自动与线程的inheritableThreadLocals域关联起来。
childValue()是个protected方法,其用在子线程创建时,用来从父线程 thread-local值时,可以设置初始值。
使用ThreadLocal和InheritableThreadLocal透传上下文时,需要注意线程间切换、异常传输时的处理,避免在传输过程中因处理不当而导致的上下文丢失。
ThreadLocal对象本身由多线程共享。
而T类型的值各线程各不相同。
例如SimpleDateFormat是线程不安全的,可以放到ThreadLocal<DateFormat>中,然每个线程单独有一份SimpleDateFormat对象。
主要问题是会产生脏数据和内存泄漏型漏桥。通常是在线程池的线程中使用ThreadLocal引发的,因为线程池有线程复用和内存常驻两个特点。
run()中没有显式地调用remove()清理与线程相关的ThreadLocal信息,下一个线程也没有set()设置初始值,则会产生脏数据。
ThreadLocal一般是static对象。因此寄希望于ThreadLocal对象失去引用后,触发弱引用回收机制来回收Value是不现实的。
为了防止内存泄漏,每次用完ThreadLocal,必须要及时调用remove()方法搜铅清理。
③ 简述脏数据的产生原因及解决办法
数据库锁的产生原因及解决办法
数据库和操作系统一样,是一个多用户使用的共享资源。当多个用户并发地存取数据 时,在数据库中悔历就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性。加锁是实现数据库并 发控制的一个非常重要的技术。在实际应用中经常会遇到的与锁相关的异常情况,当两个事务需要一组有冲突的锁,而不能将事务继续下去的话,就会出现死锁,严 重影响应用的正常执行。
在数据库中有两种基本的锁类型:排它锁碧晌搜(Exclusive Locks,即X锁)和共享锁(Share Locks,即S锁)。当数据对象被加上排它锁时,其他的事务不能对它读取和修改。加了共享锁的数据对象可以被其他事务读取,但不能修改。数据库利用这两 种基本的锁类型来对数据库的事务进行并发控制。
死锁的第一种情况
一个用户A 访问表A(锁住了表A),然后又访问表B;另一个用户B 访问表B(锁住了表B),然后企图访问表A;这时用户A由于用户B已经锁住表B,它必须等待用户B释放表B才能继续,同样用户B要等用户A释放表A才能继续,这就死锁就产生了。
解决方法:
这种死锁比较常见,是由于程序的BUG产生的,除了调整的程序的逻辑没有其它的办法。仔细分析程序的逻辑,对于数据库的多表操作时,尽量按照相同的顺序进 行处理,尽量避免同时锁定两个资源,如操作A和B两张表时,总是按先A后B的顺序处理, 必须同时锁定两个资源时,要保证在任何时刻都应该按照相同的顺序来锁定资源。
死锁的第二种情况
用户A查询一条纪录,然后修改该条纪录;这时用户B修改该条纪录,这时用户A的事务里锁的性质由查询的共享锁企图上升到独占锁,而用户B里的独占锁由于A 有共享锁存在所以必须等A释放掉共享锁,而A由于B的独占锁而无法上升的独占锁也就不可能释放共享锁,于是出现了死锁。这种死锁比较隐蔽,但在稍大点的项 目中经常发生。如在某项目中,页面上的按钮点击后,没有使按钮立刻失效,使得用户会多次快速点击同一按钮,这样同一段代码对数据库同一条记录进行多次操 作,很容易就出现这种死锁的情况。
解决方法:
1、对于按钮等控件,点击后使其立刻失效,不让用户重复点击,避免对同时对同一条记录操作。
2、使用乐观锁进行控制。乐观锁大多是基于数据版本(Version)记录机制实现。即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是 通过为数据库表增加一个“version”字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数 据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。乐观锁机制避免了长事务中的数据 库加锁开销(用户A和用户B操作过程中,都没有对数据库数据加锁),大大提升了大并发量下的系统整体性能表现。Hibernate 在其数据访问引擎中内置了乐观锁实现。需要注意的是,由于乐观锁机制是在我们的系统中实现,来自外部系统的用户更新操作不受我们系统的控制,因此可能会造 成脏数据被更新到数据库中。
3、使用悲观锁进行控制。悲观锁大多数情况下依靠数据库的锁机制实现,如Oracle的Select … for update语句,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。如一个金融系统, 当某个操作员读取用户的数据,并在读出的用户数据的基础上进行修改时(如更改用户账户余额),如果采用悲观锁机制,也就意味着整个操作过程中(从操作员读 出数据、开始修改直至提交修改结果的全过程,甚至还包括操作员中途去煮咖啡的时间),数据库记录始终处于加锁状态,可以想见,如果面对成百上千个并发,这 样的情况将导致灾难性的后果。所以,采用悲观锁进行控制时一定要考虑清楚。
死锁的第三种情况
如果在事务中执行了一条不满足条件的update语句,则执行全表扫描,把行级锁上升为表级锁,多个这样的事务执行后,就很容易产生死锁和阻塞。类似的情 况还有当表中的数据量非常庞大而索引建的过少或不合适的时候,使得经常发生全表扫描,最终应用系统会越来越慢,最终发生阻塞或死锁。
解决方法:
SQL语句中不要使用太复杂的关谨核联多表的查询;使用“执行计划”对SQL语句进行分析,对于有全表扫描的SQL语句,建立相应的索引进行优化。
5.小结
总体上来说,产生内存溢出与锁表都是由于代码写的不好造成的,因此提高代码的质量是最根本的解决办法。有的人认为先把功能实现,有BUG时再在测试阶段进 行修正,这种想法是错误的。正如一件产品的质量是在生产制造的过程中决定的,而不是质量检测时决定的,软件的质量在设计与编码阶段就已经决定了,测试只是 对软件质量的一个验证,因为测试不可能找出软件中所有的BUG。
④ oracle中脏数据是什么意思怎么产生的
脏数据就是已经写入到内存里,但是还没有写入到硬盘上的数据。一般当事物没有提交的时候会产生,当事物提交以后,脏数据就会被写进硬盘的数据块,这时他就不叫脏数据了。
⑤ SQL中脏数据是啥意思
脏读:一个用户对一个资源做了修改,此时另外一个用户正好读取了这条被修改的记录,然后,第一个用携郑户春隐拍放弃修改,数据回到修改之前,这两个不同的结果扒羡就是脏读。
⑥ innodb 数据库中的脏页数据是怎么产生的
由于等待和 Buffer Pool 的各种 latch 相关,而且 delete 操作本身会产生大量脏数据,那会不会跟刷脏页操作相关呢?我们看下 SQL 被 kill 的量和刷脏页的量之间的关系。
发现每秒刷脏页的量和 SQL 被 kill 的量的曲线有点相近,看着刷脏页的量挺大的,但是每秒 delete 的 TPS 又不是很高,为啥这么低的 TPS 会让刷脏页频率抖动以及 SQL 执行变慢呢?曾经换过不同批次的机器,段漏和发现问题依旧,并没有改善,说明并不是机器本身的问题。继续浏览 buffer pool 相关的监控指标,像是发现新大陆一样的发现了一个异常指标脏页比例达到了快 90% !!!太吓人了!!!为啥脏页比例会达到 90% 呢,无非就是刷脏页的速度跟不上产生的速度,要么就是 IO 能力不行,要么就是产生脏页的速度过快,要么就是内存池太小,导致 Buffer Pool 被脏页占满。那么这个脏页比例达到快 90% 会有什么问题呢?
innodb_max_dirty_pages_pct_lwm 表示的是当脏页比例达到该参数表示的低水位时候,刷脏线程就开始预刷脏来控制脏页比例,避免达到innodb_max_dirty_pages_pct 。刷脏页的最大 IO 能力是受 innodb_io_capacity 和 innodb_io_capacity_max 控制。生产上我们将 innodb_max_dirty_pages_pct_lwm 设置成了50当脏页比例大于 innodb_max_dirty_pages_pct 时候,InnoDB 会进行非常激烈的刷脏页操作,但是由于 DELETE 操作还是在进行,脏页产生的速度还是非常快,刷脏页的速度还是跟不上脏页产生的速度。为了避免脏页比例进一步扩大,更新将会被堵塞,从而导致 DELETE 执行变慢,直至被 KILL。发现问题之后,根据我们之前的假设,有三种解决方案:1. 调大 io_capacity ,但是由于主机是多实例部署,IO 占用已经比较高,PASS。2. 降低脏页产生速度,也就是调低 DELETE 速度,因为数据产生的速度很快,为了避免删除跟不上插入的速度,也被 PASS。3. 调大 Buffer Pool,可以容纳更多的脏页。说干就干,得益于 MySQL 5.7 的在线调整 Buffer Pool,立马将 Buffer Pool Size 扩了一倍,效果非常显着。
脏页比例立马下降,被 kill 的 SQL 也下降了。平均 SQL rt 下降很多。
总结
得益于 MySQL 的开源,很多错误都握盯可以直接确认到对应的代码,大致定位到问题发生的地方,给问题排查带来了很多方便。同时对 MySQL buffer pool 的命中率以及脏页比例也要多多关注,对 SQL 的性能搜念都有很大的影响。
⑦ 什么是脏数据
脏数据(Dirty Read)是指源系统中的数据不在给定的范围内或对于实际业务毫无意义,或是数据格侍宴式非法,以及在源系统中存在不规范的编码和含糊的业务逻辑。
通俗的讲,当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。
因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。
脏数据产生的影响:
1、丢失的修改:一个事物的更新覆盖了另一个事物的更新。例如:事物A和B读入同一数据并修渣厅改,B提交的结果破坏了A提交的结果,导致A的修改被丢失。
2、不可重复读:一个事物两次读取同一个数据,两次读取的数据不一致。不可重复读是指事物A读取数据后,事物B执行更新操作,事务A 无法再现前一次读取结果。
(1)事物A读取某一数据后,事物B对其作了修改,当事物A再次读取数据时,得到与前一次不同的值。
(2)事物A按一定的条件从数据库中读取了某些数据后,事物B删除了其中部分记录,当A再次以相同条件读取时,发现某些记录消失了。
3、脏读:一个事物读取了另一个事物未提交的数据。读“脏”数据是指事物A修改某一数据,并将其写回磁盘,事物B读取同一数据后,A由于某种原因被撤销,这时A已修改过的数据恢复原值,B读到的数据就与数据库中的数据不一致,则B读到的数据为“脏”数据,即不正确的数据。
4、幻读:一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“老梁银幻读”。
⑧ 数据库的数据脏读是什么意思,怎样有效的避免数组脏读,博客
脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。
1、如果都未更新你就读取了,或者都更新完才读取,这都不是脏读,因为得到的是更新前的有效值,或完全更新后的值。
2、如果那个用户更新一半你就读取了,也就是说更新了A,正打算要更新B但尚未更新时,就读取了,此时得到的就是脏数据。
避免脏读的办法就是采取事务,使得用户正在更新时锁定数据库,阻止你读取,直至全部完成才让读取。
(8)脏数据是如何产生的扩展阅读:
在数据库技术中,脏数据在临时更新(脏读)中产生。事务A更新了某个数据项X,但是由于某种原因,事务A出现了问题,于是要把A回滚。但是在回滚之前,另一个事务B读取了数据项X的值(A更新后),A回滚了事务,数据项恢复了原值。事务B读取的就是数据项X的就是一个“临时”的值,就是脏数据。