数据库的锁、事务

1、锁

锁策略:

1、数据库的写操作必须向服务器申请并获得写锁才能修改数据,而读操作必须申请和获得读锁才能查数据。多用户可以同时读数据,而一个表一次只能分配一个写锁,并且拒绝读请求直至写锁释放。

2、数据库的写操作必须向服务器申请并获得写锁才能修改数据,而读操作不需要任何类型的锁就可以查数据。另一方面,服务器要保证从查询开始到结束读操作看到一个一致的视图。这个方法叫做版本控制。

这两种方法各有弊利。第一种方法在有较多的并行读请求和写请求时等待时间过长;如果在修改时存在长期运行的查询,则第二种方法也是有为题的。Oracle 使用第二种方法,SQL Server 使用第一种,MySQL两种都有,取决于存储引擎。

2、锁的粒度

表锁:

        阻止多用户同事修改同一个表的数据。

页锁:

        阻止多用户同时修改表中的同一页(一页通常是一段2~16kb的内存空间)的数据

行锁:

        阻止多用户同时修改某表中同一行的数据。

同样,这些方法各有弊利。表锁需要较少的薄记就可以锁定整个表,但是用户增多时他会产生不可接受的等待时间。另一方面,行锁需要更多的薄记,但是只要用户的兴趣不在同一行,他就能允许许多人修改同一张表。SQL Server 使用表锁、页锁、行锁;Oracle 只有行锁;MySQL使用表锁、页锁、行锁(同样取决于存储引擎的选择)。某些情况下,SQL Server 会从行锁升级到也锁再到表锁,但是Oracle 从不升级锁。

3、什么是事务

事务,他是一种将多条sql语句聚集到一起,并且能够实现要么所有语句执行,要么一个都不执行(这就是原子性)。试想从储蓄账户转500到支票账户,如果已经从储蓄账户成功支出,但是支票账户没有收到,那一定是令人很沮丧的事情。

为了避免这种错误,处理转账申请的程序首先启动一个事务,然后发起sql语句把钱从储蓄账户转到支票账户,如果成功,发出commit命令结束事务;否则意外发生,就发出rollback命令撤销服务器自事务开始是的所有变化。整个过程大概如下:

START TRANSACTION;

/* withdraw money from first account, making sure balance is sufficient.
UPDATE account SET avail balance = avail balance-500 WHERE account id = 9988 AND avail balance > 500;

IF <exactly one row was updated by the previous statement> THEN
	/* deposit money into second account */
	UPDATE account SET avail balance = avail balance  500 WHERE account id = 9989;

	IF <exactly one row was updated by the previous statement> THEN
	    /* everything worked, make the changes permanent */
		COMMIT;
	ELSE
	    /* something went wrong, undo all changes in this transaction */
		ROLLBACK;
	END IF;
	
ELSE
	/* insufficient funds, or error encountered during update */
	ROLLBACK;
END IF;

提示:上面的是伪代码,不是真正的sql语句。

最后不管事务是提交了,还是回滚了,执行时获得的资源(比如写锁)在事务完成后都会被释放。

4、启动事务

两种方式启动事务:

1)一个活跃的事务总是和数据库会话相联系,所以没有必要,也没有办法能够显示的启动一个事务。当事务结束时,服务器自动为回话启动一个新的事务。

2)如果不显示的启动给一个会话,单个的sql语句会被独立于其他语句自动提交。启动一个事务之前需先提交一个命令。

Oracle 使用第一种,SQL Server、MySQL使用第二种。Oracle 优势在于,即使只是单个sql,不喜欢最终结果也可以回滚事务。

MySQL 启动事务 :start transaction。SQL Server 启动事务:begin transaction。

MySQL关闭自动提交:SET AUTOCOMMIT=0; SQL Server关闭自动提交:SET IMPLICIT_TRANSACTION

5、结束事务

除了commit 和 rollback,结束事务还可以由其他情节触发,要么作为活动的见解结果,要么作为意外结果。

1)服务器宕机,在这种情况下,服务器重启是事务将会被自动回滚;

2)提交一个SQL模式语句,比如 alter table,这将会引起当前事务提交和一个新的事务的启动。

3)提交一个 start transaction命令,将会引起前一个事务的提交。

4)因为服务器检测到一个死锁并且确定当前事务就是罪魁祸首,那么服务器就会提前结束当前事务。这种情况下,事务会回滚,同事释放错误信息。

1、3情况比较容易理解。

第二种情况来说,数据库的更改,无论是增加一个新表或者新索引还是删除表中的一列,都不能回滚。因此,如果事务正在进行,那么服务器将会提前提交当前事务,然后为回话在启动一个新的事务。服务器不会通知读者发生了什么,所以我们应该注意那些组成一个工作单元的语句不被服务器意外的分为多个事务。

第四种情景处理死锁。锁发生在两个不同的事务同事等待同一个资源,而这个资源正在被另外一个事务拥有的时候。比如说,事务A刚好更新完 account 表,现在真正等待 transaction 表的写锁,然而B事务向 transaction 表插入了一行数据,现在正在等待account 表 的写锁。如果两个事务刚好修改同一页或者行(取决于锁粒度),那么他们永远等待对方完成并释放自己所需的资源。当遇到这种情况,数据库会选择一个事务进行回滚,这样其他的事务才能进行下去。数据库会返回错误信息。

6、事务保存点

在某种情况下,可能会遇到一些问题需要回滚事务,但是并不想撤销所有做过的操作,此时可以在事务内创建一个或者多个保存点,这样就可以利用他们回滚到事务的特定位置而不是回滚到事务启动的状态。

所有的白村点都必须拥有一个名字,这样就可以在单个事务中拥有多个保存点。 建一个保存点的命令: SAVEPOINT my_point;

回到保存点:ROLLBACK TO  SAVEPOINT my_point.


MySQL 选择存储引擎:

有多种,使用不同的锁粒度;

MyISAM  采用表锁

。。。。。

最常用的  InnoDB    采用 行锁;Falcon 也是行锁,高性能。

查看表的引擎命令: SHOW TABLE STATUS LIKE   表名 ; 如:SHOW TABLE STATUS LIKE 'library_bookrack'

设置引擎:alter table 表名 ENGINE  = INNODB    

猜你喜欢

转载自blog.csdn.net/qq_15916363/article/details/80711198