テン、JDBC--総務(4)

まず、トランザクション

1.1基本概念情勢


			事务指一组最小的逻辑操作单元,里面有多个操作组成。组成这组操作的各个单元,要不全部成功,要不全部不成功。
			如果有一个操作失败,整个操作就回滚。
			
			例如:A——B转帐,对应于如下两条sql语句
			  update from account set money=money+100 where name=‘b’;
			  update from account set money=money-100 where name=‘a
	



第二には、SQLセットのトランザクションを使用します

トランザクションを作成し、提出

	START TRANSACTION;
	UPDATE account SET money=money-1000 WHERE NAME='小白';
	UPDATE account SET money=money+1000 WHERE NAME='黑四';
	COMMIT;
	
	sql执行完毕,两个sql语句都执行成功。

トランザクション、およびロールバックを作成します。

	
	START TRANSACTION;
	UPDATE account SET money=money-1000 WHERE NAME='小白';
	UPDATE account SET money=money+1000 WHERE NAME='黑四';
	ROLLBACK;
	
	sql执行完毕,两个sql都被回滚了,所以结果相当于没有执行。
	

トランザクションを作成し、ロールバックポイント、ロールバックの一部を作成します。

	
	START TRANSACTION;
	UPDATE account SET money=money-1000 WHERE NAME='小白';
	
	SAVEPOINT sp;  
	UPDATE account SET money=money+1000 WHERE NAME='黑四';
	ROLLBACK TO sp;
	
	sql执行完毕,由于设置了回滚点sp。
	所以第一个sql执行成功,第二个sql回滚。

三、API情勢

	技术:
|-- Connection
		void setAutoCommit(boolean autoCommit) ;  设置事务是否自动提交
										          如果设置为false,表示手动提交事务。
		void commit() ;						      手动提交事务
		void rollback() ;						  回滚(出现异常时候,所有已经执行成功的代码需要回退到事务开始前的状态。)
		Savepoint setSavepoint(String name)       设置回滚点

注意:	
		1.mysql默认开启隐式的事务,对已经执行成功的sql,默认提交。

例:転送のシミュレーション、トランザクションを使用しません。

	第一个sql执行成功(不回滚),
	第二个sql执行失败(回滚)。
	
	mysql默认开启隐式性事务,即sql执行完毕,默认提交。
	第一个sql执行完毕,默认提交,所以不会滚。
	第二个sql执行失败,所以回滚。
		@Test
		public void test1() throws SQLException {
			
			Connection conn=null;
			PreparedStatement st1=null;
			PreparedStatement st2=null;
			
			//模拟转账
			String sql1_zh="update account set money=money-1000 where name='小白'";
			String sql1_dz="update account set money=money+1000 where name='黑四'";

			try {
				
				conn = JdbcUtil.getConn();
				
			
				//第一次执行sql  小白转给小黑  转账
				st1 = conn.prepareStatement(sql1_zh);
				int row1 = st1.executeUpdate();
				
				if(1==1){
					throw new RuntimeException();
				}
				
				//第二次执行sql  小白转给小黑  到账
				st2 = conn.prepareStatement(sql1_dz);
				int row2 = st2.executeUpdate();

			} catch (Exception e) {
			
				throw new RuntimeException(e);
			}finally {
							
				JdbcUtil.close(conn, st1);
				JdbcUtil.close(conn, st2);	
			}
		}
		
	

例:転送、使用トランザクションをシミュレートします。

	第一个sql执行成功(回滚),
	第二个sql执行失败(回滚)。
	
	由于在执行第一个sql前,已经手动开启事务,
	事务中发生异常,则全部回滚,
	所以第一个sql回滚,第二个sql也回滚。
		
		@Test
		public void test12() throws SQLException {
			
			Connection conn=null;
			PreparedStatement st1=null;
			PreparedStatement st2=null;
			
			//模拟转账
			String sql1_zh="update account set money=money-1000 where name='小白'";
			String sql1_dz="update account set money=money+1000 where name='黑四'";

			try {
				
				conn = JdbcUtil.getConn(); //默认开启隐式事务。
				
				//一、手动开启事务
				conn.setAutoCommit(false);
				
			
				//第一次执行sql  小白转给小黑  转账
				st1 = conn.prepareStatement(sql1_zh);
				int row1 = st1.executeUpdate();
				
				if(1==1){
					throw new RuntimeException();
				}
				
				//第二次执行sql  小白转给小黑  到账
				st2 = conn.prepareStatement(sql1_dz);
				int row2 = st2.executeUpdate();

			} catch (Exception e) {
				
				//二、若发生异常,手动回滚
				conn.rollback();
				
				throw new RuntimeException(e);
			}finally {
				
				//三、手动提交事务
				conn.commit();
				
				JdbcUtil.close(conn, st1);
				JdbcUtil.close(conn, st2);	
			}
		}
		

例:2つのアナログ転送、トランザクション特定コードにロールバックを使用して

	第一次转账执行成功,(不回滚)
	第二次转账执行失败。(回滚)
	
	由于在执行第一次转账执行成功后设置了回滚点,
	事务中发生异常后,又手动回滚到了回滚点,
	所以第一次转账提交,
	第二次转账失败。
		@Test
		public void test12() throws SQLException {
			
			Connection conn=null;
			PreparedStatement st1=null;
			PreparedStatement st2=null;
			PreparedStatement st3=null;
			PreparedStatement st4=null;

			Savepoint sp=null;
			
			//模拟第一次转账
			String sql1_zh="update account set money=money-1000 where name='小白'";
			String sql1_dz="update account set money=money+1000 where name='黑四'";
			
			
			//模拟第二次转账
			String sql2_zh="update account set money=money-1000 where name='小白'";
			String sql2_dz="update account set money=money+1000 where name='黑四'";

			
			try {
				
				conn = JdbcUtil.getConn(); //默认开启隐式事务。
				
				//一、手动开启事务
				conn.setAutoCommit(false);
				
			
				//第一次转账
				st1 = conn.prepareStatement(sql1_zh);
				st1.executeUpdate();
				st2 = conn.prepareStatement(sql1_dz);
				st2.executeUpdate();
				
				//四、设置回滚点
				 sp = conn.setSavepoint();
				
				if(1==1){
					throw new RuntimeException();
				}
				
				//第二次转账
				st3 = conn.prepareStatement(sql2_zh);
				st3.executeUpdate();
				st4 = conn.prepareStatement(sql2_dz);
				st4.executeUpdate();

			} catch (Exception e) {
				
				//二、若发生异常,手动回滚,回滚到某个点
				conn.rollback(sp);
				
				throw new RuntimeException(e);
			}finally {
				
				//三、手动提交事务
				conn.commit();
				
				JdbcUtil.close(conn, st1);
				JdbcUtil.close(conn, st2);	
			}
		}
		
	

第四に、取引の特徴

4.1特性情勢

	+++ 事务ACID特性
	
				原子性(Atomicity)
					事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。 
				
				一致性(Consistency)
					事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
				
				隔离性(Isolation)
					多个用户并发访问数据库时,一个用户的事务不能被其他用户的事务所
					干扰,并发事务之间数据要相互隔离。

					如果不考虑隔离性,会引发安全问题如下:脏读、不可重复读、幻读(虚读)。
				
				持久性(Durability)
					持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响

		事务的特性:
		原子性,是一个最小逻辑操作单元 !
		一致性,事务过程中,数据处于一致状态。
		持久性, 事务一旦提交成功,对数据的更改会反映到数据库中。
		隔离性, 事务与事务之间是隔离的。

第五に、トランザクションの分離レベル(トランザクション遮断)


		多个线程开启各自事务操作数据库中数据时,数据库系统要负责隔离操作,以
		保证各个线程在获取数据时的准确性。
		

5.1あなたは、分離を考慮していない場合は、次のような問題が発生することがあり

5.1.1ダーティリード
	脏读:
		一个事务读取了另一个事务改写但还未提交的数据,如果这些数据被回滚,则读到的数据是无效的。
		
		这是非常危险的,假设A向B转帐100元,对应sql语句如下所示
		1.update account set money=money-100 while name=‘a’;	
		2.update account set money=money+100 while name=‘b’;
		
		当第1条sql执行完,第2条还没执行(A未提交时),如果此时B查询自己的
		帐户,就会发现自己多了100元钱。如果A等B走后再回滚,B就会损失100元。
5.1.2非反復可能読み取り
	不可重复读:
	
		在一个事务内读取表中的同一数据,多次读取结果不同。
		
		在同一事务中,多次读取同一数据返回的结果有所不同,读到了之前的数据
		后又读到了其他事务已经提交的更新的数据。
		
		例如:
			在事务A中,读取到张三的工资为5000,操作没有完成,事务还没提交。
			与此同时,
			事务B把张三的工资改为8000,并提交了事务。
			随后,
			在事务A中,再次读取张三的工资,此时工资变为8000。在一个事务中前后两次读取的结果并不致,导致了不可重复读。



	很多人认为这种情况就对了,无须困惑,当然是后面的为准。我们可以考虑这样一种
	情况,比如银行程序需要将查询结果分别输出到电脑屏幕和写到文件中,结果在一个
	事务中针对输出的目的地,进行的两次查询不一致,导致文件和屏幕中的结果不一
	致,银行工作人员就不知道以哪个为准了。

	和脏读的区别是:脏读是读取前一事务未提交的脏数据,不可重复读是重新读取了
	前一事务已提交的数据。
5.1.3ダミーリード(ファントムリード)
	虚读(幻读)
		
		是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。
		
		如丙存款100元未提交,这时银行做报表统计account表中所有用户的总额
	为500元,然后丙提交了,这时银行再统计发现帐户为600元了,造成虚读同样
	会使银行不知所措,到底以哪个为准。
	
5.1.4最初に失われたアップデート

場合は、トランザクション・後退、更新データBのトランザクションは、カバーを提出されました。例えば:

ここに画像を挿入説明
この時間出納トランザクションAトランザクションの後退は、更新を失った、1000年のバランスを回復します。

5.1.5第二のカテゴリー失わアップデート

Bの取引をカバーするトランザクションデータがB会社で、その結果、犯した営業損失を行います

ここに画像を挿入説明

5.1.6概要 - 違い
	脏读:是指在一个事务中读取到另外一个事务还未提交的数据。
	
	不可重复读:在同一事务中,多次读取同一数据返回的结果有所不同,读到了
				之前的数据后又读到了其他事务已经提交的更新的数据。
	幻读:是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。
	
	+++ 脏读和不可重复读的区别:
			脏读是读取前一事务未提交的脏数据,
			不可重复读是重新读取了前一事务已提交的数据。
	
	+++ 不可重复读和幻读的区别:
			不可重复度是指读的时候 别的事务修改了数据update
			幻读是指读的时候 别的事务插入或者删除了数据 insert delete 
			
			不可重复读的重点是修改: 
					同样的条件,你读取过的数据,再次读取出来发现值不一样了。
					关注的是数据的变化。
					
			幻读的重点在于新增或者删除: 
					同样的条件,第 1 次和第 2 次读出来的记录数不一样
					关注的是数据条数的变化。

5.2トランザクション分離設定文

	数据库共定义了四种隔离级别:
			Serializable:可避免脏读、不可重复读、虚读情况的发生。(串行化)
			
			Repeatable read:可避免脏读、不可重复读情况的发生。(可重复读)
			
			Read committed:可避免脏读情况发生(读已提交)。
			
			Read uncommitted:最低级别,以上情况均无法保证。(读未提交)
	
	
	Mysql默认采用REPEATABLE_READ隔离级别。

	Oracle默认采用READ_COMMITTED隔离级别。

ここに画像を挿入説明

5.2.1使用するSQLは、トランザクション分離レベルを設定します
	
		set session  transaction isolation level 设置事务隔离级别
      如:set session transaction isolation level read uncommitted;
      
		select @@tx_isolation	查询当前事务隔离级别
公開された94元の記事 ウォンの賞賛0 ビュー627

おすすめ

転載: blog.csdn.net/weixin_45602227/article/details/104238128
おすすめ