Documentos de Académico
Documentos de Profesional
Documentos de Cultura
UserGuide
WarningaboutCopyingCodefromthisDocument
No, this is not a legal warning. It is one to help you keep your sanity. Modern word processors do a great job of making text readable and formatted in an aesthetically pleasing way. However, they also tend to completely ruin code examples by inserting special characters, sometimes that look exactly the same as the one you think you want. Quotes and hyphens are a perfect example the quotes and hyphen you see to the left will not work as quotes in an IDE or text editor, at least not the way you intend. So read this document, enjoy it and hopefully it is helpful to you. When it comes to code examples, seek out the examples included with the download (including unit tests etc.), or examples from the website or mailing list.
Helpmakethisdocumentationbetter
If you find this documentation lacking in any way, or missing documentation for a feature, then the best thing to do is learn about it and then write the documentation yourself! We accept public documentation contributions through our wiki at: http://opensource.atlassian.com/confluence/oss/display/IBATIS/Contribute+Documentation Yourethebestauthorofthisdocumentation,peoplelikeyouhavetoreadit!
Contents
WhatisiBATIS? ............................................................................................................................................ 5 GettingStarted ............................................................................................................................................ 5 BuildingSqlSessionFactoryfromXML...................................................................................................... 5 BuildingSqlSessionFactorywithoutXML ................................................................................................. 6 AcquiringaSqlSessionfromSqlSessionFactory ....................................................................................... 6 ExploringMappedSQLStatements ......................................................................................................... 7 ANoteaboutNamespaces .................................................................................................................. 8 ScopeandLifecycle.................................................................................................................................. 9 MapperConfigurationXML ....................................................................................................................... 10 properties .............................................................................................................................................. 10 settings................................................................................................................................................... 11 typeAliases............................................................................................................................................. 12 typeHandlers.......................................................................................................................................... 13 objectFactory ......................................................................................................................................... 14 plugins.................................................................................................................................................... 15 environments......................................................................................................................................... 16 transactionManager .......................................................................................................................... 17 dataSource ......................................................................................................................................... 18 mappers ................................................................................................................................................. 20 SQLMapXMLFiles..................................................................................................................................... 20 select...................................................................................................................................................... 21 insert,update,delete ............................................................................................................................ 22 sql........................................................................................................................................................... 25 Parameters............................................................................................................................................. 25
iBATIS3UserGuide
resultMap............................................................................................................................................... 27 AdvancedResultMapping ................................................................................................................. 29 id,result ............................................................................................................................................. 31 SupportedJDBCTypes ....................................................................................................................... 31 constructor ........................................................................................................................................ 32 association ......................................................................................................................................... 33 collection ........................................................................................................................................... 36 discriminator...................................................................................................................................... 38 cache...................................................................................................................................................... 40 UsingaCustomCache........................................................................................................................ 41 cacheref ................................................................................................................................................ 42 DynamicSQL .............................................................................................................................................. 42 if ............................................................................................................................................................. 43 choose,when,otherwise....................................................................................................................... 43 trim,where,set ..................................................................................................................................... 44 foreach................................................................................................................................................... 46 JavaAPI ...................................................................................................................................................... 47 DirectoryStructure ................................................................................................................................ 47 SqlSessions............................................................................................................................................. 48 SqlSessionFactoryBuilder ................................................................................................................... 48 SqlSessionFactory .............................................................................................................................. 50 SqlSession .......................................................................................................................................... 51 SelectBuilder .............................................................................................................................................. 57
16August2009
iBATIS3UserGuide
WhatisiBATIS?
iBATISisafirstclasspersistenceframeworkwithsupportforcustomSQL,storedproceduresand advancedmappings.iBATISeliminatesalmostalloftheJDBCcodeandmanualsettingofparameters andretrievalofresults.iBATIScanusesimpleXMLorAnnotationsforconfigurationandmapprimitives, MapinterfacesandJavaPOJOs(PlainOldJavaObjects)todatabaserecords.
GettingStarted
EveryiBATISapplicationcentersaroundaninstanceofSqlSessionFactory.ASqlSessionFactoryinstance canbeacquiredbyusingtheSqlSessionFactoryBuilder.SqlSessionFactoryBuildercanbuilda SqlSessionFactoryinstancefromanXMLconfigurationfile,offromacustompreparedinstanceofthe Configurationclass.
BuildingSqlSessionFactoryfromXML
BuildingaSqlSessionFactoryinstancefromanXMLfileisverysimple.Itisrecommendedthatyouusea classpathresourceforthisconfiguration,butyoucoulduseanyReaderinstance,includingonecreated fromaliteralfilepathorafile://URL.iBATISincludesautilityclass,calledResources,thatcontainsa numberofmethodsthatmakeitsimplertoloadresourcesfromtheclasspathandotherlocations.
String resource = "org/apache/ibatis/example/Configuration.xml"; Reader reader = Resources.getResourceAsReader(resource); sqlMapper = new SqlSessionFactoryBuilder().build(reader);
16August2009
BuildingSqlSessionFactorywithoutXML
IfyouprefertodirectlybuildtheconfigurationfromJava,ratherthanXML,orcreateyourown configurationbuilder,iBATISprovidesacompleteConfigurationclassthatprovidesallofthesame configurationoptionsastheXMLfile.
DataSource dataSource = BlogDataSourceFactory.getBlogDataSource(); TransactionFactory transactionFactory = new JdbcTransactionFactory(); Environment environment = new Environment("development", transactionFactory, dataSource); Configuration configuration = new Configuration(environment); configuration.addMapper(BlogMapper.class); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
AcquiringaSqlSessionfromSqlSessionFactory
NowthatyouhaveaSqlSessionFactory,asthenamesuggests,youcanacquireaninstanceof SqlSession.TheSqlSessioncontainsabsolutelyeverymethodneededtoexecuteSQLcommandsagainst thedatabase.YoucanexecutemappedSQLstatementsdirectlyagainsttheSqlSessioninstance.For exmaple:
SqlSession session = sqlMapper.openSession(); try { Blog blog = (Blog) session.select( "org.apache.ibatis.example.BlogMapper.selectBlog", 101); } finally { session.close(); }
16August2009
iBATIS3UserGuide Forexample:
SqlSession session = sqlSessionFactory.openSession(); try { BlogMapper mapper = session.getMapper(BlogMapper.class); Blog blog = mapper.selectBlog(101); } finally { session.close(); }
Nowlet'sexplorewhatexactlyisbeingexecutedhere.
ExploringMappedSQLStatements
AtthispointyoumaybewonderingwhatexactlyisbeingexecutedbytheSqlSessionorMapperclass. ThetopicofMappedSQLStatementsisabigone,andthattopicwilllikelydominatethemajorityofthis documentation.Buttogiveyouanideaofwhatexactlyisbeingrun,hereareacoupleofexamples. Ineitheroftheexamplesabove,thestatementscouldhavebeendefinedbyeitherXMLorAnnotations. Let'stakealookatXMLfirst.ThefullsetoffeaturesprovidedbyiBATIScanberealizedbyusingthe XMLbasedmappinglanguagethathasmadeiBATISpopularovertheyears.Ifyou'veusediBATIS before,theconceptwillbefamiliartoyou,buttherehavebeennumerousimprovementstotheXML mappingdocumentsthatwillbecomeclearlater.HereisanexampleofanXMLbasedmapped statementthatwouldsatisfytheaboveSqlSessioncalls.
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN" "http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd"> <mapper namespace="org.apache.ibatis.example.BlogMapper"> <select id="selectBlog" parameterType="int" resultType="Blog"> select * from Blog where id = #{id} </select> </mapper>
NoticehowsimilarthisistocallingamethodonafullyqualifiedJavaclass,andthere'sareasonforthat. ThisnamecanbedirectlymappedtoaMapperclassofthesamenameasthenamespace,witha
16August2009
ANoteaboutNamespaces
Namespaces were optional in previous versions of iBATIS, which was confusing and unhelpful. Namespaces are now required and have a purpose beyond simply isolating statements with longer, fully-qualified names. Namespaces enable the interface bindings as you see here, and even if you dont think youll use them today, you should follow these practices laid out here in case you change your mind. Using the namespace once, and putting it in a proper Java package namespace will clean up your code and improve the usability of iBATIS in the long term. There'sonemoretricktoMapperclasseslikeBlogMapper.Theirmappedstatementsdon'tneedtobe mappedwithXMLatall.InsteadtheycanuseJavaAnnotations.Forexample,theXMLabovecouldbe eliminatedandreplacedwith:
package org.apache.ibatis.example; public interface BlogMapper { @Select("SELECT * FROM blog WHERE id = #{id}") Blog selectBlog(int id); }
16August2009
iBATIS3UserGuide
ScopeandLifecycle
It'sveryimportanttounderstandthevariousscopesandlifecyclesclasseswe'vediscussedsofar.Using themincorrectlycancausesevereconcurrencyproblems.
SqlSessionFactoryBuilder
Thisclasscanbeinstantiated,usedandthrownaway.Thereisnoneedtokeepitaroundonceyou've createdyourSqlSessionFactory.ThereforethebestscopeforinstancesofSqlSessionFactoryBuilderis methodscope(i.e.alocalmethodvariable).YoucanreusetheSqlSessionFactoryBuildertobuild multipleSqlSessionFactoryinstances,butit'sstillbestnottokeepitaroundtoensurethatalloftheXML parsingresourcesarefreedupformoreimportantthings.
SqlSessionFactory
Oncecreated,theSqlSessionFactoryshouldexistforthedurationofyourapplicationexecution.There shouldbelittleornoreasontoeverdisposeofitorrecreateit.It'sabestpracticetonotrebuildthe SqlSessionFactorymultipletimesinanapplicationrun.Doingsoshouldbeconsideredabadsmell. ThereforethebestscopeofSqlSessionFactoryisapplicationscope.Thiscanbeachievedanumberof ways.ThesimplestistouseaSingletonpatternorStaticSingletonpattern.However,neitherofthose iswidelyacceptedasabestpractice.Instead,youmightprefertoinvestigateadependencyinjection containersuchasGoogleGuiceorSpring.Suchframeworkswillallowyoutocreateprovidersthatwill managethesingletonlifecycleofSqlSessionFactoryforyou.
SqlSession
EachthreadshouldhaveitsowninstanceofSqlSession.InstancesofSqlSessionarenottobeshared andarenotthreadsafe.Thereforethebestscopeisrequestormethodscope.Neverkeepreferences toaSqlSessioninstanceinastaticfieldorevenaninstancefieldofaclass.Neverkeepreferencestoa SqlSessioninanysortofmanagedscope,suchasHttpSessionofoftheServletframework.Ifyou're usingawebframeworkofanysort,considertheSqlSessiontofollowasimilarscopetothatofanHTTP request.Inotherwords,uponrecievinganHTTPrequest,youcanopenaSqlSession,thenupon returningtheresponse,youcancloseit.Closingthesessionisveryimportant.Youshouldalways ensurethatit'sclosedwithinafinallyblock.Thefollowingisthestandardpatternforensuringthat SqlSessionsareclosed:
SqlSession session = sqlSessionFactory.openSession(); try { // do work } finally { session.close(); }
16August2009
iBATIS3UserGuide
MapperInstances
Mappersareinterfacesthatyoucreatetobindtoyourmappedstatements.Instancesofthemapper interfacesareacquiredfromtheSqlSession.Assuch,technicallythebroadestscopeofanymapper instanceisthesameastheSqlSessionfromwhichtheywererequestsd.However,thebestscopefor mapperinstancesismethodscope.Thatis,theyshouldberequestedwithinthemethodthattheyare used,andthenbediscarded.Theydonotneedtobeclosedexplicitly.Whileit'snotaproblemtokeep themaroundthroughoutarequest,similartotheSqlSession,youmightfindthatmanagingtoomany resourcesatthislevelwillquicklygetoutofhand.Keepitsimple,keepMappersinthemethodscope. Thefollowingexampledemonstratesthispractice.
SqlSession session = sqlSessionFactory.openSession(); try { BlogMapper mapper = session.getMapper(BlogMapper.class); // do work } finally { session.close(); }
MapperConfigurationXML
TheiBATISXMLconfigurationfilecontainssettingsandpropertiesthathaveadramaticeffectonhow iBATISbehaves.Thehighlevelstructureofthedocumentisasfollows: configuration o properties o settings o typeAliases o typeHandlers o objectFactory o plugins o environments environment transactionManager dataSource o mappers
properties
Theseareexternalizable,substitutablepropertiesthatcanbeconfiguredinatypicalJavaPropertiesfile instance,orpassedinthroughsubelementsofthepropertieselement.Forexample:
<properties resource="org/apache/ibatis/example/config.properties">
16August2009
10
iBATIS3UserGuide
<property name="username" value="dev_user"/> <property name="password" value="F2Fa3!33TYyg"/> </properties>
Thepropertiescanthenbeusedthroughouttheconfigurationfilestosubstitutevaluesthatneedtobe dynamicallyconfigured.Forexample:
<dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource>
Thus,thehighestprioritypropertiesarethosepassedinasamethodparameter,followedby resource/urlattributesandfinallythepropertiesspecifiedinthebodyofthepropertieselement.
settings
TheseareextremelyimportanttweaksthatmodifythewaythatiBATISbehavesatruntime.The followingtabledescribesthesettings,theirmeaningsandtheirdefaultvalues. Setting cacheEnabled Description Globallyenablesordisablesanycaches configuredinanymapperunderthis configuration. Globallyenablesordisableslazyloading. ValidValues true|false Default true
lazyLoadingEnabled
true|false
true
16August2009
11
iBATIS3UserGuide Whendisabled,allassociationswillbeeagerly loaded. multipleResultSetsEnabled AllowsordisallowsmultipleResultSetstobe returnedfromasinglestatement(compatible driverrequired). useColumnLabel Usesthecolumnlabelinsteadofthecolumn name.Differentdriversbehavedifferentlyin thisrespect.Refertothedriver documentation,ortestoutbothmodesto determinehowyourdriverbehaves. useGeneratedKeys AllowsJDBCsupportforgeneratedkeys.A compatibledriverisrequired.Thissetting forcesgeneratedkeystobeusedifsetto true,assomedriversdenycompatibilitybut stillwork(e.g.Derby). enhancementEnabled EnablessupportforCGLIBandlazyloading withconcretetypes.Normallyonlyinterfaces cansupportlazyloading.CGLIBallows dynamicproxiestobecreatedforanynon finaltype. defaultExecutorType Configuresthedefaultexecutor.SIMPLE executordoesnothingspecial.REUSE executorreusespreparedstatements.BATCH executorreusesstatementsandbatches updates. defaultStatementTimeout Setsthetimeoutthatdetermineshowlong thedriverwillwaitforaresponsefromthe database. Anexampleofthesettingselementfullyconfiguredisasfollows:
<settings> <setting name="cacheEnabled" value="true"/> <setting name="lazyLoadingEnabled" value="true"/> <setting name="multipleResultSetsEnabled" value="true"/> <setting name="useColumnLabel" value="true"/> <setting name="useGeneratedKeys" value="false"/> <setting name="enhancementEnabled" value="false"/> <setting name="defaultExecutorType" value="SIMPLE"/> <setting name="defaultStatementTimeout" value="25000"/> </settings>
true|false
true
true|false
true
true|false
False
true|false
False
SIMPLE
Anypositive integer
NotSet (null)
typeAliases
AtypealiasissimplyashorternameforaJavatype.It'sonlyrelevanttotheXMLconfigurationand simplyexiststoreduceredundanttypingoffullyqualifiedclassnames.Forexample:
<typeAliases> <typeAlias alias="Author" type="domain.blog.Author"/> <typeAlias alias="Blog" type="domain.blog.Blog"/>
16August2009
12
iBATIS3UserGuide
<typeAlias alias="Comment" type="domain.blog.Comment"/> <typeAlias alias="Post" type="domain.blog.Post"/> <typeAlias alias="Section" type="domain.blog.Section"/> <typeAlias alias="Tag" type="domain.blog.Tag"/> </typeAliases>
Withthisconfiguration,Blogcannowbeusedanywherethatdomain.blog.Blogcouldbe.
typeHandlers
WheneveriBATISsetsaparameteronaPreparedStatementorretrievesavaluefromaResultSet,a TypeHandlerisusedtoretrievethevalueinameansappropriatetotheJavatype.Thefollowingtable describesthedefaultTypeHandlers. TypeHandler BooleanTypeHandler ByteTypeHandler ShortTypeHandler IntegerTypeHandler LongTypeHandler FloatTypeHandler DoubleTypeHandler BigDecimalTypeHandler StringTypeHandler ClobTypeHandler NStringTypeHandler NClobTypeHandler ByteArrayTypeHandler BlobTypeHandler DateTypeHandler DateOnlyTypeHandler TimeOnlyTypeHandler SqlTimestampTypeHandler SqlDateTypeHadler SqlTimeTypeHandler ObjectTypeHandler EnumTypeHandler Youcanoverridethetypehandlersorcreateyourowntodealwithunsupportedornonstandardtypes. Todoso,simplyimplementingtheTypeHandlerinterface(org.apache.ibatis.type)andmapyournew TypeHandlerclasstoaJavatype,andoptionallyaJDBCtype.Forexample:
// ExampleTypeHandler.java public class ExampleTypeHandler implements TypeHandler { public void setParameter( PreparedStatement ps, int i, Object parameter,JdbcType jdbcType)
JavaTypes Boolean,boolean Byte,byte Short,short Integer,int Long,long Float,float Double,double BigDecimal String String String String byte[] byte[] Date(java.util) Date(java.util) Date(java.util) Timestamp(java.sql) Date(java.sql) Time(java.sql) Any EnumerationType
JDBCTypes AnycompatibleBOOLEAN AnycompatibleNUMERICorBYTE AnycompatibleNUMERICorSHORTINTEGER AnycompatibleNUMERICorINTEGER AnycompatibleNUMERICorLONGINTEGER AnycompatibleNUMERICorFLOAT AnycompatibleNUMERICorDOUBLE AnycompatibleNUMERICorDECIMAL CHAR,VARCHAR CLOB,LONGVARCHAR NVARCHAR,NCHAR NCLOB Anycompatiblebytestreamtype BLOB,LONGVARBINARY TIMESTAMP DATE TIME TIMESTAMP DATE TIME OTHER,orunspecified VARCHARanystringcompatibletype,asthe codeisstored(nottheindex).
16August2009
13
iBATIS3UserGuide
throws SQLException { ps.setString(i, (String) parameter); } public Object getResult( ResultSet rs, String columnName) throws SQLException { return rs.getString(columnName); } public Object getResult( CallableStatement cs, int columnIndex) throws SQLException { return cs.getString(columnIndex); } } // MapperConfig.xml <typeHandlers> <typeHandler javaType="String" jdbcType="VARCHAR" handler="org.apache.ibatis.example.ExampleTypeHandler"/> </typeHandlers>
objectFactory
EachtimeiBATIScreatesanewinstanceofaresultobject,itusesanObjectFactoryinstancetodoso. ThedefaultObjectFactorydoeslittlemorethaninstantiatethetargetclasswithadefaultconstructor,or aparameterizedconstructorifparametermappingsexist.Ifyouwanttooverridethedefaultbehaviour oftheObjectFactory,youcancreateyourown.Forexample:
// ExampleObjectFactory.java public class ExampleObjectFactory extends DefaultObjectFactory { public Object create(Class type) { return super.create(type); } public Object create( Class type, List<Class> constructorArgTypes, List<Object> constructorArgs) { return super.create(type, constructorArgTypes, constructorArgs); } public void setProperties(Properties properties) { super.setProperties(properties); } } // MapperConfig.xml <objectFactory type="org.apache.ibatis.example.ExampleObjectFactory"> <property name="someProperty" value="100"/>
16August2009
14
iBATIS3UserGuide
</objectFactory>
plugins
iBATISallowsyoutointerceptcallstoatcertainpointswithintheexecutionofamappedstatement.By default,iBATISallowspluginstointerceptmethodcallsof: Executor (update,query,flushStatements,commit,rollback,getTransaction,close,isClosed) ParameterHandler (getParameterObject,setParameters) ResultSetHandler (handleResultSets,handleOutputParameters) StatementHandler (prepare,parameterize,batch,update,query)
16August2009
15
iBATIS3UserGuide
// MapperConfig.xml <plugins> <plugin interceptor="org.apache.ibatis.example.ExamplePlugin"> <property name="someProperty" value="100"/> </plugin> </plugins>
environments
iBATIScanbeconfiguredwithmultipleenvironments.ThishelpsyoutoapplyyourSQLMapsto multipledatabasesforanynumberofreasons.Forexample,youmighthaveadifferentconfiguration foryourDevelopment,TestandProductionenvironments.Or,youmayhavemultipleproduction databasesthatsharethesameschema,andyoudliketousethesameSQLmapsforboth.Thereare manyusecases. Oneimportantthingtorememberthough:Whileyoucanconfiguremultipleenvironments,youcan onlychooseONEperSqlSessionFactoryinstance. Soifyouwanttoconnecttotwodatabases,youneedtocreatetwoinstancesofSqlSessionFactory,one foreach.Forthreedatabases,youdneedthreeinstances,andsoon.Itsreallyeasytoremember: OneSqlSessionFactoryinstanceperdatabase Tospecifywhichenvironmenttobuild,yousimplypassittotheSqlSessionFactoryBuilderasanoptional parameter.Thetwosignaturesthataccepttheenvironmentare: SqlSessionFactoryfactory=sqlSessionFactoryBuilder.build(reader,environment); SqlSessionFactoryfactory=sqlSessionFactoryBuilder.build(reader,environment,properties); Iftheenvironmentisomitted,thenthedefaultenvironmentisloaded,asfollows: SqlSessionFactoryfactory=sqlSessionFactoryBuilder.build(reader); SqlSessionFactoryfactory=sqlSessionFactoryBuilder.build(reader,properties); Theenvironmentselementdefineshowtheenvironmentisconfigured.
<environments default="development"> <environment id="development">
16August2009
16
iBATIS3UserGuide
<transactionManager type="JDBC"> <property name="" value=""/> </transactionManager> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments>
ThedefaultenvironmentandtheenvironmentIDsareselfexplanatory.Namethemwhateveryoulike, justmakesurethedefaultmatchesoneofthem.
transactionManager
TherearetwoTransactionManagertypes(i.e.type=[JDBC|MANAGED])thatareincludedwithiBATIS: JDBCThisconfigurationsimplymakesuseoftheJDBCcommitandrollbackfacilitiesdirectly.It reliesontheconnectionretrievedfromthedataSourcetomanagethescopeofthetransaction. MANAGEDThisconfigurationsimplydoesnothing,quiteliterally.Itnevercommits,rollsback orclosesaconnection.Instead,itletsthecontainermanagethefulllifecycleofthetransaction (e.g.SpringoraJEEApplicationServercontext).
16August2009
17
iBATIS3UserGuide
public interface Transaction { Connection getConnection(); void commit() throws SQLException; void rollback() throws SQLException; void close() throws SQLException; }
Usingthesetwointerfaces,youcancompletelycustomizehowiBATISdealswithTransactions.
dataSource
ThedataSourceelementconfiguresthesourceofJDBCConnectionobjectsusingthestandardJDBC DataSourceinterface. MostiBATISapplicationswillconfigureadataSourceasintheexample.However,itsnot required.Realizethough,thattofacilitateLazyLoading,thisdataSourceisrequired. TherearethreebuildindataSourcetypes(i.e.type=????): UNPOOLEDThisimplementationofDataSourcesimplyopensandclosesaconnectioneachtimeitis requested.Whileitsabitslower,thisisagoodchoiceforsimpleapplicationsthatdonotrequirethe performanceofimmediatelyavailableconnections.Differentdatabasesarealsodifferentinthis performancearea,soforsomeitmaybelessimportanttopoolandthisconfigurationwillbeideal.The UNPOOLEDDataSourceisconfiguredwithonlyfourproperties: driverThisisthefullyqualifiedJavaclassoftheJDBCdriver(NOToftheDataSourceclassif yourdriverincludesone). urlThisistheJDBCURLforyourdatabaseinstance. usernameThedatabaseusernametologinwith. passwordThedatabasepasswordtologinwith.
16August2009
18
iBATIS3UserGuide Inadditiontothe(UNPOOLED)propertiesabove,therearemanymorepropertiesthatcanbeusedto configurethePOOLEDdatasource: poolMaximumActiveConnectionsThisisthenumberofactive(i.e.inuse)connectionsthat canexistatanygiventime.Default:10 poolMaximumIdleConnectionsThenumberofidleconnectionsthatcanexistatanygiven time. poolMaximumCheckoutTimeThisistheamountoftimethataConnectioncanbechecked outofthepoolbeforeitwillbeforcefullyreturned.Default:20000ms(i.e.20seconds) poolTimeToWaitThisisalowlevelsettingthatgivesthepoolachancetoprintalogstatus andreattempttheacquisitionofaconnectioninthecasethatitstakingunusuallylong(to avoidfailingsilentlyforeverifthepoolismisconfigured).Default:20000ms(i.e.20seconds) poolPingQueryThePingQueryissenttothedatabasetovalidatethataconnectionisingood workingorderandisreadytoacceptrequests.Thedefaultis"NOPINGQUERYSET",whichwill causemostdatabasedriverstofailwithadecenterrormessage. poolPingEnabledThisenablesordisablesthepingquery.Ifenabled,youmustalsosetthe poolPingQuerypropertywithavalidSQLstatement(preferablyaveryfastone).Default:false.
16August2009
19
mappers
NowthatthebehaviourofiBATISisconfiguredwiththeaboveconfigurationelements,werereadyto defineourmappedSQLstatements.Butfirst,weneedtotelliBATISwheretofindthem.Javadoesnt reallyprovideanygoodmeansofautodiscoveryinthisregard,sothebestwaytodoitistosimplytell iBATISwheretofindthemappingfiles.Youcanuseclasspathrelativeresourcereferences,orliteral, fullyqualifiedurlreferences(includingfile:///URLs).Forexample:
// Using classpath relative resources <mappers> <mapper resource="org/apache/ibatis/builder/AuthorMapper.xml"/> <mapper resource="org/apache/ibatis/builder/BlogMapper.xml"/> <mapper resource="org/apache/ibatis/builder/PostMapper.xml"/> </mappers> // Using url fully qualified paths <mappers> <mapper url="file:///var/sqlmaps/AuthorMapper.xml"/> <mapper url="file:///var/sqlmaps/BlogMapper.xml"/> <mapper url="file:///var/sqlmaps/PostMapper.xml"/> </mappers>
ThesestatementsimplytelliBATISwheretogofromhere.TherestofthedetailsareineachoftheSQL Mappingfiles,andthatsexactlywhatthenextsectionwilldiscuss.
SQLMapXMLFiles
ThetruepowerofiBATISisintheMappedStatements.Thisiswherethemagichappens.Foralloftheir power,theSQLMapXMLfilesarerelativelysimple.Certainlyifyouweretocomparethemtothe equivalentJDBCcode,youwouldimmediatelyseeasavingsof95%ofthecode.iBATISwasbuiltto focusontheSQL,anddoesitsbesttostayoutofyourway. TheSQLMapXMLfileshaveonlyafewfirstclasselements(intheorderthattheyshouldbedefined): cacheConfigurationofthecacheforagivennamespace. cacherefReferencetoacacheconfigurationfromanothernamespace. resultMapThemostcomplicatedandpowerfulelementthatdescribeshowtoloadyour objectsfromthedatabaseresultsets. parameterMapDeprecated!Oldschoolwaytomapparameters.Inlineparametersare preferredandthiselementmayberemovedinthefuture.Notdocumentedhere. sqlAreusablechunkofSQLthatcanbereferencedbyotherstatements.
16August2009
20
Thenextsectionswilldescribeeachoftheseelementsindetail,startingwiththestatements themselves.
select
TheselectstatementisoneofthemostpopularelementsthatyoulluseiniBATIS.Puttingdataina databaseisntterriblyvaluableuntilyougetitbackout,somostapplicationsqueryfarmorethanthey modifythedata.Foreveryinsert,updateordelete,thereisprobablymanyselects.Thisisoneofthe foundingprinciplesofiBATIS,andisthereasonsomuchfocusandeffortwasplacedonqueryingand resultmapping.Theselectelementisquitesimpleforsimplecases.Forexample:
<select id=selectPerson parameterType=int resultType=hashmap> SELECT * FROM PERSON WHERE ID = #{id} </select>
ThistellsiBATIStocreateaPreparedStatementparameter.WithJDBC,suchaparameterwouldbe identifiedbya?inSQLpassedtoanewPreparedStatement,somethinglikethis:
// Similar JDBC code, NOT iBATIS String selectPerson = SELECT * FROM PERSON WHERE ID=?; PreparedStatement ps = conn.prepareStatement(selectPerson); ps.setInt(1,id);
16August2009
21
iBATIS3UserGuide
resultMap=personResultMap flushCache=false useCache=true timeout=10000 fetchSize=256 statementType=PREPARED resultSetType=FORWARD_ONLY >
resultMap
resultSetType
Description Auniqueidentifierinthisnamespacethatcanbeusedtoreferencethisstatement. Thefullyqualifiedclassnameoraliasfortheparameterthatwillbepassedintothis statement. ThisisadeprecatedapproachtoreferencinganexternalparameterMap.Useinline parametermappingsandtheparameterTypeattribute. Thefullyqualifiedclassnameoraliasfortheexpectedtypethatwillbereturned fromthisstatement.Notethatinthecaseofcollections,thisshouldbethetype thatthecollectioncontains,notthetypeofthecollectionitself.UseresultTypeOR resultMap,notboth. AnamedreferencetoanexternalresultMap.Resultmapsarethemostpowerful featureofiBATIS,andwithagoodunderstandingofthem,manydifficultmapping casescanbesolved.UseresultMapORresultType,notboth. Settingthistotruewillcausethecachetobeflushedwheneverthisstatementis called.Default:falseforselectstatements. Settingthistotruewillcausetheresultsofthisstatementtobecached.Default: trueforselectstatements. Thissetsthemaximumtimethedriverwillwaitforthedatabasetoreturnfroma request,beforethrowinganexception.Defaultisunset(driverdependent). Thisisadriverhintthatwillattempttocausethedrivertoreturnresultsinbatches ofrowsnumberinginsizeequaltothissetting.Defaultisunset(driverdependent). AnyoneofSTATEMENT,PREPAREDorCALLABLE.ThiscausesiBATIStouse Statement,PreparedStatementorCallableStatementrespectively.Default: PREPARED. AnyoneofFORWARD_ONLY|SCROLL_SENSITIVE|SCROLL_INSENSITIVE.Defaultis unset(driverdependent).
insert,update,delete
Thedatamodificationstatementsinsert,updateanddeleteareverysimilarintheirimplementation:
<insert id="insertAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" keyProperty="" useGeneratedKeys="" timeout="20000">
<update id="insertAuthor"
16August2009
22
iBATIS3UserGuide
parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" timeout="20000">
Attribute id parameterType
Description Auniqueidentifierinthisnamespacethatcanbeusedtoreferencethisstatement. Thefullyqualifiedclassnameoraliasfortheparameterthatwillbepassedintothis statement. parameterMap ThisisadeprecatedapproachtoreferencinganexternalparameterMap.Use inlineparametermappingsandtheparameterTypeattribute. flushCache Settingthistotruewillcausethecachetobeflushedwheneverthisstatementis called.Default:falseforselectstatements. timeout Thissetsthemaximumtimethedriverwillwaitforthedatabasetoreturnfroma request,beforethrowinganexception.Defaultisunset(driverdependent). statementType AnyoneofSTATEMENT,PREPAREDorCALLABLE.ThiscausesiBATIStouse Statement,PreparedStatementorCallableStatementrespectively.Default: PREPARED. useGeneratedKeys (insertonly)ThistellsiBATIStousetheJDBCgetGeneratedKeysmethodtoretrieve keysgeneratedinternallybythedatabase(e.g.autoincrementfieldsinRDBMSlike MySQLorSQLServer).Default:false keyProperty (insertonly)IdentifiesapropertyintowhichiBATISwillsetthekeyvaluereturned bygetGeneratedKeys,orbyaselectKeychildelementoftheinsertstatement. Default:unset. Thefollowingaresomeexamplesofinsert,updateanddeletestatemens.
<insert id="insertAuthor" parameterType="domain.blog.Author"> insert into Author (id,username,password,email,bio) values (#{id},#{username},#{password},#{email},#{bio}) </insert> <update id="updateAuthor" parameterType="domain.blog.Author"> update Author set username = #{username}, password = #{password}, email = #{email}, bio = #{bio} where id = #{id} </update> <delete id="deleteAuthor parameterType="int"> delete from Author where id = #{id} </delete>
16August2009 23
16August2009
24
statementType
sql
ThiselementcanbeusedtodefineareusablefragmentofSQLcodethatcanbeincludedinother statements.Forexample:
<sql id=userColumns> id,username,password </sql>
TheSQLfragmentcanthenbeincludedinanotherstatement,forexample:
<select id=selectUsers parameterType=int resultType=hashmap> select <include refid=userColumns/> from some_table where id = #{id} </select>
Parameters
Inallofthepaststatements,youveseenexamplesofsimpleparameters.Parametersareverypowerful elementsiniBATIS.Forsimplesituations,probably90%ofthecases,theresnotmuchtoothem,for example:
<select id=selectUsers parameterType=int resultType=User> select id, username, password from users where id = #{id} </select>
16August2009
25
iBATIS3UserGuide
#{property,javaType=int,jdbcType=NUMERIC}
Soalreadyitseemstobegettingverbose,butthetruthisthatyoullrarelysetanyofthese. FornumerictypestheresalsoanumericScalefordetermininghowmanydecimalplacesarerelevant.
#{height,javaType=double,jdbcType=NUMERIC,numericScale=2}
Despiteallofthesepowerfuloptions,mostofthetimeyoullsimplyspecifythepropertyname,and iBATISwillfigureouttherest.Atmost,youllspecifythejdbcTypefornullablecolumns.
#{firstName} #{middleInitial,jdbcType=VARCHAR} #{lastName}
HereiBATISwontmodifyorescapethestring.
16August2009
26
iBATIS3UserGuide
resultMap
TheresultMapelementisthemostimportantandpowerfulelementiniBATIS.Itswhatallowsyoutodo awaywith90%ofthecodethatJDBCrequirestoretrievedatafromResultSets,andinsomecasesallows youtodothingsthatJDBCdoesnotevensupport.Infact,towritetheequivalentcodeforsomething likeajoinmappingforacomplexstatementcouldprobablyspanthousandsoflinesofcode.Thedesign oftheResultMapsissuchthatsimplestatementsdontrequireexplicitresultmappingsatall,andmore complexstatementsrequirenomorethanisabsolutelynecessarytodescribetherelationships. YouvealreadyseenexamplesofsimplemappedstatementsthatdonthaveanexplicitresultMap.For example:
<select id=selectUsers parameterType=int resultType=hashmap> select id, username, hashedPassword from some_table where id = #{id} </sql>
iBATIS3UserGuide SuchaJavaBeancouldbemappedtoaResultSetjustaseasilyastheHashMap.
<select id=selectUsers parameterType=int resultType=com.someapp.model.User> select id, username, hashedPassword from some_table where id = #{id} </sql>
AndrememberthatTypeAliasesareyourfriend.Usethemsothatyoudonthavetokeeptypingthe fullyqualifiedpathofyourclassout.Forexample:
<!-- In Config XML file --> <typeAlias type=com.someapp.model.User alias=User/> <!-- In SQL Mapping XML file --> <select id=selectUsers parameterType=int resultType=User> select id, username, hashedPassword from some_table where id = #{id} </sql>
AndthestatementthatreferencesitusestheresultMapattributetodoso(noticeweremovedthe resultTypeattribute).Forexample:
<select id=selectUsers parameterType=int resultMap=userResultMap>
16August2009
28
iBATIS3UserGuide
select user_id, user_name, hashed_password from some_table where id = #{id} </sql>
Nowifonlytheworldwerealwaysthatsimple.
AdvancedResultMapping
iBATISwascreatedwithoneideainmind:Databasesarentalwayswhatyouwantorneedthemtobe. Whilewedloveeverydatabasetobeperfect3rdnormalformorBCNF,theyarent.Anditwouldbe greatifitwaspossibletohaveasingledatabasemapperfectlytoalloftheapplicationsthatuseit,its not.ResultMapsaretheanswerthatiBATISprovidestothisproblem. Forexample,howwouldwemapthisstatement?
<!-- Very Complex Statement --> <select id="selectBlogDetails" parameterType="int" resultMap="detailedBlogResultMap"> select B.id as blog_id, B.title as blog_title, B.author_id as blog_author_id, A.id as author_id, A.username as author_username, A.password as author_password, A.email as author_email, A.bio as author_bio, A.favourite_section as author_favourite_section, P.id as post_id, P.blog_id as post_blog_id, P.author_id as post_author_id, P.created_on as post_created_on, P.section as post_section, P.subject as post_subject, P.draft as draft, P.body as post_body, C.id as comment_id, C.post_id as comment_post_id, C.name as comment_name, C.comment as comment_text, T.id as tag_id, T.name as tag_name from Blog B left outer join Author A on B.author_id = A.id left outer join Post P on B.id = P.blog_id left outer join Comment C on P.id = C.post_id left outer join Post_Tag PT on PT.post_id = P.id left outer join Tag T on PT.tag_id = T.id where B.id = #{id} </select>
16August2009
29
iBATIS3UserGuide
<!-- Very Complex Result Map --> <resultMap id="detailedBlogResultMap" type="Blog"> <constructor> <idArg column="id" javaType="int"/> </constructor> <result property="title" column="blog_title"/> <association property="author" column="blog_author_id" javaType=" Author"> <id property="id" column="author_id"/> <result property="username" column="author_username"/> <result property="password" column="author_password"/> <result property="email" column="author_email"/> <result property="bio" column="author_bio"/> <result property="favouriteSection" column="author_favourite_section"/> </association> <collection property="posts" ofType="Post"> <id property="id" column="post_id"/> <result property="subject" column="post_subject"/> <association property="author" column="post_author_id" javaType="Author"/> <collection property="comments" column="post_id" ofType=" Comment"> <id property="id" column="comment_id"/> </collection> <collection property="tags" column="post_id" ofType=" Tag" > <id property="id" column="tag_id"/> </collection> <discriminator javaType="int" column="draft"> <case value="1" resultType="DraftPost"/> </discriminator> </collection> </resultMap>
TheresultMapelementhasanumberofsubelementsandastructureworthyofsomediscussion.The followingisaconceptualviewoftheresultMapelement. resultMap constructorusedforinjectingresultsintotheconstructorofaclassuponinstantiation o idArgIDargument;flaggingresultsasIDwillhelpimproveoverallperformance o arganormalresultinjectedintotheconstructor idanIDresult;flaggingresultsasIDwillhelpimproveoverallperformance resultanormalresultinjectedintoafieldorJavaBeanproperty associationacomplextypeassociation;manyresultswillrollupintothistype o nestedresultmappingsassociationsareresultMapsthemselves,orcanreferto one collectionacollectionofcomplextypes o nestedresultmappingscollectionsareresultMapsthemselves,orcanrefertoone discriminatorusesaresultvaluetodeterminewhichresultMaptouse o caseacaseisaresultmapbasedonsomevalue nestedresultmappingsacaseisalsoaresultmapitself,andthuscan containmanyofthesesameelements,oritcanrefertoanexternal resultMap. BestPractice:AlwaysbuildResultMapsincrementally.Unittestsreallyhelpouthere.Ifyou trytobuildagiganticresultMapliketheoneaboveallatonce,itslikelyyoullgetitwrongandit willbehardtoworkwith.Startsimple,andevolveitastepatatime.Andunittest!The downsidetousingframeworksisthattheyaresometimesabitofablackbox(opensourceor
16August2009
30
id,result
Thesearethemostbasicofresultmappings.Bothid,andresultmapasinglecolumnvaluetoasingle propertyorfieldofasimpledatatype(String,int,double,Date,etc.). Theonlydifferencebetweenthetwoisthatidwillflagtheresultasanidentifierpropertytobeused whencomparingobjectinstances.Thishelpstoimprovegeneralperformance,butespecially performanceofcachingandnestedresultmapping(i.e.joinmapping). Eachhasanumberofattributes: Attribute Description property Thefieldorpropertytomapthecolumnresultto.IfamatchingJavaBeansproperty existsforthegivenname,thenthatwillbeused.Otherwise,iBATISwilllookforafield ofthegivenname.Inbothcasesyoucanusecomplexpropertynavigationusingthe usualdotnotation.Forexample,youcanmaptosomethingsimplelike:username, ortosomethingmorecomplicatedlike:address.street.number. column Thecolumnnamefromthedatabase,orthealiasedcolumnlabel.Thisisthesame stringthatwouldnormallybepassedtoresultSet.getString(columnName). javaType AfullyqualifiedJavaclassname,oratypealias(seethetableaboveforthelistofbuilt intypealiases).iBATIScanusuallyfigureoutthetypeifyouremappingtoaJavaBean. However,ifyouaremappingtoaHashMap,thenyoushouldspecifythejavaType explicitlytoensurethedesiredbehaviour. jdbcType TheJDBCTypefromthelistofsupportedtypesthatfollowsthistable.TheJDBCtypeis onlyrequiredfornullablecolumnsuponinsert,updateordelete.ThisisaJDBC requirement,notaniBATISone.SoevenifyouwerecodingJDBCdirectly,youdneed tospecifythistypebutonlyfornullablevalues. typeHandler Wediscusseddefaulttypehandlerspreviouslyinthisdocumentation.Usingthis propertyyoucanoverridethedefaulttypehandleronamappingbymappingbasis. ThevalueiseitherafullyqualifiedclassnameofaTypeHandlerimplementation,ora typealias.
<id property="id" column="post_id"/> <result property="subject" column="post_subject"/>
SupportedJDBCTypes
Forfuturereference,iBATISsupportsthefollowingJDBCTypesviatheincludedJdbcTypeenumeration.
BIT TINYINT SMALLINT INTEGER BIGINT FLOAT REAL DOUBLE NUMERIC DECIMAL CHAR VARCHAR LONGVARCHAR DATE TIME TIMESTAMP BINARY VARBINARY LONGVARBINARY NULL OTHER BLOB CLOB BOOLEAN CURSOR UNDEFINED NVARCHAR NCHAR NCLOB
16August2009
31
iBATIS3UserGuide
constructor
<constructor> <idArg column="id" javaType="int"/> <arg column=username javaType=String/> </constructor>
Therestoftheattributesandrulesarethesameasfortheregularidandresultelements. Attribute Description column Thecolumnnamefromthedatabase,orthealiasedcolumnlabel.Thisisthesame stringthatwouldnormallybepassedtoresultSet.getString(columnName). javaType AfullyqualifiedJavaclassname,oratypealias(seethetableaboveforthelistofbuilt intypealiases).iBATIScanusuallyfigureoutthetypeifyouremappingtoaJavaBean. However,ifyouaremappingtoaHashMap,thenyoushouldspecifythejavaType explicitlytoensurethedesiredbehaviour. jdbcType TheJDBCTypefromthelistofsupportedtypesthatfollowsthistable.TheJDBCtypeis onlyrequiredfornullablecolumnsuponinsert,updateordelete.ThisisaJDBC requirement,notaniBATISone.SoevenifyouwerecodingJDBCdirectly,youdneed tospecifythistypebutonlyfornullablevalues. typeHandler Wediscusseddefaulttypehandlerspreviouslyinthisdocumentation.Usingthis propertyyoucanoverridethedefaulttypehandleronamappingbymappingbasis. ThevalueiseitherafullyqualifiedclassnameofaTypeHandlerimplementation,ora typealias.
16August2009
32
iBATIS3UserGuide
association
<association property="author" column="blog_author_id" javaType=" Author"> <id property="id" column="author_id"/> <result property="username" column="author_username"/> </association>
Theassociationelementdealswithahasonetyperelationship.Forexample,inourexample,aBlog hasoneAuthor.Anassociationmappingworksmostlylikeanyotherresult.Youspecifythetarget property,thecolumntoretrievethevaluefrom,thejavaTypeoftheproperty(whichiBATIScanfigure outmostofthetime),thejdbcTypeifnecessaryandatypeHandlerifyouwanttooverridetheretrieval oftheresultvalues. WheretheassociationdiffersisthatyouneedtotelliBATIShowtoloadtheassociation.iBATIScando sointwodifferentways: NestedSelect:ByexecutinganothermappedSQLstatementthatreturnsthecomplextype desired. NestedResults:Byusingnestedresultmappingstodealwithrepeatingsubsetsofjoined results. First,letsexaminethepropertiesoftheelement.Asyoullsee,itdiffersfromanormalresultmapping onlybytheselectandresultMapattributes. Attribute Description property Thefieldorpropertytomapthecolumnresultto.IfamatchingJavaBeansproperty existsforthegivenname,thenthatwillbeused.Otherwise,iBATISwilllookforafield ofthegivenname.Inbothcasesyoucanusecomplexpropertynavigationusingthe usualdotnotation.Forexample,youcanmaptosomethingsimplelike:username, ortosomethingmorecomplicatedlike:address.street.number. column Thecolumnnamefromthedatabase,orthealiasedcolumnlabel.Thisisthesame stringthatwouldnormallybepassedtoresultSet.getString(columnName). Note:Todealwithcompositekeys,youcanspecifymultiplecolumnnamestopass tothenestedselectstatementbyusingthesyntax column={prop1=col1,prop2=col2}.Thiswillcauseprop1andprop2tobesetagainst theparameterobjectforthetargetnestedselectstatement. javaType AfullyqualifiedJavaclassname,oratypealias(seethetableaboveforthelistofbuilt intypealiases).iBATIScanusuallyfigureoutthetypeifyouremappingtoaJavaBean. However,ifyouaremappingtoaHashMap,thenyoushouldspecifythejavaType explicitlytoensurethedesiredbehaviour. jdbcType TheJDBCTypefromthelistofsupportedtypesthatfollowsthistable.TheJDBCtypeis onlyrequiredfornullablecolumnsuponinsert,updateordelete.ThisisaJDBC requirement,notaniBATISone.SoevenifyouwerecodingJDBCdirectly,youdneed tospecifythistypebutonlyfornullablevalues. typeHandler Wediscusseddefaulttypehandlerspreviouslyinthisdocumentation.Usingthis propertyyoucanoverridethedefaulttypehandleronamappingbymappingbasis. ThevalueiseitherafullyqualifiedclassnameofaTypeHandlerimplementation,ora
16August2009
33
Forexample:
<resultMap id=blogResult type=Blog> <association property="author" column="blog_author_id" javaType="Author" select=selectAuthor/> </resultMap> <select id=selectBlog parameterType=int resultMap=blogResult> SELECT * FROM BLOG WHERE ID = #{id} </select> <select id=selectAuthor parameterType=int resultType="Author"> SELECT * FROM AUTHOR WHERE ID = #{id} </select>
Thatsit.Wehavetwoselectstatements:onetoloadtheBlog,theothertoloadtheAuthor,andthe BlogsresultMapdescribesthattheselectAuthorstatementshouldbeusedtoloaditsauthor property. Allotherpropertieswillbeloadedautomaticallyassumingtheircolumnandpropertynamesmatch. Whilethisapproachissimple,itwillnotperformwellforlargedatasetsorlists.Thisproblemisknown astheN+1SelectsProblem.Inanutshell,theN+1selectsproblemiscausedlikethis: YouexecuteasingleSQLstatementtoretrievealistofrecords(the+1). Foreachrecordreturned,youexecuteaselectstatementtoloaddetailsforeach(theN). ThisproblemcouldresultinhundredsorthousandsofSQLstatementstobeexecuted.Thisisnot alwaysdesirable. TheupsideisthatiBATIScanlazyloadsuchqueries,thusyoumightbesparedthecostofthese statementsallatonce.However,ifyouloadsuchalistandthenimmediatelyiteratethroughitto accessthenesteddata,youwillinvokeallofthelazyloads,andthusperformancecouldbeverybad. Andso,thereisanotherway. NestedResultsforAssociation
16August2009
34
Noticethejoin,aswellasthecaretakentoensurethatallresultsarealiasedwithauniqueandclear name.Thismakesmappingfareasier.Nowwecanmaptheresults:
<resultMap id="blogResult" type="Blog"> <id property=blog_id column="id" /> <result property="title" column="blog_title"/> <association property="author" column="blog_author_id" javaType="Author" resultMap=authorResult/> </resultMap>
<resultMap id="authorResult" type="Author"> <id property="id" column="author_id"/> <result property="username" column="author_username"/> <result property="password" column="author_password"/> <result property="email" column="author_email"/> <result property="bio" column="author_bio"/> </resultMap>
16August2009
35
Youveseenabovehowtodealwithahasonetypeassociation.Butwhatabouthasmany?Thats thesubjectofthenextsection.
collection
<collection property="posts" ofType="domain.blog.Post"> <id property="id" column="post_id"/> <result property="subject" column="post_subject"/> <result property="body" column="post_body"/> </collection>
16August2009
36
iBATIS3UserGuide
Readas:AcollectionofpostsinanArrayListoftypePost.
ThejavaTypeattributeisreallyunnecessary,asiBATISwillfigurethisoutforyouinmostcases.Soyou canoftenshortenthisdowntosimply:
<collection property="posts" column="blog_id" ofType="Post" select=selectPostsForBlog/>
Again,wevejoinedtheBlogandPosttables,andhavetakencaretoensurequalityresultcolumnlabels forsimplemapping.NowmappingaBlogwithitscollectionofPostmappingsisassimpleas:
<resultMap id="blogResult" type="Blog"> <id property=id column="blog_id" /> <result property="title" column="blog_title"/> <collection property="posts" ofType="Post"> <id property="id" column="post_id"/> <result property="subject" column="post_subject"/> <result property="body" column="post_body"/> </collection> </resultMap>
iBATIS3UserGuide
<resultMap id="blogResult" type="Blog"> <id property=id column="blog_id" /> <result property="title" column="blog_title"/> <collection property="posts" ofType="Post" resultMap=blogPostResult/> </resultMap> <resultMap id="blogPostResult" type="Post"> <id property="id" column="post_id"/> <result property="subject" column="post_subject"/> <result property="body" column="post_body"/> </resultMap>
discriminator
<discriminator javaType="int" column="draft"> <case value="1" resultType="DraftPost"/> </discriminator>
16August2009
38
16August2009
39
iBATIS3UserGuide
cache
iBATIShasincludesapowerfulquerycachingfeaturewhichisveryconfigurableandcustomizable.Alot ofchangeshavebeenmadeintheiBATIS3cacheimplementationtomakeitbothmorepowerfuland fareasiertoconfigure. Bydefault,thereisnocachingenabled,exceptforlocalsessioncaching,whichimprovesperformance andisrequiredtoresolvecirculardependencies.Toenableasecondlevelofcaching,yousimplyneed toaddonelinetoyourSQLMappingfile:
<cache/>
Allofthesepropertiesaremodifiablethroughtheattributesofthecacheelement.Forexample:
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
16August2009
40
iBATIS3UserGuide SOFTSoftReference:Removesobjectsbasedonthegarbagecollectorstateandtherulesof SoftReferences. WEAKWeakReference:Moreaggressivelyremovesobjectsbasedonthegarbagecollector stateandrulesofWeakReferences. ThedefaultisLRU. TheflushIntervalcanbesettoanypositiveintegerandshouldrepresentareasonableamountoftime specifiedinmilliseconds.Thedefaultisnotset,thusnoflushintervalisusedandthecacheisonly flushedbycallstostatements. Thesizecanbesettoanypositiveinteger,keepinmindthesizeoftheobjectsyourcachingandthe availablememoryresourcesofyourenvironment.Thedefaultis1024. ThereadOnlyattributecanbesettotrueorfalse.Areadonlycachewillreturnthesameinstanceof thecachedobjecttoallcallers.Thussuchobjectsshouldnotbemodified.Thisoffersasignificant performanceadvantagethough.Areadwritecachewillreturnacopy(viaserialization)ofthecached object.Thisisslower,butsafer,andthusthedefaultisfalse.
UsingaCustomCache
Inadditiontocustomizingthecacheintheseways,youcanalsocompletelyoverridethecachebehavior byimplementingyourowncache,orcreatinganadaptertoother3rdpartycachingsolutions.
<cache type=com.domain.something.MyCustomCache/>
16August2009
41
iBATIS3UserGuide
<property name=cacheFile value=/tmp/my-custom-cache.tmp/> </cache>
cacheref
Recallfromtheprevioussectionthatonlythecacheforthisparticularnamespacewillbeusedor flushedforstatementswithinthesamenamespace.Theremaycomeatimewhenyouwanttoshare thesamecacheconfigurationandinstancebetweennamespaces.Insuchcasesyoucanreference anothercachebyusingthecacherefelement.
<cache-ref namespace=com.someone.application.data.SomeMapper/>
DynamicSQL
OneofthemostpowerfulfeaturesofiBATIShasalwaysbeenitsDynamicSQLcapabilities.Ifyouhave anyexperiencewithJDBCoranysimilarframework,youunderstandhowpainfulitistoconditionally concatenatestringsofSQLtogether,makingsurenottoforgetspacesortoomitacommaattheendof alistofcolumns.DynamicSQLcanbedownrightpainfultodealwith. WhileworkingwithDynamicSQLwillneverbeaparty,iBATIScertainlyimprovesthesituationwitha powerfulDynamicSQLlanguagethatcanbeusedwithinanymappedSQLstatement. TheDynamicSQLelementsshouldbefamiliartoanyonewhohasusedJSTLoranysimilarXMLbased textprocessors.InpreviousversionsofiBATIS,therewerealotofelementstoknowandunderstand. iBATIS3greatlyimprovesuponthis,andnowtherearelessthanhalfofthoseelementstoworkwith. iBATISemployspowerfulOGNLbasedexpressionstoeliminatemostoftheotherelements.
16August2009
42
if
ThemostcommonthingtodoindynamicSQLisconditionallyincludeapartofawhereclause.For example:
<select id=findActiveBlogWithTitleLike parameterType=Blog resultType=Blog> SELECT * FROM BLOG WHERE state = ACTIVE <if test=title != null> AND title like #{title} </if> </select>
choose,when,otherwise
Sometimeswedontwantalloftheconditionalstoapply,insteadwewanttochooseonlyonecase amongmanyoptions.SimilartoaswitchstatementinJava,iBATISoffersachooseelement. Letsusetheexampleabove,butnowletssearchonlyontitleifoneisprovided,thenonlybyauthorif oneisprovided.Ifneitherisprovided,letsonlyreturnfeaturedblogs(perhapsastrategicallylist selectedbyadministrators,insteadofreturningahugemeaninglesslistofrandomblogs).
<select id=findActiveBlogLike parameterType=Blog resultType=Blog> SELECT * FROM BLOG WHERE state = ACTIVE
16August2009
43
iBATIS3UserGuide
<choose> <when test=title != null> AND title like #{title} </when> <when test=author != null && author.name != null> AND title like #{author.name} </when> <otherwise> AND featured = 1 </otherwise> </choose> </select>
trim,where,set
ThepreviousexampleshavebeenconvenientlydancingaroundanotoriousdynamicSQLchallenge. Considerwhatwouldhappenifwereturntoourifexample,butthistimewemakeACTIVE=1a dynamicconditionaswell.
<select id=findActiveBlogLike parameterType=Blog resultType=Blog> SELECT * FROM BLOG WHERE <if test=state != null> state = #{state} </if> <if test=title != null> AND title like #{title} </if> <if test=author != null && author.name != null> AND title like #{author.name} </if> </select>
Whathappensifnoneoftheconditionsaremet?YouwouldendupwithSQLthatlookedlikethis:
SELECT * FROM BLOG WHERE
Thiswouldfail.Whatifonlythesecondconditionwasmet?YouwouldendupwithSQLthatlookedlike this:
SELECT * FROM BLOG WHERE AND title like someTitle
16August2009
44
iBATIS3UserGuide
SELECT * FROM BLOG <where> <if test=state != null> state = #{state} </if> <if test=title != null> AND title like #{title} </if> <if test=author != null && author.name != null> AND title like #{author.name} </if> </where> </select>
16August2009
45
iBATIS3UserGuide Noticethatinthiscasewereoverridingasuffix,whilewerestillappendingaprefix.
foreach
AnothercommonnecessityfordynamicSQListheneedtoiterateoveracollection,oftentobuildanIN condition.Forexample:
<select id="selectPostIn" resultType="domain.blog.Post"> SELECT * FROM POST P WHERE ID in <foreach item="item" index="index" collection="list" open="(" separator="," close=")"> #{item} </foreach> </select>
Theforeachelementisverypowerful,andallowsyoutospecifyacollection,declareitemandindex variablesthatcanbeusedinsidethebodyoftheelement.Italsoallowsyoutospecifyopeningand closingstrings,andaddaseparatortoplaceinbetweeniterations.Theelementissmartinthatitwont accidentallyappendextraseparators. Note:YoucanpassaListinstanceoranArraytoiBATISasaparameterobject.Whenyoudo, iBATISwillautomaticallywrapitinaMap,andkeyitbyname.Listinstanceswillbekeyedtothe namelistandarrayinstanceswillbekeyedtothenamearray. ThiswrapsupthediscussionregardingtheXMLconfigurationfileandXMLmappingfiles.Thenext sectionwilldiscusstheJavaAPIindetail,sothatyoucangetthemostoutofthemappingsthatyouve created.
16August2009
46
iBATIS3UserGuide
JavaAPI
NowthatyouknowhowtoconfigureiBATISandcreatemappings,yourereadyforthegoodstuff.The iBATISJavaAPIiswhereyougettoreaptherewardsofyourefforts.Asyoullsee,comparedtoJDBC, iBATISgreatlysimplifiesyourcodeandkeepsitclean,easytounderstandandmaintain.iBATIS3has introducedanumberofsignificantimprovementstomakeworkingwithSQLMapsevenbetter.
DirectoryStructure
BeforewediveintotheJavaAPIitself,itsimportanttounderstandthebestpracticessurrounding directorystructures.iBATISisveryflexible,andyoucandoalmostanythingwithyourfiles.Butaswith anyframework,theresapreferredway. Letslookatatypicalapplicationdirectorystructure: /my_application /bin /devlib
/lib
/src /org/myapp/ /action
iBATIS artifacts go here, including, Mapper Classes, XML Configuration, XML Mapping Files.
/properties
/test /org/myapp/ /action /data /model /service /view /properties /web /WEB-INF /web.xml
Remember, these are preferences, not requirements, but others will thank you for using a common directory structure.
Therestoftheexamplesinthissectionwillassumeyourefollowingthisdirectorystructure. 16August2009 47
iBATIS3UserGuide
SqlSessions
TheprimaryJavainterfaceforworkingwithiBATISistheSqlSession.Throughthisinterfaceyoucan executecommands,getmappersandmanagetransactions.WelltalkmoreaboutSqlSessionitself shortly,butfirstwehavetolearnhowtoacquireaninstanceofSqlSession.SqlSessionsarecreatedby aSqlSessionFactoryinstance.TheSqlSessionFactorycontainsmethodsforcreatinginstancesof SqlSessionsalldifferentways.TheSqlSessionFactoryitselfiscreatedbytheSqlSessionFactoryBuilder thatcancreatetheSqlSessonFactoryfromXML,AnnotationsorhandcodedJavaconfiguration.
SqlSessionFactoryBuilder
TheSqlSessionFactoryBuilderhasfivebuild()methods,eachwhichallowsyoutobuildaSqlSessionfrom adifferentsource.
SqlSessionFactory SqlSessionFactory SqlSessionFactory SqlSessionFactory SqlSessionFactory build(Reader reader) build(Reader reader, String environment) build(Reader reader, Properties properties) build(Reader reader, String env, Properties props) build(Configuration config)
16August2009
48
iBATIS3UserGuide
RecallthatpropertiescanalsobereferencedfromtheSqlMapConfig.xmlfile,orspecifieddirectlywithin it.Thereforeitsimportanttounderstandthepriority.Wementioneditearlierinthisdocument,but hereitisagainforeasyreference: Ifapropertyexistsinmorethanoneoftheseplaces,iBATISloadstheminthefollowingorder: Propertiesspecifiedinthebodyofthepropertieselementarereadfirst, Propertiesloadedfromtheclasspathresourceorurlattributesoftheproperties elementarereadsecond,andoverrideanyduplicatepropertiesalreadyspecified, Propertiespassedasamethodparameterarereadlast,andoverrideanyduplicate propertiesthatmayhavebeenloadedfromthepropertiesbodyandtheresource/url attributes.
16August2009 49
iBATIS3UserGuide
NowyouhaveaSqlSessionFactory,thatcanbeusedtocreateSqlSessioninstances.
SqlSessionFactory
SqlSessionFactoryhassixmethodsthatareusedtocreateSqlSessionInstances.Ingeneral,thedecisions youllbemakingwhenselectingoneofthesemethodsare: Transaction:Doyouwanttouseatransactionscopeforthesession,oruseautocommit (usuallymeansnotransactionwithmostdatabasesand/orJDBCdrivers)? Connection:DoyouwantiBATIStoacquireaConnectionfromtheconfiguredDataSourcefor you,ordoyouwanttoprovideyourown? Execution:DoyouwantiBATIStoreusePreparedStatementsand/orbatchupdates(including insertsanddeletes)?
ThesetofoverloadedopenSession()methodsignaturesallowyoutochooseanycombinationofthese optionsthatmakessense.
SqlSession openSession() SqlSession openSession(boolean autoCommit) SqlSession openSession(Connection connection) SqlSession openSession(ExecutorType execType) SqlSession openSession(ExecutorType execType, boolean autoCommit) SqlSession openSession(ExecutorType execType, Connection connection) Configuration getConfiguration();
16August2009
50
Mostofthemethodsareprettyselfexplanatory.Toenableautocommit,passavalueoftruetothe optionalautoCommitparameter.Toprovideyourownconnection,passaninstanceofConnectionto theconnectionparameter.NotethattheresnooverridetosetboththeConnectionandautoCommit, becauseiBATISwillusewhateversettingtheprovidedconnectionobjectiscurrentlyusing. TheoneparameterthatmightbenewtoyouisExecutorType.Thisenumerationdefines3values: ExecutorType.SIMPLE Thistypeofexecutordoesnothingspecial.ItcreatesanewPreparedStatementforeach executionofastatement. ExecutorType.REUSE ThistypeofexecutorwillreusePreparedStatements. ExecutorType.BATCH ThisexecutorwillbatchallupdatestatementsanddemarcatethemasnecessaryifSELECTsare executedbetweenthem,toensureaneasytounderstandbehavior. Note:TheresonemoremethodontheSqlSessionFactorythatwedidntmention,andthatis getConfiguration().ThismethodwillreturnaninstanceofConfigurationthatyoucanusetointrospect upontheiBATISconfigurationatruntime. Note:IfyouveusedapreviousversionofiBATIS,youllrecallthatsessions,transactionsandbatches wereallsomethingseparate.Thisisnolongerthecase.Allthreeareneatlycontainedwithinthescope ofasesson.Youneednotdealwithtransactionsorbatchesseparatelytogetthefullbenefitofthem.
SqlSession
Asmentionedabove,theSqlSessioninstanceisthemostpowerfulclassiniBATIS.Itiswhereyoullfind allofthemethodstoexecutestatements,commitorrollbacktransactionsandacquiremapper instances. ThreareovertwentymethodsontheSqlSessionclass,soletsbreakthemupintomoredigestible groupings.
StatementExecutionMethods
16August2009 51
iBATIS3UserGuide
Finally,therearethreeadvancedversionsoftheselectmethodsthatallowyoutorestricttherangeof rowstoreturn,orprovidecustomresulthandlinglogic,usuallyforverylargedatasets.
List selectList (String statement, Object parameter, int offset, int limit) void select (String statement, Object parameter, ResultHandler handler) void select (String statement, Object parameter, int offset, int limit, ResultHandler handler)
16August2009
52
TransactionControlMethods
Therearefourmethodsforcontrollingthescopeofatransaction.Ofcourse,thesehavenoeffectif youvechosentouseautocommitorifyoureusinganexternaltransactionmanager.However,if youreusingtheJDBCtransactionmanager,managedbytheConnectioninstance,thenthefour methodsthatwillcomeinhandyare:
void void void void commit() commit(boolean force) rollback() rollback(boolean force)
EnsuringthatSqlSessionisClosed
void close()
Themostimportantthingyoumustensureisthatyoucloseanysessionsthatyouopen.Thebestway toensurethisistousethefollowingunitofworkpattern:
SqlSession session = sqlSessionFactory.openSession(); try { // following 3 lines pseudocod for doing some work session.insert(); session.update(); session.delete(); session.commit(); } finally { session.close(); }
Note:JustlikeSqlSessionFactory,youcangettheinstanceofConfigurationthattheSqlSessionis usingbycallingthegetConfiguration()method.
Configuration getConfiguration()
16August2009
53
iBATIS3UserGuide
UsingMappers
<T> T getMapper(Class<T> type)
MapperAnnotations
Sincetheverybeginning,iBATIShasbeenanXMLdrivenframework.TheconfigurationisXMLbased, andtheMappedStatementsaredefinedinXML.WithiBATIS3,therearenewoptionsavailable.iBATIS 3buildsontopofacomprehensiveandpowerfulJavabasedConfigurationAPI.ThisConfigurationAPIis thefoundationfortheXMLbasediBATISconfiguration,aswellasthenewAnnotationbased configuration.Annotationsofferasimplewaytoimplementsimplemappedstatementswithout introducingalotofoverhead. Note:JavaAnnotationsareunfortunatelylimitedintheirexpressivenessandflexibility.Despitealot oftimespentininvestigation,designandtrials,themostpowerfuliBATISmappingssimplycannotbe builtwithAnnotationswithoutgettingridiculousthatis.C#Attributes(forexample)donotsuffer fromtheselimitations,andthusiBATIS.NETwillenjoyamuchricheralternativetoXML.Thatsaid,the JavaAnnotationbasedconfigurationisnotwithoutitsbenefits.
16August2009
54
@CacheNamespaceRef
Class
@ConstructorArgs
Method
@Arg
Method
@TypeDiscriminator
Method
@Case
Method
@Results
Method
@Result
Method
@One
Method
XMLEquivalent Description <cache> Configuresthecacheforthegivennamespace (i.e.class).Attributes:implementation, eviction,flushInterval,sizeandreadWrite. <cacheRef> Referencesthecacheofanothernamespaceto use.Attributes:value,whichshouldbethe stringvalueofanamespace(i.e.afullyqualified classname). <constructor> Collectsagroupofresultstobepassedtoa resultobjectconstructor.Attributes:value, whichisanarrayofArgs. <arg> Asingleconstructorargumentthatispartofa <idArg> ConstructorArgscollection.Attributes:id, column,javaType,jdbcType,typeHandler.The idattributeisabooleanvaluethatidentifiesthe propertytobeusedforcomparisons,similarto the<idArg>XMLelement. <discriminator> Agroupofvaluecasesthatcanbeusedto determinetheresultmappingtoperform. Attributes:column,javaType,jdbcType, typeHandler,cases.Thecasesattributeisan arrayofCases. <case> Asinglecaseofavalueanditscorresponding mappings.Attributes:value,type,results.The resultsattributeisanarrayofResults,thusthis CaseAnnotationissimilartoanactual ResultMap,specifiedbytheResultsannotation below. <resultMap> AlistofResultmappingsthatcontaindetailsof howaparticularresultcolumnismappedtoa propertyorfield.Attributes:value,whichisan arrayofResultannotations. <result> Asingleresultmappingbetweenacolumnand <id> apropertyorfield.Attributes:id,column, property,javaType,jdbcType,typeHandler, one,many.Theidattributeisabooleanvalue thatindicatesthatthepropertyshouldbeused forcomparisons(similarto<id>intheXML mappings).Theoneattributeisforsingle associations,similarto<association>,andthe manyattributeisforcollections,similarto <collection>.Theyarenamedastheyareto avoidclassnamingconflicts. <association> Amappingtoasinglepropertyvalueofa complextype.Attributes:select,whichisthe
16August2009
55
iBATIS3UserGuide
fullyqualifiednameofamappedstatement(i.e. mappermethod)thatcanloadaninstanceof theappropriatetype.Note:Youwillnoticethat joinmappingisnotsupportedviathe AnnotationsAPI.Thisisduetothelimitationin JavaAnnotationsthatdoesnotallowfor circularreferences. Amappingtoacollectionpropertyofacomplex types.Attributes:select,whichisthefully qualifiednameofamappedstatement(i.e. mappermethod)thatcanloadacollectionof instancesoftheappropriatetypes.Note:You willnoticethatjoinmappingisnotsupported viatheAnnotationsAPI.Thisisduetothe limitationinJavaAnnotationsthatdoesnot allowforcircularreferences. Thisannotationprovidesaccesstothewide rangeofswitchesandconfigurationoptions thatarenormallypresentonthemapped statementasattributes.Ratherthan complicateeachstatementannotation,the Optionsannotationprovidesaconsistentand clearwaytoaccessthese.Attributes: useCache=true,flushCache=false, resultSetType=FORWARD_ONLY, statementType=PREPARED,fetchSize=1, timeout=1,useGeneratedKeys=false, keyProperty=id.Itsimportanttounderstand thatwithJavaAnnotations,thereisnowayto specifynullasavalue.Therefore,onceyou engagetheOptionsannotation,yourstatement issubjecttoallofthedefaultvalues.Pay attentiontowhatthedefaultvaluesareto avoidunexpectedbehavior. Eachoftheseannotationsrepresentstheactual SQLthatistobeexecuted.Theyeachtakean arrayofstrings(orasinglestringwilldo).Ifan arrayofstringsispassed,theyareconcatenated withasinglespacebetweeneachtoseparate them.Thishelpsavoidthemissingspace problemwhenbuildingSQLinJavacode. However,yourealsowelcometoconcatenate togetherasinglestringifyoulike.Attributes: value,whichisthearrayofStringstoformthe singleSQLstatement. ThesealternativeSQLannotationsallowyouto specifyaclassnameandamethodthatwill returntheSQLtorunatexecutiontime.Upon
@Many
Method <collection>
@Options
executingthemappedstatement,iBATISwill instantiatetheclass,andexecutethemethod, asspecifiedbytheprovider.Themethodcan optionallyaccepttheparameterobjectasits soleparameter,butmustonlyspecifythat parameter,ornoparameters.Attributes:type, method.Thetypeattributeisthefullyqualified nameofaclass.Themethodisthenameofthe methodonthatclass.Note:Followingthis sectionisadiscussionabouttheSelectBuilder class,whichcanhelpbuilddynamicSQLina cleaner,easiertoreadway.
SelectBuilder
OneofthenastiestthingsaJavadeveloperwilleverhavetodoisembedSQLinJavacode.Usuallythis isdonebecausetheSQLhastobedynamicallygeneratedotherwiseyoucouldexternalizeitinafileor astoredproc.Asyouvealreadyseen,iBATIShasapowerfulanswerfordynamicSQLgenerationinits XMLmappingfeatures.However,sometimesitbecomesnecessarytobuildaSQLstatementstring insideofJavacode.Inthatcase,iBATIShasonemorefeaturetohelpyouout,beforereducingyourself tothetypicalmessofplussigns,quotes,newlines,formattingproblemsandnestedconditionalstodeal withextracommasorANDconjunctionsIndeed,dynamicallygeneratingSQLcodeinJavacanbeareal nightmare. iBATIS3introducesasomewhatdifferentconcepttodealwiththeproblem.Wecouldhavejustcreated aninstanceofaclassthatletsyoucallmethodsagainstittobuildaSQLstatementonestepatatime. ButthenourSQLendsuplookingmorelikeJavaandlesslikeSQL.Instead,weretryingsomethinga littledifferent.TheendresultisaboutasclosetoaDomainSpecificLanguagethatJavawilleverachieve initscurrentform TheSecretsofSelectBuilder TheSelectBuilderclassisnotmagical,nordoesitdoanyofusanygoodifyoudontknowhowitworks. Sorightoffthebat,letslookatwhatitdoes.SelectBuilderusesacombinationofStaticImportsanda ThreadLocalvariabletoenableacleansyntaxthatcanbeeasilyinterlacedwithconditionalsandtakes careofalloftheSQLformattingforyou.Itallowsustocreatemethodslikethis:
public String selectBlogsSql() { BEGIN(); // Clears ThreadLocal variable SELECT("*"); FROM("BLOG"); return SQL(); }
Thatsaprettysimpleexamplethatyoumightjustchoosetobuildstatically.Soheresamore complicatedexample:
16August2009
57
iBATIS3UserGuide
private String selectPersonSql() { BEGIN(); // Clears ThreadLocal variable SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FULL_NAME"); SELECT("P.LAST_NAME, P.CREATED_ON, P.UPDATED_ON"); FROM("PERSON P"); FROM("ACCOUNT A"); INNER_JOIN("DEPARTMENT D on D.ID = P.DEPARTMENT_ID"); INNER_JOIN("COMPANY C on D.COMPANY_ID = C.ID"); WHERE("P.ID = A.ID"); WHERE("P.FIRST_NAME like ?"); OR(); WHERE("P.LAST_NAME like ?"); GROUP_BY("P.ID"); HAVING("P.LAST_NAME like ?"); OR(); HAVING("P.FIRST_NAME like ?"); ORDER_BY("P.ID"); ORDER_BY("P.FULL_NAME"); return SQL(); }
BuildingtheaboveSQLwouldbeabitofatrialinStringconcatenation.Forexample:
"SELECT P.ID, P.USERNAME, P.PASSWORD, P.FULL_NAME, " "P.LAST_NAME,P.CREATED_ON, P.UPDATED_ON " + "FROM PERSON P, ACCOUNT A " + "INNER JOIN DEPARTMENT D on D.ID = P.DEPARTMENT_ID " + "INNER JOIN COMPANY C on D.COMPANY_ID = C.ID " + "WHERE (P.ID = A.ID AND P.FIRST_NAME like ?) " + "OR (P.LAST_NAME like ?) " + "GROUP BY P.ID " + "HAVING (P.LAST_NAME like ?) " + "OR (P.FIRST_NAME like ?) " + "ORDER BY P.ID, P.FULL_NAME";
16August2009
58
iBATIS3UserGuide
}
Whatissospecialaboutthatexample?Well,ifyoulookclosely,itdoesnthavetoworryabout accidentallyduplicatingANDkeywords,orchoosingbetweenWHEREandANDorneither!The statementabovewillgenerateaquerybyexampleforallPERSONrecords,oneswithIDlikethe parameter,orthefirstNameliketheparameter,orthelastNameliketheparameterorany combinationofthethree.TheSelectBuildertakescareofunderstandingwhereWHENneedstogo, whereanANDshouldbeusedandalloftheStringconcatenation.Bestofall,itdoesitalmost regardlessofwhichorderyoucallthesemethodsin(theresonlyoneexceptionwiththeOR()method). Thetwomethodsthatmaycatchyoureyeare:BEGIN()andSQL().Inanutshell,everySelectBuilder methodshouldstartwithacalltoBEGIN()andendwithacalltoSQL().Ofcourseyoucanextract methodsinthemiddletobreakupyourlogic,butthescopeoftheSQLgenerationshouldalwaysbegin withBEGIN()andendwithSQL().TheBEGIN()methodclearstheThreadLocalvariable,tomakesureyou dontaccidentallycarryanystateforward,andtheSQL()methodassemblesyourSQLstatementbased onthecallsyoumadesincethelastcalltoBEGIN().NotethatBEGIN()hasasynonymcalledRESET(), whichdoesexactlythesamethingbutreadsbetterincertaincontexts. TousetheSelectBuilderasintheexamplesabove,yousimplyneedtoimportitstaticallyasfollows:
import static org.apache.ibatis.jdbc.SelectBuilder.*;
Oncethisisimported,theclassyoureworkingwithinwillhavealloftheSelectBuildermethods availabletoit.Thecompletesetofmethodsisasfollows: Method BEGIN()/RESET() Description ThesemethodscleartheThreadLocalstateoftheSelectBuilderclass,and prepareitforanewstatementtobebuilt.BEGIN()readsbestwhen startinganewstatement.RESET()readsbestwhenclearingastatement inthemiddleofexecutionforsomereason(perhapsifthelogicdemands acompletelydifferentstatementundersomeconditions). StartsorappendstoaSELECTclause.Canbecalledmorethanonce,and parameterswillbeappendedtotheSELECTclause.Theparametersare usuallyacommaseparatedlistofcolumnsandaliases,butcanbe anythingacceptabletothedriver. StartsorappendstoaFROMclause.Canbecalledmorethanonce,and parameterswillbeappendedtotheFROMclause.Parametersareusually atablenameandanalias,oranythingacceptabletothedriver. AddsanewJOINclauseoftheappropriatetype,dependingonthe methodcalled.Theparametercanincludeastandardjoinconsistingof thecolumnsandtheconditionstojoinon.
SELECT(String)
FROM(String)
JOIN(String) INNER_JOIN(String) LEFT_OUTER_JOIN(String) RIGHT_OUTER_JOIN(String) WHERE(String) AppendsanewWHEREclausecondition,concatenatedbyAND.Canbe calledmultipletimes,whichcausesittoconcatenatethenewconditions eachtimewithAND.UseOR()tosplitwithanOR. OR() SplitsthecurrentWHEREclauseconditionswithanOR.Canbecalled 16August2009 59
iBATIS3UserGuide morethanonce,butcallingmorethanonceinarowwillgenerateerratic SQL. SplitsthecurrentWHEREclauseconditionswithanAND.Canbecalled morethanonce,butcallingmorethanonceinarowwillgenerateerratic SQL.BecauseWHEREandHAVINGbothautomaticallyconcatenatewith AND,thisisaveryuncommonmethodtouseandisonlyreallyincluded forcompleteness. AppendsanewGROUPBYclauseelements,concatenatedbyacomma. Canbecalledmultipletimes,whichcausesittoconcatenatethenew conditionseachtimewithacomma. AppendsanewHAVINGclausecondition,concatenatedbyAND.Canbe calledmultipletimes,whichcausesittoconcatenatethenewconditions eachtimewithAND.UseOR()tosplitwithanOR. AppendsanewORDERBYclauseelements,concatenatedbyacomma. Canbecalledmultipletimes,whichcausesittoconcatenatethenew conditionseachtimewithacomma. ThisreturnsthegeneratedSQL()andresetstheSelectBuilderstate(asif BEGIN()orRESET()werecalled).Thus,thismethodcanonlybecalled ONCE!
AND()
GROUP_BY(String)
HAVING(String)
ORDER_BY(String)
SQL()
16August2009
60