【前言】
小编在做基础系统维护的时候,接触到了修改服务器上的sql server数据库里面的数据,之前的时候小编也学过sql的东西,不过现在全忘了(增删改查,这些基本的还是会的),在删除某一条数据的时候出现了这样一个问题,要删除这一条数据但是就是删除不了,而且在删除记录里面还有我之前操作过的删除记录,这就很奇怪了。于是乎,多方求助终于解决了,下面给大家简单的介绍一下
【问题】
由于班级代码写错了,所以不得不删除这条数据(如下图),于是在删除的时候就出现了问题,怎么删也删不掉这条数据
但是彻底删除里面却有删除的记录(如下图),试了很多遍还是不行
【原因及解决方法】
这其实是DB的脏读引起的,那么何为脏读?
所谓脏读,就是指当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的
脏读:一个事务读取到了另外一个事务没有提交的数据
事务1:更新一条数据
---------->事务2:读取事务1更新的记录
事务1:调用commit进行提交
此时事务2读到的数据是保存在数据库内存中的数据,称为脏读。读到的数据为脏数据
例如:
张三的工资为5000,事务A中把他的工资改为8000,但事务A尚未提交。
与此同时,
事务B正在读取张三的工资,读取到张三的工资为8000。
随后,
事务A发生异常,而回滚了事务。张三的工资又回滚为5000。
最后,
事务B读取到的张三工资为8000的数据即为脏数据,事务B做了一次脏读
产生数据不一致的主要原因是并发操作破坏了事务的隔离性。并发控制就是要用正确的方式调度并发操作,使一个用户事物的执行不受其它事务的干扰,从而避免造成数据的不一致性
锁就是防止其他事务访问指定的资源的手段,锁是实现并发控制的主要方法,是多个用户能够同时操纵同一个数据库中的数据而不发生不一致现象的重要保障。
处理以上隔离级别的问题,采用如下方法:
事务隔离五种级别:
TRANSACTION_NONE 不使用事务。
TRANSACTION_READ_UNCOMMITTED 允许脏读。
TRANSACTION_READ_COMMITTED 防止脏读,最常用的隔离级别,并且是大多数数据库的默认隔离级别
TRANSACTION_REPEATABLE_READ 可以防止脏读和不可重复读,
TRANSACTION_SERIALIZABLE 可以防止脏读,不可重复读取和幻读,(事务串行化)会降低数据库的效率
以上的五个事务隔离级别都是在Connection接口中定义的静态常量,使用setTransactionIsolation(int level) 方法可以设置事务隔离级别。如:con.setTransactionlsolation(Connection.REPEATABLE_READ);
注意:事务的隔离级别收到数据库的限制,不同的数据库支持的隔离级别不一定相同
脏读:修改时加排他锁,直到事务提交后才释放,读取时加上共享锁后(这样在事务1读取数据的过程中,其他事务就不会修改该数据),不允许任何事务操作该数据,只能读取,之后1如果有更新操作,那么会转换为排他锁,其他事务更无权参与进来读写,这样就防止了脏读问题
但是当事务1读取数据过程中,有可能其他事务也读取了该数据,读取完毕后共享锁释放,此时事务1修改数据,修改完毕提交事务,其他事务再次读取数据时候发现数据不一致,就会出现先不可重复读问题,所以这样不能够避免不可重复读问题
当执行不同的隔离级别时,可能会发生各种各样不同的问题。下面对他们进行总结并举例说明:
脏读发生在一个事务A读取了被另一个事务B修改,但是还未提交的数据。假如B回退,则事务A读取的是无效的数据。这跟不可重复读类似,但是第二个事务不需要执行提交。
事务1 | 事务2 |
SELECT * FROM users WHERE id=1 | |
UPDATE users SET age=21 WHERE id=1; | |
SELECT * FROM users WHERE id=1; | |
COMMIT; /* lock-based DIRTY READ */ |
【小结】
并发操作引起的问题还是比较常见的,在多用户共享系统中,许多事务可能同时对同意数据进行操作,此时可能会破环数据库的完整性
数据库真是一个神奇的东西,对于数据库的学习还在探索中,遇到问题不断总结不断积累,期待自己变成大神的一天
以上仅代表我的个人观点,如有不同见解,欢迎指正