一、事务的特性

1、事务的特性
	* 有四个特性:
		-原子性:在事务里面操作,要么都成功,要么都失败
		
		-一致性:在事务操作过程中,数据要保持一致
			--比如 小金给小丽转账10000,过程出现了异常,钱不会丢失
	
		-隔离性:在多个事务同时对一张表操作的时候,多个事务直接互相不影响
		
		-持久性:提交事务之后,数据就会真正生效

 二、事务的隔离性产生的问题

2、事务的隔离性
	* 不考虑事务的隔离性,产生一些问题,五个问题,其中三个读的问题

	* 掌握三个读的问题,以及如果解决这三个读的问题

	* 三个读的问题
		-第一个问题:脏读:一个事务获取到了另一个事务里面没有提交的数据(一个事务操作数据但是还没有提交的时候,另一个事务能够查询到修改过后的结果,导致如果修改的那个事务回滚,修改的结果不变,但是后一个事务查询的结果是看到修改的值,那么会导致一直假转账现象。 故存在的问题是 脏读)
		
		-第二个问题:不可重复读:一个事务里面查询到了,另一事务里面update的操作,导致这个事务里面两次查询的结果不一致(一个事物修改了数据也提交了数据,但是另一个事务在修改完成没提交的时候去读一次,提交后又读取一次,导致两次查询的结果不一致。 故存在的问题是 不可重复读)
		
		-第三个问题:虚读(幻读):一个事务里面查询到了,另一个事务里面insert操作,导致这个事务里面两次查询的结果不一致(一个事务进行操作数据,也提交了数据,但是另外一个事务在没结束之前,读取到的数据一直都是修改之前的数据,要想读取到最新数据,需要结束当前事务再去读取数据的时候才会是更新过后的数据。 故存在的问题是 虚读/幻读)

	* 解决方式:通过设置事务的隔离级别解决这些读的问题
		Serializable:串行的.避免脏读、不可重复读和虚读发生 
		Repeatable read:重复读. 避免脏读、不可重复读.但是虚读还是有可能发生的 
		Read committed:已提交读.避免脏读.但是不可重复读和虚读有可能发生 
		Read uncommitted:未提交读.脏读、不可重复读、虚读都可能发生 
	
	* 隔离级别的优先级:Serializable -- Repeatable read -- Read committed -- Read uncommitted
	
	* 查询当前事务隔离级别:select @@tx_isolation;  
		-mysql数据库默认的隔离级别是:Repeatable read
	
	* set session transaction isolation level  设置事务隔离级别

	(1)演示脏读
		* 第一步操作:打开两个cmd窗口,分别登录mysql
		
		* 第二步操作:切换到要操作的数据库,在左边的窗口 设置隔离级别是 Read uncommitted,
			同时查看两个窗口里面的隔离级别
			set session transaction isolation level read uncommitted
		
		* 第三步操作:在两个窗口里面分别开启事务
		
		* 第四步操作:在右边的窗口里面做转账的操作,小奥给小苍转账10000
			update account set sal=sal-1000 where name='小奥'
			update account set sal=sal+1000 where name='小苍'
		
		* 第五步操作:在左边的窗口里面查看数据,可以查看到,但是右边窗口做回滚,左边在窗口数据没有了
		================================这种效果就是脏读=====================================
	
	(2)解决脏读:设置事务的隔离级别
		* 设置Read committed,解决脏读

		* 演示不可重复读和避免脏读
		
		* 第一步操作:打开两个cmd窗口,分别登录mysql
		
		* 第二步操作:切换到要操作的数据库,在左边的窗口设置隔离级别是Read committed
			同时查看两个窗口的隔离级别
			set session transaction isolation level read committed
		* 第三步操作:在两个窗口里面分别开启事务
		
		* 第四步操作:在左边窗口查看表中的数据,
			* 在右边窗口执行转账操作 小奥给小苍转账10000,在右边窗口里面提交事务
			update account set sal=sal-1000 where name='小奥'
			update account set sal=sal+1000 where name='小苍'
			========================================避免了脏读====================================
		* 再到左边窗口里面查看数据
			- 在左边窗口里面通过事务查看数据,这两次查看的结果不一样了
		
		* 多个事务之间互相影响到了,这个问题就是======================不可重复读==================


	(3)解决不可重复读
		* 设置事务的隔离级别是Repeatable read
		
		* 演示避免不可重复读
		
		* 第一步操作:打开两个cmd窗口,分别登录mysql
		
		* 第二步操作:切换到要操作的数据库,在左边的窗口设置隔离级别是Repeatable read
			同时查看两个窗口的隔离级别
			set session transaction isolation level repeatable read
		
		* 第三步操作:在两个窗口里面分别开启事务
		
		* 第四步操作:在左边窗口查看表中的数据,
			- 在右边窗口执行转账操作 小奥给小苍转账10000,在右边窗口里面提交事务
			update account set sal=sal-1000 where name='小奥'
			update account set sal=sal+1000 where name='小苍'
			===========================================避免了脏读================================
			* 再到左边窗口里面查看数据,数据没有变化,只有提交了当前事务之后数据才会变化
			===============================避免了不可重复读,但是存在虚读========================


	(4)解决虚读,
		*设置隔离级别是Serializable:串行的
			-set session transaction isolation level serializable
		
		* 第一步操作:打开两个cmd窗口,分别登录mysql
		
		* 第二步操作:切换到要操作的数据库,在左边的窗口设置隔离级别是Serializable
			同时查看两个窗口的隔离级别
			set session transaction isolation level serializable
		
		* 第三步操作:在两个窗口里面分别开启事务
		
		* 第四步操作:在右边窗口里面执行更新操作,
			在左边窗口里面查询表中的记录,出现了等待状态,在右边事务只有提交之后,左边的窗口类里面查询语句才会执行
			==========================================避免这三个读的问题===========================
			- 因为这个级别都不允许有多个事务同时进行操作

		
		** 记住事务的特性和事务的四个隔离级别

	(5)使用jdbc也可以设置事务的隔离级别(了解)
		** 通过Connection里面setTransactionIsolation(int level)设置事务的隔离级别
		** 通过Connection里面常量设置隔离级别
		static int TRANSACTION_READ_COMMITTED 
		 指示不可以发生脏读的常量;不可重复读和虚读可以发生。 
		static int TRANSACTION_READ_UNCOMMITTED 
		 指示可以发生脏读 (dirty read)、不可重复读和虚读 (phantom read) 的常量。 
		static int TRANSACTION_REPEATABLE_READ 
		 指示不可以发生脏读和不可重复读的常量;虚读可以发生。 
		static int TRANSACTION_SERIALIZABLE 
		 指示不可以发生脏读、不可重复读和虚读的常量。