事务的隔离级别分为4个,即
读未提交(read uncommitted):
事务在读数据的时候并未对数据加锁。
事务在修改数据的时候只对数据增加行级共享锁。
读已提交(read committed):
事务对当前被读取的数据加 行级共享锁(当读到时才加锁),一旦读完该行,立即释放该行级共享锁;
事务在更新某数据的瞬间(就是发生更新的瞬间),必须先对其加 行级排他锁,直到事务结束才释放。
可重复读(Repeatable read):
事务在读取某数据的瞬间(就是开始读取的瞬间),必须先对其加 行级共享锁,直到事务结束才释放;
事务在更新某数据的瞬间(就是发生更新的瞬间),必须先对其加 行级排他锁,直到事务结束才释放。
可串行化(Serializable):
事务在读取数据时,必须先对其加 表级共享锁 ,直到事务结束才释放;
事务在更新数据时,必须先对其加 表级排他锁 ,直到事务结束才释放。
这四个级别可以逐个解决脏读、不可重复读、幻读这几类问题
脏读:读到的不是最新的数据
不可重复读:读到是是最新的数据,但是一个事务中如果多次读取,可能每次读到的数据不一致
幻读:无法保证每次读取的行数量一致,因为其它事务插入无法阻止,可能造成第一次读是15行,第二次是16行
oracle默认的隔离级别为 读已提交。mysql的默认隔离级别为 可重复读。
隔离级别越高,越能保证数据的完整性和统一性,但是对并发性能的影响也越大。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed。它能够避免脏读,而且具有较好的并发性能。尽管它会导致不可重复读、幻读和第二类丢失更新这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。MySQL支持四种事务隔离级别,其中REPEATABLE READ为默认事务隔离级别。
锁
从数据库系统的角度来看,锁分为共享锁和排他锁,从程序员的角度看,锁分为悲观锁和乐观锁。
共享锁(S锁, 读锁)
共享锁锁定的资源可以被其它用户读取,但其它用户不能修改它。在SELECT 命令执行时,SQL Server 通常会对对象进行共享锁锁定。通常加共享锁的数据页被读取完毕后,共享锁就会立即被释放。
排他/独占锁(X锁,写锁)
独占锁锁定的资源只允许进行锁定操作的程序使用,其它任何对它的操作均不会被接受。执行数据更新命令,即INSERT、UPDATE 或DELETE 命令时,SQL Server 会自动使用独占锁。但当对象上有其它锁存在时,无法对其加独占锁。独占锁一直到事务结束才能被释放。
共享锁可以一层套一层得上锁,但排他锁只能加一个。
乐观锁
总是认为不会产生并发问题,每次去取数据的时候总认为不会有其他线程对数据进行修改,因此不会上锁,但是在更新时会判断其他线程在这之前有没有对数据进行修改,一般会使用版本号机制或CAS操作实现。version方式:一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。
悲观锁
总是假设最坏的情况,每次取数据时都认为其他线程会修改,所以都会加锁(读锁、写锁、行锁等),当其他线程想要访问数据时,都需要阻塞挂起。可以依靠数据库实现,如行锁、读锁和写锁等,都是在操作之前加锁,在Java中,synchronized的思想也是悲观锁。
根据范围,锁还可以划分成行级锁和表锁。