javascript
【SSM框架系列】Spring - JdbcTemplate声明式事务
JdbcTemplate概述
-
以往使用jdbc時,每次都需要自己獲取PreparedStatement,執(zhí)行sql語句,關閉連接等操作。操作麻煩冗余,影響編碼的效率。
-
Spring把對數(shù)據(jù)庫的操作在jdbc上面做了深層次的封裝,使用spring的注入功能,可以把DataSource注冊到JdbcTemplate(jdbc模板)之中,這樣我們只需要做一些簡單的操作(eg:編寫SQL語句、傳遞參數(shù))就可以了。
-
spring框架根據(jù)不同持久層方案為我們提供了不同的JdbcTemplate(jdbc模板類)。例如:操作關系型數(shù)據(jù)的JdbcTemplate和HibernateTemplate,操作nosql數(shù)據(jù)庫的RedisTemplate,操作消息隊列的JmsTemplate等等
QuickStart
導入spring-jdbc和spring-tx坐標
<dependencies><!-- Spring上下文坐標,如果使用到了Spring的上下文容器,需要導入--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.5.RELEASE</version></dependency><!-- 使用Spring JdbcTemplate需要導入下面兩個坐標 --><!-- 導入spring-jdbc坐標 --><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.0.5.RELEASE</version></dependency><!-- 導入spring-tx事務管理坐標,如果不使用事務管理,可以不導 --><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>5.0.5.RELEASE</version></dependency><!-- 因為操作Mysql數(shù)據(jù)庫,需要導入數(shù)據(jù)庫驅(qū)動坐標 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version></dependency><!-- 數(shù)據(jù)源選擇使用c3p0連接池 --><dependency><groupId>c3p0</groupId><artifactId>c3p0</artifactId><version>0.9.1.2</version></dependency><!-- 使用單元測試 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency> </dependencies>在測試類中創(chuàng)建JdbcTemplate對象并使用
public class AccountTest {@Testpublic void test1() throws PropertyVetoException {//1. 創(chuàng)建JdbcTemplate模板對象JdbcTemplate jdbcTemplate = new JdbcTemplate();//2. 設置數(shù)據(jù)源ComboPooledDataSource對象//創(chuàng)建DataSource對象,并設置連接四要素ComboPooledDataSource dataSource = new ComboPooledDataSource();dataSource.setDriverClass("com.mysql.jdbc.Driver");dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");dataSource.setUser("root");dataSource.setPassword("root");//JdbcTemplate依賴于DataSourcejdbcTemplate.setDataSource(dataSource);//3. 執(zhí)行增刪改查操作int row = jdbcTemplate.update("insert into account values (?,?)", "趙麗穎", 666);System.out.println(row);} }Spring容器創(chuàng)建并維護JdbcTemplate及相關對象
1)思路分析
-
Spring的核心之一就是Ioc,控制反轉(zhuǎn),也就是由Spring容器負責對象的創(chuàng)建和對象間依賴關系的管理。上述代碼中DataSource、JdbcTemplate對象以及他們之間的關系都是由我們手動創(chuàng)建,并且手動設置依賴關系的。
-
經(jīng)過觀察,JdbcTemplate類可以通過無參構造創(chuàng)建該類對象,同時又setDataSource()方法用于設置數(shù)據(jù)源依賴,所以JdbcTemplate類的對象完全可以交給Spring容器管理,數(shù)據(jù)源DataSource可以交給Spring容器管理,那我們就可以使用Spring容器管理并維護上述兩個對象。
2)代碼實現(xiàn)
導入坐標:因為要使用到Spring容器創(chuàng)建對象并維護對象依賴關系,所以要在pom.xml中確定導入了spring-context坐標。
<!-- Spring上下文坐標,使用到了Spring的上下文容器,需要 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.5.RELEASE</version></dependency>Xml配置:在applicationContext.xml文件中先配置數(shù)據(jù)源,然后配置JdbcTemplate,最后將數(shù)據(jù)源注入到JdbcTemplate中。
<!-- DataSource對象 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property><property name="jdbcUrl" value="jdbc:mysql:///test"></property><property name="user" value="root"></property><property name="password" value="root"></property> </bean><!-- JdbcTemplate對象 --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"></property> </bean>Java代碼:通過Spring容器獲得JdbcTemplate對象,調(diào)用JdbcTemplate對象的update方法,傳入sql語句及參數(shù)完成插入數(shù)據(jù)的操作
@Test public void test2() throws PropertyVetoException {//1. 獲取JdbcTemplate模板對象(Spring已經(jīng)將DataSource注入其中)ApplicationContext ac= new ClassPathXmlApplicationContext("applicationContext.xml");JdbcTemplate jdbcTemplate = ac.getBean(JdbcTemplate.class);//2. 不需要設置數(shù)據(jù)源ComboPooledDataSource對象//3. 執(zhí)行增刪改查操作int row = jdbcTemplate.update("insert into account values (?,?)", "shheima", 60000);System.out.println(row); }抽取jdbc配置
-
目前的jdbc四要素已經(jīng)脫離了代碼,已經(jīng)實現(xiàn)了解耦,之后如果數(shù)據(jù)庫信息修改后直接修改配置文件即可。
-
但是目前數(shù)據(jù)庫四要素的配置耦合進了Spring的配置文件,為了更方便的維護,建議將該信息抽取到一個獨立properties文件中。
-
提取數(shù)據(jù)源的基本連接信息到配置文件jdbc.properties(名字任意,格式為properties)
引入properties文件,并修改DataSource注入基本參數(shù)的配置,具體如下:
<!-- 導入jdbc.properties文件。classpath表示文件在類路徑下 --> <context:property-placeholder location="classpath:jdbc.properties"/><!-- DataSource對象 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><!--property的name屬性名稱通過set方法截取;因為屬性值為String,所以通過value屬性設置通過${key}的方式可以從properties文件中讀取key對應的值。--><property name="driverClass" value="${jdbc.driver}"></property><property name="jdbcUrl" value="${jdbc.url}"></property><property name="user" value="${jdbc.username}"></property><property name="password" value="${jdbc.password}"></property> </bean><!-- JdbcTemplate對象 --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"></property> </bean>如果有多個properties文件需要引入可以使用通配符:
<!--如果需要導入多個文件,可以使用通配符 --> <context:property-placeholder location="classpath:*.properties"/>JdbcTemplate常用操作
jdbcTemplate更新數(shù)據(jù)庫常用方法
- update (更新數(shù)據(jù),也就是增刪改)
- queryForObject (單行查詢)
- query (多行查詢)
- queryForObject (單值查詢)
JdbcTemplate常用操作-增刪改操作
JdbcTemplate對象的update方法可以完成增刪改的操作,只是傳入的sql語句及對應參數(shù)不同。
語法:對數(shù)據(jù)庫進行增刪改的操作,返回影響的行數(shù) jdbcTemplate.update(sql語句, sql語句參數(shù)列表)代碼如下:
@RunWith(SpringJUnit4ClassRunner.class) //指定測試器 @ContextConfiguration("classpath:applicationContext.xml") //指定Spring配置文件并加載 public class JdbcTemplatetTest {@Autowired //自動注入JdbcTemplate對象private JdbcTemplate jdbcTemplate;/*** testUpdate:測試刪除*/@Testpublic void testDelete(){int row = jdbcTemplate.update("delete from account where name=?","nanjingheima");System.out.println(row);}/*** testUpdate:測試修改*/@Testpublic void testUpdate(){int row = jdbcTemplate.update("update account set money=? where name=?", 500000,"hzheima");System.out.println(row);} }JdbcTemplate常用操作-查詢操作
JdbcTemplate對象的query**()方法可以完成查詢的操作。
多行查詢 List<T> query(sql語句, new BeanPropertyRowMapper<T>(T.class)) 查詢并將結果通過BeanPropertyRowMapper將查詢的結果集封裝到List集合中 List<T> query(sql語句, new BeanPropertyRowMapper<T>(T.class), sql語句參數(shù)列表)查詢并將結果通過BeanPropertyRowMapper將查詢的結果集封裝到List集合中 單行查詢 T queryForObject(sql語句, new BeanPropertyRowMapper<T>(T.class), sql語句參數(shù)列表)單行查詢查詢并將結果通過BeanPropertyRowMapper將查詢結果封裝到javaBean對象中 單值查詢 要求的查詢結果類型 queryForObject(sql語句, 要求的查詢結果類型.class)查詢并將結果通過BeanPropertyRowMapper將聚合查詢結果轉(zhuǎn)化到要去的結果類型 要求的查詢結果類型 queryForObject(sql語句, 要求的查詢結果類型.class, sql語句參數(shù)列表)查詢并將結果通過BeanPropertyRowMapper將聚合查詢結果轉(zhuǎn)化到要去的結果類型代碼如下:
@RunWith(SpringJUnit4ClassRunner.class) //指定測試器 @ContextConfiguration("classpath:applicationContext.xml") //指定Spring配置文件并加載接卸 public class JdbcTemplatetTest {@Autowired //自動注入JdbcTemplate對象private JdbcTemplate jdbcTemplate;/*** testQueryCount:聚合查詢*/@Testpublic void testQueryCount(){long count = jdbcTemplate.queryForObject("select count(*) from " +"account",long.class);System.out.println(count);count = jdbcTemplate.queryForObject("select count(*) from " +"account where money = ?",long.class,60000);System.out.println(count);}/*** testQueryOne:查詢單個*/@Testpublic void testQueryOne(){Account account = jdbcTemplate.queryForObject("select * from account " +"where name = ?",new BeanPropertyRowMapper<Account>(Account.class) ,"hzheima");System.out.println(account);}/*** testQuerySome:按條件查詢部分*/@Testpublic void testQuerySome(){List<Account> accounts = jdbcTemplate.query("select * from account where money = ?",new BeanPropertyRowMapper<Account>(Account.class), 60000);System.out.println(accounts);}/*** testQueryAll:查詢所有*/@Testpublic void testQueryAll(){List<Account> accounts = jdbcTemplate.query("select * from account",new BeanPropertyRowMapper<Account>(Account.class));System.out.println(accounts);} }補充:
批量更新(增刪改)
//批量增刪改,batchArgs為批量更新的參數(shù)列表,類型為Object[]數(shù)組類型的List集合 jdbcTemplate.batchUpdate(String sql, List batchArgs); /***testBatechUpdate:批量更新,批量 insert,update,delete*/ @Test public void testBatechUpdate() {String sql = "insert into account(name, money) values(?,?)";List<Object[]> batchArgs = new ArrayList<Object[]>();batchArgs.add(new Object[] {"zhangsan",2000});batchArgs.add(new Object[] {"lisi",2000});batchArgs.add(new Object[] {"wangwu",2000});jdbcTemplate.batchUpdate(sql, batchArgs); }自定義綁定(使用場景較少)
除了使用系統(tǒng)提供的RowMapper的實現(xiàn)類之外,我們也可以自己手動編寫RowMapper實現(xiàn)類,以實現(xiàn)特殊的結果集到javaBean的封裝轉(zhuǎn)化,實例代碼如下:
Account account = jdbcTemplate.queryForObject("select * from account where money = ?",new Object[]{60000L},new RowMapper<Account>() {//重寫該方法時只需要將獲取的結果集中單個結果封裝到某個JavaBean中,//query方法會根據(jù)實際情況選擇選擇返回一個javaBan對象還是一個Listpublic Account mapRow(ResultSet rs, int rowNum) throws SQLException {Account account = new Account();account.setUsername(rs.getString("name"));account.setMoney(rs.getString("money"));return account;}});執(zhí)行DDL語句(使用場景很少)
Spring的JdbcTemplate也可以使用execute(…)方法運行任意SQL語句。所以,該方法通常用于DDL語句。下面代碼創(chuàng)建一個表:
jdbcTemplate.execute("create table mytable (id integer, name varchar(100))");Spring事務管理
Spring事務管理主要應用在軟件分層之后的業(yè)務層,也就是Service層。一個service層的操作依賴的多個dao層操作要被事務管理起來,保證數(shù)據(jù)安全準確。eg:轉(zhuǎn)賬。
Spring事務管理核心API
Spring事務管理的三個高層接口
-
PlatformTransactionManager:Spring提供的事務管理器核心接口,內(nèi)部規(guī)定了常用的事務管理的規(guī)則。
-
TransactionDefinition:Spring提供的封裝事務屬性的接口,用于封裝和操作事務的屬性
-
TransactionStatus:Spring提供的封裝事務狀態(tài)的接口,用于封裝事務的狀態(tài)
PlatformTransactionManager
Spring提供的事務管理器接口,整個Spring進行事務管理的核心接口,內(nèi)部規(guī)定了常用的操作事務的規(guī)則。
a) 接口中規(guī)定的操作事務的方法:
| TransactionStatus getTransaction (TransactionDefination defination) | 根據(jù)事務定義信息獲取事務狀態(tài)信息 |
| void commit(TransactionStatus status) | 提交事務 |
| void rollback(TransactionStatus status) | 回滾事務 |
根據(jù)上述方法,
? TransactionStatus getTransaction(TransactionDefination defination)
我們可以推斷:PlatformTransactionManager根據(jù)TransactionDefinition對象獲得 TransactionStatus 對象
-
三者的關系:平臺事務管理器(PlatformTransactionManager)根據(jù) 事務屬性管理器(TransactionDefinition)中定義的事務屬性對事務進行管理;事務運行過程中,每一個時間點都有對應的事務狀態(tài)信息(TransactionStatus)。
-
也就是說,干活的是Manager(PlatformTransactionManager),根據(jù)事務屬性管理器(TransactionDefinition)的配置信息干活,在干活的過程中會有一些狀態(tài)信息,通過TransactionStatus體現(xiàn)。
b) 不同的Dao層技術則有不同的實現(xiàn)類
PlatformTransactionManager是一個接口,只負責制定規(guī)范,那具體的實現(xiàn)是哪些類呢?Spring根據(jù)不同的數(shù)據(jù)持久層技術提供了不同實現(xiàn)類:
-
Dao 層技術是jdbc、 mybatis、Apache DBUtils時:org.springframework.jdbc.datasource.DataSourceTransactionManager
-
Dao層技術是hibernate時:org.springframework.orm.hibernate5.HibernateTransactionManager
TransactionDefinition
Spring提供的封裝事務屬性的接口,用于規(guī)定封裝事務的屬性,通過該接口實現(xiàn)類對象可以獲取(子類對象可以設置)事務屬性。
a) 接口中規(guī)定的獲取事務屬性的方法:
| int getIsolationLevel() | 獲取事務的隔離級別,隔離級別用于解決事務并發(fā)訪問讀問題 |
| int getPropagationBehavior() | 獲取事務的傳播行為,解決的就是兩個事務方法事務統(tǒng)一性的問題 |
| int getTimeout() | 獲取超時時間 |
| boolean isReadOnly() | 判斷當前事務是否只讀 |
-
接口中只規(guī)定了獲取的方法,在其實現(xiàn)類中有設置的方法,eg:DefaultTransactionDefinition
-
事務屬性需要在進行聲明式事務配置時,需要在配置文件中對于事務屬性進行配置,以便Spring框架進行解析。
b) 事務的四個特性:
ACID:原子性、一致性、隔離性、持久性。
-
Atomic(原子性):事務中包含的操作被看做一個邏輯單元,這個邏輯單元中的操作要么全部成 功,要么全部失敗。
-
Consistency(一致性):事務完成時,數(shù)據(jù)必須處于一致狀態(tài),數(shù)據(jù)的完整性約束沒有被破壞,事務在執(zhí)行過程中發(fā)生錯誤,會被回滾(Rollback)到事務開始前的狀態(tài),就像這個事務從來沒有執(zhí)行過一樣。
-
Isolation(隔離性):事務允許多個用戶對同一個數(shù)據(jù)進行并發(fā)訪問,而不破壞數(shù)據(jù)的正確性 和完整性。同時,并行事務的修改必須與其他并行事務的修改相互獨立。
-
Durability(持久性):事務結束后,事務處理的結果必須能夠得到持久化。
c) 事務屬性:隔離級別(理解)
在并發(fā)訪問的時候,會出現(xiàn)一些讀問題。
讀問題
- 臟讀:一個事務讀取了另外一個事務改寫但還未提交的更新數(shù)據(jù),如果這些數(shù)據(jù)被回滾,則讀到的數(shù)據(jù)是無效的。
- eg:小明工資表,老板算工資的時候被小明看到了。
- 不可重復讀:在同一個事務中,多次讀取同一個數(shù)據(jù)返回的結果有所不同。換句話說就是,后續(xù)讀取可以讀取到另一個事務已提交的更新數(shù)據(jù)。相反,“可重復讀”在同一個事務中多次讀取數(shù)據(jù)時,能保證數(shù)據(jù)時一樣,也就是,后續(xù)讀取不能讀取到另一個事務已經(jīng)提交的更新數(shù)據(jù)。
- eg:小明買手機前后老婆查賬。
- 幻讀:一個事務讀取了(按照某個規(guī)則的)全部數(shù)據(jù)后,另一個事務插入了一些記錄,當后續(xù)再次查詢的時候,幻讀就發(fā)生了。在后續(xù)查詢中,第一個事務就會發(fā)現(xiàn)有一些原來沒有的記錄。
- eg:老婆查崗打印流水,又發(fā)現(xiàn)消費多了。
設置隔離級別,可以解決事務并發(fā)產(chǎn)生的讀問題,如臟讀、不可重復讀和虛讀(幻讀)。
-
ISOLATION_DEFAULT 默認級別,使用數(shù)據(jù)庫內(nèi)部默認級別(mysql - Repeatable read,其他大多數(shù)是 - Read committed)
-
ISOLATION_READ_UNCOMMITTED 讀未提交:一個事務可以讀取另一個未提交事務的數(shù)據(jù),該級別下容易上述所讀有問題。性能最高,安全性最差。
-
ISOLATION_READ_COMMITTED 讀提交:一個事務要等另一個事務提交后才能讀取數(shù)據(jù)。能解決臟讀問題,但是可能會有不可重復讀、幻讀的問題。
-
ISOLATION_REPEATABLE_READ 重復讀,在開始讀取數(shù)據(jù)(事務開啟)時,不再允許修改操作。能解決臟讀、不可重復讀的問題,但是可能會有幻讀的問題。
-
ISOLATION_SERIALIZABLE 序列化,解決所有三個問題,相當于鎖表安全性高,串行化處理事務,但是非常耗數(shù)據(jù)庫性能,效率低下,一般不用。
列表如下(√表示可能出現(xiàn),×表示不會出現(xiàn)):
| Read uncommitted讀未提交 | √ | √ | √ |
| Read commited讀提交 | × | √ | √ |
| Repeatable read重復讀 | × | × | √ |
| Serializable | × | × | × |
上述事務的四大特性、四個隔離級別是原來是在數(shù)據(jù)庫內(nèi)部規(guī)定的,Spring從數(shù)據(jù)庫引入了 過來。但是接下來的七種傳播行為和數(shù)據(jù)庫沒有直接關系,是Spring為了解決實際開發(fā)中的問題而引入的。
d) 事務屬性:傳播行為
即然是傳播,那么至少有兩個東西,才可以發(fā)生傳播。單體不存在傳播這個行為。
事務傳播行為(propagation behavior)指的就是當一個事務方法A調(diào)用另一個事務方法B時,事務方法B應該以何種事務特性進行。是繼續(xù)在調(diào)用者methodA的事務中運行呢,還是為自己開啟一個新事務運行,這就是由methodB的事務傳播行為決定的。
事務傳播行為是為了解決業(yè)務方法相互調(diào)用時,事務如何管理的問題。
通常情況下,一個業(yè)務方法就是一個事務。但是多個業(yè)務方法相互調(diào)用的時候可能會出現(xiàn)問題。
eg:取錢打印小票
取錢 required
{
? 插卡 required
? 輸密碼 required
? 吐錢 required
? 打印小票 requires_new
}
七種事務傳播行為(當前方法:被調(diào)用的方法):
-
PROPAGATION_REQUIRED:表示當前方法必須運行在事務中。如果調(diào)用者事務存在,當前方法就會在該事務中運行;否則,會啟動一個新的事務。一般的選擇(默認值)。
-
PROPAGATION_SUPPORTS:表示當前方法不需要事務上下文,但是如果當前事務存在的話,那么該方法會在這個事務中運行。
-
PROPAGATION_MANDATORY:表示當前方法必須在事務中運行,如果當前事務不存在,則會拋出一個異常。
-
PROPAGATION_REQUERS_NEW:表示當前方法必須運行在它自己的事務中,一個新的事務將被啟動。如果存在當前事務,該方法執(zhí)行期間,當前事務會被掛起。
-
PROPAGATION_NOT_SUPPORTED:表示當前方法不應該運行在事務中。如果存在當前事務,該方法運行期間,當前事務會被掛起。
-
PROPAGATION_NEVER:表示當前方法不應該運行在事務上下文中。如果存在當前事務,則會拋出異常。
-
PROPAGATION_NESTED:表示如果當前已經(jīng)存在一個事務,那么該方法將會在嵌套事務中運行。嵌套的事務可以獨立于當前事務進行獨立的提交和回滾。如果當前事務不存在,那么其行為與PROPAGATION_REQUIRED一樣。注意各廠商對這種傳播行為的支持不同,可以參考資源管理器的文檔來確認他們是否支持嵌套事務。
e) 事務其他屬性
超時時間:默認值是-1,沒有超時限制。如果有,以秒為單位進行設置。一般使用默認。
是否只讀:建議查詢操作時設置為只讀,效率更高。
事務中的readOnly屬性表示對應的事務會優(yōu)化為只讀事務。如果值為true就會告訴Spring我這個方法里面沒有insert或者update,你只需要提供只讀的數(shù)據(jù)庫Connection就行了,這種執(zhí)行效率會比read-write的Connection高。
如果設置了只讀事務,Mysql數(shù)據(jù)庫增刪改會報錯,Oracle無影響(不支持)
TransactionStatus
Spring提供的封裝事務狀態(tài)的接口,用于封裝事務的狀態(tài)。
事務的狀態(tài)是事務自身的屬性,在事務管理不同的時間段,事務會表現(xiàn)出不同的狀態(tài),所以不需要配置。
a) 接口中規(guī)定的判斷事務狀態(tài)的方法:
| boolean isNewTransaction() | 是否是新事務。如果返回false,說明當前事務已存在,或者該操作沒在事務環(huán)境中。 |
| boolean hasSavepoint() | 是否存在回滾點 |
| boolean isRollbackOnly() | 判斷當前事務是否被設置了rollback-only |
| boolean isCompleted() | 事務是否已結束 |
聲明式事務概述
-
Spring 的聲明式事務就是采用聲明的方式來設置事務的屬性參數(shù),事務會按照指定的規(guī)則自動管理運行。
-
這里所說的聲明,指在配置文件中配置(或添加注解)<事務的屬性參數(shù)>,用在Spring 配置文件(注解)中聲明的事務來代替用代碼編寫的事務。
-
在業(yè)務代碼運行過程中,Spring容器(中的事務管理器對象)跟據(jù)配置文件中的配置參數(shù),動態(tài)的把事務加入到業(yè)務代碼中。(AOP思想)
-
(編碼時)事務管理不侵入業(yè)務組件。編寫業(yè)務代碼的時候并沒有體現(xiàn)事務管理的代碼。
-
事務管理策略維護方便。如果需要修改事務管理策略,只要在配置文件上修改,無需改變代碼重新編譯。
基于XML的聲明式事務管理
配置切點
<!--pointcut 目標對象 內(nèi)部的方法就是切點--> <bean id="accountService" class="cs.wy.service.impl.AccountServiceImpl"><property name="accountDao" ref="accountDao"/> </bean>配置通知(事務管理器)
<!-- advice 配置通知-事務管理器就是通知(增強)所在的類 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"><tx:attributes><tx:method name="*"/></tx:attributes> </tx:advice><!--jdbc 使用的(平臺)事務管理器是 DataSourceTransactionManager事務管理管理的是Service層,service層需要調(diào)用dao層操作數(shù)據(jù)庫,dao層依賴DataSource管理連接池并連接數(shù)據(jù)庫所以事務管理器中需要注入DataSource --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"></property> </bean>配置織入
<!-- weaving 配置事務的織入。 增強方法 + 目標方法 --> <aop:config><aop:advisor advice-ref="txAdvice"pointcut="execution(* cs.wy.service.impl.*.*(..))"/> </aop:config>基于XML的聲明式事務管理參數(shù)詳解
重點分析如下配置:
<!-- advice 配置通知-事務管理器就是通知(增強)所在的類 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"><tx:attributes><tx:method name="*"/></tx:attributes> </tx:advice>其中:
tx:advice advice,增強方法所在的類(transactionManager的class)tx:attributes具體的事務需要配到這個標簽里面tx:method 每一個tx:method代表一個類別事務在這個標簽里面的屬性上會配置某些業(yè)務邏輯的方法(目標方法),并同時配置對應的事務管理邏輯。tx:nethod ~ namename屬性,用于配置被切點表達式攔截的所有方法中,哪些業(yè)務邏輯方法被當前事務管理。該屬性并非Spring事務本身的屬性,而是為了讓該事務匹配關聯(lián)到某些業(yè)務邏輯方法。name值可以使用*統(tǒng)配,比方說*代表所有方法,save*代表所有save開頭的方法tx:nethod ~ isolation isolation屬性,配置當前事務的隔離級別;如不設置或設置DEFAULT,使用默認的隔離級別。mysql默認的Repeatable read,其他大多數(shù)是Read committed。tx:method ~ propagationpropagation屬性,配置當前事務的傳播行為。不設置則使用默認值REQUIRED。tx:method ~ timeouttimeout屬性,配置當前事務的超時時間,不設置則使用默認值-1,表示不限制。一般不設置。 tx:method ~ readonlyreadonly屬性,值為boolean類型。默認值為false。關于tx:attributes
a. 如果不配置該標簽,所有切點方法都會單獨開啟屬性為默認值的事務 b. 如果配置該標簽,內(nèi)部tx:method中name匹配的方法會按照當前配置開啟事務,其他未匹配成功的方法會單獨開啟屬性為默認值的事務 c. 存在多個tx:method標簽時,會按照配置順序挨個匹配,直到匹配成功,未匹配成功開啟默認事務 <tx:attributes> <tx:method name="add*" propagation="REQUIRED"/> <tx:method name="upd*" propagation="REQUIRED"/> <tx:method name="del*" propagation="REQUIRED"/> <tx:method name="*" propagation="SUPPORTS" read-only="true" /> </tx:attributes>關于切點表達式:多個切點表達式可以進行邏輯運算連接(主要使用或||):
<aop:pointcut id="tranpc" expression="execution(* cs.wy.user.service.*.*(..))|| execution(* cs.wy.goods.service.*.*(..))"/>關于readonly
對于mysql數(shù)據(jù)庫:如果是查詢操作,建議設為true,優(yōu)化查詢性能;其他設為false或者不設置使用默認值。增刪改操作如果設置為true,則會拋出異常。 對于Oracle數(shù)據(jù)庫:無效果基于注解的聲明式事務控制
使用基于注解的聲明式事務控制,步驟如下:
1、 在xml中開啟自動代理
<aop:aspectj-autoproxy/>2、然后在方法或類上配置@Transactional注解
1. 配置在類上表示該類下所有方法均開啟事務 2. 配置在方法上,表示該方法開啟事務總結
以上是生活随笔為你收集整理的【SSM框架系列】Spring - JdbcTemplate声明式事务的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【SSM框架系列】Spring 的 AO
- 下一篇: 【十大经典排序算法】java实现--冒泡