2.数据库之事务管理
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2.数据库之事务管理相关的知识,希望对你有一定的参考价值。
1.3 并发控制
不论何时,只要有多个连接在同一时刻修改数据,就会产生并发问题。但是当多个连接只做读取数据操作时,不会产生并发控制的问题,因为读取操作不会修改数据。
在事务执行过程中,只有执行commit或者rollback后,锁才会被释放,而且是该事务内所有表的锁同步释放。
1.3.1 读写锁
对于并发问题的解决方案就是并发控制。并发控制是由锁系统来完成的,锁系统包含两种锁,共享锁和排他锁,也叫读锁和写锁。读锁是共享的,相互不堵塞,也就是说在同一时刻多个连接可以读取同一资源而不相互干扰。写锁是拍他的,也就是说一个写锁会阻塞其他的读锁和写锁。
1.3.2 锁粒度
提高共享资源并发性的方式就是让锁定对象更有选择性。尽量只锁定需要修改的部分而不是所有数据。这样不会影响到其他线程对未锁定数据的读取和写操作。
问题是加锁也需要消耗资源。包括锁的各项操作,比如加锁、释放锁、检查锁是否解除,都会加大系统的开销。如果花费部分性能去管理锁而不是读取数据,也会影响到系统的性能。这就涉及到锁策略。所谓的锁策略就是在系统性能和数据安全性之间寻求平衡。mysql的每种存储引擎都有自己的锁策略。
最重要的两种锁策略:表锁和行级锁。
表锁:表锁会锁定整张表,是对系统开销最小的锁策略。当一个线程对表进行写操作时,整张表被锁定,这会阻塞其他的线程对该表的读写操作。尽管存储引擎层可以管理锁,mysql服务层也会使用有效的表锁实现不同的目的。例如服务器层会为诸如alter table之类加表锁,忽略存储引擎层的锁机制。
行级锁:行级锁可以最大程度的支持并发处理(同时也带来了最大的锁开销)。行级锁只在存储引擎层实现。
在实际的数据库系统中,每时每刻都在发生锁定,当某个用户正在修改某一部分数据时,mysql会通过锁定防止其他用户读取同一数据。
1.4 事务
1.4.1 事务的特性:原子性、隔离性、持久性
原子性:整个事务中的所有操作要么全部成功,要么全部失败,对于一个事务来说,不可能只执行其中的一部分。
隔离性:一个事务所做的修改在提交之前,其他的事务是不可见的。
持久性:一旦事务提交,所做的修改就会永久保存到数据库中。
1.4.2 事务的隔离级别:
1. 读未提交:一个事务可以读取另一个事务未提交的数据。这样会产生脏读,实际生产环境一般不会用。
2. 读提交/(另一个事务执行update操作时本事务不可重复读):一个事务A有两个相同的sql查询语句,这个事务开启第一个查询语句时,另一个事务B开始对这条数据执行更新(update)操作,那么事务B会对这条记录开启行级锁,此时事务A就会被阻塞,第二条查询的sql语句要在事务B执行完后才能执行,而此时事务A的第二次查询结果跟第一次查询结果就不一样了。这就是不可重复读。读提交可以解决脏读的问题。大部分的数据库默认采用读提交的事务隔离级别,但mysql不是。
3. 可重复读(解决了不可重复读的问题,但是在另一个事务执行insert操作时,会出现幻读):事务A开始读取数据时,其他的事务不允许进行修改(update)操作。mysql默认采用重复读的隔离级别。但是重复读可能会出现幻读,因为重复读针对的是update操作。如果事务A要预览用户的消费清单并打印清单,预览时,用户有10条消费记录,而在打印清单之前,用户又消费了一笔,事务B执行了添加操作并提交了事务,此时事务A打印的清单会发现多了一条记录,这就是幻读。
4. 串行执行事务。
mysql默认的事务隔离级别是可重复读,当然可以修改mysql默认的事务隔离级别。
1.4.3 死锁
死锁是指两个或多个事务已经锁定了某个资源,并互相请求去锁定对方已经锁定的资源,这样会造成多个事务无法释放锁导致恶性循环。这样每个事务都不会执行完并一直占有锁。
例如:
事务1:
start transaction;
update student set name = ‘zhangsan‘ where id = 1;
update student set name = ‘lisi‘ where id = 2;
commit;
事务2:
start transaction;
update student set name = ‘zhangsan‘ where id = 2;
update student set name = ‘lisi‘ where id = 1;
commit;
如果凑巧,两个事务都执行了第一条sql,更新了一条数据,也就是锁定了改行数据。接着每个事务都尝试执行第二条sql,却发现该行已被对方锁定。然后两个事务都等待对方释放锁,同时又拥有对方需要的锁,陷入死循环。除非有外部因素介入才能解除死锁。
1.4.4 mysql中的事务
mysql的事务默认采用autocommit模式。也就是说只要不显式的开启一个事务,每一条sql都会被当做当做一个事务执行提交操作。在当前jdbc连接中,可以通过设置autocommit变量来启用或禁用自动提交模式。
1.4.5 在事务中混合使用存储引擎
mysql服务器层不管理事务,事务由下层的存储引擎实现。所以在同一个事务中,使用多种存储引擎是不可靠的。
如果在事务中操作了事务型的表和非事务型的表,在正常提交事务时不会出现问题。但是如果事务回滚,事务型的表数据会回滚,而非事务型的表则不会回滚,因为非事务型的表不支持事务,这样就会导致数据紊乱。所以,为每张表选择合适的存储引擎非常重要。
mysql是自动提交事务的,使用jdbc时,只要不显式的关闭自动提交,每一条sql都是一个事务。所以最好去创建一个事务,把下面的
所有操作放到一个事务里,要不都成功,要不都失败。
以上是关于2.数据库之事务管理的主要内容,如果未能解决你的问题,请参考以下文章