事务和锁机制是什么关系? 开启事务就自动加锁了吗?
数据库锁
因为数据库要解决并发控制问题。在同一时刻,可能会有多个客户端对同一张表进行操作,比如有的在读取该行数据,其他的尝试去删除它。为了保证数据的一致性,数据库就要对这种并发操作进行控制,因此就有了锁的概念。
锁的分类
从对数据库操作的类型
读锁(共享锁):针对同一块数据,多个读操作可以同时进行而不会互相影响。由读表操作加上的锁,加锁后其他用户只能获取该表或行的共享锁,不能获取排它锁,也就是说只能读不能写。
写锁(排它锁):当当前写操作没有完成之前,它会阻断其他写锁和读锁。由写表操作加上的锁,加锁后其他用户不能获取该表或行的任何锁。
从锁定的数据范围分
表锁:锁定某个表。
行锁 :锁定某行。
为了尽可能 提高数据库的并发度,每次锁定的数据范围越小越好。理论上每次只锁定当前操作的数据的方案会得到最大的并发度,但是管理锁是很耗费资源的事情。因此数据库系统需要在高并发响应和系统性能两方面进行平衡,这样就产生了“锁粒度”的概念。
锁粒度
表锁:管理锁的开销最小,同时允许的并发量也最小的锁机制。MyIsam存储引擎使用的锁机制。当要写入数据时,把整个表都锁上,此时其他读、写动作一律等待。在MySql中,除了MyIsam存储引擎使用这种锁策略外,MySql本身也使用表锁来执行某些特定动作,比如alter table.
行锁:可以支持最大并发的锁策略。InnoDB和Falcon两张存储引擎都采用这种策略。
MySql是一种开放的架构,你可以实现自己的存储引擎,并实现自己的锁粒度策略,不像Oracle,你没有机会改变锁策略,Oracle采用的是行锁。从大到小,mysql服务器仅支持表级锁,行锁需要存储引擎完成。粒度越精细,并发性越好。即行锁的并发性最好,但需要存储引擎的支持。
数据库事务有不同的隔离级别,不同的隔离级别对锁的使用是不同的,锁的应用最终导致不同事务的隔离级别。
1、事务与锁是不同的。事务具有ACID(原子性、一致性、隔离性和持久性),锁是用于解决隔离性的一种机制。
2、事务的隔离级别通过锁的机制来实现。另外锁有不同的粒度,同时事务也是有不同的隔离级别的。
3、开启事务就自动加锁。
四种隔离级别采取不同的锁类型来实现,若读取的是同一个数据的话,就容易发生问题。例如:
脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。
不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。
幻读(Phantom Read):在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。
mysql加锁机制:
根据类型可分为共享锁(SHARED LOCK)和排他锁(EXCLUSIVE LOCK)或者叫读锁(READ LOCK)和写锁(WRITE LOCK)。
根据粒度划分又分表锁和行锁。表锁由数据库服务器实现,行锁由存储引擎实现。
mysql提供了3种事务型存储引擎,InnDB、NDB Cluster和Falcon。
一个事务执行的任何过程中都可以获得锁,但是只有事务提交或回滚的时候才释放这些锁。这些都是隐式锁定,也可以显式锁定,InnoDB支持显式锁定,例如:
SELECT .... LOCK IN SHARE MODE (加共享锁)
SELECT .....FOR UPDATE(加排他锁)
多版本并发控制(重要):
Mysql的事务存储引擎不是简单实用行加锁机制,而是叫多版本并发控制(MVCC)技术,和行加锁机制关联实用。以便应对更高的并发,当然是以消耗性能作为代价。
每种存储引擎对MVCC的实现方式不同,InnoDB引擎的简单实现方式如下:
InnoDB通过为每个数据航增加两个隐含值的方式来实现。这两个隐含值记录了行的创建时间,以及过期时间。每一行存储事件发生时的系统版本号。每一次开始一个新事务时版本号会自动加1,每个事务都会保存开始时的版本号,每个查询根据事务的版本号来查询结果。
MySQL使用以下几种机制进行隔离性的实现:
a.锁机制: 通过使用加锁机制,使用其它事务无法到读某事务末提交前的数据更新,解决脏读问题; mySQL 有:共享锁,排他锁,根据粒度,有行锁,表锁。
b.MVCC机制: 事务存储引擎使用多版本并发控制(MVCC)技术,和行加锁机制关联使用 。MySQL 的InnoDB,XtraDB 引擎通过 使用MVCC 来解决可重复读问题。
事务与锁是不同的。事务具有ACID( 原子性、一致性、隔离性和持久性),锁是用于解决隔离性的一种机制。事务的隔离级别通过锁的机制来实现。另外锁有不同的粒度,同时事务也是有不同的隔离级别的(一般有四种:读未提交Read uncommitted, 读已提交Read committed, 可重复读Repeatable read, 可串行化Serializable)。 在具体的程序设计中,开启事务其实是要数据库支持才行的,如果数据库本身不支持事务,那么仍然无法确保你在程序中使用的事务是有效的。 锁可以分为乐观锁和悲观锁: 悲观锁:认为在修改数据库数据的这段时间里存在着也想修改此数据的事务; 乐观锁:认为在短暂的时间里不会有事务来修改此数据库的数据; 我们一般意义上讲的锁其实是指悲观锁,在数据处理过程中,将数据置于锁定状态(由数据库实现)。 回到你的问题,如果开启了事务,在事务没提交之前,别人是无法修改该数据的;如果rollback,你在本次事务中的修改将撤消(不是别人修改的会没有,因为别人此时无法修改)。当然,前提是你使用的数据库支持事务。还有一个要注意的是,部分数据库支持自定义SQL锁覆盖事务隔离级别默认的锁机制,如果使用了自定义的锁,那就另当别论。 重点:一般事务使用的是悲观锁(具有排他性)。