1. 程式人生 > >spring框架事務學習

spring框架事務學習

Spring框架的第三天

課程回顧:Spring框架第二天

1. IOC的註解方式
	* @Value
	* @Resource(name="")

2. 整合JUnti單元測試
	* 先有Junit4執行環境
	* 匯入spring-test.jar包

3. Spring的AOP技術(XML的方式)	
	* 什麼是AOP:面向切面程式設計
	* 採用代理技術完成(預設採用JDK介面方式,CGLIB技術代理物件)
	* AOP的入門
		* 編寫切面類(編寫通知的方法)
		* 配置AOP
		* 切入點的表示式(execution([public] * 包名.類名.方法(..)))

今天內容

1. Spring框架的AOP之註解的方式
2. Spring框架的JDBC模板
3. Spring框架的事務管理

案例一:使用Spring框架的AOP技術對DAO層的功能進行增強

案例一:使用Spring框架的AOP技術對DAO層的功能進行增強

1. 使用Spring框架的AOP技術對DAO層的功能進行增強

技術分析之:Spring框架的AOP技術(註解方式)

1. 步驟一:建立JavaWEB專案,引入具體的開發的jar包
	* 先引入Spring框架開發的基本開發包
	* 再引入Spring框架的AOP的開發包
		* spring的傳統AOP的開發的包
			* spring-aop-4.2.4.RELEASE.jar
			* com.springsource.org.aopalliance-1.0.0.jar
		
		* aspectJ的開發包
			* com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
			* spring-aspects-4.2.4.RELEASE.jar

2. 步驟二:建立Spring的配置檔案,引入具體的AOP的schema約束
	<beans xmlns="http://www.springframework.org/schema/beans"
	       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	       xmlns:aop="http://www.springframework.org/schema/aop"
	       xsi:schemaLocation="
			http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
			http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
		
	</beans>

3. 步驟三:建立包結構,編寫具體的介面和實現類
	* com.itheima.demo1
		* CustomerDao			-- 介面
		* CustomerDaoImpl		-- 實現類

4. 步驟四:將目標類配置到Spring中
	<bean id="customerDao" class="com.itheima.demo1.CustomerDaoImpl"/>

5. 步驟五:定義切面類
	* 新增切面和通知的註解
		* @Aspect					-- 定義切面類的註解
		
		* 通知型別(註解的引數是切入點的表示式)
			* @Before				-- 前置通知
		    * @AfterReturing		-- 後置通知
		    * @Around				-- 環繞通知
		    * @After				-- 最終通知
		    * @AfterThrowing		-- 異常丟擲通知
	
	* 具體的程式碼如下
		@Aspect
		public class MyAspectAnno {
			@Before(value="execution(public void com.itheima.demo1.CustomerDaoImpl.save())")
			public void log(){
				System.out.println("記錄日誌...");
			}
		}

6. 步驟六:在配置檔案中定義切面類
	<bean id="myAspectAnno" class="com.itheima.demo1.MyAspectAnno"/>

7. 步驟七:在配置檔案中開啟自動代理
	<aop:aspectj-autoproxy/>

8. 完成測試
	@RunWith(SpringJUnit4ClassRunner.class)
	@ContextConfiguration("classpath:applicationContext.xml")
	public class Demo1 {
		
		@Resource(name="customerDao")
		private CustomerDao customerDao;
		
		@Test
		public void run1(){
			customerDao.save();
			customerDao.update();
		}
	}

技術分析之通知型別

1. 通知型別
	* @Before				-- 前置通知
    * @AfterReturing		-- 後置通知
    * @Around				-- 環繞通知(目標物件方法預設不執行的,需要手動執行)
    * @After				-- 最終通知
    * @AfterThrowing		-- 異常丟擲通知

2. 配置通用的切入點
	* 使用@Pointcut定義通用的切入點
	
	@Aspect
	public class MyAspectAnno {
		@Before(value="MyAspectAnno.fn()")
		public void log(){
			System.out.println("記錄日誌...");
		}
		@Pointcut(value="execution(public void com.itheima.demo1.CustomerDaoImpl.save())")
		public void fn(){}
	}

案例二:Spring框架的事務管理完成轉賬的案例

需求分析

1. 完成一個轉賬的功能,需要進行事務的管理,使用Spring的事務管理的方式完成

Spring框架的JDBC模板技術

技術分析之Spring框架的JDBC模板技術概述

1. Spring框架中提供了很多持久層的模板類來簡化程式設計,使用模板類編寫程式會變的簡單
2. 提供了JDBC模板,Spring框架提供的
	* JdbcTemplate類

3. Spring框架可以整合Hibernate框架,也提供了模板類
	* HibernateTemplate類

技術分析之演示JDBC的模板類

1. 步驟一:建立資料庫的表結構
	create database spring_day03;
	use spring_day03;
	create table t_account(
		id int primary key auto_increment,
		name varchar(20),
		money double
	);

2. 引入開發的jar包
	* 先引入IOC基本的6個jar包
	* 再引入Spring-aop的jar包
	* 最後引入JDBC模板需要的jar包
		* MySQL資料庫的驅動包
		* Spring-jdbc.jar
		* Spring-tx.jar

3. 編寫測試程式碼(自己來new物件的方式)
	@Test
	public void run1(){
		// 建立連線池,先使用Spring框架內建的連線池
		DriverManagerDataSource dataSource = new DriverManagerDataSource();
		dataSource.setDriverClassName("com.mysql.jdbc.Driver");
		dataSource.setUrl("jdbc:mysql:///spring_day03");
		dataSource.setUsername("root");
		dataSource.setPassword("root");
		// 建立模板類
		JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
		// 完成資料的新增
		jdbcTemplate.update("insert into t_account values (null,?,?)", "測試",10000);
	}

技術分析之使用Spring框架來管理模板類

1. 剛才編寫的程式碼使用的是new的方式,應該把這些類交給Spring框架來管理。
2. 修改的步驟如下
	* 步驟一:Spring管理內建的連線池
		<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
	    	<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
	    	<property name="url" value="jdbc:mysql:///spring_day03"/>
	    	<property name="username" value="root"/>
	    	<property name="password" value="root"/>
	    </bean>
	
	* 步驟二:Spring管理模板類
		<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
	    	<property name="dataSource" ref="dataSource"/>
	    </bean>
	
	* 步驟三:編寫測試程式
		@RunWith(SpringJUnit4ClassRunner.class)
		@ContextConfiguration("classpath:applicationContext.xml")
		public class Demo2 {
			
			@Resource(name="jdbcTemplate")
			private JdbcTemplate jdbcTemplate;
			
			@Test
			public void run2(){
				jdbcTemplate.update("insert into t_account values (null,?,?)", "測試2",10000);
			}
		}

技術分析之Spring框架管理開源的連線池

1. 管理DBCP連線池
	* 先引入DBCP的2個jar包
		* com.springsource.org.apache.commons.dbcp-1.2.2.osgi.jar
		* com.springsource.org.apache.commons.pool-1.5.3.jar
	
	* 編寫配置檔案
		<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
	    	<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
	    	<property name="url" value="jdbc:mysql:///spring_day03"/>
	    	<property name="username" value="root"/>
	    	<property name="password" value="root"/>
	    </bean>

2. 管理C3P0連線池
	* 先引入C3P0的jar包
		* com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar
	
	* 編寫配置檔案
		<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
	    	<property name="driverClass" value="com.mysql.jdbc.Driver"/>
	    	<property name="jdbcUrl" value="jdbc:mysql:///spring_day03"/>
	    	<property name="user" value="root"/>
	    	<property name="password" value="root"/>
	    </bean>

技術分析之Spring框架的JDBC模板的簡單操作

1. 增刪改查的操作
	@RunWith(SpringJUnit4ClassRunner.class)
	@ContextConfiguration("classpath:applicationContext.xml")
	public class SpringDemo3 {
		
		@Resource(name="jdbcTemplate")
		private JdbcTemplate jdbcTemplate;
		
		@Test
		// 插入操作
		public void demo1(){
			jdbcTemplate.update("insert into account values (null,?,?)", "冠希",10000d);
		}
		
		@Test
		// 修改操作
		public void demo2(){
			jdbcTemplate.update("update account set name=?,money =? where id = ?", "思雨",10000d,5);
		}
		
		@Test
		// 刪除操作
		public void demo3(){
			jdbcTemplate.update("delete from account where id = ?", 5);
		}
		
		@Test
		// 查詢一條記錄
		public void demo4(){
			Account account = jdbcTemplate.queryForObject("select * from account where id = ?", new BeanMapper(), 1);
			System.out.println(account);
		}
		
		@Test
		// 查詢所有記錄
		public void demo5(){
			List<Account> list = jdbcTemplate.query("select * from t_account", new BeanMapper());
			for (Account account : list) {
				System.out.println(account);
			}
		}
	}
	
	class BeanMapper implements RowMapper<Account>{
		public Account mapRow(ResultSet rs, int arg1) throws SQLException {
			Account account = new Account();
			account.setId(rs.getInt("id"));
			account.setName(rs.getString("name"));
			account.setMoney(rs.getDouble("money"));
			return account;
		}
	}

技術分析之Spring框架的事務管理

技術分析之事務的回顧

1. 事務:指的是邏輯上一組操作,組成這個事務的各個執行單元,要麼一起成功,要麼一起失敗!
2. 事務的特性
	* 原子性
	* 一致性
	* 隔離性
	* 永續性

3. 如果不考慮隔離性,引發安全性問題
	* 讀問題:
		* 髒讀:
		* 不可重複讀:
		* 虛讀:
	
	* 寫問題:
		* 丟失更新:

4. 如何解決安全性問題
	* 讀問題解決,設定資料庫隔離級別
	* 寫問題解決可以使用 悲觀鎖和樂觀鎖的方式解決

技術分析之Spring框架的事務管理相關的類和API

1. PlatformTransactionManager介面		-- 平臺事務管理器.(真正管理事務的類)。該介面有具體的實現類,根據不同的持久層框架,需要選擇不同的實現類!
2. TransactionDefinition介面			-- 事務定義資訊.(事務的隔離級別,傳播行為,超時,只讀)
3. TransactionStatus介面				-- 事務的狀態

4. 總結:上述物件之間的關係:平臺事務管理器真正管理事務物件.根據事務定義的資訊TransactionDefinition 進行事務管理,在管理事務中產生一些狀態.將狀態記錄到TransactionStatus中

5. PlatformTransactionManager介面中實現類和常用的方法
	1. 介面的實現類
		* 如果使用的Spring的JDBC模板或者MyBatis框架,需要選擇DataSourceTransactionManager實現類
		* 如果使用的是Hibernate的框架,需要選擇HibernateTransactionManager實現類
	
	2. 該介面的常用方法
		* void commit(TransactionStatus status) 
		* TransactionStatus getTransaction(TransactionDefinition definition) 
		* void rollback(TransactionStatus status) 
 	
6. TransactionDefinition
	1. 事務隔離級別的常量
		* static int ISOLATION_DEFAULT 					-- 採用資料庫的預設隔離級別
		* static int ISOLATION_READ_UNCOMMITTED 
		* static int ISOLATION_READ_COMMITTED 
		* static int ISOLATION_REPEATABLE_READ 
		* static int ISOLATION_SERIALIZABLE 
 		
	2. 事務的傳播行為常量(不用設定,使用預設值)
		* 先解釋什麼是事務的傳播行為:解決的是業務層之間的方法呼叫!!
		
		* PROPAGATION_REQUIRED(預設值)	-- A中有事務,使用A中的事務.如果沒有,B就會開啟一個新的事務,將A包含進來.(保證A,B在同一個事務中),預設值!!
		* PROPAGATION_SUPPORTS			-- A中有事務,使用A中的事務.如果A中沒有事務.那麼B也不使用事務.
		* PROPAGATION_MANDATORY			-- A中有事務,使用A中的事務.如果A沒有事務.丟擲異常.
		
		* PROPAGATION_REQUIRES_NEW(記)-- A中有事務,將A中的事務掛起.B建立一個新的事務.(保證A,B沒有在一個事務中)
		* PROPAGATION_NOT_SUPPORTED		-- A中有事務,將A中的事務掛起.
		* PROPAGATION_NEVER 			-- A中有事務,丟擲異常.
		
		* PROPAGATION_NESTED(記)		-- 巢狀事務.當A執行之後,就會在這個位置設定一個儲存點.如果B沒有問題.執行通過.如果B出現異常,執行客戶根據需求回滾(選擇回滾到儲存點或者是最初始狀態)

技術分析之搭建事務管理轉賬案例的環境(強調:簡化開發,以後DAO可以繼承JdbcDaoSupport類)

1. 步驟一:建立WEB工程,引入需要的jar包
	* IOC的6個包
	* AOP的4個包
	* C3P0的1個包
	* MySQL的驅動包
	* JDBC目標2個包
	* 整合JUnit測試包

2. 步驟二:引入配置檔案
	* 引入配置檔案
		* 引入log4j.properties
		
		* 引入applicationContext.xml
			<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		    	<property name="driverClass" value="com.mysql.jdbc.Driver"/>
		    	<property name="jdbcUrl" value="jdbc:mysql:///spring_day03"/>
		    	<property name="user" value="root"/>
		    	<property name="password" value="root"/>
		    </bean>

3. 步驟三:建立對應的包結構和類
	* com.itheima.demo1
		* AccountService
		* AccountServlceImpl
		* AccountDao
		* AccountDaoImpl

4. 步驟四:引入Spring的配置檔案,將類配置到Spring中
	<bean id="accountService" class="com.itheima.demo1.AccountServiceImpl">
	</bean>
	
	<bean id="accountDao" class="com.itheima.demo1.AccountDaoImpl">
	</bean>

5. 步驟五:在業務層注入DAO ,在DAO中注入JDBC模板(強調:簡化開發,以後DAO可以繼承JdbcDaoSupport類)
	<bean id="accountService" class="com.itheima.demo1.AccountServiceImpl">
		<property name="accountDao" ref="accountDao"/>
	</bean>
	
	<bean id="accountDao" class="com.itheima.demo1.AccountDaoImpl">
		<property name="dataSource" ref="dataSource"/>
	</bean>

6. 步驟六:編寫DAO和Service中的方法
	public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
		public void outMoney(String out, double money) {
			this.getJdbcTemplate().update("update t_account set money = money = ? where name = ?", money,out);
		}
		public void inMoney(String in, double money) {
			this.getJdbcTemplate().update("update t_account set money = money + ? where name = ?", money,in);
		}
	}

7. 步驟七:編寫測試程式.
	@RunWith(SpringJUnit4ClassRunner.class)
	@ContextConfiguration("classpath:applicationContext.xml")
	public class Demo1 {
		
		@Resource(name="accountService")
		private AccountService accountService;
		
		@Test
		public void run1(){
			accountService.pay("冠希", "美美", 1000);
		}
	}

技術分析之Spring框架的事務管理的分類

1. Spring的事務管理的分類
	1. Spring的程式設計式事務管理(不推薦使用)
		* 通過手動編寫程式碼的方式完成事務的管理(不推薦)
	
	2. Spring的宣告式事務管理(底層採用AOP的技術)
		* 通過一段配置的方式完成事務的管理(重點掌握註解的方式)

技術分析之Spring框架的事務管理之程式設計式的事務管理(瞭解)

1. 說明:Spring為了簡化事務管理的程式碼:提供了模板類 TransactionTemplate,所以手動程式設計的方式來管理事務,只需要使用該模板類即可!!

2. 手動程式設計方式的具體步驟如下:
	1. 步驟一:配置一個事務管理器,Spring使用PlatformTransactionManager介面來管理事務,所以咱們需要使用到他的實現類!!
		<!-- 配置事務管理器 -->
		<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
			<property name="dataSource" ref="dataSource"/>
		</bean>
	
	2. 步驟二:配置事務管理的模板
		<!-- 配置事務管理的模板 -->
		<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
			<property name="transactionManager" ref="transactionManager"/>
		</bean>
	
	3. 步驟三:在需要進行事務管理的類中,注入事務管理的模板.
		<bean id="accountService" class="com.itheima.demo1.AccountServiceImpl">
			<property name="accountDao" ref="accountDao"/>
			<property name="transactionTemplate" ref="transactionTemplate"/>
		</bean>
	
	4. 步驟四:在業務層使用模板管理事務:
		// 注入事務模板物件
		private TransactionTemplate transactionTemplate;
		public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
			this.transactionTemplate = transactionTemplate;
		}
		
		public void pay(final String out, final String in, final double money) {
			transactionTemplate.execute(new TransactionCallbackWithoutResult() {
				
				protected void doInTransactionWithoutResult(TransactionStatus status) {
					// 扣錢
					accountDao.outMoney(out, money);
					int a = 10/0;
					// 加錢
					accountDao.inMoney(in, money);
				}
			});
		}

Spring框架的事務管理之宣告式事務管理,即通過配置檔案來完成事務管理(AOP思想)

1. 宣告式事務管理又分成兩種方式
	* 基於AspectJ的XML方式(重點掌握)
	* 基於AspectJ的註解方式(重點掌握)

Spring框架的事務管理之基於AspectJ的XML方式(重點掌握)

1. 步驟一:恢復轉賬開發環境

2. 步驟二:引入AOP的開發包

3. 步驟三:配置事務管理器
	<!-- 配置事務管理器 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"/>
	</bean>

4. 步驟四:配置事務增強
	<!-- 配置事務增強 -->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<!--
				name		:繫結事務的方法名,可以使用萬用字元,可以配置多個。
				propagation	:傳播行為
				isolation	:隔離級別
				read-only	:是否只讀
				timeout		:超時資訊
				rollback-for:發生哪些異常回滾.
				no-rollback-for:發生哪些異常不回滾.
			 -->
			<!-- 哪些方法加事務 -->
			<tx:method name="pay" propagation="REQUIRED"/>
		</tx:attributes>
	</tx:advice>

5. 步驟五:配置AOP的切面
	<!-- 配置AOP切面產生代理 -->
	<aop:config>
    	<aop:advisor advice-ref="myAdvice" pointcut="execution(* com.itheima.demo2.AccountServiceImpl.pay(..))"/>
    </aop:config>
	
	* 注意:如果是自己編寫的切面,使用<aop:aspect>標籤,如果是系統製作的,使用<aop:advisor>標籤。

6. 步驟六:編寫測試類
	@RunWith(SpringJUnit4ClassRunner.class)
	@ContextConfiguration("classpath:applicationContext2.xml")
	public class Demo2 {
		
		@Resource(name="accountService")
		private AccountService accountService;
		
		@Test
		public void run1(){
			accountService.pay("冠希", "美美", 1000);
		}
	}

Spring框架的事務管理之基於AspectJ的註解方式(重點掌握,最簡單的方式)

1. 步驟一:恢復轉賬的開發環境

2. 步驟二:配置事務管理器
	<!-- 配置事務管理器  -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"/>
	</bean>

3. 步驟三:開啟註解事務
	<!-- 開啟註解事務 -->
	<tx:annotation-driven transaction-manager="transactionManager"/>

4. 步驟四:在業務層上新增一個註解:@Transactional

5. 編寫測試類
	@RunWith(SpringJUnit4ClassRunner.class)
	@ContextConfiguration("classpath:applicationContext3.xml")
	public class Demo3 {
		
		@Resource(name="accountService")
		private AccountService accountService;
		
		@Test
		public void run1(){
			accountService.pay("冠希", "美美", 1000);
		}
	}

Eclipse需要做設定

1. 統一工作空間的編碼,選擇UTF-8
2. 把建立JSP頁面的編碼修改UTF-8
3. 重新配置Tomcat伺服器
	* 先配置Tomcat伺服器
	* 選擇伺服器 --> open --> 選擇釋出專案的目錄(webapps目錄)

4. SSH自己配置約束