关于事务的简单总结(1)

事务概述

事务是指逻辑上的一组操作,这组操作要么一起成功,要么一起失败

	例如:A——B转帐,对应于如下两条sql语句
	update account set money=money-100 where name=‘a’;
	update account set money=money+100 where name=‘b’;

数据库默认有处理事务的能力,默认情况下一条语句一个事务。
也可以手动的控制事务,实现多条sql语句在一个事务中一起成功或一起失败。

数据库的事务实现

  jdbc控制事务
  
	start transaction; 开启事务,则这条语句之后的若干条sql都会处在一个事务中
	commit;	提交事务,此命令会完成这个事务,使这个事务中的所有的sql语句同时产生效果
	rollback; 回滚事务,此命令会取消这个事务,取消这个事务中的所有的sql语句产生的效果
	conn.setSavepoint();  设置保存点
	conn.rollback(sp);  回滚到保存点。

注意,回滚到保存点后,保存点之前的事务仍未提交,如果需要事务生效,仍需手动提交事务。

事务的四大特性

a. 原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
b. 一致性(Consistency)
事务前后数据的完整性必须保持一致。
c. 隔离性(Isolation)
指多个用户并发访问数据库时,一个用户的事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离。	
d. 持久性(Durability)
指一个事务一旦被提交,它对数据库中数据的改变就真实的发生了,接下来无论做任何操作哪怕是数据库故障也无法再撤销这个事务

隔离性的探讨

数据库的其他三大特性数据库可以帮我们保证,而隔离性我们需要再讨论。
如果我们是数据库的设计者,该如何考虑设计数据库保证数据库的隔离性呢?
我们知道数据库的隔离性问题本质上就是多线程并发安全性问题。
可以用锁来解决多线程并发安全问题,但是如果用了锁,必然会造成程序的性能大大的下降.对于数据库这种高并发要求的程序来说这是不可接受的.

所以我们需要对隔离性问题进行进一步的探讨

问题:

	1.	如果两个线程并发查询,会不会产生线程安全问题?
	2.	如果两个线程并发修改,会不会产生线程安全问题?
	3.	如果一个线程修改 一个线程查询  会不会产生线程安全问题?

经过分析:

  1. 如果两个线程并发查询,必然没有问题,不需要隔离
  2. 如果两个线程并发修改,必然产生多线程并发安全问题,必须隔离开
  3. 如果一个线程修改 ,一个线程查询, 可能会产生脏读,不可重复读或虚读/幻读问题,而这些问题有些场景下是问题,有些场景下不是问题。而想要防止的问题越多,对数据库性能的影响就越大,所以到底要将数据库设置到何种状态来防止哪类问题不应该在数据库中写死,而应该提供相应的选项让数据库的使用者根据不同的场景灵活的选择 – 本质上是对 数据的可靠性 和 数据库的效率 之间的选择。

所以最终数据库设计者在设计数据库时,对于并发的查询没有做隔离,对于并发的修改做了严格的隔离,对于并发的读和写提供了相应的选项允许数据库的使用者选择,来根据需求防止不同的问题,这些选项就称之为数据库的隔离级别。

在一个线程修改一个线程查询的情况下可能产生的问题

a. 脏读:一个事务读取到另一个事务未提交的数据,造成数据混乱产生的问题

	小a向小b买一双鞋
	---------------------
	a 1000
	b 1000
	---------------------
	a:
	start transaction;
	update account set money = money - 100 where name  = 'a';
	update account set money = money + 100 where name  = 'b'; 
	--------------------------------------
	b:
	set session transaction isolation level read uncommitted;
	start transaction;
	select * from account;
	commit;
	---------------------
	a 900
	b 1100
	---------------------
	--------------------------------------	 
	a:
	rollback;	 
	--------------------------------------
	b:
	start transaction;
	select * from account;
	commit;
	---------------------
	a 1000
	b 1000
	---------------------
	--------------------------------------

2. 不可重复读:一个事务可以读取到另一个事务已经提交的数据,造成同一个事务中对同一数据先后读取不一致造成问题。

		小b统计银行账户信息,小a取款,造成统计结果出错
		---------------
		a 1000 1000 1000
		--------------- 
		b:
		start transaction;
		select 活期 from account where name = 'a';   ---  活期存款:1000
		select 定期 from account where name = 'a';   ---  定期存款:1000
		select 固定 from account where name = 'a';   ---  固定资产:1000
		------------
		a:
		start transaction;
		update account set 活期 = 活期 - 100 where name = 'a';
		commit;
		---------------
		a 900 1000 1000
		--------------- 
		------------
		select 活期 + 定期 + 固定 from account where name = 'a'; --- 总资产 2900
		commit;

3. 虚读/幻读:一个事务读取到另一个事务已经提交的数据。只在读写整表数据时产生。虚读/幻读并不是每次都会产生,有可能会发生,也有可能不发生。

		小c统计银行总体账户信息,小d新建账户,造成统计结果出错
		-----------------
		a 1000
		b 2000
		-----------------
		c:
		start transaction;
		select sum(money) from account; --- 总存款:3000
		select count(1) from account; --- 总账户数:2
		--------------------
		d:
		start transaction;
		insert into account values ('d',3000);
		commit;
		-----------------
		a 1000
		b 2000
		d 3000
		-----------------
		--------------------
		select avg(money) from account; --- 平均每账户存款 2000
		commit;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值