Spring要點

Spring要點

常用註解

用於創建對象的:

相當於:< bean id="" class="" >

@Component
作用:
把資源讓 spring 來管理。相當於在 xml 中配置一個 bean。
屬性:
value:指定 bean 的 id。如果不指定 value 屬性,默認 bean 的 id 是當前類的類名。首字母小寫。

@Controller @Service @Repository
他們三個註解都是針對一個的衍生註解,他們的作用及屬性都是一模一樣的。
他們只不過是提供了更加明確的語義化。
@Controller :一般用於表現層的註解。
@Service :一般用於業務層的註解。
@Repository :一般用於持久層的註解。
細節:如果註解中有且只有一個屬性 要賦值時是 ,且名稱是 value ,value 在賦值是可以不寫。

用於注入數據的:

相當於:< property name="" ref="" >
< property name="" value="" >

@Autowired
作用:
自動按照類型注入。當使用註解注入屬性時,set方法可以省略。它只能注入其他 bean 類型。當有多個
類型匹配時,使用要注入的對象變量名稱作爲 bean 的 id,在 spring 容器查找,找到了也可以注入成功。找不到就報錯。
@Qualifier
作用:
在自動按照類型注入的基礎之上,再按照 Bean 的 id 注入。它在給字段注入時不能獨立使用,必須和
@Autowire 一起使用;但是給方法參數注入時,可以獨立使用。
屬性:
value:指定 bean 的 id。
@Resource
作用:
直接按照 Bean 的 id 注入。它也只能注入其他 bean 類型。
屬性:
name:指定 bean 的 id。
@Value
作用:
注入基本數據類型和 String 類型數據的
屬性:
value:用於指定值

用於改變作用範圍的:

相當於:< bean id="" class="" scope="" >
@Scope
作用:
指定 bean 的作用範圍。
屬性:
value:指定範圍的值。
取值:singleton prototype request session globalsession

和生命週期相關的:( 瞭解)

相當於:< bean id="" class="" init-method="" destroy-method="" />
@PostConstruct
作用:
用於指定初始化方法。
@PreDestroy
作用:
用於指定銷燬方法。

關於 Spring 註解和 XML 的選擇問題

註解的優勢:
配置簡單,維護方便(我們找到類,就相當於找到了對應的配置)。
XML 的優勢:
修改時,不用改源碼。不涉及重新編譯和部署。
Spring 管理 Bean 方式的比較:
在這裏插入圖片描述

新註解說明

@Configuration
作用:
用於指定當前類是一個 spring 配置類,當創建容器時會從該類上加載註解。獲取容器時需要使用
AnnotationApplicationContext(有@Configuration 註解的類.class)。
屬性:
value:用於指定配置類的字節碼

示例代碼:
@Configuration
public class SpringConfiguration {
}
注意:
我們已經把配置文件用類來代替了,但是如何配置創建容器時要掃描的包呢?
請看下一個註解。

@ComponentScan
作用:
用於指定 spring 在初始化容器時要掃描的包。作用和在 spring 的 xml 配置文件中的:
<context:component-scan base-package=“com.itheima”/>是一樣的。
屬性:
basePackages:用於指定要掃描的包。和該註解中的 value 屬性作用一樣。

示例代碼:
@Configuration
@ComponentScan("com.itheima")
public class SpringConfiguration {
}
注意:
我們已經配置好了要掃描的包,但是數據源和 JdbcTemplate 對象如何從配置文件中移除呢?
請看下一個註解。

@Bean
作用:
該註解只能寫在方法上,表明使用此方法創建一個對象,並且放入 spring 容器。
屬性:
name:給當前@Bean 註解方法創建的對象指定一個名稱(即 bean 的 id)。

示例代碼:
public class JdbcConfig {
/**
* 創建一個數據源,並存入 spring 容器中
* @return
*/
@Bean(name="dataSource")
public DataSource createDataSource() {
try {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setUser("root");
ds.setPassword("1234");
ds.setDriverClass("com.mysql.jdbc.Driver");
ds.setJdbcUrl("jdbc:mysql:///spring_day02");
return ds;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 創建一個 DBAssit,並且也存入 spring 容器中
* @param dataSource
* @return
*/
@Bean(name="dbAssit")
public DBAssit createDBAssit(DataSource dataSource) {
return new DBAssit(dataSource);
}
}
注意:
我們已經把數據源和 DBAssit 從配置文件中移除了,此時可以刪除 bean.xml 了。
但是由於沒有了配置文件,創建數據源的配置又都寫死在類中了。如何把它們配置出來呢?
請看下一個註解。

@PropertySource
作用:
用於加載.properties 文件中的配置。例如我們配置數據源時,可以把連接數據庫的信息寫到
properties 配置文件中,就可以使用此註解指定 properties 配置文件的位置。
屬性:
value[]:用於指定 properties 文件位置。如果是在類路徑下,需要寫上 classpath:

示例代碼:
配置:
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
/**
* 創建一個數據源,並存入 spring 容器中
* @return
*/
@Bean(name="dataSource")
public DataSource createDataSource() {
try {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass(driver);
ds.setJdbcUrl(url);
ds.setUser(username);
ds.setPassword(password);
return ds;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
jdbc.properties 文件:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/day44_ee247_spring
jdbc.username=root
jdbc.password=1234
注意:
此時我們已經有了兩個配置類,但是他們還沒有關係。如何建立他們的關係呢?
請看下一個註解。

@Import
作用:
用於導入其他配置類,在引入其他配置類時,可以不用再寫@Configuration 註解。當然,寫上也沒問
題。
屬性:
value[]:用於指定其他配置類的字節碼。

示例代碼:
@Configuration
@ComponentScan(basePackages = "com.itheima.spring")
@Import({ JdbcConfig.class})
public class SpringConfiguration {
}
@Configuration
@PropertySource("classpath:jdbc.properties")
public class JdbcConfig{
}
注意:
我們已經把要配置的都配置好了,但是新的問題產生了,由於沒有配置文件了,如何獲取容器呢?
請看下一小節。

通過註解獲取容器: :

ApplicationContext ac =
new AnnotationConfigApplicationContext(SpringConfiguration.class);

工程結構圖
在這裏插入圖片描述在這裏插入圖片描述

Spring 整合 Junit

第一步:拷貝整合 junit 的必備 jar 包到 lib 目錄
此處需要注意的是,導入 jar 包時,需要導入一個 spring 中 aop 的 jar 包。
第二步:使用@RunWith 註解替換原有運行器

@RunWith(SpringJUnit4ClassRunner.class)
public class AccountServiceTest {
}

第三步:使用@ContextConfiguration 指定 spring 配置文件的位置

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= {"classpath:bean.xml"})
public class AccountServiceTest {
}
@ContextConfiguration 註解:
locations 屬性:用於指定配置文件的位置。如果是類路徑下,需要用 classpath:表明
classes 屬性:用於指定註解的類。當不使用 xml 配置時,需要用此屬性指定註解類的位置。

第四步:使用@Autowired 給測試類中的變量注入數據

public class AccountServiceTest {
@Autowired
private IAccountService as ;
}

爲什麼到 不把測試類配到 xml 中 ?

在解釋這個問題之前,先解除大家的疑慮,配到 XML 中能不能用呢?
答案是肯定的,沒問題,可以使用。
那麼爲什麼不採用配置到 xml 中的方式呢?
這個原因是這樣的:
第一:當我們在 xml 中配置了一個 bean,spring 加載配置文件創建容器時,就會創建對象。
第二:測試類只是我們在測試功能時使用,而在項目中它並不參與程序邏輯,也不會解決需求上的問
題,所以創建完了,並沒有使用。那麼存在容器中就會造成資源的浪費。
所以,基於以上兩點,我們不應該把測試配置到 xml 文件中。

事務的隔離級別

一、併發問題

1、髒讀
事務T1正在操作一條數據,此時事務T2獲取該條數據紀錄,如果T1異常,事務回滾,T2讀取到的數據就是髒數據,這種現象稱爲髒讀。
2、不可重複讀
事務T1多次讀取某條記錄,在讀取間隔中,事務T2更新了該技術的數據,當T1再次讀取該記錄時,獲取到的數據不一致,這種現象稱爲不可重複讀。產生的原因主要是數據的更新。
3、幻讀
事務T1批量處理多條記錄,此時事務T2新增或刪除了一條或多條記錄,當T1處理完成,查詢處理結果,會發現有記錄沒有處理(T2新增的)或者發現記錄少了(T2刪除的),會有一種幻覺的感覺,這種現象稱爲幻讀。主要是數據的新增或刪除導致。

二、隔離級別

1、未提交讀(Read uncommitted)
①定義:就是一個事務讀取到其他事務未提交的數據,是級別最低的隔離機制。
②缺點:會產生髒讀、不可重複讀、幻讀。
③案例解讀:以前交易所炒股的時候,股民老王購買了5000股,操作員操作錄入(此時開啓事務),操作時手誤,多輸入了一個0,數據保存但是未提交。此時老王查詢自己的持股信息,發現自己居然有50000股,瞬間血壓升高,昏倒在地。然後操作員發現自己錄入錯誤,修改成正確的信息,錄入完成(事務結束)。老王被救醒後,哆嗦這查詢自己的持股,發現只有5000,沒有增減,他之前看到的就是髒讀數據。
④解決方案:採用更高級的隔離機制,如提交讀。

2、提交讀(Read committed)
①定義:就是一個事務讀取到其他事務提交後的數據。Oracle默認隔離級別。
②缺點:會產生不可重複讀、幻讀。
③案例解讀:股市升高後,老王查看自己持有5000股,就想賣掉4000股,在老王賣股票的時候,老王的老婆看股市太高,就登錄老王的賬號,賣掉3000股。當老王想賣股票時,發現自己只有2000股,不是之前看到的5000股,這就是不可重複讀問題。
④解決方案:採用更高級的隔離機制,如可重複讀。

3、可重複讀(Repeatable read)
①定義:就是一個事務對同一份數據讀取到的相同,不在乎其他事務對數據的修改。MySQL默認的隔離級別。
②缺點:會產生幻讀。
③問題解讀:股市忽漲忽跌,老王焦慮不安,按捺不住,想把持有的多種股票全部拋掉。與此同時,老外老婆聽信磚家所言,使用老王的賬號買了某隻神股。老王拋掉所有股票後,查看自己的持股,猛然發現自己居然還持有一隻股票,瞬間覺得一臉懵逼,這就是幻讀導致。
④解決方案:採用更高級的隔離機制,序列化。

4、序列化(Serializable)
①定義:事務串行化執行,隔離級別最高,犧牲了系統的併發性。
②缺點:可以解決併發事務的所有問題。但是效率地下,消耗數據庫性能,一般不使用。

事務的傳播行爲

REQUIRED: 如果當前沒有事務,就新建一個事務,如果已經存在一個事務中,加入到這個事務中。一般的選
擇(默認值)
SUPPORTS: 支持當前事務,如果當前沒有事務,就以非事務方式執行(沒有事務)
MANDATORY: 使用當前的事務,如果當前沒有事務,就拋出異常
REQUERS_NEW: 新建事務,如果當前在事務中,把當前事務掛起。
NOT_SUPPORTED: 以非事務方式執行操作,如果當前存在事務,就把當前事務掛起
NEVER: 以非事務方式運行,如果當前存在事務,拋出異常
NESTED: 如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則執行 REQUIRED 類似的操作。

基於 XML 的聲明式事務控制(配置方式)

第一步: 配置事務管理器

<!-- 配置一個事務管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入 DataSource -->
<property name="dataSource" ref="dataSource"></property>
</bean>

第二步:配置事務的通知引用事務管理器

<!-- 事務的配置 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
</tx:advice>

第三步:配置事務的屬性

<!--在 在 tx:advice 標籤內部 配置事務的屬性 -->
<tx:attributes>
<!-- 指定方法名稱:是業務核心方法
read-only:是否是隻讀事務。默認 false,不只讀。
isolation:指定事務的隔離級別。默認值是使用數據庫的默認隔離級別。
propagation:指定事務的傳播行爲。
timeout:指定超時時間。默認值爲:-1。永不超時。
rollback-for:用於指定一個異常,當執行產生該異常時,事務回滾。產生其他異常,事務不回滾。
沒有默認值,任何異常都回滾。
no-rollback-for:用於指定一個異常,當產生該異常時,事務不回滾,產生其他異常時,事務回
滾。沒有默認值,任何異常都回滾。
-->
<tx:method name="*" read-only="false" propagation="REQUIRED"/>
<tx:method name="find*" read-only="true" propagation="SUPPORTS"/>
</tx:attributes>

第四步:配置 AOP 切入點表達式

<!-- 配置 aop -->
<aop:config>
<!-- 配置切入點表達式 -->
<aop:pointcut expression="execution(* com.itheima.service.impl.*.*(..))"
id="pt1"/>
</aop:config>

第五步:配置切入點表達式和事務通知的對應關係

<!-- 在 在 aop:config 標籤內部:建立事務的通知和切入點表達式的關係 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"/>

基於註解 的配置

第一步:配置事務管理器 並注入數據源

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

第 二 步:在配置文件中開啓 spring 對註解事務的支持

<!-- 開啓 spring 對註解事務的支持 -->
<tx:annotation-driven transaction-manager="transactionManager"/>

第 三 步:在業務層使用@Transactional 註解

@Service("accountService")
@Transactional(readOnly=true,propagation=Propagation.SUPPORTS)
public class AccountServiceImpl implements IAccountService {}
該註解的屬性和 xml 中的屬性含義一致。該註解可以出現在接口上,類上和方法上。
出現接口上,表示該接口的所有實現類都有事務支持。
出現在類上,表示類中所有方法有事務支持
出現在方法上,表示方法有事務支持。
以上三個位置的優先級:方法>>接口
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章