Você está na página 1de 42

10/05/2016

Chapter10:DataAccess

Chapter10:DataAccess
Inthischapter,youwilllearnaboutthebasicconceptoftransactionsandSpringscapabilitiesinthe
areaoftransactionmanagement.Transactionmanagementisanessentialtechniqueinenterprise
applicationstoensuredataintegrityandconsistency.Spring,asanenterpriseapplicationframework,
providesanabstractlayerontopofdifferenttransactionmanagementAPIs.Asanapplication
developer,youcanuseSpringstransactionmanagementfacilitieswithouthavingtoknowmuch
abouttheunderlyingtransactionmanagementAPIs.
Likethebeanmanagedtransaction(BMT)andcontainermanagedtransaction(CMT)approachesin
EJB,Springsupportsbothprogrammaticanddeclarativetransactionmanagement.Theaimof
SpringstransactionsupportistoprovideanalternativetoEJBtransactionsbyaddingtransaction
capabilitiestoPOJOs.
Programmatictransactionmanagementisachievedbyembeddingtransactionmanagementcodein
yourbusinessmethodstocontrolthecommitandrollbackoftransactions.Youusuallycommita
transactionifamethodcompletesnormallyandrollbackatransactionifamethodthrowscertain
typesofexceptions.Withprogrammatictransactionmanagement,youcandefineyourownrulesto
commitandrollbacktransactions.
However,whenmanagingtransactionsprogrammatically,youhavetoincludetransaction
managementcodeineachtransactionaloperation.Asaresult,theboilerplatetransactioncodeis
repeatedineachoftheseoperations.Moreover,itshardforyoutoenableanddisabletransaction
managementfordifferentapplications.IfyouhaveasolidunderstandingofAOP,youmayalready
havenoticedthattransactionmanagementisakindofcrosscuttingconcern.
Declarativetransactionmanagementispreferabletoprogrammatictransactionmanagementinmost
cases.Itsachievedbyseparatingtransactionmanagementcodefromyourbusinessmethodsvia
declarations.Transactionmanagement,asakindofcrosscuttingconcern,canbemodularizedwith
theAOPapproach.SpringsupportsdeclarativetransactionmanagementthroughtheSpringAOP
framework.Thiscanhelpyoutoenabletransactionsforyourapplicationsmoreeasilyanddefinea
consistenttransactionpolicy.Declarativetransactionmanagementislessflexiblethanprogrammatic
transactionmanagement.Programmatictransactionmanagementallowsyoutocontroltransactions
throughyourcodeexplicitlystarting,committing,andjoiningthemasyouseefit.Youcanspecifya
setoftransactionattributestodefineyourtransactionsatafinelevelofgranularity.Thetransaction
attributessupportedbySpringincludethepropagationbehavior,isolationlevel,rollbackrules,
transactiontimeout,andwhetherornotthetransactionisreadonly.Theseattributesallowyouto
furthercustomizethebehaviorofyourtransactions.
Uponfinishingthischapter,youwillbeabletoapplydifferenttransactionmanagementstrategiesin
yourapplication.Moreover,youwillbefamiliarwithdifferenttransactionattributestofinelydefine
yourtransactions.
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

1/42

10/05/2016

Chapter10:DataAccess

Programmatictransactionmanagementisagoodideaincertaincaseswhereyoudontfeelthe
additionofSpringproxiesisworththetroubleornegligibleperformanceloss.Here,youmightaccess
thenativetransactionyourselfandcontrolthetransactionmanually.Amoreconvenientoptionthat
avoidstheoverheadofSpringproxiesistheTransactionTemplateclass,whichprovidesatemplate
methodaroundwhichatransactionalboundaryisstartedandthencommitted.
111.ProblemswithTransactionManagement
Transactionmanagementisanessentialtechniqueinenterpriseapplicationdevelopmenttoensure
dataintegrityandconsistency.Withouttransactionmanagement,yourdataandresourcesmaybe
corruptedandleftinaninconsistentstate.Transactionmanagementisparticularlyimportantfor
recoveringfromunexpectederrorsinaconcurrentanddistributedenvironment.
Insimplewords,atransactionisaseriesofactionsthataretreatedasasingleunitofwork.These
actionsshouldeithercompleteentirelyortakenoeffectatall.Ifalltheactionsgowell,thetransaction
shouldbecommittedpermanently.Incontrast,ifanyofthemgoeswrong,thetransactionshouldbe
rolledbacktotheinitialstateasifnothinghadhappened.
Theconceptoftransactionscanbedescribedwithfourkeyproperties:atomicity,consistency,
isolation,anddurability(ACID).
Atomicity:Atransactionisanatomicoperationthatconsistsofaseriesofactions.Theatomicityof
atransactionensuresthattheactionseithercompleteentirelyortakenoeffectatall.
Consistency:Onceallactionsofatransactionhavecompleted,thetransactioniscommitted.Then
yourdataandresourceswillbeinaconsistentstatethatconformstobusinessrules.
Isolation:Becausetheremaybemanytransactionsprocessingwiththesamedatasetatthe
sametime,eachtransactionshouldbeisolatedfromotherstopreventdatacorruption.
Durability:Onceatransactionhascompleted,itsresultshouldbedurabletosurviveanysystem
failure(imagineifthepowertoyourmachinewascutrightinthemiddleofatransactionscommit).
Usually,theresultofatransactioniswrittentopersistentstorage.
Tounderstandtheimportanceoftransactionmanagement,letsbeginwithanexampleabout
purchasingbooksfromanonlinebookshop.First,youhavetocreateanewschemaforthis
applicationinyourdatabase.IfyouarechoosingApacheDerbyasyourdatabaseengine,youcan
connecttoitwiththeJDBCpropertiesshowninTable111.Fortheexamplesinthisbook,were
usingDerby10.10.2.0.
Table111.JDBCPropertiesforConnectingtotheApplicationDatabase
Property

Value

Driverclass

org.apache.derby.jdbc.ClientDriver

URL

jdbc:derby://localhost:1527/bookshopcreate=true

https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

2/42

10/05/2016

Chapter10:DataAccess

Username

App

Password

App

Withtheprecedingconfiguration,thedatabasewillbecreatedforyoubecauseoftheparameteron
theJDBCURL:create=true.Foryourbookshopapplication,youneedaplacetostorethedata.Youll
createasimpledatabasetomanagebooksandaccounts.
Theentityrelational(ER)diagramforthetableslookslikeFigure111.

Figure111.BOOK_STOCKdescribeshowmanygivenBOOKsexist
Now,letscreatetheSQLfortheprecedingmodel.YoullusetheijtoolthatshipswithDerby.Ona
commandline,proceedtothedirectorywhereDerbyisinstalled(usuallyjustwhereyouunzippedit
whenyoudownloadedit.).Descendtothebindirectory.IfDerbysnotalreadystarted,run
startNetworkServer(orstartNetworkServer.batonWindows).Now,youneedtologinandexecute
theSQLDDL.BackgroundtheDerbyServerprocessoropenupasecondshellandreturntothe
samebindirectoryintheDerbyinstallationdirectory.Executeij.Intheshell,executethefollowing:
connect'jdbc:derby://localhost:1527/bookshop;create=true';
PastethefollowingSQLintotheshellandverifyitssuccess:
CREATETABLEBOOK(
ISBNVARCHAR(50)NOTNULL,
BOOK_NAMEVARCHAR(100)NOTNULL,
PRICEINT,
PRIMARYKEY(ISBN)
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

3/42

10/05/2016

Chapter10:DataAccess

);
CREATETABLEBOOK_STOCK(
ISBNVARCHAR(50)NOTNULL,
STOCKINTNOTNULL,
PRIMARYKEY(ISBN),
CHECK(STOCK>=0)
);
CREATETABLEACCOUNT(
USERNAMEVARCHAR(50)NOTNULL,
BALANCEINTNOTNULL,
PRIMARYKEY(USERNAME),
CHECK(BALANCE>=0)
);
Arealworldapplicationofthistypewouldprobablyfeatureapricefieldwithadecimaltype,butusing
anintmakestheprogrammingsimplertofollow,soleaveitasanint.
TheBOOKtablestoresbasicbookinformationsuchasthenameandprice,withthebookISBNas
theprimarykey.TheBOOK_STOCKtablekeepstrackofeachbooksstock.Thestockvalueis
restrictedbyaCHECKconstrainttobeapositivenumber.AlthoughtheCHECKconstrainttypeis
definedinSQL99,notalldatabaseenginessupportit.Atthetimeofthiswriting,thislimitationis
mainlytrueofMySQLbecauseSybase,Derby,HSQL,Oracle,DB2,SQLServer,Access,
PostgreSQL,andFireBirdallsupportit.IfyourdatabaseenginedoesntsupportCHECKconstraints,
pleaseconsultitsdocumentationforsimilarconstraintsupport.Finally,theACCOUNTtablestores
customeraccountsandtheirbalances.Again,thebalanceisrestrictedtobepositive.
TheoperationsofyourbookshoparedefinedinthefollowingBookShopinterface.Fornow,thereis
onlyoneoperation:purchase().
packagecom.apress.springrecipes.bookshop;
publicinterfaceBookShop{
publicvoidpurchase(Stringisbn,Stringusername);
}
BecauseyouwillimplementthisinterfacewithJDBC,youcreatethefollowingJdbcBookShopclass.
Tobetterunderstandthenatureoftransactions,letsimplementthisclasswithoutthehelpofSprings
JDBCsupport.
packagecom.apress.springrecipes.bookshop;
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

4/42

10/05/2016

Chapter10:DataAccess

importjava.sql.Connection;
importjava.sql.PreparedStatement;
importjava.sql.ResultSet;
importjava.sql.SQLException;
importjavax.sql.DataSource;
publicclassJdbcBookShopimplementsBookShop{
privateDataSourcedataSource;
publicvoidsetDataSource(DataSourcedataSource){
this.dataSource=dataSource;
}
publicvoidpurchase(Stringisbn,Stringusername){
Connectionconn=null;
try{
conn=dataSource.getConnection();
PreparedStatementstmt1=conn.prepareStatement(
"SELECTPRICEFROMBOOKWHEREISBN=?");
stmt1.setString(1,isbn);
ResultSetrs=stmt1.executeQuery();
rs.next();
intprice=rs.getInt("PRICE");
stmt1.close();
PreparedStatementstmt2=conn.prepareStatement(
"UPDATEBOOK_STOCKSETSTOCK=STOCK1"+
"WHEREISBN=?");
stmt2.setString(1,isbn);
stmt2.executeUpdate();
stmt2.close();
PreparedStatementstmt3=conn.prepareStatement(
"UPDATEACCOUNTSETBALANCE=BALANCE?"+
"WHEREUSERNAME=?");
stmt3.setInt(1,price);
stmt3.setString(2,username);
stmt3.executeUpdate();
stmt3.close();
}catch(SQLExceptione){
thrownewRuntimeException(e);
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

5/42

10/05/2016

Chapter10:DataAccess

}finally{
if(conn!=null){
try{
conn.close();
}catch(SQLExceptione){}
}
}
}
}
Forthepurchase()operation,youhavetoexecutethreeSQLstatementsintotal.Thefirstistoquery
thebookprice.Thesecondandthirdupdatethebookstockandaccountbalanceaccordingly.
Then,youcandeclareabookshopinstanceintheSpringIoCcontainertoprovidepurchasing
services.Forsimplicityssake,youcanuseDriverManagerDataSource,whichopensanew
connectiontothedatabaseforeveryrequest.

NoteToaccessadatabaserunningontheDerbyserver,youhavetoaddtheDerbyclientlibraryto
yourCLASSPATH.IfyoureusingMaven,addthefollowingdependencytoyourproject.
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derbyclient</artifactId>
<version>10.10.2.0</version>
</dependency>

packagecom.apress.springrecipes.bookshop.config;
importcom.apress.springrecipes.bookshop.BookShop;
importcom.apress.springrecipes.bookshop.JdbcBookShop;
importorg.apache.derby.jdbc.ClientDriver;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.jdbc.datasource.DriverManagerDataSource;
importjavax.sql.DataSource;
@Configuration
publicclassBookstoreConfiguration{
@Bean
publicDataSourcedataSource(){
DriverManagerDataSourcedataSource=newDriverManagerDataSource();
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

6/42

10/05/2016

Chapter10:DataAccess

dataSource.setDriverClassName(ClientDriver.class.getName());
dataSource.setUrl("jdbc:derby://localhost:1527/bookstore;create=true");
dataSource.setUsername("app");
dataSource.setPassword("app");
returndataSource;
}
@Bean
publicBookShopbookShop(){
JdbcBookShopbookShop=newJdbcBookShop();
bookShop.setDataSource(dataSource());
returnbookShop;
}
}
Todemonstratetheproblemsthatcanarisewithouttransactionmanagement,supposeyouhavethe
datashowninTables112,113,and114enteredinyourbookshopdatabase.
Table112.SampleDataintheBOOKTableforTestingTransactions
ISBN

BOOK_NAME

PRICE

0001

TheFirstBook

30

Table113.SampleDataintheBOOK_STOCKTableforTestingTransactions
ISBN

STOCK

0001

10

Table114.SampleDataintheACCOUNTTableforTestingTransactions
USERNAME

BALANCE

user1

20

Then,writethefollowingMainclassforpurchasingthebookwithISBN0001bytheuseruser1.
Becausethatusersaccounthasonly$20,thefundsarenotsufficienttopurchasethebook.
packagecom.apress.springrecipes.bookshop;
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

7/42

10/05/2016

Chapter10:DataAccess

importorg.springframework.context.ApplicationContext;
importorg.springframework.context.support.ClassPathXmlApplicationContext;
publicclassMain{
publicstaticvoidmain(String[]args){
ApplicationContextcontext=
newClassPathXmlApplicationContext("beans.xml");
BookShopbookShop=(BookShop)context.getBean("bookShop");
bookShop.purchase("0001","user1");
}
}
Whenyourunthisapplication,youwillencounteraSQLException,becausetheCHECKconstraintof
theACCOUNTtablehasbeenviolated.Thisisanexpectedresultbecauseyouweretryingtodebit
morethantheaccountbalance.However,ifyoucheckthestockforthisbookintheBOOK_STOCK
table,youwillfindthatitwasaccidentallydeductedbythisunsuccessfuloperation!Thereasonisthat
youexecutedthesecondSQLstatementtodeductthestockbeforeyougotanexceptioninthethird
statement.
Asyoucansee,thelackoftransactionmanagementcausesyourdatatobeleftinaninconsistent
state.Toavoidthisinconsistency,yourthreeSQLstatementsforthepurchase()operationshouldbe
executedwithinasingletransaction.Onceanyoftheactionsinatransactionfail,theentire
transactionshouldberolledbacktoundoallchangesmadebytheexecutedactions.
ManagingTransactionswithJDBCCommitandRollback
WhenusingJDBCtoupdateadatabase,bydefault,eachSQLstatementwillbecommitted
immediatelyafteritsexecution.Thisbehaviorisknownasautocommit.However,itdoesnotallow
youtomanagetransactionsforyouroperations.
JDBCsupportstheprimitivetransactionmanagementstrategyofexplicitlycallingthecommit()and
rollback()methodsonaconnection.Butbeforeyoucandothat,youmustturnoffautocommit,which
isturnedonbydefault.
packagecom.apress.springrecipes.bookshop;
...
publicclassJdbcBookShopimplementsBookShop{
...
publicvoidpurchase(Stringisbn,Stringusername){
Connectionconn=null;
try{
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

8/42

10/05/2016

Chapter10:DataAccess

conn=dataSource.getConnection();
conn.setAutoCommit(false);
...
conn.commit();
}catch(SQLExceptione){
if(conn!=null){
try{
conn.rollback();
}catch(SQLExceptione1){}
}
thrownewRuntimeException(e);
}finally{
if(conn!=null){
try{
conn.close();
}catch(SQLExceptione){}
}
}
}
}
TheautocommitbehaviorofadatabaseconnectioncanbealteredbycallingthesetAutoCommit()
method.Bydefault,autocommitisturnedontocommiteachSQLstatementimmediatelyafterits
execution.Toenabletransactionmanagement,youmustturnoffthisdefaultbehaviorandcommit
theconnectiononlywhenalltheSQLstatementshavebeenexecutedsuccessfully.Ifanyofthe
statementsgowrong,youmustrollbackallchangesmadebythisconnection.
Now,ifyourunyourapplicationagain,thebookstockwillnotbedeductedwhentheusersbalanceis
insufficienttopurchasethebook.
AlthoughyoucanmanagetransactionsbyexplicitlycommittingandrollingbackJDBCconnections,
thecoderequiredforthispurposeisboilerplatecodethatyouhavetorepeatfordifferentmethods.
Moreover,thiscodeisJDBCspecific,soonceyouhavechosenanotherdataaccesstechnology,it
needstobechangedalso.Springstransactionsupportoffersasetoftechnologyindependent
facilities,includingtransactionmanagers(e.g.,
org.springframework.transaction.PlatformTransactionManager),atransactiontemplate(e.g.,
org.springframework.transaction.support.TransactionTemplate),andtransactiondeclarationsupport
tosimplifyyourtransactionmanagementtasks.
112.ChoosingaTransactionManagerImplementation
Problem
Typically,ifyourapplicationinvolvesonlyasingledatasource,youcansimplymanagetransactions
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

9/42

10/05/2016

Chapter10:DataAccess

bycallingthecommit()androllback()methodsonadatabaseconnection.However,ifyour
transactionsextendacrossmultipledatasourcesoryouprefertomakeuseofthetransaction
managementcapabilitiesprovidedbyyourJavaEEapplicationserver,youmaychoosetheJava
TransactionAPI(JTA).Besides,youmayhavetocalldifferentproprietarytransactionAPIsfor
differentobject/relationalmappingframeworkssuchasHibernateandJPA.
Asaresult,youhavetodealwithdifferenttransactionAPIsfordifferenttechnologies.Itwouldbe
hardforyoutoswitchfromonesetofAPIstoanother.
Solution
SpringabstractsageneralsetoftransactionfacilitiesfromdifferenttransactionmanagementAPIs.As
anapplicationdeveloper,youcansimplyutilizeSpringstransactionfacilitieswithouthavingtoknow
muchabouttheunderlyingtransactionAPIs.Withthesefacilities,yourtransactionmanagementcode
willbeindependentofanyspecifictransactiontechnology.
Springscoretransactionmanagementabstractionisbasedontheinterface
PlatformTransactionManager.Itencapsulatesasetoftechnologyindependentmethodsfor
transactionmanagement.Rememberthatatransactionmanagerisneedednomatterwhich
transactionmanagementstrategy(programmaticordeclarative)youchooseinSpring.The
PlatformTransactionManagerinterfaceprovidesthreemethodsforworkingwithtransactions:
TransactionStatusgetTransaction(TransactionDefinitiondefinition)throwsTransactionException
voidcommit(TransactionStatusstatus)throwsTransactionException
voidrollback(TransactionStatusstatus)throwsTransactionException
HowItWorks
PlatformTransactionManagerisageneralinterfaceforallSpringtransactionmanagers.Springhas
severalbuiltinimplementationsofthisinterfaceforusewithdifferenttransactionmanagementAPIs:
IfyouhavetodealwithonlyasingledatasourceinyourapplicationandaccessitwithJDBC,
DataSourceTransactionManagershouldmeetyourneeds.
IfyouareusingJTAfortransactionmanagementonaJavaEEapplicationserver,youshoulduse
JtaTransactionManagertolookupatransactionfromtheapplicationserver.Additionally,
JtaTransactionManagerisappropriatefordistributedtransactions(transactionsthatspanmultiple
resources).NotethatwhileitscommontouseaJTAtransactionmanagertointegratethe
applicationserverstransactionmanager,theresnothingstoppingyoufromusingastandalone
JTAtransactionmanagersuchasAtomikos.
Ifyouareusinganobject/relationalmappingframeworktoaccessadatabase,youshouldchoose
acorrespondingtransactionmanagerforthisframework,suchasHibernateTransactionManager
andJpaTransactionManager.
Figure112showsthecommonimplementationsofthePlatformTransactionManagerinterfacein
Spring.
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

10/42

10/05/2016

Chapter10:DataAccess

Figure112.CommonimplementationsofthePlatformTransactionManagerinterface
AtransactionmanagerisdeclaredintheSpringIoCcontainerasanormalbean.Forexample,the
followingbeanconfigurationdeclaresaDataSourceTransactionManagerinstance.Itrequiresthe
dataSourcepropertytobesetsothatitcanmanagetransactionsforconnectionsmadebythisdata
source.
@Bean
publicPlatformTransactionManagertransactionManager(){
DataSourceTransactionManagertransactionManager=new
DataSourceTransactionManager()
transactionManager.setDataSource(dataSource());
returntransactionManager;
}
113.ManagingTransactionsProgrammaticallywiththeTransactionManagerAPI
Problem
Youneedtopreciselycontrolwhentocommitandrollbacktransactionsinyourbusinessmethods,
butyoudontwanttodealwiththeunderlyingtransactionAPIdirectly.
Solution
SpringstransactionmanagerprovidesatechnologyindependentAPIthatallowsyoutostartanew
transaction(orobtainthecurrentlyactivetransaction)bycallingthegetTransaction()methodand
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

11/42

10/05/2016

Chapter10:DataAccess

manageitbycallingthecommit()androllback()methods.BecausePlatformTransactionManageris
anabstractunitfortransactionmanagement,themethodsyoucalledfortransactionmanagement
areguaranteedtobetechnologyindependent.
HowItWorks
TodemonstratehowtousethetransactionmanagerAPI,letscreateanewclass,
TransactionalJdbcBookShop,whichwillmakeuseoftheSpringJDBCtemplate.Becauseithasto
dealwithatransactionmanager,youaddapropertyoftypePlatformTransactionManagerandallowit
tobeinjectedviaasettermethod.
packagecom.apress.springrecipes.bookshop;
importorg.springframework.dao.DataAccessException;
importorg.springframework.jdbc.core.support.JdbcDaoSupport;
importorg.springframework.transaction.PlatformTransactionManager;
importorg.springframework.transaction.TransactionDefinition;
importorg.springframework.transaction.TransactionStatus;
importorg.springframework.transaction.support.DefaultTransactionDefinition;
publicclassTransactionalJdbcBookShopextendsJdbcDaoSupportimplements
BookShop{
privatePlatformTransactionManagertransactionManager;
publicvoidsetTransactionManager(
PlatformTransactionManagertransactionManager){
this.transactionManager=transactionManager;
}
publicvoidpurchase(Stringisbn,Stringusername){
TransactionDefinitiondef=newDefaultTransactionDefinition();
TransactionStatusstatus=transactionManager.getTransaction(def);
try{
intprice=getJdbcTemplate().queryForInt(
"SELECTPRICEFROMBOOKWHEREISBN=?",
newObject[]{isbn});
getJdbcTemplate().update(
"UPDATEBOOK_STOCKSETSTOCK=STOCK1"+
"WHEREISBN=?",newObject[]{isbn});
getJdbcTemplate().update(
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

12/42

10/05/2016

Chapter10:DataAccess

"UPDATEACCOUNTSETBALANCE=BALANCE?"+
"WHEREUSERNAME=?",
newObject[]{price,username});
transactionManager.commit(status);
}catch(DataAccessExceptione){
transactionManager.rollback(status);
throwe;
}
}
}
Beforeyoustartanewtransaction,youhavetospecifythetransactionattributesinatransaction
definitionobjectoftypeTransactionDefinition.Forthisexample,youcansimplycreateaninstanceof
DefaultTransactionDefinitiontousethedefaulttransactionattributes.
Onceyouhaveatransactiondefinition,youcanaskthetransactionmanagertostartanew
transactionwiththatdefinitionbycallingthegetTransaction()method.Then,itwillreturna
TransactionStatusobjecttokeeptrackofthetransactionstatus.Ifallthestatementsexecute
successfully,youaskthetransactionmanagertocommitthistransactionbypassinginthe
transactionstatus.BecauseallexceptionsthrownbytheSpringJDBCtemplatearesubclassesof
DataAccessException,youaskthetransactionmanagertorollbackthetransactionwhenthiskindof
exceptioniscaught.
Inthisclass,youhavedeclaredthetransactionmanagerpropertyofthegeneraltype
PlatformTransactionManager.Now,youhavetoinjectanappropriatetransactionmanager
implementation.BecauseyouaredealingwithonlyasingledatasourceandaccessingitwithJDBC,
youshouldchooseDataSourceTransactionManager.Here,youalsowireadataSourcebecausethe
classisasubclassofSpringsJdbcDaoSupport,whichrequiresit.

@Configuration
publicclassBookstoreConfiguration{
...
@Bean
publicPlatformTransactionManagertransactionManager(){
DataSourceTransactionManagertransactionManager=new
DataSourceTransactionManager();
transactionManager.setDataSource(dataSource());
returntransactionManager;
}
@Bean
publicBookShopbookShop(){
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

13/42

10/05/2016

Chapter10:DataAccess

TransactionalJdbcBookShopbookShop=newTransactionalJdbcBookShop();
bookShop.setDataSource(dataSource());
bookShop.setTransactionManager(transactionManager());
returnbookShop;
}
}
114.ManagingTransactionsProgrammaticallywithaTransactionTemplate
Problem
Supposethatyouhaveacodeblock,butnottheentirebody,ofabusinessmethodthathasthe
followingtransactionrequirements:
Startanewtransactionatthebeginningoftheblock.
Committhetransactionaftertheblockcompletessuccessfully.
Rollbackthetransactionifanexceptionisthrownintheblock.
IfyoucallSpringstransactionmanagerAPIdirectly,thetransactionmanagementcodecanbe
generalizedinatechnologyindependentmanner.However,youmaynotwanttorepeatthe
boilerplatecodeforeachsimilarcodeblock.
Solution
AswiththeJDBCtemplate,SpringalsoprovidesaTransactionTemplatetohelpyoucontrolthe
overalltransactionmanagementprocessandtransactionexceptionhandling.Youjusthaveto
encapsulateyourcodeblockinacallbackclassthatimplementstheTransactionCallback<T>
interfaceandpassittotheTransactionTemplatesexecutemethodforexecution.Inthisway,you
dontneedtorepeattheboilerplatetransactionmanagementcodeforthisblock.Thetemplate
objectsthatSpringprovidesarelightweightandusuallycanbediscardedorrecreatedwithno
performanceimpact.AJDBCtemplatecanberecreatedontheflywithaDataSourcereference,for
example,andsotoocanaTransactionTemplateberecreatedbyprovidingareferencetoa
transactionmanager.Youcan,ofcourse,simplycreateoneinyourSpringapplicationcontext,too.
HowItWorks
ATransactionTemplateiscreatedonatransactionmanagerjustasaJDBCtemplateiscreatedona
datasource.Atransactiontemplateexecutesatransactioncallbackobjectthatencapsulatesa
transactionalcodeblock.Youcanimplementthecallbackinterfaceeitherasaseparateclassoras
aninnerclass.Ifitsimplementedasaninnerclass,youhavetomakethemethodargumentsfinal
forittoaccess.
packagecom.apress.springrecipes.bookshop.spring;
...
importorg.springframework.transaction.PlatformTransactionManager;
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

14/42

10/05/2016

Chapter10:DataAccess

importorg.springframework.transaction.TransactionStatus;
importorg.springframework.transaction.support.TransactionCallbackWithoutResult;
importorg.springframework.transaction.support.TransactionTemplate;
publicclassTransactionalJdbcBookShopextendsJdbcDaoSupportimplements
BookShop{
privatePlatformTransactionManagertransactionManager;
publicvoidsetTransactionManager(
PlatformTransactionManagertransactionManager){
this.transactionManager=transactionManager;
}
publicvoidpurchase(finalStringisbn,finalStringusername){
TransactionTemplatetransactionTemplate=
newTransactionTemplate(transactionManager);
transactionTemplate.execute(newTransactionCallbackWithoutResult(){
protectedvoiddoInTransactionWithoutResult(
TransactionStatusstatus){
intprice=getJdbcTemplate().queryForObject(
"SELECTPRICEFROMBOOKWHEREISBN=?",
newObject[]{isbn},Integer.class);
getJdbcTemplate().update(
"UPDATEBOOK_STOCKSETSTOCK=STOCK1"+
"WHEREISBN=?",newObject[]{isbn});
getJdbcTemplate().update(
"UPDATEACCOUNTSETBALANCE=BALANCE?"+
"WHEREUSERNAME=?",
newObject[]{price,username});
}
});
}
}
ATransactionTemplatecanacceptatransactioncallbackobjectthatimplementseitherthe
TransactionCallback<T>oraninstanceoftheoneimplementerofthatinterfaceprovidedbythe
framework,theTransactionCallbackWithoutResultclass.Forthecodeblockinthepurchase()
methodfordeductingthebookstockandaccountbalance,theresnoresulttobereturned,so
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

15/42

10/05/2016

Chapter10:DataAccess

TransactionCallbackWithoutResultisfine.Foranycodeblockswithreturnvalues,youshould
implementtheTransactionCallback<T>interfaceinstead.Thereturnvalueofthecallbackobjectwill
finallybereturnedbythetemplatesTexecute()method.Themainbenefitisthattheresponsibilityof
starting,rollingback,orcommittingthetransactionhasbeenremoved.
Duringtheexecutionofthecallbackobject,ifitthrowsanuncheckedexception(e.g.,
RuntimeExceptionandDataAccessExceptionfallintothiscategory),orifyouexplicitlycalled
setRollbackOnly()ontheTransactionStatusargumentinthedoInTransactionWithoutResultmethod,
thetransactionwillberolledback.Otherwise,itwillbecommittedafterthecallbackobjectcompletes.
Inthebeanconfigurationfile,thebookshopbeanstillrequiresatransactionmanagertocreatea
TransactionTemplate.
@Configuration
publicclassBookstoreConfiguration{
...
@Bean
publicPlatformTransactionManagertransactionManager(){
DataSourceTransactionManagertransactionManager=new
DataSourceTransactionManager();
transactionManager.setDataSource(dataSource());
returntransactionManager;
}
@Bean
publicBookShopbookShop(){
TransactionalJdbcBookShopbookShop=newTransactionalJdbcBookShop();
bookShop.setDataSource(dataSource());
bookShop.setTransactionManager(transactionManager());
returnbookShop;
}
}
YoucanalsohavetheIoCcontainerinjectatransactiontemplateinsteadofcreatingitdirectly.
Becauseatransactiontemplatehandlesalltransactions,theresnoneedforyourclasstorefertothe
transactionmanageranymore.
packagecom.apress.springrecipes.bookshop;
...
importorg.springframework.transaction.support.TransactionTemplate;
publicclassTransactionalJdbcBookShopextendsJdbcDaoSupportimplements
BookShop{

https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

16/42

10/05/2016

Chapter10:DataAccess

privateTransactionTemplatetransactionTemplate;
publicvoidsetTransactionTemplate(
TransactionTemplatetransactionTemplate){
this.transactionTemplate=transactionTemplate;
}
publicvoidpurchase(finalStringisbn,finalStringusername){
transactionTemplate.execute(newTransactionCallbackWithoutResult(){
protectedvoiddoInTransactionWithoutResult(TransactionStatusstatus)
{
...
}
});
}
}
Thenyoudefineatransactiontemplateinthebeanconfigurationfileandinjectit,insteadofthe
transactionmanager,intoyourbookshopbean.Noticethatthetransactiontemplateinstancecanbe
usedformorethanonetransactionalbeanbecauseitisathreadsafeobject.Finally,dontforgetto
setthetransactionmanagerpropertyforyourtransactiontemplate.
packagecom.apress.springrecipes.bookshop.config;
...
importorg.springframework.transaction.support.TransactionTemplate;
@Configuration
publicclassBookstoreConfiguration{
...
@Bean
publicPlatformTransactionManagertransactionManager(){...}
@Bean
publicTransactionTemplatetransactionTemplate(){
TransactionTemplatetransactionTemplate=newTransactionTemplate();
transactionTemplate.setTransactionManager(transactionManager());
returntransactionTemplate;
}
@Bean
publicBookShopbookShop(){
TransactionalJdbcBookShopbookShop=newTransactionalJdbcBookShop();
bookShop.setDataSource(dataSource());
bookShop.setTransactionTemplate(transactionTemplate());
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

17/42

10/05/2016

Chapter10:DataAccess

returnbookShop;
}
}
115.ManagingTransactionsDeclarativelywithTransactionAdvices
Problem
Becausetransactionmanagementisakindofcrosscuttingconcern,youshouldmanagetransactions
declarativelywiththeAOPapproachavailablefromSpring2.xonward.Managingtransactions
manuallycanbetediousanderrorprone.Itissimplertospecify,declaratively,whatbehavioryouare
expectingandtonotprescribehowthatbehavioristobeachieved.
Solution
Spring(sinceversion2.0)offersatransactionadvicethatcanbeeasilyconfiguredviathe<tx:advice>
elementdefinedinthetxschema.ThisadvicecanbeenabledwiththeAOPconfigurationfacilities
definedintheaopschema.
HowItWorks
Toenabledeclarativetransactionmanagement,youcandeclareatransactionadviceviathe
<tx:advice>elementdefinedinthetxschema,soyouhavetoaddthisschemadefinitiontothe
<beans>rootelementbeforehand.Onceyouhavedeclaredthisadvice,youneedtoassociateitwith
apointcut.Becauseatransactionadviceisdeclaredoutsidethe<aop:config>element,itcannotlink
withapointcutdirectly.Youhavetodeclareanadvisorinthe<aop:config>elementtoassociatean
advicewithapointcut.

NoteBecauseSpringAOPusestheAspectJpointcutexpressionstodefinepointcuts,youhaveto
includetheAspectJWeaversupportonyourCLASSPATH.IfyoureusingMaven,addthefollowing
dependencytoyourproject.
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.0</version>
</dependency>

<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchemainstance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

18/42

10/05/2016

Chapter10:DataAccess

http://www.springframework.org/schema/beans/springbeans3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/springtx3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/springaop3.0.xsd">
<tx:adviceid="bookShopTxAdvice"
transactionmanager="transactionManager">
<tx:attributes>
<tx:methodname="purchase"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcutid="bookShopOperation"expression=
"execution(*com.apress.springrecipes.bookshop.BookShop.*(..))"/>
<aop:advisoradviceref="bookShopTxAdvice"
pointcutref="bookShopOperation"/>
</aop:config>
...
<beanid="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<propertyname="dataSource"ref="dataSource"/>
</bean>
<beanid="bookShop"
class="com.apress.springrecipes.bookshop.TransactionalJdbcBookShop">
<propertyname="dataSource"ref="dataSource"/>
</bean>
</beans>
TheprecedingAspectJpointcutexpressionmatchesallthemethodsdeclaredintheBookShop
interface.However,becauseSpringAOPisbasedonproxies,itcanapplyonlytopublicmethods.
ThusonlypublicmethodscanbemadetransactionalwithSpringAOP.
EachtransactionadvicerequiresanidentifierandareferencetoatransactionmanagerintheIoC
container.Ifyoudontspecifyatransactionmanagerexplicitly,Springwillsearchtheapplication
contextforaTransactionManagerwithabeannameoftransactionManager.Themethodsthat
requiretransactionmanagementarespecifiedwithmultiple<tx:method>elementsinsidethe
<tx:attributes>element.Themethodnamesupportswildcardsforyoutomatchagroupofmethods.
Youcanalsodefinetransactionattributesforeachgroupofmethods,butletsusethedefault
attributesforsimplicityssake.ThedefaultsareshowninTable115.
Now,youcanretrievethebookShopbeanfromtheSpringIoCcontainertouse.Becausethisbeans
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

19/42

10/05/2016

Chapter10:DataAccess

methodsarematchedbythepointcut,Springwillreturnaproxythathastransactionmanagement
enabledforthisbean.
packagecom.apress.springrecipes.bookshop;
...
publicclassMain{
publicstaticvoidmain(String[]args){
ApplicationContextcontext=new
ClassPathXmlApplicationContext("bookstorecontext.xml");
BookShopbookShop=context.getBean(BookShop.class);
bookShop.purchase("0001","user1");}
}
116.ManagingTransactionsDeclarativelywiththe@TransactionalAnnotation
Problem
DeclaringtransactionsinthebeanconfigurationfilerequiresknowledgeofAOPconceptssuchas
pointcuts,advices,andadvisors.Developerswholackthisknowledgemightfindithardtoenable
declarativetransactionmanagement.
Solution
Inadditiontodeclaringtransactionsinthebeanconfigurationfilewithpointcuts,advices,and
advisors,Springallowsyoutodeclaretransactionssimplybyannotatingyourtransactionalmethods
with@Transactionalandenablingthe<tx:annotationdriven>element.However,Java1.5orhigheris
requiredtousethisapproach.Notethatalthoughyoucouldapplytheannotationtoaninterface
method,itsnotarecommendedpractice.
HowItWorks
Todefineamethodastransactional,youcansimplyannotateitwith@Transactional.Notethatyou
shouldonlyannotatepublicmethodsduetotheproxybasedlimitationsofSpringAOP.
packagecom.apress.springrecipes.bookshop.spring;
...
importorg.springframework.transaction.annotation.Transactional;
importorg.springframework.jdbc.core.support.JdbcDaoSupport;
publicclassJdbcBookShopextendsJdbcDaoSupportimplementsBookShop{
@Transactional
publicvoidpurchase(Stringisbn,Stringusername){
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

20/42

10/05/2016

Chapter10:DataAccess

intprice=getJdbcTemplate().queryForInt(
"SELECTPRICEFROMBOOKWHEREISBN=?",
newObject[]{isbn});
getJdbcTemplate().update(
"UPDATEBOOK_STOCKSETSTOCK=STOCK1"+
"WHEREISBN=?",newObject[]{isbn});
getJdbcTemplate().update(
"UPDATEACCOUNTSETBALANCE=BALANCE?"+
"WHEREUSERNAME=?",
newObject[]{price,username});
}
}
Notethat,asweareextendingJdbcDaoSupport,wenolongerneedthemutatorsforthe
DataSourceremoveitfromyourDAOclass.
Youmayapplythe@Transactionalannotationatthemethodlevelortheclasslevel.Whenapplying
thisannotationtoaclass,allofthepublicmethodswithinthisclasswillbedefinedastransactional.
Althoughyoucanapply@Transactionaltointerfacesormethoddeclarationsinaninterface,itsnot
recommendedbecauseitmaynotworkproperlywithclassbasedproxies(i.e.,CGLIBproxies).
Inthebeanconfigurationfile,youonlyhavetoenablethe<tx:annotationdriven>elementandspecify
atransactionmanagerforit.Thatsallyouneedtomakeitwork.Springwilladvisemethodswith
@Transactional,ormethodsinaclasswith@Transactional,frombeansdeclaredintheIoC
container.Asaresult,Springcanmanagetransactionsforthesemethods.
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchemainstance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/springbeans3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/springtx3.0.xsd">
<tx:annotationdriventransactionmanager="transactionManager"/>
...
<beanid="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<propertyname="dataSource"ref="dataSource"/>
</bean>

https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

21/42

10/05/2016

Chapter10:DataAccess

<beanid="bookShop"
class="com.apress.springrecipes.bookshop.spring.JdbcBookShop">
<propertyname="dataSource"ref="dataSource"/>
</bean>
</beans>
Infact,youcanomitthetransactionmanagerattributeinthe<tx:annotationdriven>elementifyour
transactionmanagerhasthenametransactionManager.Thiselementwillautomaticallydetecta
transactionmanagerwiththisname.Youhavetospecifyatransactionmanageronlywhenithasa
differentname.
<beans...>
<tx:annotationdriven/>
...
</beans>
Enable@TransactionalwithJavabasedConfiguration
WhenusingJavabasedconfigurationtransactionmanagementcanbeenabledbyusingthe
@EnableTransactionManagementannotation.Thisannotationistheequivalentofthe<tx:annotation
driven/>inXMLbasedconfiguration.
@Configuration
@EnableTransactionManagement
publicclassBookstoreConfiguration{...}
Whenusingthe@EnableTransactionManagementannotationitisntpossibletospecifywhich
transactionmanagertouse.WhenthereisonlyonePlatformTransactionManagerinyour
configurationthiswillbeautomaticallydetectedandusedformanagingtransactions.
ForthesituationswheretherearemultiplePlatformTransactionManagersinyourconfiguration,you
havetospecifyonthe@Transactionalannotationwhichofthetransactionmanagerstousefor
controllingthetransaction.Forthisyoucanusethevalueattributeofthe@Transactionalannotation.
@Transaction("transactionmanager1")
publicvoidtransactionalMethod(){...}
@Transaction("transactionmanager2")
publicvoidotherTransactionalMethod(){...}
117.SettingthePropagationTransactionAttribute
Problem
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

22/42

10/05/2016

Chapter10:DataAccess

Whenatransactionalmethodiscalledbyanothermethod,itisnecessarytospecifyhowthe
transactionshouldbepropagated.Forexample,themethodmaycontinuetorunwithintheexisting
transaction,oritmaystartanewtransactionandrunwithinitsowntransaction.
Solution
Atransactionspropagationbehaviorcanbespecifiedbythepropagationtransactionattribute.Spring
definessevenpropagationbehaviors,asshowninTable116.Thesebehaviorsaredefinedinthe
org.springframework.transaction.TransactionDefinitioninterface.Notethatnotalltypesoftransaction
managerssupportallofthesepropagationbehaviors.Theirbehavioriscontingentontheunderlying
resource.Databases,forexample,maysupportvaryingisolationlevels,whichconstrainswhat
propagationbehaviorsthetransactionmanagercansupport.
Table116.PropagationBehaviorsSupportedbySpring
Propagation

REQUIRED

Description

Iftheresanexistingtransactioninprogress,thecurrentmethodshouldrun
withinthistransaction.Otherwise,itshouldstartanewtransactionandrun
withinitsowntransaction.

REQUIRES_NEW

Thecurrentmethodmuststartanewtransactionandrunwithinitsown
transaction.Iftheresanexistingtransactioninprogress,itshouldbe
suspended.

SUPPORTS

Iftheresanexistingtransactioninprogress,thecurrentmethodcanrun
withinthistransaction.Otherwise,itisnotnecessarytorunwithina
transaction.

NOT_SUPPORTED

Thecurrentmethodshouldnotrunwithinatransaction.Iftheresanexisting
transactioninprogress,itshouldbesuspended.

MANDATORY

Thecurrentmethodmustrunwithinatransaction.Iftheresnoexisting
transactioninprogress,anexceptionwillbethrown.

NEVER

Thecurrentmethodshouldnotrunwithinatransaction.Iftheresanexisting
transactioninprogress,anexceptionwillbethrown.

NESTED

Iftheresanexistingtransactioninprogress,thecurrentmethodshouldrun
withinthenestedtransaction(supportedbytheJDBC3.0savepointfeature)
ofthistransaction.Otherwise,itshouldstartanewtransactionandrunwithin

https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

23/42

10/05/2016

Chapter10:DataAccess

itsowntransaction.ThisfeatureisuniquetoSpring(whereastheprevious
propagationbehaviorshaveanalogsinJavaEEtransactionpropagation).
Thebehaviorisusefulforsituationssuchasbatchprocessing,inwhich
youvegotalongrunningprocess(imagineprocessing1millionrecords)and
youwanttochunkthecommitsonthebatch.Soyoucommitevery10,000
records.Ifsomethinggoeswrong,yourollbackthenestedtransactionand
youvelostonly10,000recordsworthofwork(asopposedtotheentire1
million).

HowItWorks
Transactionpropagationhappenswhenatransactionalmethodiscalledbyanothermethod.For
example,supposeacustomerwouldliketocheckoutallbookstopurchaseatthebookshopcashier.
Tosupportthisoperation,youdefinetheCashierinterfaceasfollows:
packagecom.apress.springrecipes.bookshop;
...
publicinterfaceCashier{
publicvoidcheckout(List<String>isbns,Stringusername);
}
Youcanimplementthisinterfacebydelegatingthepurchasestoabookshopbeanbycallingits
purchase()methodmultipletimes.Notethatthecheckout()methodismadetransactionalbyapplying
the@Transactionalannotation.
packagecom.apress.springrecipes.bookshop;
...
importorg.springframework.transaction.annotation.Transactional;
publicclassBookShopCashierimplementsCashier{
privateBookShopbookShop;
publicvoidsetBookShop(BookShopbookShop){
this.bookShop=bookShop;
}
@Transactional
publicvoidcheckout(List<String>isbns,Stringusername){
for(Stringisbn:isbns){
bookShop.purchase(isbn,username);
}
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

24/42

10/05/2016

Chapter10:DataAccess

}
}
Thendefineacashierbeaninyourbeanconfigurationfileandrefertothebookshopbeanfor
purchasingbooks.
@Configuration
@EnableTransactionManagement()
publicclassBookstoreConfiguration{
...
@Bean
publicCashiercashier(){
BookShopCashiercashier=newBookShopCashier();
cashier.setBookShop(bookShop());
returncashier;
}
}
Toillustratethepropagationbehaviorofatransaction,enterthedatashowninTables117,118,and
119inyourbookshopdatabase.
Table117.SampleDataintheBOOKTableforTestingPropagationBehaviors
ISBN

BOOK_NAME

PRICE

0001

TheFirstBook

30

0002

TheSecondBook

50

Table118.SampleDataintheBOOK_STOCKTableforTestingPropagationBehaviors
ISBN

STOCK

0001

10

0002

10

Table119.SampleDataintheACCOUNTTableforTestingPropagationBehaviors

https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

25/42

10/05/2016

Chapter10:DataAccess

USERNAME

BALANCE

user1

40

TheREQUIREDPropagationBehavior
Whentheuseruser1checksoutthetwobooksfromthecashier,thebalanceissufficienttopurchase
thefirstbookbutnotthesecond.
packagecom.apress.springrecipes.bookshop.spring;
...
publicclassMain{
publicstaticvoidmain(String[]args){
...
Cashiercashier=context.getBean(Cashier.class);
List<String>isbnList=Arrays.asList(newString[]{"0001","0002"});
cashier.checkout(isbnList,"user1");
}
}
Whenthebookshopspurchase()methodiscalledbyanothertransactionalmethod,suchas
checkout(),itwillrunwithintheexistingtransactionbydefault.Thisdefaultpropagationbehavioris
calledREQUIRED.Thatmeanstherewillbeonlyonetransactionwhoseboundaryisthebeginning
andendingofthecheckout()method.Thistransactionwillbecommittedonlyattheendofthe
checkout()method.Asaresult,theusercanpurchasenoneofthebooks.Figure113illustratesthe
REQUIREDpropagationbehavior.

Figure113.TheREQUIREDtransactionpropagationbehavior
However,ifthepurchase()methodiscalledbyanontransactionalmethodandtheresnoexisting
transactioninprogress,itwillstartanewtransactionandrunwithinitsowntransaction.
Thepropagationtransactionattributecanbedefinedinthe@Transactionalannotation.Forexample,
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

26/42

10/05/2016

Chapter10:DataAccess

youcansettheREQUIREDbehaviorforthisattributeasfollows.Infact,thisisunnecessary,because
itsthedefaultbehavior.
packagecom.apress.springrecipes.bookshop.spring;
...
importorg.springframework.transaction.annotation.Propagation;
importorg.springframework.transaction.annotation.Transactional;
publicclassJdbcBookShopextendsJdbcDaoSupportimplementsBookShop{
@Transactional(propagation=Propagation.REQUIRED)
publicvoidpurchase(Stringisbn,Stringusername){
...
}
}
packagecom.apress.springrecipes.bookshop.spring;
...
importorg.springframework.transaction.annotation.Propagation;
importorg.springframework.transaction.annotation.Transactional;
publicclassBookShopCashierimplementsCashier{
...
@Transactional(propagation=Propagation.REQUIRED)
publicvoidcheckout(List<String>isbns,Stringusername){
...
}
}
TheREQUIRES_NEWPropagationBehavior
AnothercommonpropagationbehaviorisREQUIRES_NEW.Itindicatesthatthemethodmuststarta
newtransactionandrunwithinitsnewtransaction.Iftheresanexistingtransactioninprogress,it
shouldbesuspendedfirst(as,forexample,withthecheckoutmethodonBookShopCashier,witha
propagationofREQUIRED).
packagecom.apress.springrecipes.bookshop.spring;
...
importorg.springframework.transaction.annotation.Propagation;
importorg.springframework.transaction.annotation.Transactional;
publicclassJdbcBookShopextendsJdbcDaoSupportimplementsBookShop{
@Transactional(propagation=Propagation.REQUIRES_NEW)
publicvoidpurchase(Stringisbn,Stringusername){
...
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

27/42

10/05/2016

Chapter10:DataAccess

}
}
Inthiscase,therewillbethreetransactionsstartedintotal.Thefirsttransactionisstartedbythe
checkout()method,butwhenthefirstpurchase()methodiscalled,thefirsttransactionwillbe
suspendedandanewtransactionwillbestarted.Attheendofthefirstpurchase()method,thenew
transactioncompletesandcommits.Whenthesecondpurchase()methodiscalled,anothernew
transactionwillbestarted.However,thistransactionwillfailandrollback.Asaresult,thefirstbook
willbepurchasedsuccessfully,whilethesecondwillnot.Figure114illustratestheREQUIRES_NEW
propagationbehavior.

Figure114.TheREQUIRES_NEWtransactionpropagationbehavior
SettingthePropagationAttributeinTransactionAdvicesandAPIs
InaSpringtransactionadvice,thepropagationtransactionattributecanbespecifiedinthe
<tx:method>elementasfollows:
<tx:advice...>
<tx:attributes>
<tx:methodname="..."
propagation="REQUIRES_NEW"/>
</tx:attributes>
</tx:advice>
InSpringstransactionmanagementAPI,thepropagationtransactionattributecanbespecifiedina
DefaultTransactionDefinitionobjectandthenpassedtoatransactionmanagersgetTransaction()
methodoratransactiontemplatesconstructor.
DefaultTransactionDefinitiondef=newDefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
118.SettingtheIsolationTransactionAttribute
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

28/42

10/05/2016

Chapter10:DataAccess

Problem
Whenmultipletransactionsofthesameapplicationordifferentapplicationsareoperating
concurrentlyonthesamedataset,manyunexpectedproblemsmayarise.Youmustspecifyhowyou
expectyourtransactionstobeisolatedfromoneanother.
Solution
Theproblemscausedbyconcurrenttransactionscanbecategorizedintofourtypes:
Dirtyread:FortwotransactionsT1andT2,T1readsafieldthathasbeenupdatedbyT2butnot
yetcommitted.Later,ifT2rollsback,thefieldreadbyT1willbetemporaryandinvalid.
Nonrepeatableread:FortwotransactionsT1andT2,T1readsafieldandthenT2updatesthe
field.Later,ifT1readsthesamefieldagain,thevaluewillbedifferent.
Phantomread:FortwotransactionsT1andT2,T1readssomerowsfromatableandthenT2
insertsnewrowsintothetable.Later,ifT1readsthesametableagain,therewillbeadditional
rows.
Lostupdates:FortwotransactionsT1andT2,theybothselectarowforupdate,andbasedon
thestateofthatrow,makeanupdatetoit.Thus,oneoverwritestheotherwhenthesecond
transactiontocommitshouldhavewaiteduntilthefirstonecommittedbeforeperformingits
selection.
Intheory,transactionsshouldbecompletelyisolatedfromeachother(i.e.,serializable)toavoidall
thementionedproblems.However,thisisolationlevelwillhavegreatimpactonperformance,
becausetransactionshavetoruninserialorder.Inpractice,transactionscanruninlowerisolation
levelsinordertoimproveperformance.
Atransactionsisolationlevelcanbespecifiedbytheisolationtransactionattribute.Springsupports
fiveisolationlevels,asshowninTable1110.Theselevelsaredefinedinthe
org.springframework.transaction.TransactionDefinitioninterface.
Table1110.IsolationLevelsSupportedbySpring
Isolation

DEFAULT

Description

Usesthedefaultisolationleveloftheunderlyingdatabase.Formost
databases,thedefaultisolationlevelisREAD_COMMITTED.

READ_UNCOMMITTED

Allowsatransactiontoreaduncommittedchangesbyothertransactions.
Thedirtyread,nonrepeatableread,andphantomreadproblemsmay
occur.

READ_COMMITTED

Allowsatransactiontoreadonlythosechangesthathavebeen

https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

29/42

10/05/2016

Chapter10:DataAccess

committedbyothertransactions.Thedirtyreadproblemcanbe
avoided,butthenonrepeatablereadandphantomreadproblemsmay
stilloccur.

REPEATABLE_READ

Ensuresthatatransactioncanreadidenticalvaluesfromafieldmultiple
times.Forthedurationofthistransaction,updatesmadebyother
transactionstothisfieldareprohibited.Thedirtyreadand
nonrepeatablereadproblemscanbeavoided,butthephantomread
problemmaystilloccur.

SERIALIZABLE

Ensuresthatatransactioncanreadidenticalrowsfromatablemultiple
times.Forthedurationofthistransaction,inserts,updates,anddeletes
madebyothertransactionstothistableareprohibited.Allthe
concurrencyproblemscanbeavoided,buttheperformancewillbelow.

Notethattransactionisolationissupportedbytheunderlyingdatabaseenginebutnotanapplication
oraframework.However,notalldatabaseenginessupportalltheseisolationlevels.Youcanchange
theisolationlevelofaJDBCconnectionbycallingthesetTransactionIsolation()methodonthe
java.sql.Connectionijava.sql.Connectioninterface.
HowItWorks
Toillustratetheproblemscausedbyconcurrenttransactions,letsaddtwonewoperationstoyour
bookshopforincreasingandcheckingthebookstock.
packagecom.apress.springrecipes.bookshop;
publicinterfaceBookShop{
...
publicvoidincreaseStock(Stringisbn,intstock);
publicintcheckStock(Stringisbn);
}
Then,youimplementtheseoperationsasfollows.Notethatthesetwooperationsshouldalsobe
declaredastransactional.
packagecom.apress.springrecipes.bookshop;
...
importorg.springframework.transaction.annotation.Transactional;
publicclassJdbcBookShopextendsJdbcDaoSupportimplementsBookShop{
...
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

30/42

10/05/2016

Chapter10:DataAccess

@Transactional
publicvoidincreaseStock(Stringisbn,intstock){
StringthreadName=Thread.currentThread().getName();
System.out.println(threadName+"Preparetoincreasebookstock");
getJdbcTemplate().update(
"UPDATEBOOK_STOCKSETSTOCK=STOCK+?"+
"WHEREISBN=?",
newObject[]{stock,isbn});
System.out.println(threadName+"Bookstockincreasedby"+stock);
sleep(threadName);
System.out.println(threadName+"Bookstockrolledback");
thrownewRuntimeException("Increasedbymistake");
}
@Transactional
publicintcheckStock(Stringisbn){
StringthreadName=Thread.currentThread().getName();
System.out.println(threadName+"Preparetocheckbookstock");
intstock=getJdbcTemplate().queryForInt(
"SELECTSTOCKFROMBOOK_STOCKWHEREISBN=?",
newObject[]{isbn});
System.out.println(threadName+"Bookstockis"+stock);
sleep(threadName);
returnstock;
}
privatevoidsleep(StringthreadName){
System.out.println(threadName+"Sleeping");
try{
Thread.sleep(10000);
}catch(InterruptedExceptione){}
System.out.println(threadName+"Wakeup");
}
}
Tosimulateconcurrency,youroperationsneedtobeexecutedbymultiplethreads.Youcantrackthe
currentstatusoftheoperationsthroughtheprintlnstatements.Foreachoperation,youprinta
coupleofmessagestotheconsolearoundtheSQLstatementsexecution.Themessagesshould
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

31/42

10/05/2016

Chapter10:DataAccess

includethethreadnameforyoutoknowwhichthreadiscurrentlyexecutingtheoperation.
AftereachoperationexecutestheSQLstatement,youaskthethreadtosleepfor10seconds.Asyou
know,thetransactionwillbecommittedorrolledbackimmediatelyoncetheoperationcompletes.
Insertingasleepstatementcanhelptopostponethecommitorrollback.Fortheincrease()
operation,youeventuallythrowaRuntimeExceptiontocausethetransactiontorollback.Letslook
atasimpleclientthatrunstheseexamples.
Beforeyoustartwiththeisolationlevelexamples,enterthedatafromTables1111and1112into
yourbookshopdatabase.(NotethattheACCOUNTtableisntneededinthisexample.)
Table1111.SampleDataintheBOOKTableforTestingIsolationLevels
ISBN

BOOK_NAME

PRICE

0001

TheFirstBook

30

Table1112.SampleDataintheBOOK_STOCKTableforTestingIsolationLevels
ISBN

STOCK

0001

10

TheREAD_UNCOMMITTEDandREAD_COMMITTEDIsolationLevels
READ_UNCOMMITTEDisthelowestisolationlevelthatallowsatransactiontoreaduncommitted
changesmadebyothertransactions.Youcansetthisisolationlevelinthe@Transactionannotation
ofyourcheckStock()method.
packagecom.apress.springrecipes.bookshop.spring;
...
importorg.springframework.transaction.annotation.Isolation;
importorg.springframework.transaction.annotation.Transactional;
publicclassJdbcBookShopextendsJdbcDaoSupportimplementsBookShop{
...
@Transactional(isolation=Isolation.READ_UNCOMMITTED)
publicintcheckStock(Stringisbn){
...
}
}

https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

32/42

10/05/2016

Chapter10:DataAccess

Youcancreatesomethreadstoexperimentonthistransactionisolationlevel.InthefollowingMain
class,therearetwothreadsyouaregoingtocreate.Thread1increasesthebookstock,whilethread
2checksthebookstock.Thread1starts5secondsbeforethread2.
packagecom.apress.springrecipes.bookshop.spring;
...
publicclassMain{
publicstaticvoidmain(String[]args){
...
finalBookShopbookShop=context.getBean(BookShop.class);
Threadthread1=newThread(newRunnable(){
publicvoidrun(){
try{
bookShop.increaseStock("0001",5);
}catch(RuntimeExceptione){}
}
},"Thread1");
Threadthread2=newThread(newRunnable(){
publicvoidrun(){
bookShop.checkStock("0001");
}
},"Thread2");
thread1.start();
try{
Thread.sleep(5000);
}catch(InterruptedExceptione){}
thread2.start();
}
}
Ifyouruntheapplication,youwillgetthefollowingresult:
Thread1Preparetoincreasebookstock
Thread1Bookstockincreasedby5
Thread1Sleeping
Thread2Preparetocheckbookstock
Thread2Bookstockis15
Thread2Sleeping
Thread1Wakeup
Thread1Bookstockrolledback
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

33/42

10/05/2016

Chapter10:DataAccess

Thread2Wakeup
First,thread1increasedthebookstockandthenwenttosleep.Atthattime,thread1stransaction
hadnotyetbeenrolledback.Whilethread1wassleeping,thread2startedandattemptedtoread
thebookstock.WiththeREAD_UNCOMMITTEDisolationlevel,thread2wouldbeabletoreadthe
stockvaluethathadbeenupdatedbyanuncommittedtransaction.
However,whenthread1wakesup,itstransactionwillberolledbackduetoaRuntimeException,so
thevaluereadbythread2istemporaryandinvalid.Thisproblemisknownasdirtyread,becausea
transactionmayreadvaluesthataredirty.
Toavoidthedirtyreadproblem,youshouldraisetheisolationlevelofcheckStock()to
READ_COMMITTED.
packagecom.apress.springrecipes.bookshop.spring;
...
importorg.springframework.transaction.annotation.Isolation;
importorg.springframework.transaction.annotation.Transactional;
publicclassJdbcBookShopextendsJdbcDaoSupportimplementsBookShop{
...
@Transactional(isolation=Isolation.READ_COMMITTED)
publicintcheckStock(Stringisbn){
...
}
}
Ifyouruntheapplicationagain,thread2wontbeabletoreadthebookstockuntilthread1has
rolledbackthetransaction.Inthisway,thedirtyreadproblemcanbeavoidedbypreventinga
transactionfromreadingafieldthathasbeenupdatedbyanotheruncommittedtransaction.
Thread1Preparetoincreasebookstock
Thread1Bookstockincreasedby5
Thread1Sleeping
Thread2Preparetocheckbookstock
Thread1Wakeup
Thread1Bookstockrolledback
Thread2Bookstockis10
Thread2Sleeping
Thread2Wakeup
InorderfortheunderlyingdatabasetosupporttheREAD_COMMITTEDisolationlevel,itmay
acquireanupdatelockonarowthatwasupdatedbutnotyetcommitted.Then,othertransactions
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

34/42

10/05/2016

Chapter10:DataAccess

mustwaittoreadthatrowuntiltheupdatelockisreleased,whichhappenswhenthelocking
transactioncommitsorrollsback.
TheREPEATABLE_READIsolationLevel
Now,letsrestructurethethreadstodemonstrateanotherconcurrencyproblem.Swapthetasksof
thetwothreadssothatthread1checksthebookstockbeforethread2increasesthebookstock.
packagecom.apress.springrecipes.bookshop.spring;
...
publicclassMain{
publicstaticvoidmain(String[]args){
...
finalBookShopbookShop=(BookShop)context.getBean("bookShop");
Threadthread1=newThread(newRunnable(){
publicvoidrun(){
bookShop.checkStock("0001");
}
},"Thread1");
Threadthread2=newThread(newRunnable(){
publicvoidrun(){
try{
bookShop.increaseStock("0001",5);
}catch(RuntimeExceptione){}
}
},"Thread2");
thread1.start();
try{
Thread.sleep(5000);
}catch(InterruptedExceptione){}
thread2.start();
}
}
Ifyouruntheapplication,youwillgetthefollowingresult:
Thread1Preparetocheckbookstock
Thread1Bookstockis10
Thread1Sleeping
Thread2Preparetoincreasebookstock
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

35/42

10/05/2016

Chapter10:DataAccess

Thread2Bookstockincreasedby5
Thread2Sleeping
Thread1Wakeup
Thread2Wakeup
Thread2Bookstockrolledback
First,thread1readthebookstockandthenwenttosleep.Atthattime,thread1stransactionhad
notyetbeencommitted.Whilethread1wassleeping,thread2startedandattemptedtoincreasethe
bookstock.WiththeREAD_COMMITTEDisolationlevel,thread2wouldbeabletoupdatethestock
valuethatwasreadbyanuncommittedtransaction.
However,ifthread1readsthebookstockagain,thevaluewillbedifferentfromitsfirstread.This
problemisknownasnonrepeatablereadbecauseatransactionmayreaddifferentvaluesforthe
samefield.
Toavoidthenonrepeatablereadproblem,youshouldraisetheisolationlevelofcheckStock()to
REPEATABLE_READ.
packagecom.apress.springrecipes.bookshop.spring;
...
importorg.springframework.transaction.annotation.Isolation;
importorg.springframework.transaction.annotation.Transactional;
publicclassJdbcBookShopextendsJdbcDaoSupportimplementsBookShop{
...
@Transactional(isolation=Isolation.REPEATABLE_READ)
publicintcheckStock(Stringisbn){
...
}
}
Ifyouruntheapplicationagain,thread2wontbeabletoupdatethebookstockuntilthread1has
committedthetransaction.Inthisway,thenonrepeatablereadproblemcanbeavoidedby
preventingatransactionfromupdatingavaluethathasbeenreadbyanotheruncommitted
transaction.
Thread1Preparetocheckbookstock
Thread1Bookstockis10
Thread1Sleeping
Thread2Preparetoincreasebookstock
Thread1Wakeup
Thread2Bookstockincreasedby5
Thread2Sleeping
Thread2Wakeup
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

36/42

10/05/2016

Chapter10:DataAccess

Thread2Bookstockrolledback
InorderfortheunderlyingdatabasetosupporttheREPEATABLE_READisolationlevel,itmay
acquireareadlockonarowthatwasreadbutnotyetcommitted.Then,othertransactionsmustwait
toupdatetherowuntilthereadlockisreleased,whichhappenswhenthelockingtransaction
commitsorrollsback.
TheSERIALIZABLEIsolationLevel
Afteratransactionhasreadseveralrowsfromatable,anothertransactioninsertsnewrowsintothe
sametable.Ifthefirsttransactionreadsthesametableagain,itwillfindadditionalrowsthatare
differentfromthefirstread.Thisproblemisknownasphantomread.Actually,phantomreadisvery
similartononrepeatablereadbutinvolvesmultiplerows.
Toavoidthephantomreadproblem,youshouldraisetheisolationleveltothehighest:
SERIALIZABLE.Noticethatthisisolationlevelistheslowestbecauseitmayacquireareadlockon
thefulltable.Inpractice,youshouldalwayschoosethelowestisolationlevelthatcansatisfyyour
requirements.
SettingtheIsolationLevelAttributeinTransactionAdvicesandAPIs
InaSpringtransactionadvice,theisolationlevelcanbespecifiedinthe<tx:method>elementas
follows:
<tx:advice...>
<tx:attributes>
<tx:methodname="*"
isolation="REPEATABLE_READ"/>
</tx:attributes>
</tx:advice>
InSpringstransactionmanagementAPI,theisolationlevelcanbespecifiedina
DefaultTransactionDefinitionobjectandthenpassedtoatransactionmanagersgetTransaction()
methodoratransactiontemplatesconstructor.
DefaultTransactionDefinitiondef=newDefaultTransactionDefinition();
def.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ);
119.SettingtheRollbackTransactionAttribute
Problem
Bydefault,onlyuncheckedexceptions(i.e.,oftypeRuntimeExceptionandError)willcausea
transactiontorollback,whilecheckedexceptionswillnot.Sometimes,youmaywishtobreakthis
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

37/42

10/05/2016

Chapter10:DataAccess

ruleandsetyourownexceptionsforrollingback.
Solution
Theexceptionsthatcauseatransactiontorollbackornotcanbespecifiedbytherollback
transactionattribute.Anyexceptionsnotexplicitlyspecifiedinthisattributewillbehandledbythe
defaultrollbackrule(i.e.,rollingbackforuncheckedexceptionsandnotrollingbackforchecked
exceptions).
HowItWorks
Atransactionsrollbackrulecanbedefinedinthe@TransactionalannotationviatherollbackForand
noRollbackForattributes.ThesetwoattributesaredeclaredasClass[],soyoucanspecifymorethan
oneexceptionforeachattribute.
packagecom.apress.springrecipes.bookshop.spring;
...
importorg.springframework.transaction.annotation.Propagation;
importorg.springframework.transaction.annotation.Transactional;
importjava.io.IOException;
publicclassJdbcBookShopextendsJdbcDaoSupportimplementsBookShop{
...
@Transactional(
propagation=Propagation.REQUIRES_NEW,
rollbackFor=IOException.class,
noRollbackFor=ArithmeticException.class)
publicvoidpurchase(Stringisbn,Stringusername)throwsException{
thrownewArithmeticException();
//thrownewIOException();
}
}
InaSpringtransactionadvice,therollbackrulecanbespecifiedinthe<tx:method>element.Youcan
separatetheexceptionswithcommasiftheresmorethanoneexception.
<tx:advice...>
<tx:attributes>
<tx:methodname="..."
rollbackfor="java.io.IOException"
norollbackfor="java.lang.ArithmeticException"/>
...
</tx:attributes>
</tx:advice>
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

38/42

10/05/2016

Chapter10:DataAccess

InSpringstransactionmanagementAPI,therollbackrulecanbespecifiedina
RuleBasedTransactionAttributeobject.BecauseitimplementstheTransactionDefinitioninterface,it
canbepassedtoatransactionmanagersgetTransaction()methodoratransactiontemplates
constructor.
RuleBasedTransactionAttributeattr=newRuleBasedTransactionAttribute();
attr.getRollbackRules().add(
newRollbackRuleAttribute(IOException.class));
attr.getRollbackRules().add(
newNoRollbackRuleAttribute(SendFailedException.class));
1110.SettingtheTimeoutandReadOnlyTransactionAttributes
Problem
Becauseatransactionmayacquirelocksonrowsandtables,alongtransactionwilltieupresources
andhaveanimpactonoverallperformance.Besides,ifatransactiononlyreadsbutdoesnotupdate
data,thedatabaseenginecouldoptimizethistransaction.Youcanspecifytheseattributesto
increasetheperformanceofyourapplication.
Solution
Thetimeouttransactionattribute(anintegerthatdescribesseconds)indicateshowlongyour
transactioncansurvivebeforeitisforcedtorollback.Thiscanpreventalongtransactionfromtying
upresources.Thereadonlyattributeindicatesthatthistransactionwillonlyreadbutnotupdate
data.Thereadonlyflagisjustahinttoenablearesourcetooptimizethetransaction,andaresource
mightnotnecessarilycauseafailureifawriteisattempted.
HowItWorks
Thetimeoutandreadonlytransactionattributescanbedefinedinthe@Transactionalannotation.
Notethattimeoutismeasuredinseconds.
packagecom.apress.springrecipes.bookshop.spring;
...
importorg.springframework.transaction.annotation.Isolation;
importorg.springframework.transaction.annotation.Transactional;
publicclassJdbcBookShopextendsJdbcDaoSupportimplementsBookShop{
...
@Transactional(
isolation=Isolation.REPEATABLE_READ,
timeout=30,
readOnly=true)
publicintcheckStock(Stringisbn){
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

39/42

10/05/2016

Chapter10:DataAccess

...
}
}
InaSpring2.0transactionaladvice,thetimeoutandreadonlytransactionattributescanbespecified
inthe<tx:method>element.
<tx:advice...>
<tx:attributes>
<tx:methodname="checkStock"
timeout="30"
readonly="true"/>
</tx:attributes>
</tx:advice>
InSpringstransactionmanagementAPI,thetimeoutandreadonlytransactionattributescanbe
specifiedinaDefaultTransactionDefinitionobjectandthenpassedtoatransactionmanagers
getTransaction()methodoratransactiontemplatesconstructor.
DefaultTransactionDefinitiondef=newDefaultTransactionDefinition();
def.setTimeout(30);
def.setReadOnly(true);
1111.ManagingTransactionswithLoadTimeWeaving
Problem
Bydefault,SpringsdeclarativetransactionmanagementisenabledviaitsAOPframework.However,
asSpringAOPcanonlyadvisepublicmethodsofbeansdeclaredintheIoCcontainer,youare
restrictedtomanagingtransactionswithinthisscopeusingSpringAOP.Sometimes,youmaywishto
managetransactionsfornonpublicmethods,ormethodsofobjectscreatedoutsidetheSpringIoC
container(e.g.,domainobjects).
Solution
SpringprovidesanAspectJaspectnamedAnnotationTransactionAspectthatcanmanage
transactionsforanymethodsofanyobjects,evenifthemethodsarenonpublicortheobjectsare
createdoutsidetheSpringIoCcontainer.Thisaspectwillmanagetransactionsforanymethodswith
the@Transactionalannotation.YoucanchooseeitherAspectJscompiletimeweavingorloadtime
weavingtoenablethisaspect.
HowItWorks
Toweavethisaspectintoyourdomainclassesatloadtime,youhavetoputthe
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

40/42

10/05/2016

Chapter10:DataAccess

@EnableLoadTimeWeavingannotationonyourconfigurationclass.ToenableSprings
AnnotationTransactionAspectfortransactionmanagement,youjustdefinethe
@EnableTransactionManagementannotationandsetitsmodeattributetoaspectj.The
@EnableTransactionManagementannotationtakestwovaluesforthemodeattribute:aspectjand
proxy.aspectstipulatesthatthecontainershoulduseloadtimeorcompiletimeweavingtoenable
thetransactionadvice.Thisrequiresthespringinstrumentjartobeontheclasspath,aswellasthe
appropriateconfigurationatloadtimeorcompiletime.Alternatively,proxystipulatesthatthe
containershouldusetheSpringAOPmechanisms.Itsimportanttonotethattheaspectmode
doesntsupportconfigurationofthe@Transactionalannotationoninterfaces.Thenthetransaction
aspectwillautomaticallygetenabled.Youalsohavetoprovideatransactionmanagerforthisaspect.
Bydefault,itwilllookforatransactionmanagerwhosenameistransactionManager.
packagecom.apress.springrecipes.bookshop;
Configuration
@EnableTransactionManagement(mode=AdviceMode.ASPECTJ)
@EnableLoadTimeWeaving
publicclassBookstoreConfiguration{...}
InXMLyouadd<context:loadtimeweaver/>andspecifythemodeattributeon
<tx:annotationdriven/>.
<beans...>
...
<context:loadtimeweaver/>
<tx:annotationdrivenmode="aspectj"/>
</beans>

NoteTousetheSpringaspectlibraryforAspectJyouhavetoincludespringaspectsmoduleon
yourCLASSPATH.Toenableloadtimeweavingwealsohavetoincludeajavaagent,thisisavailable
inthespringinstrumentmodule.IfyoureusingMaven,addthefollowingdependenciestoyour
project.
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springaspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springinstrument</artifactId>
https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

41/42

10/05/2016

Chapter10:DataAccess

<version>${spring.version}</version>
</dependency>
ForasimpleJavaapplication,youcanweavethisaspectintoyourclassesatloadtimewiththe
SpringagentspecifiedasaVMargument.
javajavaagent:lib/springinstrument4.0.5.RELEASE.jarjarRecipe_12_11_i.jar
Summary
Thischapterdiscussedtransactionsandwhyyoushouldusethem.Youexploredtheapproachtaken
fortransactionmanagementhistoricallyinJavaEEandthenlearnedhowtheapproachtheSpring
frameworkoffersdiffers.Youexploredexplicituseoftransactionsinyourcodeaswellasimplicituse
withannotationdrivenaspects.Yousetupadatabaseandusedtransactionstoenforcevalidstatein
thedatabase.
Inthenextchapter,youwillexploreSpringBatch.SpringBatchprovidesinfrastructureand
componentsthatcanbeusedasthefoundationforbatchprocessingjobs.

Peoplewhofinishedthisalsoenjoyed:
BookSection

Released:November2009
Released:November2012

https://www.safaribooksonline.com/library/view/springrecipesa/9781430259091/9781430259084_Ch11.xhtml

42/42

Você também pode gostar