1、Spring簡介
1.1 Spring是什麼
Spring 是一個開源框架.java
Spring 爲簡化企業級應用開發而生. 使用 Spring 可使簡單的 JavaBean 實現之前只有 EJB 才能實現的功能.正則表達式
Spring 是一個 IOC(DI) 和 AOP 容器框架.spring
具體描述 Spring:sql
- 輕量級:Spring 是非侵入性的 - 基於 Spring 開發的應用中的對象能夠不依賴於 Spring 的 API
- 依賴注入(DI --- dependency injection、IOC)
- 面向切面編程(AOP --- aspect oriented programming)
- 容器: Spring 是一個容器, 由於它包含而且管理應用對象的生命週期
- 框架: Spring 實現了使用簡單的組件配置組合成一個複雜的應用. 在 Spring 中可使用 XML 和 Java 註解組合這些對象
- 一站式:在 IOC 和 AOP 的基礎上能夠整合各類企業應用的開源框架和優秀的第三方類庫 (實際上 Spring 自身也提供了展示層的 SpringMVC 和 持久層的 Spring JDBC)
1.2 Spring模塊

2、Spring中的Bean配置
2.1 IOC和DI
IOC(Inversion of Control):其思想是反轉資源獲取的方向. 傳統的資源查找方式要求組件向容器發起請求查找資源. 做爲迴應, 容器適時的返回資源. 而應用了 IOC 以後, 則是<u>容器主動地將資源推送給它所管理的組件, 組件所要作的僅是選擇一種合適的方式來接受資源</u>. 這種行爲也被稱爲查找的被動形式數據庫
DI(Dependency Injection) — IOC 的另外一種表述方式:即<u>組件以一些預先定義好的方式(例如: setter 方法)接受來自如容器的資源注入.</u> 相對於 IOC 而言,這種表述更直接。編程
IOC的演化過程設計模式
需求: 生成 HTML 或 PDF 格式的不一樣類型的報表. 數組
一、分離接口與實現 安全

二、採用工廠設計模式 併發

三、採用反轉控制

2.2 配置Bean
配置 bean
- 配置形式:基於 XML 文件的方式;基於註解的方式
- Bean 的配置方式:經過全類名(反射)、經過工廠方法(靜態工廠方法 & 實例工廠方法)、FactoryBean
- IOC 容器 BeanFactory & ApplicationContext 概述
- 依賴注入的方式:屬性注入;構造器注入
- 注入屬性值細節
- 自動轉配
- bean 之間的關係:繼承;依賴
- bean 的做用域:singleton;prototype;WEB 環境做用域
- 使用外部屬性文件
- spEL
- IOC 容器中 Bean 的生命週期
- Spring 4.x 新特性:泛型依賴注入
2.2.1 Spring容器
在 Spring IOC 容器讀取 Bean 配置建立 Bean 實例以前, 必須對它進行實例化. 只有在容器實例化後, 才能夠從 IOC 容器裏獲取 Bean 實例並使用.
Spring 提供了兩種類型的 IOC 容器實現.
- BeanFactory: IOC 容器的基本實現.
- ApplicationContext: 提供了更多的高級特性. 是 BeanFactory 的子接口.
- BeanFactory 是 Spring 框架的基礎設施,面向 Spring 自己;ApplicationContext 面向使用 Spring 框架的開發者,幾乎全部的應用場合都直接使用 ApplicationContext 而非底層的 BeanFactory
- 不管使用何種方式, 配置文件時相同的.
2.2.2 ApplicationContext

ApplicationContext 的主要實現類:
- ClassPathXmlApplicationContext:從類路徑下加載配置文件
- FileSystemXmlApplicationContext: 從文件系統中加載配置文件
ConfigurableApplicationContext 擴展於 ApplicationContext,新增長兩個主要方法:refresh() 和 close(), 讓 ApplicationContext 具備啓動、刷新和關閉上下文的能力
ApplicationContext 在初始化上下文時就實例化全部單例的 Bean。
WebApplicationContext 是專門爲 WEB 應用而準備的,它容許從相對於 WEB 根目錄的路徑中完成初始化工做
2.2.3 從IOC容器中獲取Bean的方法
調用 ApplicationContext 的 getBean() 方法

2.2.4 依賴注入的方式
-
屬性注入
- 屬性注入即經過 setter 方法注入Bean 的屬性值或依賴的對象
- 屬性注入使用 <property> 元素, 使用 name 屬性指定 Bean 的屬性名稱,value 屬性或 <value> 子節點指定屬性值
- 屬性注入是實際應用中最經常使用的注入方式
-
構造器注入
- 經過構造方法注入Bean 的屬性值或依賴的對象,它保證了 Bean 實例在實例化後就可使用。
- 構造器注入在 <constructor-arg> 元素裏聲明屬性, <constructor-arg> 中沒有 name 屬性
2.2.5 注入屬性值的細節
-
字面值
- 字面值:可用字符串表示的值,能夠經過 <value> 元素標籤或 value 屬性進行注入。
- 基本數據類型及其封裝類、String 等類型均可以採起字面值注入的方式
- 若字面值中包含特殊字符,可使用 <![CDATA[]]> 把字面值包裹起來。
-
引用其餘Bean

-
內部Bean
- 當 Bean 實例僅僅給一個特定的屬性使用時, 能夠將其聲明爲內部 Bean. 內部 Bean 聲明直接包含在 <property> 或 <constructor-arg> 元素裏, 不須要設置任何 id 或 name 屬性
- 內部 Bean 不能使用在任何其餘地方,即不能被外部引用
-
注入參數詳解:null 值和級聯屬性
- 可使用專用的 <null/> 元素標籤爲 Bean 的字符串或其它對象類型的屬性注入 null 值
- 和 Struts、Hiberante 等框架同樣,Spring 支持級聯屬性的配置。
-
集合屬性
-
List及Set
- 在 Spring中能夠經過一組內置的 xml 標籤(例如: <list>, <set> 或 <map>) 來配置集合屬性.
- 配置 java.util.List 類型的屬性, 須要指定 <list> 標籤, 在標籤裏包含一些元素. 這些標籤能夠經過 <value> 指定簡單的常量值, 經過 <ref> 指定對其餘 Bean 的引用. 經過<bean> 指定內置 Bean 定義. 經過 <null/> 指定空元素. 甚至能夠內嵌其餘集合.
- 數組的定義和 List 同樣, 都使用 <list>
- 配置 java.util.Set 須要使用 <set> 標籤, 定義元素的方法與 List 同樣.
-
Map
- Java.util.Map 經過 <map> 標籤訂義, <map> 標籤裏可使用多個 <entry> 做爲子標籤. 每一個條目包含一個鍵和一個值.
- 必須在 <key> 標籤裏定義鍵
- 由於鍵和值的類型沒有限制, 因此能夠自由地爲它們指定 <value>, <ref>, <bean> 或 <null> 元素.
- 能夠將 Map 的鍵和值做爲 <entry> 的屬性定義: 簡單常量使用 key 和 value 來定義; Bean 引用經過 key-ref 和 value-ref 屬性定義
- 使用 <props> 定義 java.util.Properties, 該標籤使用多個 <prop> 做爲子標籤. 每一個 <prop> 標籤必須定義 key 屬性.
-
使用 utility scheme 定義集合
- 使用基本的集合標籤訂義集合時, 不能將集合做爲獨立的 Bean 定義, 致使其餘 Bean 沒法引用該集合, 因此沒法在不一樣 Bean 之間共享集合.
- 可使用 util schema 裏的集合標籤訂義獨立的集合 Bean. 須要注意的是, 必須在 <beans> 根元素裏添加 util schema 定義
-
使用 p 命名空間
- 爲了簡化 XML 文件的配置,愈來愈多的 XML 文件採用屬性而非子元素配置信息。
- Spring 從 2.5 版本開始引入了一個新的 p 命名空間,能夠經過 <bean> 元素屬性的方式配置 Bean 的屬性。
- 使用 p 命名空間後,基於 XML 的配置方式將進一步簡化
2.2.6 自動裝配
-
XML 配置裏的 Bean 自動裝配
- Spring IOC 容器能夠自動裝配 Bean. 須要作的僅僅是在 <bean> 的 autowire 屬性裏指定自動裝配的模式
- byType(根據類型自動裝配): 若 IOC 容器中有多個與目標 Bean 類型一致的 Bean. 在這種狀況下, Spring 將沒法斷定哪一個 Bean 最合適該屬性, 因此不能執行自動裝配.
- byName(根據名稱自動裝配): 必須將目標 Bean 的名稱和屬性名設置的徹底相同.
- constructor(經過構造器自動裝配): 當 Bean 中存在多個構造器時, 此種自動裝配方式將會很複雜. 不推薦使用
-
XML 配置裏的 Bean 自動裝配的缺點
- 在 Bean 配置文件裏設置 autowire 屬性進行自動裝配將會裝配 Bean 的全部屬性. 然而, 若只但願裝配個別屬性時, autowire 屬性就不夠靈活了.
- autowire 屬性要麼根據類型自動裝配, 要麼根據名稱自動裝配, 不能二者兼而有之.
- 通常狀況下,在實際的項目中不多使用自動裝配功能,由於和自動裝配功能所帶來的好處比起來,明確清晰的配置文檔更有說服力一些
2.2.7 Bean之間的關係:繼承、依賴
-
繼承 Bean 配置
-
Spring 容許繼承 bean 的配置, 被繼承的 bean 稱爲父 bean. 繼承這個父 Bean 的 Bean 稱爲子 Bean
<bean id="address" class="com.meituan.spring.bean.Address" p:city="BeiJing" p:street="WuDaoKou"></bean>
<bean id="address2" parent="address" p:street="DaZhongSi"></bean>
- 子 Bean 從父 Bean 中繼承配置, 包括 Bean 的屬性配置
- 子 Bean 也能夠覆蓋從父 Bean 繼承過來的配置
- 父 Bean 能夠做爲配置模板, 也能夠做爲 Bean 實例. 若只想把父 Bean 做爲模板, 能夠設置 <bean> 的abstract 屬性爲 true, 這樣 Spring 將不會實例化這個 Bean
- 並非 <bean> 元素裏的全部屬性都會被繼承. 好比: autowire, abstract 等.
- 也能夠忽略父 Bean 的 class 屬性, 讓子 Bean 指定本身的類, 而共享相同的屬性配置. 但此時 abstract 必須設爲 true
-
依賴 Bean 配置
- Spring 容許用戶經過 depends-on 屬性設定 Bean 前置依賴的Bean,前置依賴的 Bean 會在本 Bean 實例化以前建立好
- 若是前置依賴於多個 Bean,則能夠經過逗號,空格或的方式配置 Bean 的名稱
2.2.8 Bean的做用域
- 在 Spring 中, 能夠在 <bean> 元素的 scope 屬性裏設置 Bean 的做用域.
- 默認狀況下, Spring 只爲每一個在 IOC 容器裏聲明的 Bean 建立惟一一個實例, 整個 IOC 容器範圍內都能共享該實例:全部後續的 getBean() 調用和 Bean 引用都將返回這個惟一的 Bean 實例.該做用域被稱爲 singleton, 它是全部 Bean 的默認做用域.

2.2.9 使用外部屬性文件
2.2.10 Spring表達式語言:SpEL
-
簡介
- Spring 表達式語言(簡稱SpEL):是一個支持運行時查詢和操做對象圖的強大的表達式語言。
- 語法相似於 EL:SpEL 使用 #{…} 做爲定界符,全部在大框號中的字符都將被認爲是 SpEL
- SpEL 爲 bean 的屬性進行動態賦值提供了便利
-
經過 SpEL 能夠實現:
- 經過 bean 的 id 對 bean 進行引用
- 調用方法以及引用對象中的屬性
- 計算表達式的值
- 正則表達式的匹配
-
SpEL表示字面量
-
字面量的表示:
- 整數:
<property name="count" value="#{5}"/>
- 小數:
<property name="frequency" value="#{89.7}"/>
- 科學計數法:
<property name="capacity" value="#{1e4}"/>
- String可使用單引號或者雙引號做爲字符串的定界符號:
<property name=「name」 value="#{'Chuck'}"/>
或 <property name='name' value='#{"Chuck"}'/>
- Boolean:
<property name="enabled" value="#{false}"/>
-
SpEL引用 Bean、屬性和方法
- 引用其餘對象:

- 引用其餘對象的屬性

- 調用其餘方法,還能夠鏈式操做


- 調用靜態方法或靜態屬性:經過 T() 調用一個類的靜態方法,它將返回一個 Class Object,而後再調用相應的方法或屬性:

- SpEL還支持運算符號
2.2.11 IOC 容器中 Bean 的生命週期
2.2.12 經過工廠方法配置Bean
2.2.13 經過註解配置bean
-
在 classpath 中掃描組件
- 組件裝配
<context:component-scan>
元素還會自動註冊 AutowiredAnnotationBeanPostProcessor 實例, 該實例能夠自動裝配具備 @Autowired 和 @Resource 、@Inject註解的屬性.
-
使用 @Autowired 自動裝配 Bean
@Autowired 註解自動裝配具備兼容類型的單個 Bean屬性
- 構造器, 普通字段(即便是非 public), 一切具備參數的方法均可以應用@Authwired 註解
- 默認狀況下, 全部使用 @Authwired 註解的屬性都須要被設置. 當 Spring 找不到匹配的 Bean 裝配屬性時, 會拋出異常, 若某一屬性容許不被設置, 能夠設置 @Authwired 註解的 required 屬性爲 false
- 默認狀況下, 當 IOC 容器裏存在多個類型兼容的 Bean 時, 經過類型的自動裝配將沒法工做. 此時能夠在 @Qualifier 註解裏提供 Bean 的名稱. Spring 容許對方法的入參標註 @Qualifiter 已指定注入 Bean 的名稱
- @Authwired 註解也能夠應用在數組類型的屬性上, 此時 Spring 將會把全部匹配的 Bean 進行自動裝配.
- @Authwired 註解也能夠應用在集合屬性上, 此時 Spring 讀取該集合的類型信息, 而後自動裝配全部與之兼容的 Bean.
- @Authwired 註解用在 java.util.Map 上時, 若該 Map 的鍵值爲 String, 那麼 Spring 將自動裝配與之 Map 值類型兼容的 Bean, 此時 Bean 的名稱做爲鍵值
-
使用 @Resource 或 @Inject 自動裝配 Bean
- Spring 還支持 @Resource 和 @Inject 註解,這兩個註解和 @Autowired 註解的功用相似
- @Resource 註解要求提供一個 Bean 名稱的屬性,若該屬性爲空,則自動採用標註處的變量或方法名做爲 Bean 的名稱
- @Inject 和 @Autowired 註解同樣也是按類型匹配注入的 Bean, 但沒有 reqired 屬性
- 建議使用 @Autowired 註解
2.2.14 泛型依賴注入

3、AOP

需求1-日誌:在程序執行期間追蹤正在發生的活動
需求2-驗證:但願計算器只能處理正數的運算

問題:
- 代碼混亂:愈來愈多的非業務需求(日誌和驗證等)加入後, 原有的業務方法急劇膨脹. 每一個方法在處理核心邏輯的同時還必須兼顧其餘多個關注點.
- 代碼分散: 以日誌需求爲例, 只是爲了知足這個單一需求, 就不得不在多個模塊(方法)裏屢次重複相同的日誌代碼. 若是日誌需求發生變化, 必須修改全部模塊.
3.1 使用動態代理解決上述問題
代理設計模式的原理: 使用一個代理將對象包裝起來, 而後用該代理對象取代原始對象. 任何對原始對象的調用都要經過代理. 代理對象決定是否以及什麼時候將方法調用轉到原始對象上.

代理類
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
public class ArithmeticCalculatorLoggingProxy {
private ArithmeticCalculator target;
public void setTarget(ArithmeticCalculator target) {
this.target = target;
}
public ArithmeticCalculatorLoggingProxy(ArithmeticCalculator target) {
this.target = target;
}
public ArithmeticCalculator getLogginProxy() {
ArithmeticCalculator proxy = null;
//代理對象由哪個類加載器負責加載
ClassLoader loader = target.getClass().getClassLoader();
//代理對象的類型,即其中有哪些方法
Class[] interfaces = new Class[]{ArithmeticCalculator.class};
//當調用代理對象中期的方法時,該執行的代碼
InvocationHandler h = new InvocationHandler() {
/**
* @param proxy 正在返回的那個代理對象,通常狀況下,在invoke方法中ftjbn 不使用該對象
* @param method 正在被調用的方法
* @param args 調用方法時,傳入的參數
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
System.out.println("The method " + methodName + "() begins with " + Arrays.asList(args));
Object result = method.invoke(target, args);
System.out.println("The method " + methodName + "() ends with " + result);
return result;
}
};
proxy = (ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, h);
return proxy;
}
}
測試類
public static void main(String[] args) {
ArithmeticCalculator target = new ArithmeticCalculatorImpl();
ArithmeticCalculatorLoggingProxy proxy = new ArithmeticCalculatorLoggingProxy(target);
ArithmeticCalculator logginProxy = proxy.getLogginProxy();
logginProxy.add(1, 2);
}
3.2 AOP簡介
- AOP(Aspect-Oriented Programming, 面向切面編程): 是一種新的方法論, 是對傳統 OOP(Object-Oriented Programming, 面向對象編程) 的補充.
- AOP 的主要編程對象是切面(aspect), 而切面模塊化橫切關注點.
- 在應用 AOP 編程時, 仍然須要定義公共功能, 但能夠明確的定義這個功能在哪裏, 以什麼方式應用, 而且沒必要修改受影響的類. 這樣一來橫切關注點就被模塊化到特殊的對象(切面)裏.
-
AOP 的好處:
- 每一個事物邏輯位於一個位置, 代碼不分散, 便於維護和升級
- 業務模塊更簡潔, 只包含核心業務代碼.

3.3 AOP術語
- 切面(Aspect): 橫切關注點(跨越應用程序多個模塊的功能)被模塊化的特殊對象
- 通知(Advice): 切面必需要完成的工做
- 目標(Target): 被通知的對象
- 代理(Proxy): 向目標對象應用通知以後建立的對象
- 鏈接點(Joinpoint):程序執行的某個特定位置:如類某個方法調用前、調用後、方法拋出異常後等。鏈接點由兩個信息肯定:方法表示的程序執行點;相對點表示的方位。例如 ArithmethicCalculator#add() 方法執行前的鏈接點,執行點爲 ArithmethicCalculator#add(); 方位爲該方法執行前的位置
- 切點(pointcut):每一個類都擁有多個鏈接點:例如 ArithmethicCalculator 的全部方法實際上都是鏈接點,即鏈接點是程序類中客觀存在的事務。AOP 經過切點定位到特定的鏈接點。類比:鏈接點至關於數據庫中的記錄,切點至關於查詢條件。切點和鏈接點不是一對一的關係,一個切點匹配多個鏈接點,切點經過 org.springframework.aop.Pointcut 接口進行描述,它使用類和方法做爲鏈接點的查詢條件。
3.4 Spring AOP
3.5 用 AspectJ 註解聲明切面
- 要在 Spring 中聲明 AspectJ 切面, 只須要在 IOC 容器中將切面聲明爲 Bean 實例. 當在 Spring IOC 容器中初始化 AspectJ 切面以後, Spring IOC 容器就會爲那些與 AspectJ 切面相匹配的 Bean 建立代理.
- 在 AspectJ 註解中, 切面只是一個帶有 @Aspect 註解的 Java 類.
- 通知是標註有某種註解的簡單的 Java 方法.
-
AspectJ 支持 5 種類型的通知註解:
- @Before: 前置通知, 在方法執行以前執行
- @After: 後置通知, 在方法執行以後執行
- @AfterRunning: 返回通知, 在方法返回結果以後執行
- @AfterThrowing: 異常通知, 在方法拋出異常以後
- @Around: 環繞通知, 圍繞着方法執行
3.6 實現步驟
一、添加依賴
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
二、在配置文件中添加aop的命名空間
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
三、加入配置
<!--使AspectJ註解起做用:自動爲匹配的類生成代理對象-->
<aop:aspectj-autoproxy/>
四、建立切面
- 切面首先是IOC中的bean,即加上@Component註解
- 切面還須要加上@Aspect註解
五、在類中聲明各類通知
AspectJ 支持 5 種類型的通知註解:
- @Before: 前置通知, 在方法執行以前執行
- @After: 後置通知, 在方法執行以後執行
- @AfterRunning: 返回通知, 在方法返回結果以後執行
- @AfterThrowing: 異常通知, 在方法拋出異常以後
- @Around: 環繞通知, 圍繞着方法執行
之前置通知爲例:
//把這個類聲明爲一個切面
@Component
@Aspect
public class LoggingAspect {
//聲明該方法是一個前置通知:在目標方法開始以前執行
@Before("execution(public int com.meituan.spring.aop.helloworld.ArithmeticCalculatorImpl.*(int, int))")
public void beforeMethod(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
List<Object> args = Arrays.asList(joinPoint.getArgs());
System.out.println("The method " + signature.getName() + args + " begins");
}
}
3.7 後置通知、返回通知、異常通知、環繞通知
一個切面能夠包括一個或者多個通知.
3.8 切面的優先級
- 在同一個鏈接點上應用不止一個切面時, 除非明確指定, 不然它們的優先級是不肯定的.
- 切面的優先級能夠經過實現 Ordered 接口或利用 @Order 註解指定.
- 實現 Ordered 接口, getOrder() 方法的返回值越小, 優先級越高.
- 若使用 @Order 註解, 序號出如今註解中
3.9 重用切入點定義
- 在編寫 AspectJ 切面時, 能夠直接在通知註解中書寫切入點表達式. 但同一個切點表達式可能會在多個通知中重複出現.
- 在 AspectJ 切面中, 能夠經過 @Pointcut 註解將一個切入點聲明成簡單的方法. 切入點的方法體一般是空的, 由於將切入點定義與應用程序邏輯混在一塊兒是不合理的.
- 切入點方法的訪問控制符同時也控制着這個切入點的可見性. 若是切入點要在多個切面中共用, 最好將它們集中在一個公共的類中. 在這種狀況下, 它們必須被聲明爲 public. 在引入這個切入點時, 必須將類名也包括在內. 若是類沒有與這個切面放在同一個包中, 還必須包含包名.
- 其餘通知能夠經過方法名稱引入該切入點.

4、Spring對JDBC的支持
4.1 JdbcTemplate 簡介
- 爲了使 JDBC 更加易於使用, Spring 在 JDBC API 上定義了一個抽象層, 以此創建一個 JDBC 存取框架.
- 做爲 Spring JDBC 框架的核心, JDBC 模板的設計目的是爲不一樣類型的 JDBC 操做提供模板方法. 每一個模板方法都能控制整個過程, 並容許覆蓋過程當中的特定任務. 經過這種方式, 能夠在儘量保留靈活性的狀況下, 將數據庫存取的工做量降到最低.
4.2 簡化JDBC模板查詢
- 每次使用都建立一個 JdbcTemplate 的新實例, 這種作法效率很低下.
- JdbcTemplate 類被設計成爲線程安全的, 因此能夠再 IOC 容器中聲明它的單個實例, 並將這個實例注入到全部的 DAO 實例中.
- JdbcTemplate 也利用了 Java 1.5 的特定(自動裝箱, 泛型, 可變長度等)來簡化開發
- Spring JDBC 框架還提供了一個 JdbcDaoSupport 類來簡化 DAO 實現. 該類聲明瞭 jdbcTemplate 屬性, 它能夠從 IOC 容器中注入, 或者自動從數據源中建立.
4.3 注入JDBC模板示例代碼

4.4 在 JDBC 模板中使用具名參數
- 在經典的 JDBC 用法中, SQL 參數是用佔位符 ? 表示,而且受到位置的限制. 定位參數的問題在於, 一旦參數的順序發生變化, 就必須改變參數綁定.
- 在 Spring JDBC 框架中, 綁定 SQL 參數的另外一種選擇是使用具名參數(named parameter).
- 具名參數: SQL 按名稱(以冒號開頭)而不是按位置進行指定. 具名參數更易於維護, 也提高了可讀性. 具名參數由框架類在運行時用佔位符取代
- 具名參數只在 NamedParameterJdbcTemplate 中獲得支持
- 在 SQL 語句中使用具名參數時, 能夠在一個 Map 中提供參數值, 參數名爲鍵
- 也可使用 SqlParameterSource 參數
- 批量更新時能夠提供 Map 或 SqlParameterSource 的數組

5、Spring中的事務管理
5.1 事務簡介
- 事務管理是企業級應用程序開發中必不可少的技術, 用來確保數據的完整性和一致性.
- 事務就是一系列的動做, 它們被當作一個單獨的工做單元. 這些動做要麼所有完成, 要麼所有不起做用
-
事務的四個關鍵屬性(ACID)
- 原子性(atomicity): 事務是一個原子操做, 由一系列動做組成. 事務的原子性確保動做要麼所有完成要麼徹底不起做用.
- 一致性(consistency): 一旦全部事務動做完成, 事務就被提交. 數據和資源就處於一種知足業務規則的一致性狀態中.
- 隔離性(isolation): 可能有許多事務會同時處理相同的數據, 所以每一個事物都應該與其餘事務隔離開來, 防止數據損壞.
- 持久性(durability): 一旦事務完成, 不管發生什麼系統錯誤, 它的結果都不該該受到影響. 一般狀況下, 事務的結果被寫到持久化存儲器中.
5.2 事務管理中的問題
- 必須爲不一樣的方法重寫相似的樣板代碼
- 這段代碼是特定於 JDBC 的, 一旦選擇類其它數據庫存取技術, 代碼須要做出相應的修改

獲取鏈接、開啓事務==》前置通知
提交事務==》返回通知
回滾事務==》異常通知
finally部分==》後置通知
5.3 Spring的事務管理
- 做爲企業級應用程序框架, Spring 在不一樣的事務管理 API 之上定義了一個抽象層. 而應用程序開發人員沒必要了解底層的事務管理 API, 就可使用 Spring 的事務管理機制.
- Spring 既支持1)編程式事務管理(即編程), 也支持2)聲明式的事務管理(即配置文件).
- 編程式事務管理: 將事務管理代碼嵌入到業務方法中來控制事務的提交和回滾. 在編程式管理事務時, 必須在每一個事務操做中包含額外的事務管理代碼.
- 聲明式事務管理: <u>大多數狀況下比編程式事務管理更好用</u>. 它將事務管理代碼從業務方法中分離出來, 以聲明的方式來實現事務管理. 事務管理做爲一種橫切關注點, 能夠經過 AOP 方法模塊化. Spring 經過 Spring AOP 框架支持聲明式事務管理.
5.3 Spring中的事務管理器
- Spring 從不一樣的事務管理 API 中抽象了一整套的事務機制. 開發人員沒必要了解底層的事務 API, 就能夠利用這些事務機制. 有了這些事務機制, 事務管理代碼就能獨立於特定的事務技術了.
- Spring 的核心事務管理抽象是
org.springframework.transaction.PlatformTransactionManager;
它爲事務管理封裝了一組獨立於技術的方法. 不管使用 Spring 的哪一種事務管理策略(編程式或聲明式), 事務管理器都是必須的.
5.4 實現步驟
-
配置事務管理器
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
-
啓動事務註解
<tx:annotation-driven transaction-manager="transactionManager" />
- 在對應的方法上添加註解
@Transactional
5.5 事務的傳播行爲
- 當事務方法被另外一個事務方法調用時, 必須指定事務應該如何傳播. 例如: 方法可能繼續在現有事務中運行, 也可能開啓一個新事務, 並在本身的事務中運行.
- 事務的傳播行爲能夠由傳播屬性指定. Spring 定義了 7 種類傳播行爲.

5.5.1 REQUIRED 傳播行爲
- 當 bookService 的 purchase() 方法被另外一個事務方法 checkout() 調用時, 它默認會在現有的事務內運行. 這個默認的傳播行爲就是 REQUIRED. 所以在 checkout() 方法的開始和終止邊界內只有一個事務. 這個事務只在 checkout() 方法結束的時候被提交, 結果用戶一本書都買不了
- 事務傳播屬性能夠在 @Transactional 註解的 propagation 屬性中定義

5.5.2 REQUIRES_NEW 傳播行爲
另外一種常見的傳播行爲是 REQUIRES_NEW. 它表示該方法必須啓動一個新事務, 並在本身的事務內運行. 若是有事務在運行, 就應該先掛起它.

5.6 事務的隔離級別
5.6.1 併發事務所致使的問題
- 當同一個應用程序或者不一樣應用程序中的多個事務在同一個數據集上併發執行時, 可能會出現許多意外的問題
-
併發事務所致使的問題能夠分爲下面三種類型:
- 髒讀: 對於兩個事物 T1, T2, T1 讀取了已經被 T2 更新但 尚未被提交的字段. 以後, 若 T2 回滾, T1讀取的內容就是臨時且無效的.
- 不可重複讀:對於兩個事物 T1, T2, T1 讀取了一個字段, 而後 T2 更新了該字段. 以後, T1再次讀取同一個字段, 值就不一樣了.
- 幻讀:對於兩個事物 T1, T2, T1 從一個表中讀取了一個字段, 而後 T2 在該表中插入了一些新的行. 以後, 若是 T1 再次讀取同一個表, 就會多出幾行.
5.6.2 隔離級別
- 從理論上來講, 事務應該彼此徹底隔離, 以免併發事務所致使的問題. 然而, 那樣會對性能產生極大的影響, 由於事務必須按順序運行.
- 在實際開發中, 爲了提高性能, 事務會以較低的隔離級別運行.
- 事務的隔離級別能夠經過隔離事務屬性指定
5.6.3 Spring 支持的事務隔離級別

- 事務的隔離級別要獲得底層數據庫引擎的支持, 而不是應用程序或者框架的支持.
- Oracle 支持的 2 種事務隔離級別:READ_COMMITED , SERIALIZABLE
- Mysql 支持 4 中事務隔離級別.
5.6.4 設置隔離事務屬性
用 @Transactional 註解聲明式地管理事務時能夠在 @Transactional 的 isolation 屬性中設置隔離級別.

5.6.5 設置回滾事務屬性
5.7 超時和只讀屬性
- 因爲事務能夠在行和表上得到鎖, 所以長事務會佔用資源, 並對總體性能產生影響.
- 若是一個事物只讀取數據但不作修改, 數據庫引擎能夠對這個事務進行優化.
- 超時事務屬性: 事務在強制回滾以前能夠保持多久. 這樣能夠防止長期運行的事務佔用資源.
- 只讀事務屬性: 表示這個事務只讀取數據但不更新數據, 這樣能夠幫助數據庫引擎優化事務.