spring的簡單入門(四)之事務

1.什麼是事務

►事務管理是企業級應用程序開發中必不可少的技術,  用來確保數據的完整性和一致性.
►事務就是一系列的動作, 它們被當做一個單獨的工作單元. 這些動作要麼全部完成, 要麼全部不起作用
►事務的四個關鍵屬性(ACID)
§原子性(atomicity):事務是一個原子操作, 由一系列動作組成. 事務的原子性確保動作要麼全部完成要麼完全不起作用.
§一致性(consistency):一旦所有事務動作完成, 事務就被提交. 數據和資源就處於一種滿足業務規則的一致性狀態中.
§隔離性(isolation):可能有許多事務會同時處理相同的數據, 因此每個事物都應該與其他事務隔離開來, 防止數據損壞.
持久性(durability):一旦事務完成, 無論發生什麼系統錯誤, 它的結果都不應該受到影響. 通常情況下, 事務的結果被寫到持久化存儲器中.

二.事務的傳播性,簡單的引用

創建maven項目,在pom.xml中加載架包

<project xmlns="http://maven.apache.org/POM/4.0.0" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>cn</groupId>
  <artifactId>spring</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <dependencies>
  <!-- 加載spring的包 -->
  	<dependency>
  		<groupId>org.springframework</groupId>
  		<artifactId>spring-context</artifactId>
  		<version>4.3.12.RELEASE</version>
  	</dependency>
  	
  	<dependency>
  		<groupId>aopalliance</groupId>
  		<artifactId>aopalliance</artifactId>
  		<version>1.0</version>
  	</dependency>
  	<dependency>
  		<groupId>aspectj</groupId>
  		<artifactId>aspectjweaver</artifactId>
  		<version>1.5.3</version>
  	</dependency>
  	<!-- 添加jdbc的架包 -->
  	<dependency>
  		<groupId>org.springframework</groupId>
  		<artifactId>spring-jdbc</artifactId>
  		<version>4.3.12.RELEASE</version>
  	</dependency>
  		<!-- 加載數據庫的架包 -->
  	<dependency>
  		<groupId>mysql</groupId>
  		<artifactId>mysql-connector-java</artifactId>
  		<version>5.1.26</version>
  	</dependency>
  	<!-- 面向切面編程 -->
  	<dependency>
  		<groupId>org.springframework</groupId>
  		<artifactId>spring-aop</artifactId>
  		<version>4.3.12.RELEASE</version>
  	</dependency>
  	<dependency>
  		<groupId>org.springframework</groupId>
  		<artifactId>spring-orm</artifactId>
  		<version>4.3.12.RELEASE</version>
  	</dependency>
  	
  	<dependency>
  		<groupId>log4j</groupId>
  		<artifactId>log4j</artifactId>
  		<version>1.2.17</version>
  	</dependency>
  	<dependency>
			<groupId>aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>1.2</version>
		</dependency>
  </dependencies>
  	
  
</project>
創建連接數據的四要素jdbc.properties文件

url=jdbc:mysql://localhost:3306/news
driverClassName=com.mysql.jdbc.Driver
userName1=root
password=123456

創建spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans
	xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="
	http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
	http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-4.2.xsd
	http://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
	http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
	
	">
	<!-- 掃描bean -->
   <context:component-scan base-package="less04.testm"></context:component-scan>
   <context:property-placeholder location="classpath:/less04/jdbc.properties"/>
   <bean id="dataSource"  class="org.springframework.jdbc.datasource.DriverManagerDataSource">
     <property name="url" value="${url}" ></property>
     <property name="username" value="${userName1}" ></property>
     <property name="password" value="${password}" ></property>
     <property name="driverClassName" value="${driverClassName}" ></property>
   </bean>
   <!-- 事務管理器  不再使用jdbc的commit和rollback 必須由事務管理器提供 -->
   <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
     <property name="dataSource" ref="dataSource"></property> 
   </bean>
   <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
   	   <property name="dataSource" ref="dataSource"></property> 
   </bean>
   <!-- 定義通知  通知的代碼 spring已經實現  -->
   <tx:advice id="myAdvise"  transaction-manager="transactionManager">
	   	<tx:attributes>
	   	    <!-- 
	   	       propagation="REQUIRED" 方法和方法之間父子關係
	   	         REQUIRED 沒有事務創建一個事務 有事務使用當前事務
	   	         REQUIRED_NEW 不管父方法是否存在事務 都會新建事務
	   	         SUPPORTS 父方法存在事務 使用當前事務  沒有事務 使用jdbc的事務(自動提交)
	   	         NOT_SUPPORTED 不管父方法是否存在事務 都不會使用事務(掛起事務)
	   	         MANDATORY 必須在事務環境下運行 父方法沒有事務 拋出異常
	   	           No existing transaction found for transaction marked with propagation 'mandatory'
	   	         NEVER 父方法不能存在 事務 有事務拋出異常   
	   	           Existing transaction found for transaction marked with propagation 'never'
	   	           
	   	           isolation="DEFAULT"隔離級別
	   	           	DEFAULT使用數據庫本身的隔離級別ORACLE(讀已提交)MYSQL(可重複讀)
	   	           	READ_UNCOMMITTED spring實現讀未提交(髒讀)
	   	           	REA_COMMITTED spring實現讀已提交(不重複讀+幻讀)
	   	           	REPEATABLE_READ spring實現可重複讀(幻讀)
	   	           	SERIALIZABLE spring實現串行化(已解決)
	   	           	
	   	           	spring事務運行過程中碰到運行時異常自動回滾 非運行時異常不會回滾
	   	           	rollback-for=""指定會自動回滾的非運行時異常
	   	           	no-rollback-for=""指定某些運行時異常拋出時不回滾
	   	           	
	   	           	只讀事務(除特定的方法以外其他的業務邏輯方法都不應該操作事務)
	   	           	read-only="true"設置只讀事務
	   	           	timeout=""設置超時時間
	   	     -->
	   		<tx:method name="update*" propagation="REQUIRED"/>
	   		<tx:method name="save*" />
	   		<tx:method name="delete*"/>
	   		<tx:method name="*" read-only="true"/>
	   	</tx:attributes>
   </tx:advice>
    <!-- 定義切點 advice-ref引用通知 -->
   <aop:config>
   	<aop:pointcut expression="execution(* less04.testm.dao.*.*(..))  " id="myPoint"/>
    <aop:advisor advice-ref="myAdvise" pointcut-ref="myPoint"/>
   </aop:config>
   
   
</beans>


持久層

package less04.testm.dao;

import java.sql.SQLException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class AcDaoImpl {
	@Autowired
	JdbcTemplate jdbc;
	@Autowired
	BcDaoImpl b;
	public  void updateAminus(int money) throws SQLException{
		//扣錢
		String sql="update mymoney set lostedmoney=lostedmoney-"+money+" where usid=1";
		jdbc.execute(sql);
		
		//加錢
		b.saveBadd(money);
		int i=5/0;
	}
}



package less04.testm.dao;

import java.sql.SQLException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class BcDaoImpl {
	@Autowired
	JdbcTemplate jdbc;
	public  void saveBadd(int money) throws SQLException{
		String sql="update mymoney set lostedmoney=lostedmoney+"+money+" where usid=2";
		jdbc.execute(sql);
	}
}

測試main方法
import java.sql.SQLException;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import less04.testm.dao.AcDaoImpl;

/**
 * 編程式事務 
 * 聲明式事務
 *    xml聲明(全局)
 *    註解聲明
 */

public class TestTa {
	static AcDaoImpl myMoneyDao;
	static{
		ApplicationContext context = new GenericXmlApplicationContext("classpath:less04/testm/spring.xml");
		myMoneyDao=(AcDaoImpl)context.getBean("acDaoImpl");
	}

	public static void main(String[] args) throws SQLException {
		myMoneyDao.updateAminus(10);
	}
	
}

三.事務的隔離級別

1.什麼是事務的隔離級別

事務隔離級別指的是一個事務對數據的修改與另一個並行的事務的隔離程度,當多個事務同時訪問相同數據時,如果沒有采取必要的隔離機制,就可能發生以下問題:

 髒讀:一個事務讀到另一個事務未提交的更新數據。

    幻讀:例如第一個事務對一個表中的數據進行了修改,比如這種修改涉及到表中的“全部數據行”。同時,第二個事務也修改這個表中的數據,這種修改是向表中插入“一行新數據”。那麼,以後就會發生操作第一個事務的用戶發現表中還存在沒有修改的數據行,就好象發生了幻覺一樣。

    不可重複讀:比方說在同一個事務中先後執行兩條一模一樣的select語句,期間在此次事務中沒有執行過任何DDL語句,但先後得到的結果不一致,這就是不可重複讀。

2.Spring支持的隔離級別

1.DEFAULT 使用數據庫本身的隔離級別ORACLE(讀已提交)MYSQL(可重複讀)
2. READ_UNCOMMITTED 讀未提交(髒讀)最低的隔離級別,一切皆有可能。 spring實現讀未提交(髒讀)
3.REA_COMMITTED 讀已提交,ORACLE默認隔離級別,有幻讀以及不可重複讀風險 .spring 實現讀已提交(不重複讀+幻讀)
4.REPEATABLE_READ 可重複讀,解決不可重複讀的隔離級別,但還是有幻讀風險.spring實現可重複讀(幻讀)
5.SERIALIZABLE 串行化,最高隔離級別,杜絕一切隱患,缺點是效率低.spring實現串行化(已解決)

3.事務的回滾

spring事務運行過程中碰到運行時異常自動回滾 非運行時異常不會回滾

rollback-for=""指定會自動回滾的非運行時異常

no-rollback-for=""指定某些運行時異常拋出時不回滾


  timeout=""設置超時時間 超時時間一般在5到20之間

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章