Spring最成功,最吸引人的地方莫過於輕量級的聲明式事務管理,僅此一點,它就宣告了重量級EJB容器的覆滅.Spring聲明式事務管理將開發者從繁複的事務管理代碼中解脫出來,專註於業務邏輯的開發上,這是一件可以被拿來頂禮膜拜的事情.
但是,世界並未從此消停,開發人員需要面對的是層出不窮的應用場景,這些場景往往逾越了普通Spring技術書籍的理想界定.因此,隨著應用開發的深入,在使用經過Spring層層封裝的聲明式事務時,開發人員越來越覺得自己墜入了迷霧,陷入了沼澤,體會不到外界所宣稱的那種暢快淋漓.本系列文章的目標旨在整理並剖析實際應用中種種讓我們迷茫的場景,讓陽光照進雲遮霧障的山頭.
很少有使用Spring但不使用Spring事務管理器的應用,因此常常有人會問:是否用了Spring,就一定要用Spring事務管理器,否則就無法進行數據的持久化操作呢?事務管理器和DAO是什麼關係呢?
也許是DAO和事務管理如影隨行的緣故吧,這個看似簡單的問題實實在在地存在著,從初學者心中湧出,縈繞在開發老手的腦際.答案當然是否定的!我們都知道:Spring事務管理是保證數據操作的事務性(即原子性、一致性、隔離性、持久性,也即所謂的ACID),脫離了事務性,DAO照樣可以順利地進行數據的操作.下面,我們來看一段使用SpringJDBC進行數據訪問的代碼:
清單1.UserJdbcWithoutTransManagerService.java
1.packageuser.withouttm;
2.
3.importorg.springframework.beans.factory.annotation.Autowired;
4.importorg.springframework.jdbc.core.JdbcTemplate;
5.importorg.springframework.stereotype.Service;
6.importorg.springframework.context.ApplicationContext;
7.importorg.springframework.context.support.ClassPathXmlApplicationContext;
8.importorg.apache.commons.dbcp.BasicDataSource;
9.
10.@Service("service1")
11.publicclassUserJdbcWithoutTransManagerService{
12.@Autowired
13.privateJdbcTemplatejdbcTemplate;
14.
15.publicvoidaddScore(StringuserName,inttoAdd){
16.Stringsql="UPDATEt_useruSETu.score=u.score ?WHEREuser_name=?";
17.jdbcTemplate.update(sql,toAdd,userName);
18.}
19.
20.publicstaticvoidmain(String[]args){
21.ApplicationContextctx=
22.newClassPathXmlApplicationContext("user/withouttm/jdbcWithoutTransManager.xml");
23.UserJdbcWithoutTransManagerServiceservice=
24.(UserJdbcWithoutTransManagerService)ctx.getBean("service1");
25.JdbcTemplatejdbcTemplate=(JdbcTemplate)ctx.getBean("jdbcTemplate");
26.BasicDataSourcebasicDataSource=(BasicDataSource)jdbcTemplate.getDataSource();
27.
28.//①.檢查數據源autoCommit的設置
29.System.out.println("autoCommit:" basicDataSource.getDefaultAutoCommit());
30.
31.//②.插入一條記錄,初始分數為10
32.jdbcTemplate.execute(
33."INSERTINTOt_user(user_name,password,score)VALUES('tom','123456',10)");
34.
35.//③.調用工作在無事務環境下的服務類方法,將分數添加20分
36.service.addScore("tom",20);
37.
38.//④.查看此時用戶的分數
39.intscore=jdbcTemplate.queryForInt(
40."SELECTscoreFROMt_userWHEREuser_name='tom'");
41.System.out.println("score:" score);
42.jdbcTemplate.execute("DELETEFROMt_userWHEREuser_name='tom'");
43.}
44.}
jdbcWithoutTransManager.xml的配置文件如下所示:
清單2.jdbcWithoutTransManager.xml
45.<?xmlversionxmlversion="1.0"encoding="UTF-8"?>
46.<beansxmlnsbeansxmlns="http://www.springframework.org/schema/beans"
47.xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
48.xmlns:context="http://www.springframework.org/schema/context"
49.xmlns:p="http://www.springframework.org/schema/p"
50.xsi:schemaLocation="http://www.springframework.org/schema/beans
51.http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
52.http://www.springframework.org/schema/context
53.http://www.springframework.org/schema/context/spring-context-3.0.xsd">
54.<context:component-scanbase-packagecontext:component-scanbase-package="user.withouttm"/>
55.
56.<beanidbeanid="dataSource"
57.class="org.apache.commons.dbcp.BasicDataSource"
58.destroy-method="close"
59.p:driverClassName="oracle.jdbc.driver.OracleDriver"
60.p:url="jdbc:oracle:thin:@localhost:1521:orcl"
61.p:username="test"
62.p:password="test"/>
63.<beanidbeanid="jdbcTemplate"
64.class="org.springframework.jdbc.core.JdbcTemplate"
65.p:dataSource-ref="dataSource"/>
66.</< span>beans>
運行UserJdbcWithoutTransManagerService,在控制台上打出如下的結果:
67.defaultAutoCommit:true
68.score:30
在jdbcWithoutTransManager.xml中,沒有配置任何事務管理器,但是數據已經成功持久化到資料庫中.在默認情況下,dataSource數據源的autoCommit被設置為true――這也意謂著所有通過JdbcTemplate執行的語句馬上提交,沒有事務.如果將dataSource的defaultAutoCommit設置為false,再次運行UserJdbcWithoutTransManagerService,將拋出錯誤,原因是新增及更改數據的操作都沒有提交到資料庫,所以④處的語句因無法從資料庫中查詢到匹配的記錄而引發異常.
對於強調讀速度的應用,資料庫本身可能就不支持事務,如使用MyISAM引擎的MySQL資料庫.這時,無須在Spring應用中配置事務管理器,即使配置了,也是沒有實際用處的.
不過,對於Hibernate來說,情況就有點複雜了.Hibernate的事務管理擁有其自身的意義,它和Hibernate一級緩存有密切的關係:當我們調用Session的save、update等方法時,Hibernate並不直接向資料庫發送SQL語句,而是在提交事務(commit)或flush一級緩存時才真正向資料庫發送SQL.所以,即使底層資料庫不支持事務,Hibernate的事務管理也是有一定好處的,不會對數據操作的效率造成負面影響.所以,如果是使用Hibernate數據訪問技術,沒有理由不配置HibernateTransactionManager事務管理器.但是,不使用Hibernate事務管理器,在Spring中,Hibernate照樣也可以工作,來看下面的例子:
清單3.UserHibernateWithoutTransManagerService.java
1.packageuser.withouttm;
2.
3.importorg.springframework.beans.factory.annotation.Autowired;
4.importorg.springframework.jdbc.core.JdbcTemplate;
5.importorg.springframework.stereotype.Service;
6.importorg.springframework.context.ApplicationContext;
7.importorg.springframework.context.support.ClassPathXmlApplicationContext;
8.importorg.springframework.orm.hibernate3.HibernateTemplate;
9.importorg.apache.commons.dbcp.BasicDataSource;
10.importuser.User;
11.
12.@Service("service2")
13.publicclassUserHibernateWithoutTransManagerService{
14.@Autowired
15.privateHibernateTemplatehibernateTemplate;
16.
17.publicvoidaddScore(StringuserName,inttoAdd){
18.Useruser=(User)hibernateTemplate.get(User.class,userName);
19.user.setScore(user.getScore() toAdd);
20.hibernateTemplate.update(user);
21.}
22.
23.publicstaticvoidmain(String[]args){
24.//參考UserJdbcWithoutTransManagerService相應代碼
25.…
26.}
27.}
此時,採用hiberWithoutTransManager.xml的配置文件,其配置內容如下:
清單4.hiberWithoutTransManager.xml
28.<?xmlversionxmlversion="1.0"encoding="UTF-8"?>
29.<beansxmlnsbeansxmlns="http://www.springframework.org/schema/beans"
30.xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
31.xmlns:context="http://www.springframework.org/schema/context"
32.xmlns:p="http://www.springframework.org/schema/p"
33.xsi:schemaLocation="http://www.springframework.org/schema/beans
34.http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
35.http://www.springframework.org/schema/context
36.http://www.springframework.org/schema/context/spring-context-3.0.xsd">
37.
38.…
39.<beanidbeanid="sessionFactory"
40.class=
41."org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"
42.p:dataSource-ref="dataSource">
43.<propertynamepropertyname="annotatedClasses">
44.<list>
45.<value>user.User</< span>value>
46.</< span>list>
47.</< span>property>
48.<propertynamepropertyname="hibernateProperties">
49.<props>
50.<propkeypropkey="hibernate.dialect">
51.org.hibernate.dialect.Oracle10gDialect
52.</< span>prop>
53.<propkeypropkey="hibernate.show_sql">true</< span>prop>
54.</< span>props>
55.</< span>property>
56.</< span>bean>
57.
58.<beanidbeanid="hibernateTemplate"
59.class="org.springframework.orm.hibernate3.HibernateTemplate"
60.p:sessionFactory-ref="sessionFactory"/>
61.</< span>beans>
運行UserHibernateWithoutTransManagerService,程序正確執行,並得到類似於UserJdbcWithoutTransManagerService的執行結果,這說明Hibernate在Spring中,在沒有事務管理器的情況下,依然可以正常地進行數據的訪問.
[火星人 ] Spring事務管理高級應用難點剖析(1)已經有769次圍觀