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 都是一个事务所以最好去创建一个事务, 把下面的
所有操作放到一个事务里, 要不都成功, 要不都失败
来源: http://www.bubuko.com/infodetail-2518761.html