You are on page 1of 69

!

"#$%&' )

!"#$ &'()#









"#$%&%' #()*+ ,)-.&%' ,)/0 1$)2 +3&4 5)6*20%+
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.


708- 2#90 +3&4 /)6*20%+#+&)% (0++0$:
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:
hLLp://opensource.aLlasslan.com/confluence/oss/dlsplay/l8A1lS/ConLrlbuLe+uocumenLaLlon
?ou're Lhe besL auLhor of Lhls documenLaLlon, people llke you have Lo read lL!
,)%+0%+4
WhaL ls My8aLls? ......................................................................................................................................... 6
CeLLlng SLarLed ............................................................................................................................................ 6
8ulldlng SqlSesslonlacLory from xML...................................................................................................... 6
8ulldlng SqlSesslonlacLory wlLhouL xML................................................................................................. 7
Acqulrlng a SqlSesslon from SqlSesslonlacLory....................................................................................... 7
Lxplorlng Mapped SCL SLaLemenLs ......................................................................................................... 8
A noLe abouL namespaces .................................................................................................................. 9
Scope and Llfecycle................................................................................................................................ 10
Mapper ConflguraLlon xML ....................................................................................................................... 11
properLles .............................................................................................................................................. 12
seLLlngs................................................................................................................................................... 13
LypeAllases............................................................................................................................................. 14
LypePandlers.......................................................................................................................................... 13
ob[ecLlacLory ......................................................................................................................................... 16
pluglns.................................................................................................................................................... 17
envlronmenLs......................................................................................................................................... 18
LransacLlonManager .......................................................................................................................... 19
daLaSource......................................................................................................................................... 20
mappers ................................................................................................................................................. 22
SCL Map xML llles..................................................................................................................................... 22
selecL...................................................................................................................................................... 23
lnserL, updaLe, deleLe ............................................................................................................................ 23
sql........................................................................................................................................................... 27
arameLers............................................................................................................................................. 27
My8aLls 3 - user Culde
1 March 2011 4
resulLMap............................................................................................................................................... 29
Advanced 8esulL Mapplng ................................................................................................................. 31
ld, resulL ............................................................................................................................................. 33
SupporLed !u8C 1ypes ....................................................................................................................... 34
consLrucLor ........................................................................................................................................ 34
assoclaLlon ......................................................................................................................................... 33
collecLlon ........................................................................................................................................... 38
dlscrlmlnaLor...................................................................................................................................... 41
cache...................................................................................................................................................... 42
uslng a CusLom Cache........................................................................................................................ 44
cache-ref ................................................................................................................................................ 43
uynamlc SCL .............................................................................................................................................. 43
lf ............................................................................................................................................................. 43
choose, when, oLherwlse....................................................................................................................... 46
Lrlm, where, seL ..................................................................................................................................... 46
foreach................................................................................................................................................... 48
!ava Al ...................................................................................................................................................... 30
ulrecLory SLrucLure ................................................................................................................................ 30
SqlSesslons............................................................................................................................................. 31
SqlSesslonlacLory8ullder................................................................................................................... 31
SqlSesslonlacLory .............................................................................................................................. 33
SqlSesslon .......................................................................................................................................... 33
SelecL8ullder .............................................................................................................................................. 62
Sql8ullder................................................................................................................................................... 66
Logglng....................................................................................................................................................... 67
My8aLls 3 - user Culde
1 March 2011 3

My8aLls 3 - user Culde
1 March 2011 6
"3#+ &4 ;.<#+&4=
My8aLls ls a flrsL class perslsLence framework wlLh supporL for cusLom SCL, sLored procedures and
advanced mapplngs. My8aLls ellmlnaLes almosL all of Lhe !u8C code and manual seLLlng of parameLers
and reLrleval of resulLs. My8aLls can use slmple xML or AnnoLaLlons for conflguraLlon and map
prlmlLlves, Map lnLerfaces and !ava C!Cs (laln Cld !ava Cb[ecLs) Lo daLabase records.
>0++&%' ?+#$+0/
Lvery My8aLls appllcaLlon cenLers around an lnsLance of SqlSesslonlacLory. A SqlSesslonlacLory
lnsLance can be acqulred by uslng Lhe SqlSesslonlacLory8ullder. SqlSesslonlacLory8ullder can bulld a
SqlSesslonlacLory lnsLance from an xML conflguraLlon flle, of from a cusLom prepared lnsLance of Lhe
ConflguraLlon class.
<*&8/&%' ?@8?044&)%A#6+)$. 1$)2 B;C
8ulldlng a SqlSesslonlacLory lnsLance from an xML flle ls very slmple. lL ls recommended LhaL you use a
classpaLh resource for Lhls conflguraLlon, buL you could use any 8eader lnsLance, lncludlng one creaLed
from a llLeral flle paLh or a flle:// u8L. My8aLls lncludes a uLlllLy class, called 8esources, LhaL conLalns a
number of meLhods LhaL make lL slmpler Lo load resources from Lhe classpaLh and oLher locaLlons.
String resource = "org/mybatis/example/Configuration.xml";
Reader reader = Resources.getResourceAsReader(resource);
sqlMapper = new SqlSessionFactoryBuilder().build(reader);

1he conflguraLlon xML flle conLalns seLLlngs for Lhe core of Lhe My8aLls sysLem, lncludlng a uaLaSource
for acqulrlng daLabase ConnecLlon lnsLances, as well as a 1ransacLlonManager for deLermlnlng how
LransacLlons should be scoped and conLrolled. 1he full deLalls of Lhe xML conflguraLlon flle can be found
laLer ln Lhls documenL, buL here ls a slmple example:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<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>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
My8aLls 3 - user Culde
1 March 2011 7
Whlle Lhere ls a loL more Lo Lhe xML conflguraLlon flle, Lhe above example polnLs ouL Lhe mosL crlLlcal
parLs. noLlce Lhe xML header, requlred Lo valldaLe Lhe xML documenL. 1he body of Lhe envlronmenL
elemenL conLalns Lhe envlronmenL conflguraLlon for LransacLlon managemenL and connecLlon poollng.
1he mappers elemenL conLalns a llsL of mappers - Lhe xML flles LhaL conLaln Lhe SCL code and mapplng
deflnlLlons.
<*&8/&%' ?@8?044&)%A#6+)$. D&+3)*+ B;C
lf you prefer Lo dlrecLly bulld Lhe conflguraLlon from !ava, raLher Lhan xML, or creaLe your own
conflguraLlon bullder, My8aLls provldes a compleLe ConflguraLlon class LhaL provldes all of Lhe same
conflguraLlon opLlons as Lhe xML flle.
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);

noLlce ln Lhls case Lhe conflguraLlon ls addlng a mapper class. Mapper classes are !ava classes LhaL
conLaln SCL Mapplng AnnoLaLlons LhaL avold Lhe need for xML. Powever, due Lo some llmlLaLlons of
!ava AnnoLaLlons and Lhe complexlLy of some My8aLls mapplngs, xML mapplng ls sLlll requlred for Lhe
mosL advanced mapplngs (e.g. nesLed !oln Mapplng). lor Lhls reason, My8aLls wlll auLomaLlcally look
for and load a peer xML flle lf lL exlsLs (ln Lhls case, 8logMapper.xml would be loaded based on Lhe
classpaLh and name of 8logMapper.class). More on Lhls laLer.
E6@*&$&%' # ?@8?044&)% 1$)2 ?@8?044&)%A#6+)$.
now LhaL you have a SqlSesslonlacLory, as Lhe name suggesLs, you can acqulre an lnsLance of
SqlSesslon. 1he SqlSesslon conLalns absoluLely every meLhod needed Lo execuLe SCL commands agalnsL
Lhe daLabase. ?ou can execuLe mapped SCL sLaLemenLs dlrecLly agalnsL Lhe SqlSesslon lnsLance. lor
exmaple:
SqlSession session = sqlMapper.openSession();
try {
Blog blog = (Blog) session.selectOne(
"org.mybatis.example.BlogMapper.selectBlog", 101);
} finally {
session.close();
}

Whlle Lhls approach works, and ls famlllar Lo users of prevlous verslons of My8aLls, Lhere ls now a
cleaner approach. uslng an lnLerface (e.g. 8logMapper.class) LhaL properly descrlbes Lhe parameLer and
reLurn value for a glven sLaLemenL, you can now execuLe cleaner and more Lype safe code, wlLhouL error
prone sLrlng llLerals and casLlng.
My8aLls 3 - user Culde
1 March 2011 8
lor example:
SqlSession session = sqlSessionFactory.openSession();
try {
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);
} finally {
session.close();
}

now leL's explore whaL exacLly ls belng execuLed here.
FG-8)$&%' ;#--0/ ?HC ?+#+020%+4
AL Lhls polnL you may be wonderlng whaL exacLly ls belng execuLed by Lhe SqlSesslon or Mapper class.
1he Loplc of Mapped SCL SLaLemenLs ls a blg one, and LhaL Loplc wlll llkely domlnaLe Lhe ma[orlLy of Lhls
documenLaLlon. 8uL Lo glve you an ldea of whaL exacLly ls belng run, here are a couple of examples.
ln elLher of Lhe examples above, Lhe sLaLemenLs could have been deflned by elLher xML or AnnoLaLlons.
LeL's Lake a look aL xML flrsL. 1he full seL of feaLures provlded by My8aLls can be reallzed by uslng Lhe
xML based mapplng language LhaL has made My8aLls popular over Lhe years. lf you've used My8aLls
before, Lhe concepL wlll be famlllar Lo you, buL Lhere have been numerous lmprovemenLs Lo Lhe xML
mapplng documenLs LhaL wlll become clear laLer. Pere ls an example of an xML based mapped
sLaLemenL LhaL would saLlsfy Lhe above SqlSesslon calls.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.mybatis.example.BlogMapper">
<select id="selectBlog" parameterType="int" resultType="Blog">
select * from Blog where id = #{id}
</select>
</mapper>

Whlle Lhls looks llke a loL of overhead for Lhls slmple example, lL ls acLually very llghL. ?ou can deflne as
many mapped sLaLemenLs ln a slngle mapper xML flle as you llke, so you geL a loL of mllage ouL of Lhe
xML header and docLype declaraLlon. 1he resL of Lhe flle ls preLLy self explanaLory. lL deflnes a name for
Lhe mapped sLaLemenL selecL8log", ln Lhe namespace org.mybaLls.example.8logMapper", whlch
would allow you Lo call lL by speclfylng Lhe fully quallfled name of
org.mybaLls.example.8logMapper.selecL8log", as we dld above ln Lhe followlng example:
Blog blog = (Blog) session.selectOne(
"org.mybatis.example.BlogMapper.selectBlog", 101);

noLlce how slmllar Lhls ls Lo calllng a meLhod on a fully quallfled !ava class, and Lhere's a reason for LhaL.
1hls name can be dlrecLly mapped Lo a Mapper class of Lhe same name as Lhe namespace, wlLh a
My8aLls 3 - user Culde
1 March 2011 9
meLhod LhaL maLches Lhe name, parameLer, and reLurn Lype as Lhe mapped selecL sLaLemenL. 1hls
allows you Lo very slmply call Lhe meLhod agalnsL Lhe Mapper lnLerface as you sawabove, buL here lL ls
agaln ln Lhe followlng example:
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);

1he second approach has a loL of advanLages. llrsL, lL doesn'L depend on a sLrlng llLeral, so lL's much
safer. Second, lf your luL has code compleLlon, you can leverage LhaL when navlgaLlng your mapped
SCL sLaLemenLs. 1hlrd, you don'L need Lo casL Lhe reLurn Lype, as Lhe 8logMapper lnLerface can have
clean, Lypesafe reLurn Lypes (and a Lypesafe parameLer).
E I)+0 #()*+ I#204-#604

! Namespaces were optional in previous versions of MyBatis, 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 MyBatis in the long term.
! Name Resolution: To reduce the amount of typing, MyBatis uses the following name
resolution rules for all named configuration elements, including statements, result maps,
caches, etc.
Fully qualified names (e.g. com.mypackage.MyMapper.selectAllThings) are looked up
directly and used if found.
Short names (e.g. selectAllThings) can be used to reference any unambiguous entry.
However if there are two or more (e.g. com.foo.selectAllThings and
com.bar.selectAllThings), then you will receive an error reporting that the short name is
ambiguous and therefore must be fully qualified.

1here's one more Lrlck Lo Mapper classes llke 8logMapper. 1helr mapped sLaLemenLs don'L need Lo be
mapped wlLh xML aL all. lnsLead Lhey can use !ava AnnoLaLlons. lor example, Lhe xML above could be
ellmlnaLed and replaced wlLh:
package org.mybatis.example;
public interface BlogMapper {
@Select("SELECT * FROM blog WHERE id = #{id}")
Blog selectBlog(int id);
}
My8aLls 3 - user Culde
1 March 2011 10

1he annoLaLlons are a loL cleaner for slmple sLaLemenLs, however, !ava AnnoLaLlons are boLh llmlLed and
messler for more compllcaLed sLaLemenLs. 1herefore, lf you have Lo do anyLhlng compllcaLed, you're
beLLer off wlLh xML mapped sLaLemenLs.
lL wlll be up Lo you and your pro[ecL Leam Lo deLermlne whlch ls rlghL for you, and how lmporLanL lL ls Lo
you LhaL your mapped sLaLemenLs be deflned ln a conslsLenL way. 1haL sald, you're never locked lnLo a
slngle approach. ?ou can very easlly mlgraLe AnnoLaLlon based Mapped SLaLemenLs Lo xML and vlce
versa.
?6)-0 #%/ C&106.680
lL's very lmporLanL Lo undersLand Lhe varlous scopes and llfecycles classes we've dlscussed so far. uslng
Lhem lncorrecLly can cause severe concurrency problems.
!"#!$%%&'()*+,'-./0&#1$-
1hls class can be lnsLanLlaLed, used and Lhrown away. 1here ls no need Lo keep lL around once you've
creaLed your SqlSesslonlacLory. 1herefore Lhe besL scope for lnsLances of SqlSesslonlacLory8ullder ls
meLhod scope (l.e. a local meLhod varlable). ?ou can reuse Lhe SqlSesslonlacLory8ullder Lo bulld
mulLlple SqlSesslonlacLory lnsLances, buL lL's sLlll besL noL Lo keep lL around Lo ensure LhaL all of Lhe xML
parslng resources are freed up for more lmporLanL Lhlngs.
!"#!$%%&'()*+,'-.
Cnce creaLed, Lhe SqlSesslonlacLory should exlsL for Lhe duraLlon of your appllcaLlon execuLlon. 1here
should be llLLle or no reason Lo ever dlspose of lL or recreaLe lL. lL's a besL pracLlce Lo noL rebulld Lhe
SqlSesslonlacLory mulLlple Llmes ln an appllcaLlon run. uolng so should be consldered a bad smell".
1herefore Lhe besL scope of SqlSesslonlacLory ls appllcaLlon scope. 1hls can be achleved a number of
ways. 1he slmplesL ls Lo use a SlngleLon paLLern or SLaLlc SlngleLon paLLern. Powever, nelLher of Lhose
ls wldely accepLed as a besL pracLlce. lnsLead, you mlghL prefer Lo lnvesLlgaLe a dependency ln[ecLlon
conLalner such as Coogle Culce or Sprlng. Such frameworks wlll allow you Lo creaLe provlders LhaL wlll
manage Lhe slngleLon llfecycle of SqlSesslonlacLory for you.
!"#!$%%&'(
Lach Lhread should have lLs own lnsLance of SqlSesslon. lnsLances of SqlSesslon are noL Lo be shared
and are noL Lhread safe. 1herefore Lhe besL scope ls requesL or meLhod scope. never keep references
Lo a SqlSesslon lnsLance ln a sLaLlc fleld or even an lnsLance fleld of a class. never keep references Lo a
SqlSesslon ln any sorL of managed scope, such as PLLpSesslon of of Lhe ServleL framework. lf you're
uslng a web framework of any sorL, conslder Lhe SqlSesslon Lo follow a slmllar scope Lo LhaL of an P11
requesL. ln oLher words, upon reclevlng an P11 requesL, you can open a SqlSesslon, Lhen upon
reLurnlng Lhe response, you can close lL. Closlng Lhe sesslon ls very lmporLanL. ?ou should always
My8aLls 3 - user Culde
1 March 2011 11
ensure LhaL lL's closed wlLhln a flnally block. 1he followlng ls Lhe sLandard paLLern for ensurlng LhaL
SqlSesslons are closed:
SqlSession session = sqlSessionFactory.openSession();
try {
// do work
} finally {
session.close();
}

uslng Lhls paLLern conslsLenLly LhroughouL your code wlll ensure LhaL all daLabase resources are properly
closed (assumlng you dld noL pass ln your own connecLlon, whlch ls an lndlcaLlon Lo My8aLls LhaL you
wlsh Lo manage your own connecLlon resources).
2*33$- 5(%,*(+$%
Mappers are lnLerfaces LhaL you creaLe Lo blnd Lo your mapped sLaLemenLs. lnsLances of Lhe mapper
lnLerfaces are acqulred from Lhe SqlSesslon. As such, Lechnlcally Lhe broadesL scope of any mapper
lnsLance ls Lhe same as Lhe SqlSesslon from whlch Lhey were requesLsd. Powever, Lhe besL scope for
mapper lnsLances ls meLhod scope. 1haL ls, Lhey should be requesLed wlLhln Lhe meLhod LhaL Lhey are
used, and Lhen be dlscarded. 1hey do noL need Lo be closed expllclLly. Whlle lL's noL a problem Lo keep
Lhem around LhroughouL a requesL, slmllar Lo Lhe SqlSesslon, you mlghL flnd LhaL managlng Loo many
resources aL Lhls level wlll qulckly geL ouL of hand. keep lL slmple, keep Mappers ln Lhe meLhod scope.
1he followlng example demonsLraLes Lhls pracLlce.
SqlSession session = sqlSessionFactory.openSession();
try {
BlogMapper mapper = session.getMapper(BlogMapper.class);
// do work
} finally {
session.close();
}
;#--0$ ,)%1&'*$#+&)% B;C
1he My8aLls xML conflguraLlon flle conLalns seLLlngs and properLles LhaL have a dramaLlc effecL on how
My8aLls behaves. 1he hlgh level sLrucLure of Lhe documenL ls as follows:
conflguraLlon
o properLles
o seLLlngs
o LypeAllases
o LypePandlers
o ob[ecLlacLory
o pluglns
o envlronmenLs
My8aLls 3 - user Culde
1 March 2011 12
" envlronmenL
LransacLlonManager
daLaSource
o mappers
-$)-0$+&04
1hese are exLernallzable, subsLlLuLable properLles LhaL can be conflgured ln a Lyplcal !ava roperLles flle
lnsLance, or passed ln Lhrough sub-elemenLs of Lhe properLles elemenL. lor example:
<properties resource="org/mybatis/example/config.properties">
<property name="username" value="dev_user"/>
<property name="password" value="F2Fa3!33TYyg"/>
</properties>
1he properLles can Lhen be used LhroughouL Lhe conflguraLlon flles Lo subsLlLuLe values LhaL need Lo be
dynamlcally conflgured. lor example:
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>

1he username and password ln Lhls example wlll be replaced by Lhe values seL ln Lhe properLles
elemenLs. 1he drlver and url properLles would be replaced wlLh values conLalned from Lhe
conflg.properLles flle. 1hls provldes a loL of opLlons for conflguraLlon.
roperLles can also be passed lnLo Lhe SqlSesslon8ullder.bulld() meLhods. lor example:
SqlSessionFactory factory =
sqlSessionFactoryBuilder.build(reader, props);

// ... or ...

SqlSessionFactory factory =
sqlSessionFactoryBuilder.build(reader, environment, props);

lf a properLy exlsLs ln more Lhan one of Lhese places, My8aLls loads Lhem ln Lhe followlng order:
roperLles speclfled ln Lhe body of Lhe properLles elemenL are read flrsL,
roperLles loaded from Lhe classpaLh resource or url aLLrlbuLes of Lhe properLles elemenL are
read second, and overrlde any dupllcaLe properLles already speclfled ,
roperLles passed as a meLhod parameLer are read lasL, and overrlde any dupllcaLe properLles
LhaL may have been loaded from Lhe properLles body and Lhe resource/url aLLrlbuLes.
1hus, Lhe hlghesL prlorlLy properLles are Lhose passed ln as a meLhod parameLer, followed by
resource/url aLLrlbuLes and flnally Lhe properLles speclfled ln Lhe body of Lhe properLles elemenL.
My8aLls 3 - user Culde
1 March 2011 13
40++&%'4
1hese are exLremely lmporLanL Lweaks LhaL modlfy Lhe way LhaL My8aLls behaves aL runLlme. 1he
followlng Lable descrlbes Lhe seLLlngs, Lhelr meanlngs and Lhelr defaulL values.
Sett|ng Descr|pt|on Va||d Va|ues Defau|t
cacheLnabled Clobally enables or dlsables any caches
conflgured ln any mapper under Lhls
conflguraLlon.
Lrue | false Lrue
lazyLoadlngLnabled Clobally enables or dlsables lazy loadlng.
When dlsabled, all assoclaLlons wlll be eagerly
loaded.
Lrue | false Lrue
aggresslveLazyLoadlng When enabled, an ob[ecL wlLh lazy loaded
properLles wlll be loaded enLlrely upon a call
Lo any of Lhe lazy properLles. CLherwlse, each
properLy ls loaded on demand.
Lrue | false Lrue
mulLlple8esulLSeLsLnabled Allows or dlsallows mulLlple 8esulLSeLs Lo be
reLurned from a slngle sLaLemenL (compaLlble
drlver requlred).
Lrue | false Lrue
useColumnLabel uses Lhe column label lnsLead of Lhe column
name. ulfferenL drlvers behave dlfferenLly ln
Lhls respecL. 8efer Lo Lhe drlver
documenLaLlon, or LesL ouL boLh modes Lo
deLermlne how your drlver behaves.
Lrue | false Lrue
useCeneraLedkeys Allows !u8C supporL for generaLed keys. A
compaLlble drlver ls requlred. 1hls seLLlng
forces generaLed keys Lo be used lf seL Lo
Lrue, as some drlvers deny compaLlblllLy buL
sLlll work (e.g. uerby).
Lrue | false lalse
auLoMapplng8ehavlor Speclfles lf and how My8aLls should
auLomaLlcally map columns Lo
flelds/properLles. A81lAL wlll only auLo-
map slmple, non-nesLed resulLs. luLL wlll
auLo-map resulL mapplngs of any complexlLy
(nesLed or oLherwlse).
nCnL,
A81lAL,
luLL
A81lAL
defaulLLxecuLor1ype Conflgures Lhe defaulL execuLor. SlMLL
execuLor does noLhlng speclal. 8LuSL
execuLor reuses prepared sLaLemenLs. 8A1CP
execuLor reuses sLaLemenLs and baLches
updaLes.
SlMLL
8LuSL
8A1CP
SlMLL
defaulLSLaLemenL1lmeouL SeLs Lhe LlmeouL LhaL deLermlnes how long
Lhe drlver wlll walL for a response from Lhe
daLabase.
Any poslLlve
lnLeger
noL SeL
(null)

An example of Lhe seLLlngs elemenL fully conflgured ls as follows:
<settings>
<setting name="cacheEnabled" value="true"/>
My8aLls 3 - user Culde
1 March 2011 14
<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>
+.-0E8&#404
A Lype allas ls slmply a shorLer name for a !ava Lype. lL's only relevanL Lo Lhe xML conflguraLlon and
slmply exlsLs Lo reduce redundanL Lyplng of fully quallfled classnames. lor example:
<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
<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>

WlLh Lhls conflguraLlon, 8log" can now be used anywhere LhaL domaln.blog.8log" could be.
1here are many bullL-ln Lype allases for common !ava Lypes. 1hey are all case lnsenslLlve, noLe Lhe
speclal handllng of prlmlLlves due Lo Lhe overloaded names.
A||as Mapped 1ype
_byLe 8yLe
_long Long
_shorL ShorL
_lnL lnL
_lnLeger lnL
_double double
_floaL floaL
_boolean boolean
sLrlng SLrlng
byLe 8yLe
long Long
shorL ShorL
lnL lnLeger
lnLeger lnLeger
double uouble
floaL lloaL
boolean 8oolean
daLe uaLe
declmal 8lgueclmal
blgdeclmal 8lgueclmal
My8aLls 3 - user Culde
1 March 2011 13
A||as Mapped 1ype
ob[ecL Cb[ecL
map Map
hashmap PashMap
llsL LlsL
arrayllsL ArrayLlsL
collecLlon CollecLlon
lLeraLor lLeraLor

+.-07#%/80$4
Whenever My8aLls seLs a parameLer on a reparedSLaLemenL or reLrleves a value from a 8esulLSeL, a
1ypePandler ls used Lo reLrleve Lhe value ln a means approprlaLe Lo Lhe !ava Lype. 1he followlng Lable
descrlbes Lhe defaulL 1ypePandlers.
1ype nand|er Iava 1ypes ID8C 1ypes
8oolean1ypePandler 8oolean, boolean Any compaLlble 8CCLLAn
8yLe1ypePandler 8yLe, byLe Any compaLlble nuML8lC or 8?1L
ShorL1ypePandler ShorL, shorL Any compaLlble nuML8lC or SPC81 ln1LCL8
lnLeger1ypePandler lnLeger, lnL Any compaLlble nuML8lC or ln1LCL8
Long1ypePandler Long, long Any compaLlble nuML8lC or LCnC ln1LCL8
lloaL1ypePandler lloaL, floaL Any compaLlble nuML8lC or lLCA1
uouble1ypePandler uouble, double Any compaLlble nuML8lC or uCu8LL
8lgueclmal1ypePandler 8lgueclmal Any compaLlble nuML8lC or uLClMAL
SLrlng1ypePandler SLrlng CPA8, vA8CPA8
Clob1ypePandler SLrlng CLC8, LCnCvA8CPA8
nSLrlng1ypePandler SLrlng nvA8CPA8, nCPA8
nClob1ypePandler SLrlng nCLC8
8yLeArray1ypePandler byLe[] Any compaLlble byLe sLream Lype
8lob1ypePandler byLe[] 8LC8, LCnCvA88lnA8?
uaLe1ypePandler uaLe ([ava.uLll) 1lMLS1AM
uaLeCnly1ypePandler uaLe ([ava.uLll) uA1L
1lmeCnly1ypePandler uaLe ([ava.uLll) 1lML
Sql1lmesLamp1ypePandler 1lmesLamp ([ava.sql) 1lMLS1AM
SqluaLe1ypePadler uaLe ([ava.sql) uA1L
Sql1lme1ypePandler 1lme ([ava.sql) 1lML
Cb[ecL1ypePandler Any C1PL8, or unspeclfled
Lnum1ypePandler LnumeraLlon 1ype vA8CPA8 - any sLrlng compaLlble Lype, as Lhe
code ls sLored (noL Lhe lndex).

?ou can overrlde Lhe Lype handlers or creaLe your own Lo deal wlLh unsupporLed or non-sLandard Lypes.
1o do so, slmply lmplemenLlng Lhe 1ypePandler lnLerface (org.mybaLls.Lype) and map your new
1ypePandler class Lo a !ava Lype, and opLlonally a !u8C Lype. lor example:
// ExampleTypeHandler.java
My8aLls 3 - user Culde
1 March 2011 16
public class ExampleTypeHandler implements TypeHandler {
public void setParameter(
PreparedStatement ps, int i, Object parameter,JdbcType jdbcType)
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.mybatis.example.ExampleTypeHandler"/>
</typeHandlers>

uslng such a 1ypePandler would overrlde Lhe exlsLlng Lype handler for !ava SLrlng properLles and
vA8CPA8 parameLers and resulLs. noLe LhaL My8aLls does noL lnLrospecL upon Lhe daLabase meLadaLa
Lo deLermlne Lhe Lype, so you musL speclfy LhaL lL's a vA8CPA8 fleld ln Lhe parameLer and resulL
mapplngs Lo hook ln Lhe correcL Lype handler. 1hls ls due Lo Lhe facL LhaL My8aLls ls unaware of Lhe daLa
Lype unLll Lhe sLaLemenL ls execuLed.
)(J06+A#6+)$.
Lach Llme My8aLls creaLes a new lnsLance of a resulL ob[ecL, lL uses an Cb[ecLlacLory lnsLance Lo do so.
1he defaulL Cb[ecLlacLory does llLLle more Lhan lnsLanLlaLe Lhe LargeL class wlLh a defaulL consLrucLor, or
a parameLerlzed consLrucLor lf parameLer mapplngs exlsL. lf you wanL Lo overrlde Lhe defaulL behavlour
of Lhe Cb[ecLlacLory, you can creaLe your own. lor example:
// 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);
}
}

My8aLls 3 - user Culde
1 March 2011 17
// MapperConfig.xml
<objectFactory type="org.mybatis.example.ExampleObjectFactory">
<property name="someProperty" value="100"/>
</objectFactory>

1he Cb[ecLlacLory lnLerface ls very slmple. lL conLalns Lwo creaLe meLhods, one Lo deal wlLh Lhe defaulL
consLrucLor, and Lhe oLher Lo deal wlLh parameLerlzed consLrucLors. llnally, Lhe seLroperLles meLhod
can be used Lo conflgure Lhe Cb[ecLlacLory. roperLles deflned wlLhln Lhe body of Lhe ob[ecLlacLory
elemenL wlll be passed Lo Lhe seLroperLles meLhod afLer lnlLlallzaLlon of your Cb[ecLlacLory lnsLance.
-8*'&%4
My8aLls allows you Lo lnLercepL calls Lo aL cerLaln polnLs wlLhln Lhe execuLlon of a mapped sLaLemenL.
8y defaulL, My8aLls allows plug-lns Lo lnLercepL meLhod calls of:
LxecuLor
(updaLe, query, flushSLaLemenLs, commlL, rollback, geL1ransacLlon, close, lsClosed)
arameLerPandler
(geLarameLerCb[ecL, seLarameLers)
8esulLSeLPandler
(handle8esulLSeLs, handleCuLpuLarameLers)
SLaLemenLPandler
(prepare, parameLerlze, baLch, updaLe, query)
1he deLalls of Lhese classes meLhods can be dlscovered by looklng aL Lhe full meLhod slgnaLure of each,
and Lhe source code whlch ls avallable wlLh each My8aLls release. ?ou should undersLand Lhe behavlour
of Lhe meLhod you're overrldlng, assumlng you're dolng someLhlng more Lhan [usL monlLorlng calls. lf
you aLLempL Lo modlfy or overrlde Lhe behavlour of a glven meLhod, you're llkely Lo break Lhe core of
My8aLls. 1hese are low level classes and meLhods, so use plug-lns wlLh cauLlon.
uslng plug-lns ls preLLy slmple glven Lhe power Lhey provlde. Slmply lmplemenL Lhe lnLercepLor
lnLerface, belng sure Lo speclfy Lhe slgnaLures you wanL Lo lnLercepL.
// ExamplePlugin.java
@Intercepts({@Signature(
type= Executor.class,
method = "update",
args = {MappedStatement.class,Object.class})})
public class ExamplePlugin implements Interceptor {
public Object intercept(Invocation invocation) throws Throwable {
return invocation.proceed();
}
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
public void setProperties(Properties properties) {
My8aLls 3 - user Culde
1 March 2011 18
}
}

// MapperConfig.xml
<plugins>
<plugin interceptor="org.mybatis.example.ExamplePlugin">
<property name="someProperty" value="100"/>
</plugin>
</plugins>

1he plug-ln above wlll lnLercepL all calls Lo Lhe updaLe" meLhod on Lhe LxecuLor lnsLance, whlch ls an
lnLernal ob[ecL responslble for Lhe low level execuLlon of mapped sLaLemenLs.
Cverr|d|ng the Conf|gurat|on C|ass
ln addlLlon Lo modlfylng core My8aLls behavlour wlLh pluglns, you can also overrlde Lhe ConflguraLlon
class enLlrely. Slmply exLend lL and overrlde any meLhods lnslde, and pass lL lnLo Lhe call Lo Lhe
sqlSesslonlacLory8ullder.bulld(myConflg) meLhod. Agaln Lhough, Lhls could have a severe lmpacL on Lhe
behavlour of My8aLls, so use cauLlon.
0%K&$)%20%+4
My8aLls can be conflgured wlLh mulLlple envlronmenLs. 1hls helps you Lo apply your SCL Maps Lo
mulLlple daLabases for any number of reasons. lor example, you mlghL have a dlfferenL conflguraLlon
for your uevelopmenL, 1esL and roducLlon envlronmenLs. Cr, you may have mulLlple producLlon
daLabases LhaL share Lhe same schema, and you'd llke Lo use Lhe same SCL maps for boLh. 1here are
many use cases.
Cne |mportant th|ng to remember though: Wh||e you can conf|gure mu|t|p|e env|ronments, you can
on|y choose CNL per Sq|Sess|onIactory |nstance.
So lf you wanL Lo connecL Lo Lwo daLabases, you need Lo creaLe Lwo lnsLances of SqlSesslonlacLory, one
for each. lor Lhree daLabases, you'd need Lhree lnsLances, and so on. lL's really easy Lo remember:
# Cne Sq|Sess|onIactory |nstance per database
1o speclfy whlch envlronmenL Lo bulld, you slmply pass lL Lo Lhe SqlSesslonlacLory8ullder as an opLlonal
parameLer. 1he Lwo slgnaLures LhaL accepL Lhe envlronmenL are:
Sq|Sess|onIactory factory = sq|Sess|onIactory8u||der.bu||d(reader, env|ronment),
Sq|Sess|onIactory factory = sq|Sess|onIactory8u||der.bu||d(reader, env|ronment,propert|es),
lf Lhe envlronmenL ls omlLLed, Lhen Lhe defaulL envlronmenL ls loaded, as follows:
Sq|Sess|onIactory factory = sq|Sess|onIactory8u||der.bu||d(reader),
Sq|Sess|onIactory factory = sq|Sess|onIactory8u||der.bu||d(reader,propert|es),
1he envlronmenLs elemenL deflnes how Lhe envlronmenL ls conflgured.
My8aLls 3 - user Culde
1 March 2011 19
<environments default="development">
<environment id="development">
<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>

noLlce Lhe key secLlons here:
1he defaulL LnvlronmenL lu (e.g. defaulL="developmenL").
1he LnvlronmenL lu for each envlronmenL deflned (e.g. ld="developmenL").
1he 1ransacLlonManager conflguraLlon (e.g. Lype="!u8C")
1he uaLaSource conflguraLlon (e.g. Lype="CCLLu")
1he defaulL envlronmenL and Lhe envlronmenL lus are self explanaLory. name Lhem whaLever you llke,
[usL make sure Lhe defaulL maLches one of Lhem.
+$#%4#6+&)%;#%#'0$
1here are Lwo 1ransacLlonManager Lypes (l.e. Lype="[!u8C|MAnACLu]") LhaL are lncluded wlLh
My8aLls:
ID8C - 1hls conflguraLlon slmply makes use of Lhe !u8C commlL and rollback faclllLles dlrecLly. lL
relles on Lhe connecLlon reLrleved from Lhe daLaSource Lo manage Lhe scope of Lhe LransacLlon.
MANAGLD - 1hls conflguraLlon slmply does almosL noLhlng. lL never commlLs, or rolls back a
connecLlon. lnsLead, lL leLs Lhe conLalner manage Lhe full llfecycle of Lhe LransacLlon (e.g. Sprlng
or a !LL AppllcaLlon Server conLexL). 8y defaulL lL does close Lhe connecLlon. Powever, some
conLalners don'L expecL Lhls, and Lhus lf you need Lo sLop lL from closlng Lhe connecLlon, seL Lhe
closeConnecLlon properLy Lo false. lor example:
<transactionManager type="MANAGED">
<property name="closeConnection" value="false"/>
</transactionManager>

nelLher of Lhese 1ransacLlonManager Lypes requlre any properLles. Powever, Lhey are boLh 1ype
Allases, so ln oLher words, lnsLead of uslng Lhem, you could puL your own fully quallfled class name or
1ype Allas LhaL refers Lo your own lmplemenLaLlon of Lhe 1ransacLlonlacLory lnLerface.
public interface TransactionFactory {
My8aLls 3 - user Culde
1 March 2011 20
void setProperties(Properties props);
Transaction newTransaction(Connection conn, boolean autoCommit);
}

Any properLles conflgured ln Lhe xML wlll be passed Lo Lhe seLroperLles() meLhod afLer lnsLanLlaLlon.
?our lmplemenLaLlon would also need Lo creaLe a 1ransacLlon lmplemenLaLlon, whlch ls also a very
slmple lnLerface:
public interface Transaction {
Connection getConnection();
void commit() throws SQLException;
void rollback() throws SQLException;
void close() throws SQLException;
}

uslng Lhese Lwo lnLerfaces, you can compleLely cusLomlze how My8aLls deals wlLh 1ransacLlons.

/#+#?)*$60
1he daLaSource elemenL conflgures Lhe source of !u8C ConnecLlon ob[ecLs uslng Lhe sLandard !u8C
uaLaSource lnLerface.
# MosL My8aLls appllcaLlons wlll conflgure a daLaSource as ln Lhe example. Powever, lL's noL
requlred. 8eallze Lhough, LhaL Lo faclllLaLe Lazy Loadlng, Lhls daLaSource ls requlred.
1here are Lhree bulld-ln daLaSource Lypes (l.e. Lype="????"):
UNCCLLD - 1hls lmplemenLaLlon of uaLaSource slmply opens and closes a connecLlon each Llme lL ls
requesLed. Whlle lL's a blL slower, Lhls ls a good cholce for slmple appllcaLlons LhaL do noL requlre Lhe
performance of lmmedlaLely avallable connecLlons. ulfferenL daLabases are also dlfferenL ln Lhls
performance area, so for some lL may be less lmporLanL Lo pool and Lhls conflguraLlon wlll be ldeal. 1he
unCCLLu uaLaSource ls conflgured wlLh only flve properLles:
dr|ver - 1hls ls Lhe fully quallfled !ava class of Lhe !u8C drlver (nC1 of Lhe uaLaSource class lf
your drlver lncludes one).
ur| - 1hls ls Lhe !u8C u8L for your daLabase lnsLance.
username - 1he daLabase username Lo log ln wlLh.
password - 1he daLabase password Lo log ln wlLh.
defau|t1ransact|onIso|at|onLeve| - 1he defaulL LransacLlon lsolaLlon level for connecLlons.
My8aLls 3 - user Culde
1 March 2011 21
CpLlonally, you can pass properLles Lo Lhe daLabase drlver as well. 1o do Lhls, preflx Lhe properLles wlLh
drlver.", for example:
dr|ver.encod|ng=U1I8
1hls wlll pass Lhe properLy encodlng", wlLh Lhe value u1l8", Lo your daLabase drlver vla Lhe
urlverManager.geLConnecLlon(url, drlverroperLles) meLhod.
CCLLD - 1hls lmplemenLaLlon of uaLaSource pools !u8C ConnecLlon ob[ecLs Lo avold Lhe lnlLlal
connecLlon and auLhenLlcaLlon Llme requlred Lo creaLe a new ConnecLlon lnsLance. 1hls ls a popular
approach for concurrenL web appllcaLlons Lo achleve Lhe fasLesL response.
ln addlLlon Lo Lhe (unCCLLu) properLles above, Lhere are many more properLles LhaL can be used Lo
conflgure Lhe CCLLu daLasource:
poo|Max|mumAct|veConnect|ons - 1hls ls Lhe number of acLlve (l.e. ln use) connecLlons LhaL
can exlsL aL any glven Llme. uefaulL: 10
poo|Max|mumId|eConnect|ons - 1he number of ldle connecLlons LhaL can exlsL aL any glven
Llme.
poo|Max|mumCheckout1|me - 1hls ls Lhe amounL of Llme LhaL a ConnecLlon can be checked
ouL" of Lhe pool before lL wlll be forcefully reLurned. uefaulL: 20000ms (l.e. 20 seconds)
poo|1|me1oWa|t - 1hls ls a low level seLLlng LhaL glves Lhe pool a chance Lo prlnL a log sLaLus
and re-aLLempL Lhe acqulslLlon of a connecLlon ln Lhe case LhaL lL's Laklng unusually long (Lo
avold falllng sllenLly forever lf Lhe pool ls mlsconflgured). uefaulL: 20000ms (l.e. 20 seconds)
poo||nguery - 1he lng Cuery ls senL Lo Lhe daLabase Lo valldaLe LhaL a connecLlon ls ln good
worklng order and ls ready Lo accepL requesLs. 1he defaulL ls "nC lnC CuL8? SL1", whlch wlll
cause mosL daLabase drlvers Lo fall wlLh a decenL error message.
poo||ngLnab|ed - 1hls enables or dlsables Lhe plng query. lf enabled, you musL also seL Lhe
poollngCuery properLy wlLh a valld SCL sLaLemenL (preferably a very fasL one). uefaulL: false.
poo||ngConnect|onsNotUsedIor - 1hls conflgures how ofLen Lhe poollngCuery wlll be used.
1hls can be seL Lo maLch Lhe Lyplcal LlmeouL for a daLabase connecLlon, Lo avold unnecessary
plngs. uefaulL: 0 (l.e. all connecLlons are plnged every Llme - buL only lf poollngLnabled ls Lrue
of course).
INDI - 1hls lmplemenLaLlon of uaLaSource ls lnLended for use wlLh conLalners such as Sprlng or
AppllcaLlon Servers LhaL may conflgure Lhe uaLaSource cenLrally or exLernally and place a reference Lo lL
ln a !nul conLexL. 1hls uaLaSource conflguraLlon only requlres Lwo properLles:
My8aLls 3 - user Culde
1 March 2011 22
|n|t|a|_context - 1hls properLy ls used for Lhe ConLexL lookup from Lhe lnlLlalConLexL (l.e.
lnlLlalConLexL.lookup(lnlLlal_conLexL)). 1hls properLy ls opLlonal, and lf omlLLed, Lhen Lhe
daLa_source properLy wlll be looked up agalnsL Lhe lnlLlalConLexL dlrecLly.
data_source - 1hls ls Lhe conLexL paLh where Lhe reference Lo Lhe lnsLance of Lhe uaLaSource
can be found. lL wlll be looked up agalnsL Lhe conLexL reLurned by Lhe lnlLlal_conLexL lookup, or
agalnsL Lhe lnlLlalConLexL dlrecLly lf no lnlLlal_conLexL ls supplled.
Slmllar Lo Lhe oLher uaLaSource conflguraLlons, lL's posslble Lo send properLles dlrecLly Lo Lhe
lnlLlalConLexL by preflxlng Lhose properLles wlLh env.", for example:
env.encodlng=u1l8
1hls would send Lhe properLy encodlng" wlLh Lhe value of u1l8" Lo Lhe consLrucLor of Lhe
lnlLlalConLexL upon lnsLanLlaLlon.
2#--0$4
now LhaL Lhe behavlour of My8aLls ls conflgured wlLh Lhe above conflguraLlon elemenLs, we're ready Lo
deflne our mapped SCL sLaLemenLs. 8uL flrsL, we need Lo Lell My8aLls where Lo flnd Lhem. !ava doesn'L
really provlde any good means of auLo-dlscovery ln Lhls regard, so Lhe besL way Lo do lL ls Lo slmply Lell
My8aLls where Lo flnd Lhe mapplng flles. ?ou can use class paLh relaLlve !"#$%!&" references, or llLeral,
fully quallfled %!' references (lncludlng flle:/// u8Ls). lor example:
// Using classpath relative resources
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/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>

1hese sLaLemenL slmply Lell My8aLls where Lo go from here. 1he resL of Lhe deLalls are ln each of Lhe
SCL Mapplng flles, and LhaL's exacLly whaL Lhe nexL secLlon wlll dlscuss.
?HC ;#- B;C A&804
1he Lrue power of My8aLls ls ln Lhe Mapped SLaLemenLs. 1hls ls where Lhe maglc happens. lor all of
Lhelr power, Lhe SCL Map xML flles are relaLlvely slmple. CerLalnly lf you were Lo compare Lhem Lo Lhe
equlvalenL !u8C code, you would lmmedlaLely see a savlngs of 93 of Lhe code. My8aLls was bullL Lo
focus on Lhe SCL, and does lLs besL Lo sLay ouL of your way.
My8aLls 3 - user Culde
1 March 2011 23
1he SCL Map xML flles have only a few flrsL class elemenLs (ln Lhe order LhaL Lhey should be deflned):
cache - ConflguraLlon of Lhe cache for a glven namespace.
cache-ref - 8eference Lo a cache conflguraLlon from anoLher namespace.
resu|tMap - 1he mosL compllcaLed and powerful elemenL LhaL descrlbes how Lo load your
ob[ecLs from Lhe daLabase resulL seLs.
parameterMap - ueprecaLed! Cld-school way Lo map parameLers. lnllne parameLers are
preferred and Lhls elemenL may be removed ln Lhe fuLure. noL documenLed here.
sq| - A reusable chunk of SCL LhaL can be referenced by oLher sLaLemenLs.
|nsert - A mapped lnSL81 sLaLemenL.
update - A mapped uuA1L sLaLemenL.
de|ete - A mapped uLLLL1L sLaLemenL.
se|ect - A mapped SLLLC1 sLaLemenL.
1he nexL secLlons wlll descrlbe each of Lhese elemenLs ln deLall, sLarLlng wlLh Lhe sLaLemenLs
Lhemselves.
40806+
1he selecL sLaLemenL ls one of Lhe mosL popular elemenLs LhaL you'll use ln My8aLls. uLLlng daLa ln a
daLabase lsn'L Lerrlbly valuable unLll you geL lL back ouL, so mosL appllcaLlons query far more Lhan Lhey
modlfy Lhe daLa. lor every lnserL, updaLe or deleLe, Lhere ls probably many selecLs. 1hls ls one of Lhe
foundlng prlnclples of My8aLls, and ls Lhe reason so much focus and efforL was placed on querylng and
resulL mapplng. 1he selecL elemenL ls qulLe slmple for slmple cases. lor example:
<select id=selectPerson parameterType=int resultType=hashmap>
SELECT * FROM PERSON WHERE ID = #{id}
</select>

1hls sLaLemenL ls called selecLerson, Lakes a parameLer of Lype lnL (or lnLeger), and reLurns a PashMap
keyed by column names mapped Lo row values.

noLlce Lhe parameLer noLaLlon:

#{id}

1hls Lells My8aLls Lo creaLe a reparedSLaLemenL parameLer. WlLh !u8C, such a parameLer would be
ldenLlfled by a ?" ln SCL passed Lo a new reparedSLaLemenL, someLhlng llke Lhls:

// Similar JDBC code, NOT MyBatis
String selectPerson = SELECT * FROM PERSON WHERE ID=?;
PreparedStatement ps = conn.prepareStatement(selectPerson);
My8aLls 3 - user Culde
1 March 2011 24
ps.setInt(1,id);

Cf course, Lhere's a loL more code requlred by !u8C alone Lo exLracL Lhe resulLs and map Lhem Lo an
lnsLance of an ob[ecL, whlch ls whaL My8aLls saves you from havlng Lo do. 1here's a loL more Lo know
abouL parameLer and resulL mapplng. 1hose deLalls warranL Lhelr own secLlon, whlch follows laLer ln
Lhls secLlon.

1he selecL elemenL has more aLLrlbuLes LhaL allow you Lo conflgure Lhe deLalls of how each sLaLemenL
should behave.

<select
id=selectPerson
parameterType=int
parameterMap=deprecated
resultType=hashmap
resultMap=personResultMap
flushCache=false
useCache=true
timeout=10000
fetchSize=256
statementType=PREPARED
resultSetType=FORWARD_ONLY
>

Attr|bute Descr|pt|on
ld A unlque ldenLlfler ln Lhls namespace LhaL can be used Lo reference Lhls sLaLemenL.
parameLer1ype 1he fully quallfled class name or allas for Lhe parameLer LhaL wlll be passed lnLo Lhls
sLaLemenL.
parameLerMap 1hls ls a deprecaLed approach Lo referenclng an exLernal parameLerMap. use lnllne
parameLer mapplngs and Lhe parameLer1ype aLLrlbuLe.
resulL1ype 1he fully quallfled class name or allas for Lhe expecLed Lype LhaL wlll be reLurned
from Lhls sLaLemenL. noLe LhaL ln Lhe case of collecLlons, Lhls should be Lhe Lype
LhaL Lhe collecLlon conLalns, noL Lhe Lype of Lhe collecLlon lLself. use resulL1ype C8
resulLMap, noL boLh.
resulLMap A named reference Lo an exLernal resulLMap. 8esulL maps are Lhe mosL powerful
feaLure of My8aLls, and wlLh a good undersLandlng of Lhem, many dlfflculL mapplng
cases can be solved. use resulLMap C8 resulL1ype, noL boLh.
flushCache SeLLlng Lhls Lo Lrue wlll cause Lhe cache Lo be flushed whenever Lhls sLaLemenL ls
called. uefaulL: false for selecL sLaLemenLs.
useCache SeLLlng Lhls Lo Lrue wlll cause Lhe resulLs of Lhls sLaLemenL Lo be cached. uefaulL:
Lrue for selecL sLaLemenLs.
LlmeouL 1hls seLs Lhe maxlmum Llme Lhe drlver wlll walL for Lhe daLabase Lo reLurn from a
requesL, before Lhrowlng an excepLlon. uefaulL ls unseL (drlver dependenL).
feLchSlze 1hls ls a drlver hlnL LhaL wlll aLLempL Lo cause Lhe drlver Lo reLurn resulLs ln baLches
of rows numberlng ln slze equal Lo Lhls seLLlng. uefaulL ls unseL (drlver dependenL).
sLaLemenL1ype Any one of S1A1LMLn1, 8LA8Lu or CALLA8LL. 1hls causes My8aLls Lo use
SLaLemenL, reparedSLaLemenL or CallableSLaLemenL respecLlvely. uefaulL:
8LA8Lu.
resulLSeL1ype Any one of lC8WA8u_CnL?|SC8CLL_SLnSl1lvL|SC8CLL_lnSLnSl1lvL. uefaulL ls
unseL (drlver dependenL).
My8aLls 3 - user Culde
1 March 2011 23
&%40$+L *-/#+0L /080+0
1he daLa modlflcaLlon sLaLemenLs lnserL, updaLe and deleLe are very slmllar ln Lhelr lmplemenLaLlon:
<insert
id="insertAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
keyProperty=""
keyColumn=""
useGeneratedKeys=""
timeout="20000">

<update
id="insertAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
timeout="20000">

<delete
id="insertAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
timeout="20000">

Attr|bute Descr|pt|on
ld A unlque ldenLlfler ln Lhls namespace LhaL can be used Lo reference Lhls sLaLemenL.
parameLer1ype 1he fully quallfled class name or allas for Lhe parameLer LhaL wlll be passed lnLo Lhls
sLaLemenL.
parameLerMap 1hls ls a deprecaLed approach Lo referenclng an exLernal parameLerMap. use
lnllne parameLer mapplngs and Lhe parameLer1ype aLLrlbuLe.
flushCache SeLLlng Lhls Lo Lrue wlll cause Lhe cache Lo be flushed whenever Lhls sLaLemenL ls
called. uefaulL: false for selecL sLaLemenLs.
1lmeouL 1hls seLs Lhe maxlmum Llme Lhe drlver wlll walL for Lhe daLabase Lo reLurn from a
requesL, before Lhrowlng an excepLlon. uefaulL ls unseL (drlver dependenL).
sLaLemenL1ype Any one of S1A1LMLn1, 8LA8Lu or CALLA8LL. 1hls causes My8aLls Lo use
SLaLemenL, reparedSLaLemenL or CallableSLaLemenL respecLlvely. uefaulL:
8LA8Lu.
useCeneraLedkeys (lnserL only) 1hls Lells My8aLls Lo use Lhe !u8C geLCeneraLedkeys meLhod Lo
reLrleve keys generaLed lnLernally by Lhe daLabase (e.g. auLo lncremenL flelds ln
8u8MS llke MySCL or SCL Server). uefaulL: false
keyroperLy (lnserL only) ldenLlfles a properLy lnLo whlch My8aLls wlll seL Lhe key value reLurned
by geLCeneraLedkeys, or by a selecLkey chlld elemenL of Lhe lnserL sLaLemenL.
uefaulL: unseL.
keyColumn (lnserL only) SeLs Lhe name of Lhe column ln Lhe Lable wlLh a generaLed key. 1hls ls
only requlred ln cerLaln daLabases (llke osLgreSCL) when Lhe key column ls noL Lhe
flrsL column ln Lhe Lable.

My8aLls 3 - user Culde
1 March 2011 26
1he followlng are some examples of lnserL, updaLe and deleLe sLaLemens.

<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>

As menLloned, lnserL ls a llLLle blL more rlch ln LhaL lL has a few exLra aLLrlbuLes and sub-elemenLs LhaL
allow lL Lo deal wlLh key generaLlon ln a number of ways.

llrsL, lf your daLabase supporLs auLo-generaLed key flelds (e.g. MySCL and SCL Server), Lhen you can
slmply seL useCeneraLedkeys="Lrue" and seL Lhe keyroperLy Lo Lhe LargeL properLy and you're done.
lor example, lf Lhe AuLhor Lable above had used an auLo-generaLed column Lype for Lhe ld, Lhe
sLaLemenL would be modlfled as follows:

<insert id="insertAuthor" parameterType="domain.blog.Author"
useGeneratedKeys=true keyProperty=id>
insert into Author (username,password,email,bio)
values (#{username},#{password},#{email},#{bio})
</insert>

My8aLls has anoLher way Lo deal wlLh key generaLlon for daLabases LhaL don'L supporL auLo-generaLed
column Lypes, or perhaps don'L yeL supporL Lhe !u8C drlver supporL for auLo-generaLed keys.

Pere's a slmple (sllly) example LhaL would generaLe a random lu (someLhlng you'd llkely never do, buL
Lhls demonsLraLes Lhe flexlblllLy and how My8aLls really doesn'L mlnd):

<insert id="insertAuthor" parameterType="domain.blog.Author">
<selectKey keyProperty="id" resultType="int" order="BEFORE">
select CAST(RANDOM()*1000000 as INTEGER) a from SYSIBM.SYSDUMMY1
</selectKey>
insert into Author
(id, username, password, email,bio, favourite_section)
values
(#{id}, #{username}, #{password}, #{email}, #{bio},
#{favouriteSection,jdbcType=VARCHAR}
)
</insert>

My8aLls 3 - user Culde
1 March 2011 27
ln Lhe example above, Lhe selecLkey sLaLemenL would be run flrsL, Lhe AuLhor ld properLy would be seL,
and Lhen Lhe lnserL sLaLemenL would be called. 1hls glves you a slmllar behavlour Lo an auLo-generaLed
key ln your daLabase wlLhouL compllcaLlng your !ava code.

1he selecLkey elemenL ls descrlbed as follows:

<selectKey
keyProperty="id"
resultType="int"
order="BEFORE"
statementType="PREPARED">

Attr|bute Descr|pt|on
keyroperLy 1he LargeL properLy where Lhe resulL of Lhe selecLkey sLaLemenL should be seL.
resulL1ype 1he Lype of Lhe resulL. My8aLls can usually flgure Lhls ouL, buL lL doesn'L hurL Lo
add lL Lo be sure. My8aLls allows any slmple Lype Lo be used as Lhe key, lncludlng
SLrlngs.
order 1hls can be seL Lo 8LlC8L or Al1L8. lf seL Lo 8LlC8L, Lhen lL wlll selecL Lhe key
flrsL, seL Lhe keyroperLy and Lhen execuLe Lhe lnserL sLaLemenL. lf seL Lo Al1L8, lL
runs Lhe lnserL sLaLemenL and Lhen Lhe selecLkey sLaLemenL - whlch ls common
wlLh daLabases llke Cracle LhaL may have embedded sequence calls lnslde of lnserL
sLaLemenLs.
sLaLemenL1ype Same as above, My8aLls supporLs S1A1LMLn1, 8LA8Lu and CALLA8LL sLaLemenL
Lypes LhaL map Lo SLaLemenL, reparedSLaLemenL and CallableSLaLemenL
respecLlvely.

4@8
1hls elemenL can be used Lo deflne a reusable fragmenL of SCL code LhaL can be lncluded ln oLher
sLaLemenLs. lor example:

<sql id=userColumns> id,username,password </sql>

1he SCL fragmenL can Lhen be lncluded ln anoLher sLaLemenL, for example:

<select id=selectUsers parameterType=int resultType=hashmap>
select <include refid=userColumns/>
from some_table
where id = #{id}
</select>

M#$#20+0$4
ln all of Lhe pasL sLaLemenLs, you've seen examples of slmple parameLers. arameLers are very powerful
elemenLs ln My8aLls. lor slmple slLuaLlons, probably 90 of Lhe cases, Lhere's noL much Loo Lhem, for
example:

<select id=selectUsers parameterType=int resultType=User>
select id, username, password
from users
My8aLls 3 - user Culde
1 March 2011 28
where id = #{id}
</select>

1he example above demonsLraLes a very slmple named parameLer mapplng. 1he parameLer1ype ls seL
Lo lnL", so Lherefore Lhe parameLer could be named anyLhlng. rlmlLlve or slmply daLa Lypes such as
lnLeger and SLrlng have no relevanL properLles, and Lhus wlll replace Lhe full value of Lhe parameLer
enLlrely. Powever, lf you pass ln a complex ob[ecL, Lhen Lhe behavlour ls a llLLle dlfferenL. lor example:

<insert id=insertUser parameterType=User >
insert into users (id, username, password)
values (#{id}, #{username}, #{password})
</insert>

lf a parameLer ob[ecL of Lype user was passed lnLo LhaL sLaLemenL, Lhe ()* %#"!,-." and /-##0$!)
properLy would be looked up and Lhelr values passed Lo a reparedSLaLemenL parameLer.

1haL's nlce and slmple for passlng parameLers lnLo sLaLemenLs. 8uL Lhere are a loL of oLher feaLures of
parameLer maps.

llrsL, llke oLher parLs of My8aLls, parameLers can speclfy a more speclflc daLa Lype.

#{property,javaType=int,jdbcType=NUMERIC}

Llke Lhe resL of My8aLls, Lhe [ava1ype can almosL always be deLermlned from Lhe parameLer ob[ecL,
unless LhaL ob[ecL ls a PashMap. 1hen Lhe [ava1ype should be speclfled Lo ensure Lhe correcL
1ypePandler ls used.

! Note: 1he !u8C 1ype ls requlred by !u8C for all nullable columns, lf null ls passed as a value. ?ou can
lnvesLlgaLe Lhls yourself by readlng Lhe !avauocs for Lhe reparedSLaLemenL.seLnull() meLhod.

1o furLher cusLomlze Lype handllng, you can also speclfy a speclflc 1ypePandler class (or allas), for
example:

#{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}

So already lL seems Lo be geLLlng verbose, buL Lhe LruLh ls LhaL you'll rarely seL any of Lhese.

lor numerlc Lypes Lhere's also a numerlcScale for deLermlnlng how many declmal places are relevanL.

#{height,javaType=double,jdbcType=NUMERIC,numericScale=2}

llnally, Lhe .$)" aLLrlbuLe allows you Lo speclfy ln, Cu1 or lnCu1 parameLers. lf a parameLer ls Cu1 or
lnCu1, Lhe acLual value of Lhe parameLer ob[ecL properLy wlll be changed, [usL as you would expecL lf
you were calllng for an ouLpuL parameLer. lf Lhe mode=Cu1 (or lnCu1) and Lhe [dbc1ype=Cu8SC8 (l.e.
Cracle 8LlCu8SC8), you musL speclfy a resulLMap Lo map Lhe 8esulLSeL Lo Lhe Lype of Lhe parameLer.
noLe LhaL Lhe [ava1ype aLLrlbuLe ls opLlonal here, lL wlll be auLomaLlcally seL Lo 8esulLSeL lf lefL blank
wlLh a Cu8SC8 as Lhe [dbc1ype.

#{department,
mode=OUT,
jdbcType=CURSOR,
My8aLls 3 - user Culde
1 March 2011 29
javaType=ResultSet,
resultMap=departmentResultMap}

My8aLls also supporLs more advanced daLa Lypes such as sLrucLs, buL you musL Lell Lhe sLaLemenL Lhe
Lype name when reglsLerlng Lhe ouL parameLer. lor example (agaln, don'L break llnes llke Lhls ln
pracLlce):

#{middleInitial,
mode=OUT,
jdbcType=STRUCT,
jdbcTypeName=MY_TYPE,
resultMap=departmentResultMap}
uesplLe all of Lhese powerful opLlons, mosL of Lhe Llme you'll slmply speclfy Lhe properLy name, and
My8aLls wlll flgure ouL Lhe resL. AL mosL, you'll speclfy Lhe [dbc1ype for nullable columns.

#{firstName}
#{middleInitial,jdbcType=VARCHAR}
#{lastName}


Str|ng Subst|tut|on

8y defaulL, uslng Lhe #[} synLax wlll cause My8aLls Lo generaLe reparedSLaLemenL properLles and seL
Lhe values safely agalnsL Lhe reparedSLaLemenL parameLers (e.g. ?). Whlle Lhls ls safer, fasLer and
almosL always preferred, someLlmes you [usL wanL Lo dlrecLly ln[ecL a sLrlng unmodlfled lnLo Lhe SCL
SLaLemenL. lor example, for C8uL8 8?, you mlghL use someLhlng llke Lhls:

ORDER BY ${columnName}

Pere My8aLls won'L modlfy or escape Lhe sLrlng.

! IMCk1AN1: lL's noL safe Lo accepL lnpuL from a user and supply lL Lo a sLaLemenL unmodlfled ln Lhls
way. 1hls leads Lo poLenLlal SCL ln[ecLlon aLLacks and Lherefore you should elLher dlsallow user lnpuL ln
Lhese flelds, or always perform your own escapes and checks.
$04*8+;#-
1he resulLMap elemenL ls Lhe mosL lmporLanL and powerful elemenL ln My8aLls. lL's whaL allows you Lo
do away wlLh 90 of Lhe code LhaL !u8C requlres Lo reLrleve daLa from 8esulLSeLs, and ln some cases
allows you Lo do Lhlngs LhaL !u8C does noL even supporL. ln facL, Lo wrlLe Lhe equlvalenL code for
someLhlng llke a [oln mapplng for a complex sLaLemenL could probably span Lhousands of llnes of code.
1he deslgn of Lhe 8esulLMaps ls such LhaL slmple sLaLemenLs don'L requlre expllclL resulL mapplngs aL all,
and more complex sLaLemenLs requlre no more Lhan ls absoluLely necessary Lo descrlbe Lhe
relaLlonshlps.

?ou've already seen examples of slmple mapped sLaLemenLs LhaL don'L have an expllclL resulLMap. lor
example:

<select id=selectUsers parameterType=int resultType=hashmap>
select id, username, hashedPassword
from some_table
where id = #{id}
My8aLls 3 - user Culde
1 March 2011 30
</sql>

Such a sLaLemenL slmply resulLs ln all columns belng auLomaLlcally mapped Lo Lhe keys of a PashMap, as
speclfled by Lhe resulL1ype aLLrlbuLe. Whlle useful ln many cases, a PashMap doesn'L make a very good
domaln model. lL's more llkely LhaL your appllcaLlon wlll use !ava8eans or C!Cs (laln Cld !ava Cb[ecLs)
for Lhe domaln model. My8aLls supporLs boLh. Conslder Lhe followlng !ava8ean:

package com.someapp.model;
public class User {
private int id;
private String username;
private String hashedPassword;

public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getHashedPassword() {
return hashedPassword;
}
public void setHashedPassword(String hashedPassword) {
this.hashedPassword = hashedPassword;
}
}
8ased on Lhe !ava8eans speclflcaLlon, Lhe above class has 3 properLles: ld, username, and
hashedassword. 1hese maLch up exacLly wlLh Lhe column names ln Lhe selecL sLaLemenL.

Such a !ava8ean could be mapped Lo a 8esulLSeL [usL as easlly as Lhe PashMap.

<select id=selectUsers parameterType=int
resultType=com.someapp.model.User>
select id, username, hashedPassword
from some_table
where id = #{id}
</sql>

And remember LhaL 1ypeAllases are your frlend. use Lhem so LhaL you don'L have Lo keep Lyplng Lhe
fully quallfled paLh of your class ouL. lor example:

<!-- 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
My8aLls 3 - user Culde
1 March 2011 31
from some_table
where id = #{id}
</sql>

ln Lhese cases My8aLls ls auLomaLlcally creaLlng a 8esulLMap behlnd Lhe scenes Lo map Lhe columns Lo
Lhe !ava8ean properLles based on name. lf Lhe column names dld noL maLch exacLly, you could employ
selecL clause allases (a sLandard SCL feaLure) on Lhe column names Lo make Lhe labels maLch. lor
example:

<select id=selectUsers parameterType=int resultType=User>
select
user_id as id,
user_name as userName,
hashed_password as hashedPassword
from some_table
where id = #{id}
</sql>

1he greaL Lhlng abouL 8esulLMaps ls LhaL you've already learned a loL abouL Lhem, buL you haven'L even
seen one yeL! 1hese slmple cases don'L requlre any more Lhan you've seen here. !usL for example sake,
leL's see whaL Lhls lasL example would look llke as an exLernal resulLMap, as LhaL ls anoLher way Lo solve
column name mlsmaLches.

<resultMap id="userResultMap" type="User">
<id property="id" column="user_id" />
<result property="username" column="username"/>
<result property="password" column="password"/>
</resultMap>

And Lhe sLaLemenL LhaL references lL uses Lhe resulLMap aLLrlbuLe Lo do so (noLlce we removed Lhe
resulL1ype aLLrlbuLe). lor example:

<select id=selectUsers parameterType=int resultMap=userResultMap>
select user_id, user_name, hashed_password
from some_table
where id = #{id}
</sql>

now lf only Lhe world were always LhaL slmple.
E/K#%60/ N04*8+ ;#--&%'
My8aLls was creaLed wlLh one ldea ln mlnd: uaLabases aren'L always whaL you wanL or need Lhem Lo
be. Whlle we'd love every daLabase Lo be perfecL 3
rd
normal form or 8Cnl, Lhey aren'L. And lL would be
greaL lf lL was posslble Lo have a slngle daLabase map perfecLly Lo all of Lhe appllcaLlons LhaL use lL, lL's
noL. 8esulL Maps are Lhe answer LhaL My8aLls provldes Lo Lhls problem.

lor example, how would we map Lhls sLaLemenL?

<!-- Very Complex Statement -->
<select id="selectBlogDetails" parameterType="int" resultMap="detailedBlogResultMap">
select
B.id as blog_id,
My8aLls 3 - user Culde
1 March 2011 32
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>

?ou'd probably wanL Lo map lL Lo an lnLelllgenL ob[ecL model conslsLlng of a 8log LhaL was wrlLLen by an
AuLhor, and has many osLs, each of whlch may have zero or many CommenLs and 1ags. 1he followlng
ls a compleLe example of a complex 8esulLMap (assume AuLhor, 8log, osL, CommenLs and 1ags are all
Lype allases). Pave a look aL lL, buL don'L worry, we're golng Lo go Lhrough each sLep. Whlle lL may look
daunLlng aL flrsL, lL's acLually very slmple.

<!-- Very Complex Result Map -->
<resultMap id="detailedBlogResultMap" type="Blog">
<constructor>
<idArg column="blog_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>
My8aLls 3 - user Culde
1 March 2011 33
<discriminator javaType="int" column="draft">
<case value="1" resultType="DraftPost"/>
</discriminator>
</collection>
</resultMap>

1he resulLMap elemenL has a number of sub-elemenLs and a sLrucLure worLhy of some dlscusslon. 1he
followlng ls a concepLual vlew of Lhe resulLMap elemenL.

resu|tMap
constructor - used for ln[ecLlng resulLs lnLo Lhe consLrucLor of a class upon lnsLanLlaLlon
o |dArg - lu argumenL, flagglng resulLs as lu wlll help lmprove overall performance
o arg - a normal resulL ln[ecLed lnLo Lhe consLrucLor
|d - an lu resulL, flagglng resulLs as lu wlll help lmprove overall performance
resu|t - a normal resulL ln[ecLed lnLo a fleld or !ava8ean properLy
assoc|at|on - a complex Lype assoclaLlon, many resulLs wlll roll up lnLo Lhls Lype
o ,"#1") !"#%'1 .-//(,2# - assoclaLlons are resulLMaps Lhemselves, or can refer Lo
one
co||ect|on - a collecLlon of complex Lypes
o ,"#1") !"#%'1 .-//(,2# - collecLlons are resulLMaps Lhemselves, or can refer Lo one
d|scr|m|nator - uses a resulL value Lo deLermlne whlch resulLMap Lo use
o case - a case ls a resulL map based on some value
" ,"#1") !"#%'1 .-//(,2# - a case ls also a resulL map lLself, and Lhus can
conLaln many of Lhese same elemenLs, or lL can refer Lo an exLernal
resulLMap.

! 8est ract|ce: Always bulld 8esulLMaps lncremenLally. unlL LesLs really help ouL here. lf you
Lry Lo bulld a glganLlc resulLMap llke Lhe one above all aL once, lL's llkely you'll geL lL wrong and lL
wlll be hard Lo work wlLh. SLarL slmple, and evolve lL a sLep aL a Llme. And unlL LesL! 1he
downslde Lo uslng frameworks ls LhaL Lhey are someLlmes a blL of a black box (open source or
noL). ?our besL beL Lo ensure LhaL you're achlevlng Lhe behavlour LhaL you lnLend, ls Lo wrlLe
unlL LesLs. lL also helps Lo have Lhem when submlLLlng bugs.

1he nexL secLlons wlll walk Lhrough each of Lhe elemenLs ln more deLall.
&/L $04*8+
<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>

1hese are Lhe mosL baslc of resulL mapplngs. 8oLh (), and !"#%'1 map a slngle column value Lo a slngle
properLy or fleld of a slmple daLa Lype (SLrlng, lnL, double, uaLe, eLc.).

1he only dlfference beLween Lhe Lwo ls LhaL () wlll flag Lhe resulL as an ldenLlfler properLy Lo be used
when comparlng ob[ecL lnsLances. 1hls helps Lo lmprove general performance, buL especlally
performance of cachlng and nesLed resulL mapplng (l.e. [oln mapplng).

Lach has a number of aLLrlbuLes:

My8aLls 3 - user Culde
1 March 2011 34
Attr|bute Descr|pt|on
properLy 1he fleld or properLy Lo map Lhe column resulL Lo. lf a maLchlng !ava8eans properLy
exlsLs for Lhe glven name, Lhen LhaL wlll be used. CLherwlse, My8aLls wlll look for a
fleld of Lhe glven name. ln boLh cases you can use complex properLy navlgaLlon uslng
Lhe usual doL noLaLlon. lor example, you can map Lo someLhlng slmple llke:
username", or Lo someLhlng more compllcaLed llke: address.sLreeL.number".
column 1he column name from Lhe daLabase, or Lhe allased column label. 1hls ls Lhe same
sLrlng LhaL would normally be passed Lo resulLSeL.geLSLrlng(columnname).
[ava1ype A fully quallfled !ava class name, or a Lype allas (see Lhe Lable above for Lhe llsL of bullL-
ln Lype allases). My8aLls can usually flgure ouL Lhe Lype lf you're mapplng Lo a
!ava8ean. Powever, lf you are mapplng Lo a PashMap, Lhen you should speclfy Lhe
[ava1ype expllclLly Lo ensure Lhe deslred behavlour.
[dbc1ype 1he !u8C 1ype from Lhe llsL of supporLed Lypes LhaL follows Lhls Lable. 1he ID8C type |s
on|y requ|red for nu||ab|e co|umns upon |nsert, update or de|ete. 1hls ls a !u8C
requlremenL, noL an My8aLls one. So even lf you were codlng !u8C dlrecLly, you'd
need Lo speclfy Lhls Lype - buL only for nullable values.
LypePandler We dlscussed defaulL Lype handlers prevlously ln Lhls documenLaLlon. uslng Lhls
properLy you can overrlde Lhe defaulL Lype handler on a mapplng-by-mapplng basls.
1he value ls elLher a fully quallfled class name of a 1ypePandler lmplemenLaLlon, or a
Lype allas.
?*--)$+0/ O5<, P.-04
lor fuLure reference, My8aLls supporLs Lhe followlng !u8C 1ypes vla Lhe lncluded !dbc1ype
enumeraLlon.

BIT FLOAT CHAR TIMESTAMP OTHER UNDEFINED
TINYINT REAL VARCHAR BINARY BLOB NVARCHAR
SMALLINT DOUBLE LONGVARCHAR VARBINARY CLOB NCHAR
INTEGER NUMERIC DATE LONGVARBINARY BOOLEAN NCLOB
BIGINT DECIMAL TIME NULL CURSOR

6)%4+$*6+)$
<constructor>
<idArg column="id" javaType="int"/>
<arg column=username javaType=String/>
</constructor>

Whlle properLles wlll work for mosL uaLa 1ransfer Cb[ecL (u1C) Lype classes, and llkely mosL of your
domaln model, Lhere may be some cases where you wanL Lo use lmmuLable classes. CfLen Lables LhaL
conLaln reference or lookup daLa LhaL rarely or never changes ls sulLed Lo lmmuLable classes.
ConsLrucLor ln[ecLlon allows you Lo seL values on a class upon lnsLanLlaLlon, wlLhouL exposlng publlc
meLhods. My8aLls also supporLs prlvaLe properLles and prlvaLe !ava8eans properLles Lo achleve Lhls, buL
some people prefer ConsLrucLor ln[ecLlon. 1he &$,#1!%&1$! elemenL enables Lhls.

Conslder Lhe followlng consLrucLor:

public class User {
My8aLls 3 - user Culde
1 March 2011 33
//
public User(int id, String username) {
//
}
//
}

ln order Lo ln[ecL Lhe resulLs lnLo Lhe consLrucLor, My8aLls needs Lo ldenLlfy Lhe consLrucLor by Lhe Lype
of lLs parameLers. !ava has no way Lo lnLrospecL (or reflecL) on parameLer names. So when creaLlng a
consLrucLor elemenL, ensure LhaL Lhe argumenLs are ln order, and LhaL Lhe daLa Lypes are speclfled.

<constructor>
<idArg column="id" javaType="int"/>
<arg column=username javaType=String/>
</constructor>

1he resL of Lhe aLLrlbuLes and rules are Lhe same as for Lhe regular () and !"#%'1 elemenLs.

Attr|bute Descr|pt|on
column 1he column name from Lhe daLabase, or Lhe allased column label. 1hls ls Lhe same
sLrlng LhaL would normally be passed Lo resulLSeL.geLSLrlng(columnname).
[ava1ype A fully quallfled !ava class name, or a Lype allas (see Lhe Lable above for Lhe llsL of bullL-
ln Lype allases). My8aLls can usually flgure ouL Lhe Lype lf you're mapplng Lo a
!ava8ean. Powever, lf you are mapplng Lo a PashMap, Lhen you should speclfy Lhe
[ava1ype expllclLly Lo ensure Lhe deslred behavlour.
[dbc1ype 1he !u8C 1ype from Lhe llsL of supporLed Lypes LhaL follows Lhls Lable. 1he ID8C type |s
on|y requ|red for nu||ab|e co|umns upon |nsert, update or de|ete. 1hls ls a !u8C
requlremenL, noL an My8aLls one. So even lf you were codlng !u8C dlrecLly, you'd
need Lo speclfy Lhls Lype - buL only for nullable values.
LypePandler We dlscussed defaulL Lype handlers prevlously ln Lhls documenLaLlon. uslng Lhls
properLy you can overrlde Lhe defaulL Lype handler on a mapplng-by-mapplng basls.
1he value ls elLher a fully quallfled class name of a 1ypePandler lmplemenLaLlon, or a
Lype allas.

#44)6&#+&)%
<association property="author" column="blog_author_id" javaType=" Author">
<id property="id" column="author_id"/>
<result property="username" column="author_username"/>
</association>

1he assoclaLlon elemenL deals wlLh a has-one" Lype relaLlonshlp. lor example, ln our example, a 8log
has one AuLhor. An assoclaLlon mapplng works mosLly llke any oLher resulL. ?ou speclfy Lhe LargeL
properLy, Lhe column Lo reLrleve Lhe value from, Lhe [ava1ype of Lhe properLy (whlch My8aLls can flgure
ouL mosL of Lhe Llme), Lhe [dbc1ype lf necessary and a LypePandler lf you wanL Lo overrlde Lhe reLrleval
of Lhe resulL values.

Where Lhe assoclaLlon dlffers ls LhaL you need Lo Lell My8aLls how Lo load Lhe assoclaLlon. My8aLls can
do so ln Lwo dlfferenL ways:

My8aLls 3 - user Culde
1 March 2011 36
Nested Se|ect: 8y execuLlng anoLher mapped SCL sLaLemenL LhaL reLurns Lhe complex Lype
deslred.
Nested kesu|ts: 8y uslng nesLed resulL mapplngs Lo deal wlLh repeaLlng subseLs of [olned
resulLs.

llrsL, leL's examlne Lhe properLles of Lhe elemenL. As you'll see, lL dlffers from a normal !"#%'1 mapplng
only by Lhe #"'"&1 and !"#%'13-/ aLLrlbuLes.

Attr|bute Descr|pt|on
properLy 1he fleld or properLy Lo map Lhe column resulL Lo. lf a maLchlng !ava8eans properLy
exlsLs for Lhe glven name, Lhen LhaL wlll be used. CLherwlse, My8aLls wlll look for a
fleld of Lhe glven name. ln boLh cases you can use complex properLy navlgaLlon uslng
Lhe usual doL noLaLlon. lor example, you can map Lo someLhlng slmple llke:
username", or Lo someLhlng more compllcaLed llke: address.sLreeL.number".
column 1he column name from Lhe daLabase, or Lhe allased column label. 1hls ls Lhe same
sLrlng LhaL would normally be passed Lo resulLSeL.geLSLrlng(columnname).
Note: 1o dea| w|th compos|te keys, you can spec|fy mu|t|p|e co|umn names to pass
to the nested se|ect statement by us|ng the syntax
+'#06(7893-'3:7+'#:;3-'3<7+'#<=8. 1h|s w||| cause prop1 and prop2 to be set aga|nst
the parameter ob[ect for the target nested se|ect statement.
[ava1ype A fully quallfled !ava class name, or a Lype allas (see Lhe Lable above for Lhe llsL of bullL-
ln Lype allases). My8aLls can usually flgure ouL Lhe Lype lf you're mapplng Lo a
!ava8ean. Powever, lf you are mapplng Lo a PashMap, Lhen you should speclfy Lhe
[ava1ype expllclLly Lo ensure Lhe deslred behavlour.
[dbc1ype 1he !u8C 1ype from Lhe llsL of supporLed Lypes LhaL follows Lhls Lable. 1he ID8C type |s
on|y requ|red for nu||ab|e co|umns upon |nsert, update or de|ete. 1hls ls a !u8C
requlremenL, noL an My8aLls one. So even lf you were codlng !u8C dlrecLly, you'd
need Lo speclfy Lhls Lype - buL only for nullable values.
LypePandler We dlscussed defaulL Lype handlers prevlously ln Lhls documenLaLlon. uslng Lhls
properLy you can overrlde Lhe defaulL Lype handler on a mapplng-by-mapplng basls.
1he value ls elLher a fully quallfled class name of a 1ypePandler lmplemenLaLlon, or a
Lype allas.

Nested Se|ect for Assoc|at|on
selecL 1he lu of anoLher mapped sLaLemenL LhaL wlll load Lhe complex Lype requlred by Lhls
properLy mapplng. 1he values reLrleved from columns speclfled ln Lhe &$'%.,
aLLrlbuLe wlll be passed Lo Lhe LargeL #"'"&1 sLaLemenL as parameLers. 4 )"1-('")
"5-./'" 6$''$0# 17(# 1-8'"9
Note: 1o dea| w|th compos|te keys, you can spec|fy mu|t|p|e co|umn names to pass
to the nested se|ect statement by us|ng the syntax
+'#06(7893-'3:7+'#:;3-'3<7+'#<=8. 1h|s w||| cause prop1 and prop2 to be set aga|nst
the parameter ob[ect for the target nested se|ect statement.

lor example:

<resultMap id=blogResult type=Blog>
<association property="author" column="blog_author_id" javaType="Author"
My8aLls 3 - user Culde
1 March 2011 37
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>

1haL's lL. We have Lwo selecL sLaLemenLs: one Lo load Lhe 8log, Lhe oLher Lo load Lhe AuLhor, and Lhe
8log's resulLMap descrlbes LhaL Lhe selecLAuLhor" sLaLemenL should be used Lo load lLs auLhor
properLy.

4'' $17"! /!$/"!1("# 0('' 8" '$-)") -%1$.-1(&-'': -##%.(,2 17"(! &$'%., -,) /!$/"!1: ,-."# .-1&79

Whlle Lhls approach ls slmple, lL wlll noL perform well for large daLa seLs or llsLs. 1hls problem ls known
as Lhe n+1 SelecLs roblem". ln a nuLshell, Lhe n+1 selecLs problem ls caused llke Lhls:

?ou execuLe a slngle SCL sLaLemenL Lo reLrleve a llsL of records (Lhe +1").
lor each record reLurned, you execuLe a selecL sLaLemenL Lo load deLalls for each (Lhe n").

1hls problem could resulL ln hundreds or Lhousands of SCL sLaLemenLs Lo be execuLed. 1hls ls noL
always deslrable.

1he upslde ls LhaL My8aLls can lazy load such querles, Lhus you mlghL be spared Lhe cosL of Lhese
sLaLemenLs all aL once. Powever, lf you load such a llsL and Lhen lmmedlaLely lLeraLe Lhrough lL Lo
access Lhe nesLed daLa, you wlll lnvoke all of Lhe lazy loads, and Lhus performance could be very bad.

And so, Lhere ls anoLher way.
Nested kesu|ts for Assoc|at|on
resulLMap 1hls ls Lhe lu of a 8esulLMap LhaL can map Lhe nesLed resulLs of Lhls assoclaLlon lnLo an
approprlaLe ob[ecL graph. 1hls ls an alLernaLlve Lo uslng a call Lo anoLher selecL
sLaLemenL. lL allows you Lo [oln mulLlple Lables LogeLher lnLo a slngle 8esulLSeL. Such a
8esulLSeL wlll conLaln dupllcaLed, repeaLlng groups of daLa LhaL needs Lo be
decomposed and mapped properly Lo a nesLed ob[ecL graph. 1o faclllLaLe Lhls, My8aLls
leLs you chaln" resulL maps LogeLher, Lo deal wlLh Lhe nesLed resulLs. 4, "5-./'" 0(''
8" 6-! "-#("! 1$ 6$''$0* -,) $," 6$''$0# 17(# 1-8'"9

?ou've already seen a very compllcaLed example of nesLed assoclaLlons above. 1he followlng ls a far
slmpler example Lo demonsLraLe how Lhls works. lnsLead of execuLlng a separaLe sLaLemenL, we'll [oln
Lhe 8log and AuLhor Lables LogeLher, llke so:

<select id="selectBlog" parameterType="int" resultMap="blogResult">
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,
My8aLls 3 - user Culde
1 March 2011 38
A.password as author_password,
A.email as author_email,
A.bio as author_bio
from Blog B left outer join Author A on B.author_id = A.id
where B.id = #{id}
</select>

noLlce Lhe [oln, as well as Lhe care Laken Lo ensure LhaL all resulLs are allased wlLh a unlque and clear
name. 1hls makes mapplng far easler. now we can map Lhe resulLs:

<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>

ln Lhe example above you can see aL Lhe 8log's auLhor" -##$&(-1($, delegaLes Lo Lhe auLhor8esulL"
!"#%'13-/ Lo load Lhe AuLhor lnsLance.

Very Important: () elemenLs play a very lmporLanL role ln nesLed 8esulL mapplng. ?ou should always
speclfy one or more properLles LhaL can be used Lo unlquely ldenLlfy Lhe resulLs. 1he LruLh ls LhaL
My8aLls wlll sLlll work lf you leave lL ouL, buL aL a severe performance cosL. Choose as few properLles as
posslble LhaL can unlquely ldenLlfy Lhe resulL. 1he prlmary key ls an obvlous cholce (even lf composlLe).

now, Lhe above example used an exLernal !"#%'13-/ elemenL Lo map Lhe assoclaLlon. 1hls makes Lhe
AuLhor resulLMap reusable. Powever, lf you have no need Lo reuse lL, or lf you slmply prefer Lo co-
locaLe your resulL mapplngs lnLo a slngle descrlpLlve resulLMap, you can nesL Lhe assoclaLlon resulL
mapplngs. Pere's Lhe same example uslng Lhls approach:

<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">
<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"/>
</association>
</resultMap>

?ou've seen above how Lo deal wlLh a has one" Lype assoclaLlon. 8uL whaL abouL has many"? 1haL's
Lhe sub[ecL of Lhe nexL secLlon.
6)8806+&)%

My8aLls 3 - user Culde
1 March 2011 39
<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>

1he &$''"&1($, elemenL works almosL ldenLlcally Lo Lhe assoclaLlon. ln facL, lL's so slmllar, Lo documenL
Lhe slmllarlLles would be redundanL. So leL's focus on Lhe dlfferences.

1o conLlnue wlLh our example above, a 8log only had one AuLhor. 8uL a 8log has many osLs. Cn Lhe
blog class, Lhls would be represenLed by someLhlng llke:

private List<Post> posts;

1o map a seL of nesLed resulLs Lo a LlsL llke Lhls, we use Lhe &$''"&1($, elemenL. !usL llke Lhe -##$&(-1($,
elemenL, we can use a nesLed selecL, or nesLed resulLs from a [oln.
Nested Se|ect for Co||ect|on
llrsL, leL's look aL uslng a nesLed selecL Lo load Lhe osLs for Lhe 8log.

<resultMap id=blogResult type=Blog>
<collection property="posts" javaType=ArrayList column="blog_id"
ofType="Post" select=selectPostsForBlog/>
</resultMap>

<select id=selectBlog parameterType=int resultMap=blogResult>
SELECT * FROM BLOG WHERE ID = #{id}
</select>

<select id=selectPostsForBlog parameterType=int resultType="Blog">
SELECT * FROM POST WHERE BLOG_ID = #{id}
</select>

1here are a number Lhlngs you'll noLlce lmmedlaLely, buL for Lhe mosL parL lL looks very slmllar Lo Lhe
-##$&(-1($, elemenL we learned abouL above. llrsL, you'll noLlce LhaL we're uslng Lhe &$''"&1($, elemenL.
1hen you'll noLlce LhaL Lhere's a new >'?@.3$8 aLLrlbuLe. 1hls aLLrlbuLe ls necessary Lo dlsLlngulsh
beLween Lhe !ava8ean (or fleld) properLy Lype and Lhe Lype LhaL Lhe collecLlon conLalns. So you could
read Lhe followlng mapplng llke Lhls:
<collection property="posts" javaType=ArrayList column="blog_id"
ofType="Post" select=selectPostsForBlog/>

! 8ead as: A collecLlon of posLs ln an ArrayLlsL of Lype osL."
1he [ava1ype aLLrlbuLe ls really unnecessary, as My8aLls wlll flgure Lhls ouL for you ln mosL cases. So you
can ofLen shorLen Lhls down Lo slmply:
<collection property="posts" column="blog_id" ofType="Post"
select=selectPostsForBlog/>

Nested kesu|ts for Co||ect|on
My8aLls 3 - user Culde
1 March 2011 40
8y Lhls polnL, you can probably guess how nesLed resulLs for a collecLlon wlll work, because lL's exacLly
Lhe same as an assoclaLlon, buL wlLh Lhe same addlLlon of Lhe >'?@.3$8 aLLrlbuLe applled.
llrsL, leL's look aL Lhe SCL:
<select id="selectBlog" parameterType="int" resultMap="blogResult">
select
B.id as blog_id,
B.title as blog_title,
B.author_id as blog_author_id,
P.id as post_id,
P.subject as post_subject,
P.body as post_body,
from Blog B
left outer join Post P on B.id = P.blog_id
where B.id = #{id}
</select>
Agaln, we've [olned Lhe 8log and osL Lables, and have Laken care Lo ensure quallLy resulL column labels
for slmple mapplng. now mapplng a 8log wlLh lLs collecLlon of osL mapplngs ls as slmple as:
<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>

Agaln, remember Lhe lmporLance of Lhe () elemenLs here, or read Lhe -##$&(-1($, secLlon above lf you
haven'L already.
Also, lf you prefer Lhe longer form LhaL allows for more reusablllLy of your resulL maps, you can use Lhe
followlng alLernaLlve mapplng:
<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>

! Note: 1here's no llmlL Lo Lhe depLh, breadLh or comblnaLlons of Lhe assoclaLlons and collecLlons LhaL
you map. ?ou should keep performance ln mlnd when mapplng Lhem. unlL LesLlng and performance
LesLlng of your appllcaLlon goes a long way Loward dlscoverlng Lhe besL approach for your appllcaLlon.
1he nlce Lhlng ls LhaL My8aLls leLs you change your mlnd laLer, wlLh very llLLle (lf any) lmpacL Lo your
code.
My8aLls 3 - user Culde
1 March 2011 41
Advanced assoclaLlon and collecLlon mapplng ls a deep sub[ecL. uocumenLaLlon can only geL you so far.
WlLh a llLLle pracLlce, lL wlll all become clear very qulckly.
/&46$&2&%#+)$
<discriminator javaType="int" column="draft">
<case value="1" resultType="DraftPost"/>
</discriminator>

SomeLlmes a slngle daLabase query mlghL reLurn resulL seLs of many dlfferenL (buL hopefully somewhaL
relaLed) daLa Lypes. 1he )(#&!(.(,-1$! elemenL was deslgned Lo deal wlLh Lhls slLuaLlon, and oLhers,
lncludlng class lnherlLance hlerarchles. 1he dlscrlmlnaLor ls preLLy slmple Lo undersLand, as lL behaves
much llke a swlLch sLaLemenL ln !ava.

A dlscrlmlnaLor deflnlLlon speclfles &$'%., and ;-<-=:/" aLLrlbuLes. 1he column ls where My8aLls wlll
look for Lhe value Lo compare. 1he [ava1ype ls requlred Lo ensure Lhe proper klnd of equallLy LesL ls
performed (alLhough SLrlng would probably work for almosL any slLuaLlon). lor example:


<resultMap id="vehicleResult" type="Vehicle">
<id property=id column="id" />
<result property="vin" column="vin"/>
<result property="year" column="year"/>
<result property="make" column="make"/>
<result property="model" column="model"/>
<result property="color" column="color"/>
<discriminator javaType="int" column="vehicle_type">
<case value="1" resultMap="carResult"/>
<case value="2" resultMap="truckResult"/>
<case value="3" resultMap="vanResult"/>
<case value="4" resultMap="suvResult"/>
</discriminator>
</resultMap>


ln Lhls example, My8aLls would reLrleve each record from Lhe resulL seL and compare lLs vehlcle Lype
value. lf lL maLches any of Lhe dlscrlmlnaLor cases, Lhen lL wlll use Lhe resulLMap speclfled by Lhe case.
1hls ls done excluslvely, so ln oLher words, Lhe resL of Lhe resulLMap ls lgnored (unless lL ls exLended,
whlch we Lalk abouL ln a second). lf none of Lhe cases maLch, Lhen My8aLls slmply uses Lhe resulLMap
as deflned ouLslde of Lhe dlscrlmlnaLor block. So, lf Lhe car8esulL was declared as follows:

<resultMap id="carResult" type="Car">
<result property=doorCount column="door_count" />
</resultMap>

1hen CnL? Lhe doorCounL properLy would be loaded. 1hls ls done Lo allow compleLely lndependenL
groups of dlscrlmlnaLor cases, even ones LhaL have no relaLlonshlp Lo Lhe parenL resulLMap. ln Lhls case
we do of course know LhaL Lhere's a relaLlonshlp beLween cars and vehlcles, as a Car ls-a vehlcle.
1herefore, we wanL Lhe resL of Lhe properLles loaded Loo. Cne slmple change Lo Lhe resulLMap and
we're seL Lo go.

<resultMap id="carResult" type="Car" extends=vehicleResult>
<result property=doorCount column="door_count" />
</resultMap>
My8aLls 3 - user Culde
1 March 2011 42

now all of Lhe properLles from boLh Lhe vehlcle8esulL and car8esulL wlll be loaded.

Cnce agaln Lhough, some may flnd Lhls exLernal deflnlLlon of maps somewhaL Ledlous. 1herefore
Lhere's an alLernaLlve synLax for Lhose LhaL prefer a more conclse mapplng sLyle. lor example:

<resultMap id="vehicleResult" type="Vehicle">
<id property=id column="id" />
<result property="vin" column="vin"/>
<result property="year" column="year"/>
<result property="make" column="make"/>
<result property="model" column="model"/>
<result property="color" column="color"/>
<discriminator javaType="int" column="vehicle_type">
<case value="1" resultType="carResult">
<result property=doorCount column="door_count" />
</case>
<case value="2" resultType="truckResult">
<result property=boxSize column="box_size" />
<result property=extendedCab column="extended_cab" />
</case>
<case value="3" resultType="vanResult">
<result property=powerSlidingDoor column="power_sliding_door" />
</case>
<case value="4" resultType="suvResult">
<result property=allWheelDrive column="all_wheel_drive" />
</case>
</discriminator>
</resultMap>

! kemember LhaL Lhese are all 8esulL Maps, and lf you don'L speclfy any resulLs aL all, Lhen My8aLls wlll
auLomaLlcally maLch up columns and properLles for you. So mosL of Lhese examples are more verbose
Lhan Lhey really need Lo be. 1haL sald, mosL daLabases are klnd of complex and lL's unllkely LhaL we'll be
able Lo depend on LhaL for all cases.
6#630
My8aLls has lncludes a powerful query cachlng feaLure whlch ls very conflgurable and cusLomlzable. A
loL of changes have been made ln Lhe My8aLls 3 cache lmplemenLaLlon Lo make lL boLh more powerful
and far easler Lo conflgure.
8y defaulL, Lhere ls no cachlng enabled, excepL for local sesslon cachlng, whlch lmproves performance
and ls requlred Lo resolve clrcular dependencles. 1o enable a second level of cachlng, you slmply need
Lo add one llne Lo your SCL Mapplng flle:
<cache/>

LlLerally LhaL's lL. 1he effecL of Lhls one slmple sLaLemenL ls as follows:
All resulLs from se|ect sLaLemenLs ln Lhe mapped sLaLemenL flle wlll be cached.
All |nsert, update and de|ete sLaLemenLs ln Lhe mapped sLaLemenL flle wlll flush Lhe cache.
My8aLls 3 - user Culde
1 March 2011 43
1he cache wlll use a Least kecent|y Used (LkU) algorlLhm for evlcLlon.
1he cache wlll noL flush on any sorL of Llme based schedule (l.e. no I|ush Interva|).
1he cache wlll sLore 1024 references Lo llsLs or ob[ecLs (whaLever Lhe query meLhod reLurns).
1he cache wlll be LreaLed as a read]wr|te cache, meanlng ob[ecLs reLrleved are noL shared and
can be safely modlfled by Lhe caller, wlLhouL lnLerferlng wlLh oLher poLenLlal modlflcaLlons by
oLher callers or Lhreads.
All of Lhese properLles are modlflable Lhrough Lhe aLLrlbuLes of Lhe cache elemenL. lor example:
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>

1hls more advanced conflguraLlon creaLes a lllC cache LhaL flushes once every 60 seconds, sLores up Lo
312 references Lo resulL ob[ecLs or llsLs, and ob[ecLs reLurned are consldered read-only, Lhus modlfylng
Lhem could cause confllcLs beLween callers ln dlfferenL Lhreads.
1he avallable ev|ct|on pollcles avallable are:
LkU - LeasL 8ecenLly used: 8emoves ob[ecLs LhaL haven'L been used for Lhe longsL perlod of
Llme.
IIIC - llrsL ln llrsL CuL: 8emoves ob[ecLs ln Lhe order LhaL Lhey enLered Lhe cache.
SCI1 - SofL 8eference: 8emoves ob[ecLs based on Lhe garbage collecLor sLaLe and Lhe rules of
SofL 8eferences.
WLAk - Weak 8eference: More aggresslvely removes ob[ecLs based on Lhe garbage collecLor
sLaLe and rules of Weak 8eferences.
1he defaulL ls L8u.
1he f|ushInterva| can be seL Lo any poslLlve lnLeger and should represenL a reasonable amounL of Llme
speclfled ln mllllseconds. 1he defaulL ls noL seL, Lhus no flush lnLerval ls used and Lhe cache ls only
flushed by calls Lo sLaLemenLs.
1he s|ze can be seL Lo any poslLlve lnLeger, keep ln mlnd Lhe slze of Lhe ob[ecLs your cachlng and Lhe
avallable memory resources of your envlronmenL. 1he defaulL ls 1024.
1he readCn|y aLLrlbuLe can be seL Lo 1!%" or 6-'#". A read-only cache wlll reLurn Lhe same lnsLance of
Lhe cached ob[ecL Lo all callers. 1hus such ob[ecLs should noL be modlfled. 1hls offers a slgnlflcanL
My8aLls 3 - user Culde
1 March 2011 44
performance advanLage Lhough. A read-wrlLe cache wlll reLurn a copy (vla serlallzaLlon) of Lhe cached
ob[ecL. 1hls ls slower, buL safer, and Lhus Lhe defaulL ls 6-'#"9
Q4&%' # ,*4+)2 ,#630
ln addlLlon Lo cusLomlzlng Lhe cache ln Lhese ways, you can also compleLely overrlde Lhe cache behavlor
by lmplemenLlng your own cache, or creaLlng an adapLer Lo oLher 3
rd
parLy cachlng soluLlons.
<cache type=com.domain.something.MyCustomCache/>

1hls example demonsLraLes how Lo use a cusLom cache lmplemenLaLlon. 1he class speclfled ln Lhe Lype
aLLrlbuLe musL lmplemenL Lhe org.mybaLls.cache.Cache lnLerface. 1hls lnLerface ls one of Lhe more
complex ln Lhe My8aLls framework, buL slmple glven whaL lL does.
public interface Cache {
String getId();
int getSize();
void putObject(Object key, Object value);
Object getObject(Object key);
boolean hasKey(Object key);
Object removeObject(Object key);
void clear();
ReadWriteLock getReadWriteLock();
}

1o conflgure your cache, slmply add publlc !ava8eans properLles Lo your Cache lmplemenLaLlon, and
pass properLles vla Lhe cache LlemenL, for example, Lhe followlng would call a meLhod called
seLCachellle(SLrlng flle)" on your Cache lmplemenLaLlon:
<cache type=com.domain.something.MyCustomCache>
<property name=cacheFile value=/tmp/my-custom-cache.tmp/>
</cache>

?ou can use !ava8eans properLles of all slmple Lypes, My8aLls wlll do Lhe converslon.
lL's lmporLanL Lo remember LhaL a cache conflguraLlon and Lhe cache lnsLance are bound Lo Lhe
namespace of Lhe SCL Map flle. 1hus, all sLaLemenLs ln Lhe same namespace as Lhe cache are bound by
lL. SLaLemenLs can modlfy how Lhey lnLeracL wlLh Lhe cache, or exclude Lhemselves compleLely by uslng
Lwo slmple aLLrlbuLes on a sLaLemenL-by-sLaLemenL basls. 8y defaulL, sLaLemenLs are conflgured llke
Lhls:
<select ... flushCache=false useCache=true/>
<insert ... flushCache=true/>
<update ... flushCache=true/>
<delete ... flushCache=true/>

My8aLls 3 - user Culde
1 March 2011 43
Slnce LhaL's Lhe defaulL, you obvlously should never expllclLly conflgure a sLaLemenL LhaL way. lnsLead,
only seL Lhe flushCache and useCache aLLrlbuLes lf you wanL Lo change Lhe defaulL behavlor. lor
example, ln some cases you may wanL Lo exclude Lhe resulLs of a parLlcular selecL sLaLemenL from Lhe
cache, or you mlghL wanL a selecL sLaLemenL Lo flush Lhe cache. Slmllarly, you may have some updaLe
sLaLemenLs LhaL don'L need Lo flush Lhe cache upon execuLlon.
6#630R$01
8ecall from Lhe prevlous secLlon LhaL only Lhe cache for Lhls parLlcular namespace wlll be used or
flushed for sLaLemenLs wlLhln Lhe same namespace. 1here may come a Llme when you wanL Lo share
Lhe same cache conflguraLlon and lnsLance beLween namespaces. ln such cases you can reference
anoLher cache by uslng Lhe cache-ref elemenL.
<cache-ref namespace=com.someone.application.data.SomeMapper/>
5.%#2&6 ?HC
Cne of Lhe mosL powerful feaLures of My8aLls has always been lLs uynamlc SCL capablllLles. lf you have
any experlence wlLh !u8C or any slmllar framework, you undersLand how palnful lL ls Lo condlLlonally
concaLenaLe sLrlngs of SCL LogeLher, maklng sure noL Lo forgeL spaces or Lo omlL a comma aL Lhe end of
a llsL of columns. uynamlc SCL can be downrlghL palnful Lo deal wlLh.
Whlle worklng wlLh uynamlc SCL wlll never be a parLy, My8aLls cerLalnly lmproves Lhe slLuaLlon wlLh a
powerful uynamlc SCL language LhaL can be used wlLhln any mapped SCL sLaLemenL.
1he uynamlc SCL elemenLs should be famlllar Lo anyone who has used !S1L or any slmllar xML based
LexL processors. ln prevlous verslons of My8aLls, Lhere were a loL of elemenLs Lo know and undersLand.
My8aLls 3 greaLly lmproves upon Lhls, and now Lhere are less Lhan half of Lhose elemenLs Lo work wlLh.
My8aLls employs powerful CCnL based expresslons Lo ellmlnaLe mosL of Lhe oLher elemenLs.
lf
choose (when, oLherwlse)
Lrlm (where, seL)
foreach
&1
1he mosL common Lhlng Lo do ln dynamlc SCL ls condlLlonally lnclude a parL of a where clause. lor
example:
<select id=findActiveBlogWithTitleLike
parameterType=Blog resultType=Blog>
SELECT * FROM BLOG
WHERE state = ACTIVE
<if test=title != null>
AND title like #{title}
My8aLls 3 - user Culde
1 March 2011 46
</if>
</select>

1hls sLaLemenL would provlde an opLlonal LexL search Lype of funcLlonallLy. lf you passed ln no LlLle, Lhen
all acLlve 8logs would be reLurned. 8uL lf you do pass ln a LlLle, lL wlll look for a LlLle llke LhaL (for Lhe
keen eyed, yes ln Lhls case your parameLer value would need Lo lnclude any masklng or wlldcard
characLers).
WhaL lf we wanLed Lo opLlonally search by LlLle and auLhor? llrsL, l'd change Lhe name of Lhe sLaLemenL
Lo make more sense. 1hen slmply add anoLher condlLlon.
<select id=findActiveBlogLike
parameterType=Blog resultType=Blog>
SELECT * FROM BLOG WHERE state = ACTIVE
<if test=title != null>
AND title like #{title}
</if>
<if test=author != null and author.name != null>
AND author_name like #{author.name}
</if>
</select>
63))40L D30%L )+30$D&40
SomeLlmes we don'L wanL all of Lhe condlLlonals Lo apply, lnsLead we wanL Lo choose only one case
among many opLlons. Slmllar Lo a swlLch sLaLemenL ln !ava, My8aLls offers a choose elemenL.
LeL's use Lhe example above, buL now leL's search only on LlLle lf one ls provlded, Lhen only by auLhor lf
one ls provlded. lf nelLher ls provlded, leL's only reLurn feaLured blogs (perhaps a sLraLeglcally llsL
selecLed by admlnlsLraLors, lnsLead of reLurnlng a huge meanlngless llsL of random blogs).
<select id=findActiveBlogLike
parameterType=Blog resultType=Blog>
SELECT * FROM BLOG WHERE state = ACTIVE
<choose>
<when test=title != null>
AND title like #{title}
</when>
<when test=author != null and author.name != null>
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
+$&2L D30$0L 40+
1he prevlous examples have been convenlenLly danclng around a noLorlous dynamlc SCL challenge.
Conslder whaL would happen lf we reLurn Lo our >(6? example, buL Lhls Llme we make AC1lvL = 1" a
dynamlc condlLlon as well.
My8aLls 3 - user Culde
1 March 2011 47
<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 and author.name != null>
AND author_name like #{author.name}
</if>
</select>
WhaL happens lf none of Lhe condlLlons are meL? ?ou would end up wlLh SCL LhaL looked llke Lhls:
SELECT * FROM BLOG
WHERE

1hls would fall. WhaL lf only Lhe second condlLlon was meL? ?ou would end up wlLh SCL LhaL looked llke
Lhls:
SELECT * FROM BLOG
WHERE
AND title like someTitle

1hls would also fall. 1hls problem ls noL easlly solved wlLh condlLlonals, and lf you've ever had Lo wrlLe
lL, Lhen you llkely never wanL Lo do so agaln.
My8aLls has a slmple answer LhaL wlll llkely work ln 90 of Lhe cases. And ln cases where lL doesn'L, you
can cusLomlze lL so LhaL lL does. WlLh one slmple change, everyLhlng works flne:
<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 and author.name != null>
AND author_name like #{author.name}
</if>
</where>
</select>
1he 07"!" elemenL knows Lo only lnserL WPL8L" lf Lhere ls any conLenL reLurned by Lhe conLalnlng
Lags. lurLhermore, lf LhaL conLenL beglns wlLh Anu" or C8", lL knows Lo sLrlp lL off.
My8aLls 3 - user Culde
1 March 2011 48
lf Lhe 07"!" elemenL does noL behave exacLly as you llke, you can cusLomlze lL by deflnlng your own 1!(.
elemenL. lor example, Lhe 1!(. equlvalenL Lo Lhe 07"!" elemenL ls:
<trim prefix="WHERE" prefixOverrides="AND |OR ">

</trim>

1he overrldes aLLrlbuLe Lakes a plpe dellmlLed llsL of LexL Lo overrlde, where whlLespace ls relevanL. 1he
resulL ls Lhe removal of anyLhlng speclfled ln Lhe $<"!!()"# aLLrlbuLe, and Lhe lnserLlon of anyLhlng ln Lhe
0(17 aLLrlbuLe.
1here ls a slmllar soluLlon for dynamlc updaLe sLaLemenLs called #"1. 1he #"1 elemenL can be used Lo
dynamlcally lnclude columns Lo updaLe, and leave ouL oLhers. lor example:
<update id="updateAuthorIfNecessary"
parameterType="domain.blog.Author">
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio}</if>
</set>
where id=#{id}
</update>

Pere, Lhe #"1 elemenL wlll dynamlcally prepend Lhe SL1 keyword, and also ellmlnaLe any exLraneous
commas LhaL mlghL Lrall Lhe value asslgnmenLs afLer Lhe condlLlons are applled.
lf you're curlous abouL whaL Lhe equlvalenL 1!(. elemenL would look llke, here lL ls:
<trim prefix="SET" suffixOverrides=",">

</trim>
noLlce LhaL ln Lhls case we're overrldlng a sufflx, whlle we're sLlll appendlng a preflx.
1)$0#63
AnoLher common necesslLy for dynamlc SCL ls Lhe need Lo lLeraLe over a collecLlon, ofLen Lo bulld an ln
condlLlon. lor example:
<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>

My8aLls 3 - user Culde
1 March 2011 49
1he 6$!"-&7 elemenL ls very powerful, and allows you Lo speclfy a collecLlon, declare lLem and lndex
varlables LhaL can be used lnslde Lhe body of Lhe elemenL. lL also allows you Lo speclfy openlng and
closlng sLrlngs, and add a separaLor Lo place ln beLween lLeraLlons. 1he elemenL ls smarL ln LhaL lL won'L
accldenLally append exLra separaLors.
# noLe: ?ou can pass a LlsL lnsLance or an Array Lo My8aLls as a parameLer ob[ecL. When you do,
My8aLls wlll auLomaLlcally wrap lL ln a Map, and key lL by name. LlsL lnsLances wlll be keyed Lo
Lhe name llsL" and array lnsLances wlll be keyed Lo Lhe name array".
1hls wraps up Lhe dlscusslon regardlng Lhe xML conflguraLlon flle and xML mapplng flles. 1he nexL
secLlon wlll dlscuss Lhe !ava Al ln deLall, so LhaL you can geL Lhe mosL ouL of Lhe mapplngs LhaL you've
creaLed.
My8aLls 3 - user Culde
1 March 2011 30
O#K# EMS
now LhaL you know how Lo conflgure My8aLls and creaLe mapplngs, you're ready for Lhe good sLuff.
1he My8aLls !ava Al ls where you geL Lo reap Lhe rewards of your efforLs. As you'll see, compared Lo
!u8C, My8aLls greaLly slmpllfles your code and keeps lL clean, easy Lo undersLand and malnLaln. My8aLls
3 has lnLroduced a number of slgnlflcanL lmprovemenLs Lo make worklng wlLh SCL Maps even beLLer.
5&$06+)$. ?+$*6+*$0
8efore we dlve ln Lo Lhe !ava Al lLself, lL's lmporLanL Lo undersLand Lhe besL pracLlces surroundlng
dlrecLory sLrucLures. My8aLls ls very flexlble, and you can do almosL anyLhlng wlLh your flles. 8uL as
wlLh any framework, Lhere's a preferred way.
LeL's look aL a Lyplcal appllcaLlon dlrecLory sLrucLure:

/my_application
/bin
/devlib
/lib
/src
/org/myapp/
/action
/data
/SqlMapConfig.xml
/BlogMapper.java
/BlogMapper.xml
/model
/service
/view
/properties
/test
/org/myapp/
/action
/data
/model
/service
/view
/properties
/web
/WEB-INF
/web.xml




$ MyBatis *.jar files go
here.


$ MyBatis artifacts go
here, including, Mapper
Classes, XML Configuration,
XML Mapping Files.



$ Properties included in
your XML Configuration go
here.


Remember, these are
preferences, not
requirements, but others
will thank you for using a
common directory structure.

1he resL of Lhe examples ln Lhls secLlon wlll assume you're followlng Lhls dlrecLory sLrucLure.
My8aLls 3 - user Culde
1 March 2011 31
?@8?044&)%4
1he prlmary !ava lnLerface for worklng wlLh My8aLls ls Lhe SqlSesslon. 1hrough Lhls lnLerface you can
execuLe commands, geL mappers and manage LransacLlons. We'll Lalk more abouL SqlSesslon lLself
shorLly, buL flrsL we have Lo learn how Lo acqulre an lnsLance of SqlSesslon. SqlSesslons are creaLed by
a SqlSesslonlacLory lnsLance. 1he SqlSesslonlacLory conLalns meLhods for creaLlng lnsLances of
SqlSesslons all dlfferenL ways. 1he SqlSesslonlacLory lLself ls creaLed by Lhe SqlSesslonlacLory8ullder
LhaL can creaLe Lhe SqlSessonlacLory from xML, AnnoLaLlons or hand coded !ava conflguraLlon.
?@8?044&)%A#6+)$.<*&8/0$
1he SqlSesslonlacLory8ullder has flve bulld() meLhods, each whlch allows you Lo bulld a SqlSesslon from
a dlfferenL source.
SqlSessionFactory build(Reader reader)
SqlSessionFactory build(Reader reader, String environment)
SqlSessionFactory build(Reader reader, Properties properties)
SqlSessionFactory build(Reader reader, String env, Properties props)
SqlSessionFactory build(Configuration config)

1he flrsL four meLhods are Lhe mosL common, as Lhey Lake a @"-)"! lnsLance LhaL refers Lo an xML
documenL, or more speclflcally, Lhe SqlMapConflg.xml flle dlscussed above. 1he opLlonal parameLers are
",<(!$,.",1 and /!$/"!1("#. LnvlronmenL deLermlnes whlch envlronmenL Lo load, lncludlng Lhe
daLasource and LransacLlon manager. lor example:
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">

<dataSource type="POOLED">

</environment>
<environment id="production">
<transactionManager type="EXTERNAL">

<dataSource type="JNDI">

</environment>
</environments>

lf you call a bulld meLhod LhaL Lakes Lhe ",<(!$,.",1 parameLer, Lhen My8aLls wlll use Lhe conflguraLlon
for LhaL envlronmenL. Cf course, lf you speclfy an lnvalld envlronmenL, you wlll recelve an error. lf you
call one of Lhe bulld meLhods LhaL does noL Lake Lhe ",<(!$,.",1 parameLer, Lhen Lhe defaulL
envlronmenL ls uses (whlch ls speclfled as defaulL=developmenL" ln Lhe example above).
lf you call a meLhod LhaL Lakes a properLles lnsLance, Lhen My8aLls wlll load Lhose properLles and make
Lhem avallable Lo your conflguraLlon. 1hose properLles can be used ln place of mosL values ln Lhe
conflguraLlon uslng Lhe synLax: $[propname}
My8aLls 3 - user Culde
1 March 2011 32
8ecall LhaL properLles can also be referenced from Lhe SqlMapConflg.xml flle, or speclfled dlrecLly wlLhln
lL. 1herefore lL's lmporLanL Lo undersLand Lhe prlorlLy. We menLloned lL earller ln Lhls documenL, buL
here lL ls agaln for easy reference:

lf a properLy exlsLs ln more Lhan one of Lhese places, My8aLls loads Lhem ln Lhe followlng order:
roperLles speclfled ln Lhe body of Lhe properLles elemenL are read flrsL,
roperLles loaded from Lhe classpaLh resource or url aLLrlbuLes of Lhe properLles
elemenL are read second, and overrlde any dupllcaLe properLles already speclfled ,
roperLles passed as a meLhod parameLer are read lasL, and overrlde any dupllcaLe
properLles LhaL may have been loaded from Lhe properLles body and Lhe resource/url
aLLrlbuLes.
1hus, Lhe hlghesL prlorlLy properLles are Lhose passed ln as a meLhod parameLer, followed by
resource/url aLLrlbuLes and flnally Lhe properLles speclfled ln Lhe body of Lhe properLles
elemenL.
So Lo summarlze, Lhe flrsL four meLhods are largely Lhe same, buL wlLh overrldes Lo allow you Lo
opLlonally speclfy Lhe envlronmenL and/or properLles. Pere ls an example of bulldlng a
SqlSesslonlacLory from an SqlMapConflg.xml flle.
String resource = "org/mybatis/builder/MapperConfig.xml";
Reader reader = Resources.getResourceAsReader(resource);
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(reader);

noLlce LhaL we're maklng use of Lhe @"#$%!&"# uLlllLy class, whlch llves ln Lhe org.mybaLls.lo package.
1he @"#$%!&"# class, as lLs name lmplles, helps you load resources from Lhe classpaLh, fllesysLem or even
a web u8L. A qulck look aL Lhe class source code or lnspecLlon Lhrough your luL wlll reveal lLs falrly
obvlous seL of useful meLhods. Pere's a qulck llsL:
URL getResourceURL(String resource)
URL getResourceURL(ClassLoader loader, String resource)
InputStream getResourceAsStream(String resource)
InputStream getResourceAsStream(ClassLoader loader, String resource)
Properties getResourceAsProperties(String resource)
Properties getResourceAsProperties(ClassLoader loader, String resource)
Reader getResourceAsReader(String resource)
Reader getResourceAsReader(ClassLoader loader, String resource)
File getResourceAsFile(String resource)
File getResourceAsFile(ClassLoader loader, String resource)
InputStream getUrlAsStream(String urlString)
Reader getUrlAsReader(String urlString)
Properties getUrlAsProperties(String urlString)
Class classForName(String className)

My8aLls 3 - user Culde
1 March 2011 33
1he flnal bulld meLhod Lakes an lnsLance of ConflguraLlon. 1he ConflguraLlon class conLalns everyLhlng
you could posslbly need Lo know abouL a SqlSesslonlacLory lnsLance. 1he ConflguraLlon class ls useful
for lnLrospecLlng on Lhe conflguraLlon, lncludlng flndlng and manlpulaLlng SCL maps (noL recommended
once Lhe appllcaLlon ls accepLlng requesLs). 1he conflguraLlon class has every conflguraLlon swlLch LhaL
you've learned abouL already, only exposed as a !ava Al. Pere's a slmple example of how Lo manually a
ConflguraLlon lnsLance and pass lL Lo Lhe bulld() meLhod Lo creaLe a SqlSesslonlacLory.
DataSource dataSource = BaseDataTest.createBlogDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();

Environment environment =
new Environment("development", transactionFactory, dataSource);

Configuration configuration = new Configuration(environment);
configuration.setLazyLoadingEnabled(true);
configuration.setEnhancementEnabled(true);
configuration.getTypeAliasRegistry().registerAlias(Blog.class);
configuration.getTypeAliasRegistry().registerAlias(Post.class);
configuration.getTypeAliasRegistry().registerAlias(Author.class);
configuration.addMapper(BoundBlogMapper.class);
configuration.addMapper(BoundAuthorMapper.class);

SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(configuration);

now you have a SqlSesslonlacLory, LhaL can be used Lo creaLe SqlSesslon lnsLances.
?@8?044&)%A#6+)$.
SqlSesslonlacLory has slx meLhods LhaL are used Lo creaLe SqlSesslonlnsLances. ln general, Lhe declslons
you'll be maklng when selecLlng one of Lhese meLhods are:
1ransact|on: uo you wanL Lo use a LransacLlon scope for Lhe sesslon, or use auLo-commlL
(usually means no LransacLlon wlLh mosL daLabases and/or !u8C drlvers)?
Connect|on: uo you wanL My8aLls Lo acqulre a ConnecLlon from Lhe conflgured uaLaSource for
you, or do you wanL Lo provlde your own?
Lxecut|on: uo you wanL My8aLls Lo reuse reparedSLaLemenLs and/or baLch updaLes (lncludlng
lnserLs and deleLes)?
1he seL of overloaded openSesslon() meLhod slgnaLures allow you Lo choose any comblnaLlon of Lhese
opLlons LhaL makes sense.
SqlSession openSession()
SqlSession openSession(boolean autoCommit)
SqlSession openSession(Connection connection)
SqlSession openSession(TransactionIsolationLevel level)
SqlSession openSession(ExecutorType execType,TransactionIsolationLevel level)
SqlSession openSession(ExecutorType execType)
SqlSession openSession(ExecutorType execType, boolean autoCommit)
My8aLls 3 - user Culde
1 March 2011 34
SqlSession openSession(ExecutorType execType, Connection connection)
Configuration getConfiguration();

1he defaulL openSesslon() meLhod LhaL Lakes no parameLers wlll creaLe a SqlSesslon wlLh Lhe followlng
characLerlsLlcs:
A LransacLlon scope wlll be sLarLed (l.e. nC1 auLo-commlL)
A ConnecLlon ob[ecL wlll be acqulred from Lhe uaLaSource lnsLance conflgured by Lhe acLlve
envlronmenL.
1he LransacLlon lsolaLlon level wlll be Lhe defaulL used by Lhe drlver or daLa source.
no reparedSLaLemenLs wlll be reused, and no updaLes wlll be baLched.
MosL of Lhe meLhods are preLLy self explanaLory. 1o enable auLo-commlL, pass a value of Lrue" Lo Lhe
opLlonal -%1$A$..(1 parameLer. 1o provlde your own connecLlon, pass an lnsLance of ConnecLlon Lo
Lhe &$,,"&1($, parameLer. noLe LhaL Lhere's no overrlde Lo seL boLh Lhe ConnecLlon and auLoCommlL,
because My8aLls wlll use whaLever seLLlng Lhe provlded connecLlon ob[ecL ls currenLly uslng. My8aLls
uses a !ava enumeraLlon wrapper for LransacLlon lsolaLlon levels called, 1ransacLlonlsolaLlonLevel, buL
oLherwlse Lhey work as expecLed and has Lhe 3 levels supporLed by !u8C (nCnL, 8LAu_unCCMMl11Lu,
8LAu_CCMMl11Lu, 8LLA1A8LL_8LAu, SL8lALlZA8LL).
1he one parameLer LhaL mlghL be new Lo you ls LxecuLor1ype. 1hls enumeraLlon deflnes 3 values:
Lxecutor1ype.SIMLL
1hls Lype of execuLor does noLhlng speclal. lL creaLes a new reparedSLaLemenL for each
execuLlon of a sLaLemenL.
Lxecutor1ype.kLUSL
1hls Lype of execuLor wlll reuse reparedSLaLemenLs.
Lxecutor1ype.8A1Cn
1hls execuLor wlll baLch all updaLe sLaLemenLs and demarcaLe Lhem as necessary lf SLLLC1s are
execuLed beLween Lhem, Lo ensure an easy-Lo-undersLand behavlor.
! noLe: 1here's one more meLhod on Lhe SqlSesslonlacLory LhaL we dldn'L menLlon, and LhaL ls
2"1A$,6(2%!-1($,BC. 1hls meLhod wlll reLurn an lnsLance of ConflguraLlon LhaL you can use Lo lnLrospecL
upon Lhe My8aLls conflguraLlon aL runLlme.
! noLe: lf you've used a prevlous verslon of My8aLls, you'll recall LhaL sesslons, LransacLlons and
baLches were all someLhlng separaLe. 1hls ls no longer Lhe case. All Lhree are neaLly conLalned wlLhln
Lhe scope of a sesson. ?ou need noL deal wlLh LransacLlons or baLches separaLely Lo geL Lhe full beneflL
of Lhem.
My8aLls 3 - user Culde
1 March 2011 33
?@8?044&)%
As menLloned above, Lhe SqlSesslon lnsLance ls Lhe mosL powerful class ln My8aLls. lL ls where you'll flnd
all of Lhe meLhods Lo execuLe sLaLemenLs, commlL or rollback LransacLlons and acqulre mapper
lnsLances.
1hre are over LwenLy meLhods on Lhe SqlSesslon class, so leL's break Lhem up lnLo more dlgesLlble
grouplngs.
!,*,$6$(, AB$+0,&'( 2$,C'1%
1hese meLhods are used Lo execuLe SLLLC1, lnSL81, uuA1L and uLLL1L sLaLemenLs LhaL are deflned ln
your SCL Mapplng xML flles . 1hey are preLLy self explanaLory, each Lakes Lhe lu of Lhe sLaLemenL and
Lhe arameLer Cb[ecL, whlch can be a prlmlLlve (auLo-boxed, or wrapper), a !ava8ean, a C!C or a Map.
Object selectOne(String statement, Object parameter)
List selectList(String statement, Object parameter)
Map selectMap(String statement, Object parameter, String mapKey)
int insert(String statement, Object parameter)
int update(String statement, Object parameter)
int delete(String statement, Object parameter)

1he dlfference beLween selecLCne and selecLLlsL ls only ln LhaL selecLCne musL reLurn exacLly one
ob[ecL. lf any more Lhan one, or none (null) ls reLurned, an excepLlon wlll be Lhrown. lf you don'L' know
how many ob[ecLs are expecLed, use selecLLlsL. lf you wanL Lo check for Lhe exlsLence of an ob[ecL,
you're beLLer off reLurnlng a counL (0 or 1). 1he selecLMap ls a speclal case ln LhaL lL ls deslgned Lo
converL a llsL of resulLs lnLo a Map based on one of Lhe properLles ln Lhe resulLlng ob[ecLs. 8ecause noL
all sLaLemenLs requlre a parameLer, Lhese meLhods are overloaded wlLh verslons LhaL do noL requlre Lhe
parameLer ob[ecL.

Object selectOne(String statement)
List selectList(String statement)
Map selectMap(String statement, String mapKey)
int insert(String statement)
int update(String statement)
int delete(String statement)

llnally, Lhere are Lhree advanced verslons of Lhe selecL meLhods LhaL allow you Lo resLrlcL Lhe range of
rows Lo reLurn, or provlde cusLom resulL handllng loglc, usually for very large daLa seLs.

List selectList
(String statement, Object parameter, RowBounds rowBounds)
Map selectMap(String statement, Object parameter, String mapKey,
RowBounds rowbounds)
void select
(String statement, Object parameter, ResultHandler handler)
void select
(String statement, Object parameter, RowBounds rowBounds,
ResultHandler handler)
My8aLls 3 - user Culde
1 March 2011 36

1he 8ow8ounds parameLer causes My8aLls Lo sklp Lhe number of records speclfled, as well as llmlL Lhe
number of resulLs reLurned Lo some number. 1he 8ow8ounds class has a consLrucLor Lo Lake boLh Lhe
offseL and llmlL, and ls oLherwlse lmmuLable.
int offset = 100;
int limit = 25;
RowBounds rowBounds = new RowBounds(offset, limit);

ulfferenL drlvers are able Lo achleve dlfferenL levels of efflclency ln Lhls regard. lor Lhe besL
performance, use resulL seL Lypes of SC8CLL_SLnSl1lvL or SC8CLL_lnSLnSl1lvL (ln oLher words: noL
lC8WA8u_CnL?).
1he 8esulLPandler parameLer allows you Lo handle each row however you llke. ?ou can add lL Lo a LlsL,
creaLe a Map, SeL, or Lhrow each resulL away and lnsLead keep only rolled up LoLals of calculaLlons. ?ou
can do preLLy much anyLhlng wlLh Lhe 8esulLPandler, and lL's whaL My8aLls uses lnLernally lLself Lo bulld
resulL seL llsLs.
1he lnLerface ls very slmple.
package org.mybatis.executor.result;
public interface ResultHandler {
void handleResult(ResultContext context);
}

1he 8esulLConLexL parameLer glves you access Lo Lhe resulL ob[ecL lLself, a counL of Lhe number of resulL
ob[ecLs creaLed, and a 8oolean sLop() meLhod LhaL you can use Lo sLop My8aLls from loadlng any more
resulLs.
@-*(%*+,&'( D'(,-'# 2$,C'1%
1here are four meLhods for conLrolllng Lhe scope of a LransacLlon. Cf course, Lhese have no effecL lf
you've chosen Lo use auLo-commlL or lf you're uslng an exLernal LransacLlon manager. Powever, lf
you're uslng Lhe !u8C LransacLlon manager, managed by Lhe ConnecLlon lnsLance, Lhen Lhe four
meLhods LhaL wlll come ln handy are:
void commit()
void commit(boolean force)
void rollback()
void rollback(boolean force)

8y defaulL My8aLls does noL acLually commlL unless lL deLecLs LhaL Lhe daLabase has been changed by a
call Lo lnserL, updaLe or deleLe. lf you've somehow made changes wlLhouL calllng Lhese meLhods, Lhen
you can pass Lrue lnLo Lhe commlL and rollback meLhods Lo guaranLee LhaL lL wlll be commlLLed (noLe,
you sLlll can'L force a sesslon ln auLo-commlL mode, or one LhaL ls uslng an exLernal LransacLlon
manager. MosL of Lhe Llme you won'L have Lo call rollback(), as My8aLls wlll do LhaL for you lf you don'L
call commlL. Powever, lf you need more flne gralned conLrol over a sesslon where mulLlple commlLs and
rollbacks are posslble, you have Lhe rollback opLlon Lhere Lo make LhaL posslble.
My8aLls 3 - user Culde
1 March 2011 37
D#$*-&(E ,C$ !$%%&'( F$G$# D*+C$

void clearCache()

1he SqlSesslon lnsLance has a local cache LhaL ls cleared upon updaLe, commlL, rollback and close. 1o
close lL expllclLly (perhaps wlLh Lhe lnLenLlon Lo do more work), you can call clearCache().
A(%0-&(E ,C*, !"#!$%%&'( &% D#'%$1

void close()

1he mosL lmporLanL Lhlng you musL ensure ls LhaL you close any sesslons LhaL you open. 1he besL way
Lo ensure Lhls ls Lo use Lhe followlng unlL of work paLLern:

SqlSession session = sqlSessionFactory.openSession();
try {
// following 3 lines pseudocod for doing some work
session.insert();
session.update();
session.delete();
session.commit();
} finally {
session.close();
}

! noLe: !usL llke SqlSesslonlacLory, you can geL Lhe lnsLance of ConflguraLlon LhaL Lhe SqlSesslon ls
uslng by calllng Lhe geLConflguraLlon() meLhod.
Configuration getConfiguration()

H%&(E 2*33$-%

<T> T getMapper(Class<T> type)

Whlle Lhe varlous lnserL, updaLe, deleLe and selecL meLhods above are powerful, Lhey are also very
verbose, noL Lype safe and noL as helpful Lo your luL or unlL LesLs as Lhey could be. We've already seen
an example of uslng Mappers ln Lhe CeLLlng SLarLed secLlon above.

1herefore, a more common way Lo execuLe mapped sLaLemenLs ls Lo use Mapper classes. A mapper
class ls slmply an lnLerface wlLh meLhod deflnlLlons LhaL maLch up agalnsL Lhe SqlSesslon meLhods. 1he
followlng example class demonsLraLes some meLhod slgnaLures and how Lhey map Lo Lhe SqlSesslon.

public interface AuthorMapper {
// (Author) selectOne(selectAuthor,5);
Author selectAuthor(int id);
// (List<Author>) selectList(selectAuthors)
List<Author> selectAuthors();


My8aLls 3 - user Culde
1 March 2011 38
// (Map<Integer,Author>) selectMap(selectAuthors, id)
@MapKey(id)
List<Author> selectAuthorsAsMap();
// insert(insertAuthor, author)
int insertAuthor(Author author);
// updateAuthor(updateAuthor, author)
int updateAuthor(Author author);
// delete(deleteAuthor,5)
int deleteAuthor(int id);
}
ln a nuLshell, each Mapper meLhod slgnaLure should maLch LhaL of Lhe SqlSesslon meLhod LhaL lL's
assoclaLed Lo, buL wlLhouL Lhe SLrlng parameLer lu. lnsLead, Lhe meLhod name musL maLch Lhe mapped
sLaLemenL lu.
ln addlLlon, Lhe reLurn Lype musL maLch LhaL of Lhe expecLed resulL Lype. All of Lhe usual Lypes are
supporLed, lncludlng: rlmlLlves, Maps, C!Cs and !ava8eans.
! Mapper lnLerfaces do noL need Lo lmplemenL any lnLerface or exLend any class. As long as Lhe
meLhod slgnaLure can be used Lo unlquely ldenLlfy a correspondlng mapped sLaLemenL.
! Mapper lnLerfaces can exLend oLher lnLerfaces. 8e sure LhaL you have Lhe sLaLemenLs ln Lhe
approprlaLe namespace when uslng xML blndlng Lo Mapper lnLerfaces. Also, Lhe only llmlLaLlon ls LhaL
you cannoL have Lhe same meLhod slgnaLure ln Lwo lnLerfaces ln a hlerarchy (a bad ldea anyway).
?ou can pass mulLlple parameLers Lo a mapper meLhod. lf you do, Lhey wlll be named by Lhelr poslLlon
ln Lhe parameLer llsL by defaulL, for example: #[1}, #[2} eLc. lf you wlsh Lo change Lhe name of Lhe
parameLers (mulLlple only), Lhen you can use Lhe [aram(paramname") annoLaLlon on Lhe parameLer.
?ou can also pass a 8ow8ounds lnsLance Lo Lhe meLhod Lo llmlL query resulLs.
2*33$- I((',*,&'(%
Slnce Lhe very beglnnlng, My8aLls has been an xML drlven framework. 1he conflguraLlon ls xML based,
and Lhe Mapped SLaLemenLs are deflned ln xML. WlLh My8aLls 3, Lhere are new opLlons avallable.
My8aLls 3 bullds on Lop of a comprehenslve and powerful !ava based ConflguraLlon Al. 1hls
ConflguraLlon Al ls Lhe foundaLlon for Lhe xML based My8aLls conflguraLlon, as well as Lhe new
AnnoLaLlon based conflguraLlon. AnnoLaLlons offer a slmple way Lo lmplemenL slmple mapped
sLaLemenLs wlLhouL lnLroduclng a loL of overhead.
! noLe: !ava AnnoLaLlons are unforLunaLely llmlLed ln Lhelr expresslveness and flexlblllLy. uesplLe a loL
of Llme spenL ln lnvesLlgaLlon, deslgn and Lrlals, Lhe mosL powerful My8aLls mapplngs slmply cannoL be
bullL wlLh AnnoLaLlons - wlLhouL geLLlng rldlculous LhaL ls. C# ALLrlbuLes (for example) do noL suffer
from Lhese llmlLaLlons, and Lhus My8aLls.nL1 wlll en[oy a much rlcher alLernaLlve Lo xML. 1haL sald, Lhe
!ava AnnoLaLlon based conflguraLlon ls noL wlLhouL lLs beneflLs.
1he Annotat|ons are as fo||ows:
My8aLls 3 - user Culde
1 March 2011 39
Annotat|on 1arget kML Lqu|va|ent Descr|pt|on
QCacheNamespace Class <cache> Conflgures Lhe cache for Lhe glven
namespace (l.e. class). ALLrlbuLes:
|mp|ementat|on, ev|ct|on, f|ushInterva|, s|ze
and readWr|te.
QCacheNamespacekef Class <cache8ef> 8eferences Lhe cache of anoLher namespace
Lo use. ALLrlbuLes: va|ue, whlch should be
Lhe sLrlng value of a namespace (l.e. a fully
quallfled class name).
QConstructorArgs MeLhod <consLrucLor> CollecLs a group of resulLs Lo be passed Lo a
resulL ob[ecL consLrucLor. ALLrlbuLes: va|ue,
whlch ls an array of Args.
QArg MeLhod <arg>
<ldArg>
A slngle consLrucLor argumenL LhaL ls parL of a
ConsLrucLorArgs collecLlon. ALLrlbuLes: |d,
co|umn, [ava1ype, [dbc1ype, typenand|er.
1he ld aLLrlbuLe ls a boolean value LhaL
ldenLlfles Lhe properLy Lo be used for
comparlsons, slmllar Lo Lhe <ldArg> xML
elemenL.
Q1ypeD|scr|m|nator MeLhod <dlscrlmlnaLor> A group of value cases LhaL can be used Lo
deLermlne Lhe resulL mapplng Lo perform.
ALLrlbuLes: co|umn, [ava1ype, [dbc1ype,
typenand|er, cases. 1he cases aLLrlbuLe ls an
array of Cases.
QCase MeLhod <case> A slngle case of a value and lLs correspondlng
mapplngs. ALLrlbuLes: va|ue, type, resu|ts.
1he resulLs aLLrlbuLe ls an array of 8esulLs,
Lhus Lhls Case AnnoLaLlon ls slmllar Lo an
acLual 8esulLMap, speclfled by Lhe 8esulLs
annoLaLlon below.
Qkesu|ts MeLhod <resulLMap> A llsL of 8esulL mapplngs LhaL conLaln deLalls
of how a parLlcular resulL column ls mapped
Lo a properLy or fleld. ALLrlbuLes: va|ue,
whlch ls an array of 8esulL annoLaLlons.
Qkesu|t MeLhod <resulL>
<ld>

A slngle resulL mapplng beLween a column
and a properLy or fleld. ALLrlbuLes: |d,
co|umn, property, [ava1ype, [dbc1ype,
typenand|er, one, many. 1he ld aLLrlbuLe ls a
boolean value LhaL lndlcaLes LhaL Lhe
properLy should be used for comparlsons
(slmllar Lo <ld> ln Lhe xML mapplngs). 1he
one aLLrlbuLe ls for slngle assoclaLlons, slmllar
Lo <assoclaLlon>, and Lhe many aLLrlbuLe ls
for collecLlons, slmllar Lo <collecLlon>. 1hey
are named as Lhey are Lo avold class namlng
confllcLs.
My8aLls 3 - user Culde
1 March 2011 60
Annotat|on 1arget kML Lqu|va|ent Descr|pt|on
QCne MeLhod <assoclaLlon> A mapplng Lo a slngle properLy value of a
complex Lype. ALLrlbuLes: se|ect, whlch ls
Lhe fully quallfled name of a mapped
sLaLemenL (l.e. mapper meLhod) LhaL can load
an lnsLance of Lhe approprlaLe Lype. J',$K
D$% 0('' ,$1(&" 17-1 ;$(, .-//(,2 (# ,$1
#%//$!1") <(- 17" 4,,$1-1($,# 4EF9 =7(# (# )%"
1$ 17" '(.(1-1($, (, G-<- 4,,$1-1($,# 17-1
)$"# ,$1 -''$0 6$! &(!&%'-! !"6"!",&"#9
QMany MeLhod <collecLlon> A mapplng Lo a collecLlon properLy of a
complex Lypes. ALLrlbuLes: se|ect, whlch ls
Lhe fully quallfled name of a mapped
sLaLemenL (l.e. mapper meLhod) LhaL can load
a collecLlon of lnsLances of Lhe approprlaLe
Lypes. J',$K D$% 0('' ,$1(&" 17-1 ;$(, .-//(,2
(# ,$1 #%//$!1") <(- 17" 4,,$1-1($,# 4EF9 =7(#
(# )%" 1$ 17" '(.(1-1($, (, G-<- 4,,$1-1($,#
17-1 )$"# ,$1 -''$0 6$! &(!&%'-! !"6"!",&"#9
QMapkey MeLhod 1hls ls used on meLhods whlch reLurn Lype ls
a Map. lL ls used Lo converL a LlsL of resulL
ob[ecLs as a Map based on a properLy of
Lhose ob[ecLs.
QCpt|ons MeLhod ALLrlbuLes of
mapped
sLaLemenLs.
1hls annoLaLlon provldes access Lo Lhe wlde
range of swlLches and conflguraLlon opLlons
LhaL are normally presenL on Lhe mapped
sLaLemenL as aLLrlbuLes. 8aLher Lhan
compllcaLe each sLaLemenL annoLaLlon, Lhe
CpLlons annoLaLlon provldes a conslsLenL and
clear way Lo access Lhese. ALLrlbuLes:
useCache=true, f|ushCache=fa|se,
resu|tSet1ype=ICkWAkD_CNL,
statement1ype=kLAkLD, fetchS|ze=-1,
t|meout=-1, useGeneratedkeys=fa|se,
keyroperty="|d", keyCo|umn="". lL's
lmporLanL Lo undersLand LhaL wlLh !ava
AnnoLaLlons, Lhere ls no way Lo speclfy null"
as a value. 1herefore, once you engage Lhe
CpLlons annoLaLlon, your sLaLemenL ls sub[ecL
Lo all of Lhe defaulL values. ay aLLenLlon Lo
whaL Lhe defaulL values are Lo avold
unexpecLed behavlor.

noLe LhaL keyColumn ls only requlred ln
cerLaln daLabases (llke osLgreSCL) when Lhe
key column ls noL Lhe flrsL column ln Lhe
Lable.
My8aLls 3 - user Culde
1 March 2011 61
Annotat|on 1arget kML Lqu|va|ent Descr|pt|on
QInsert
QUpdate
QDe|ete
QSe|ect
MeLhod <lnserL>
<updaLe>
<deleLe>
<selecL>
Lach of Lhese annoLaLlons represenLs Lhe
acLual SCL LhaL ls Lo be execuLed. 1hey each
Lake an array of sLrlngs (or a slngle sLrlng wlll
do). lf an array of sLrlngs ls passed, Lhey are
concaLenaLed wlLh a slngle space beLween
each Lo separaLe Lhem. 1hls helps avold Lhe
mlsslng space" problem when bulldlng SCL
ln !ava code. Powever, you're also welcome
Lo concaLenaLe LogeLher a slngle sLrlng lf you
llke. ALLrlbuLes: va|ue, whlch ls Lhe array of
SLrlngs Lo form Lhe slngle SCL sLaLemenL.
QInsertrov|der
QUpdaterov|der
QDe|eterov|der
QSe|ectrov|der
MeLhod <lnserL>
<updaLe>
<deleLe>
<selecL>
Allows for
creaLlon of
dynamlc SCL.
1hese alLernaLlve SCL annoLaLlons allow you
Lo speclfy a class name and a meLhod LhaL wlll
reLurn Lhe SCL Lo run aL execuLlon Llme.
upon execuLlng Lhe mapped sLaLemenL,
My8aLls wlll lnsLanLlaLe Lhe class, and execuLe
Lhe meLhod, as speclfled by Lhe provlder. 1he
meLhod can opLlonally accepL Lhe parameLer
ob[ecL as lLs sole parameLer, buL musL only
speclfy LhaL parameLer, or no parameLers.
ALLrlbuLes: type, method. 1he Lype aLLrlbuLe
ls Lhe fully quallfled name of a class. 1he
meLhod ls Lhe name of Lhe meLhod on LhaL
class. J',$: lollowlng Lhls secLlon ls a
dlscusslon abouL Lhe SelecL8ullder class,
whlch can help bulld dynamlc SCL ln a
cleaner, easler Lo read way.
Qaram arameLer n/A lf your mapper meLhod Lakes mulLlple
parameLers, Lhls annoLaLlon can be applled Lo
a mapper meLhod parameLer Lo glve each of
Lhem a name. CLherwlse, mulLlple
parameLers wlll be named by Lhelr ordlnal
poslLlon (noL lncludlng any 8ow8ounds
parameLers). lor example #[1}, #[2} eLc. ls
Lhe defaulL. WlLh [aram(person"), Lhe
parameLer would be named #[person}.
My8aLls 3 - user Culde
1 March 2011 62
Annotat|on 1arget kML Lqu|va|ent Descr|pt|on
QSe|ectkey MeLhod <selecLkey> 1hls annoLaLlon dupllcaLes Lhe <selecLkey>
funcLlonallLy for meLhods annoLaLed wlLh
[lnserL or [lnserLrovlder. lL ls lgnored for
oLher meLhods. lf you speclfy a [SelecLkey
annoLaLlon, Lhen My8aLls wlll lgnore any
generaLed key properLles seL vla Lhe
[CpLlons annoLaLlon, or conflguraLlon
properLles. ALLrlbuLes: statement an array of
sLrlngs whlch ls Lhe SCL sLaLemenL Lo
execuLe, keyroperty whlch ls Lhe properLy of
Lhe parameLer ob[ecL LhaL wlll be updaLed
wlLh Lhe new value, before whlch musL be
elLher Lrue or false Lo denoLe lf Lhe SCL
sLaLemenL should be execuLed before or afLer
Lhe lnserL, resu|t1ype whlch ls Lhe !ava Lype
of Lhe keyroperLy, and
statement1ype=8LA8Lu.
Qkesu|tMap MeLhod n/A 1hls annoLaLlon ls used Lo provlde Lhe ld of a
<resulLMap> elemenL ln an xML mapper Lo a
[SelecL or [SelecLrovlder annoLaLlon. 1hls
allows annoLaLed selecLs Lo reuse resulLmaps
LhaL are deflned ln xML. 1hls annoLaLlon wlll
overrlde any [8esulLs or [ConsLrucLorArgs
annoLaLlon lf boLh are speclfled on an
annoLaLed selecL.
2*33$- I((',*,&'( AB*63#$%
1hls example shows uslng Lhe [SelecLkey annoLaLlon Lo reLrleve a value from a sequence before an
lnserL:
@Insert("insert into table3 (id, name) values(#{nameId}, #{name})")
@SelectKey(statement="call next value for TestSequence",
keyProperty="nameId", before=true, resultType=int.class)
int insertTable3(Name name);

1hls example shows uslng Lhe [SelecLkey annoLaLlon Lo reLrleve an ldenLlLy value afLer an lnserL:
@Insert("insert into table2 (name) values(#{name})")
@SelectKey(statement="call identity()", keyProperty="nameId",
before=false, resultType=int.class)
int insertTable2(Name name);
?0806+<*&8/0$
Cne of Lhe nasLlesL Lhlngs a !ava developer wlll ever have Lo do ls embed SCL ln !ava code. usually Lhls
ls done because Lhe SCL has Lo be dynamlcally generaLed - oLherwlse you could exLernallze lL ln a flle or
My8aLls 3 - user Culde
1 March 2011 63
a sLored proc. As you've already seen, My8aLls has a powerful answer for dynamlc SCL generaLlon ln lLs
xML mapplng feaLures. Powever, someLlmes lL becomes necessary Lo bulld a SCL sLaLemenL sLrlng
lnslde of !ava code. ln LhaL case, My8aLls has one more feaLure Lo help you ouL, before reduclng
yourself Lo Lhe Lyplcal mess of plus slgns, quoLes, newllnes, formaLLlng problems and nesLed condlLlonals
Lo deal wlLh exLra commas or Anu con[uncLlons. lndeed, dynamlcally generaLlng SCL code ln !ava can
be a real nlghLmare.
My8aLls 3 lnLroduces a somewhaL dlfferenL concepL Lo deal wlLh Lhe problem. We could have [usL
creaLed an lnsLance of a class LhaL leLs you call meLhods agalnsL lL Lo bulld a SCL sLaLemenL one sLep aL a
Llme. 8uL Lhen our SCL ends up looklng more llke !ava and less llke SCL. lnsLead, we're Lrylng
someLhlng a llLLle dlfferenL. 1he end resulL ls abouL as close Lo a uomaln Speclflc Language LhaL !ava wlll
ever achleve ln lLs currenL form.
1he Secrets of Se|ect8u||der
1he SelecL8ullder class ls noL maglcal, nor does lL do any of us any good lf you don'L know how lL works.
So rlghL off Lhe baL, leL's look aL whaL lL does. SelecL8ullder uses a comblnaLlon of SLaLlc lmporLs and a
1hreadLocal varlable Lo enable a clean synLax LhaL can be easlly lnLerlaced wlLh condlLlonals and Lakes
care of all of Lhe SCL formaLLlng for you. lL allows us Lo creaLe meLhods llke Lhls:
public String selectBlogsSql() {
BEGIN(); // Clears ThreadLocal variable
SELECT("*");
FROM("BLOG");
return SQL();
}

1haL's a preLLy slmple example LhaL you mlghL [usL choose Lo bulld sLaLlcally. So here's a more
compllcaLed example:

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();
}
My8aLls 3 - user Culde
1 March 2011 64

8ulldlng Lhe above SCL would be a blL of a Lrlal ln SLrlng concaLenaLlon. lor example:
"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";

lf you prefer LhaL synLax, Lhen you're sLlll welcome Lo use lL. lL ls qulLe error prone Lhough. noLlce Lhe
careful addlLlon of a space aL Lhe end of each llne. now even lf you do prefer LhaL synLax, Lhe nexL
example ls lnarguably far slmpler Lhan !ava SLrlng concaLenaLlon:
private String selectPersonLike(Person p){
BEGIN(); // Clears ThreadLocal variable
SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FIRST_NAME, P.LAST_NAME");
FROM("PERSON P");
if (p.id != null) {
WHERE("P.ID like #{id}");
}
if (p.firstName != null) {
WHERE("P.FIRST_NAME like #{firstName}");
}
if (p.lastName != null) {
WHERE("P.LAST_NAME like #{lastName}");
}
ORDER_BY("P.LAST_NAME");
return SQL();
}

WhaL ls so speclal abouL LhaL example? Well, lf you look closely, lL doesn'L have Lo worry abouL
accldenLally dupllcaLlng Anu" keywords, or chooslng beLween WPL8L" and Anu" or nelLher! 1he
sLaLemenL above wlll generaLe a query by example for all L8SCn records, ones wlLh lu llke Lhe
parameLer, or Lhe flrsLname llke Lhe parameLer, or Lhe lasLname llke Lhe parameLer -or any
comblnaLlon of Lhe Lhree. 1he SelecL8ullder Lakes care of undersLandlng where WPLn" needs Lo go,
where an Anu" should be used and all of Lhe SLrlng concaLenaLlon. 8esL of all, lL does lL almosL
regardless of whlch order you call Lhese meLhods ln (Lhere's only one excepLlon wlLh Lhe C8() meLhod).
1he Lwo meLhods LhaL may caLch your eye are: 8LCln() and SCL(). ln a nuLshell, every SelecL8ullder
meLhod should sLarL wlLh a call Lo 8LCln() and end wlLh a call Lo SCL(). Cf course you can exLracL
meLhods ln Lhe mlddle Lo break up your loglc, buL Lhe scope of Lhe SCL generaLlon should always begln
wlLh 8LCln() and end wlLh SCL(). 1he 8LCln() meLhod clears Lhe 1hreadLocal varlable, Lo make sure you
don'L accldenLally carry any sLaLe forward, and Lhe SCL() meLhod assembles your SCL sLaLemenL based
on Lhe calls you made slnce Lhe lasL call Lo 8LCln(). noLe LhaL 8LCln() has a synonym called 8LSL1(),
whlch does exacLly Lhe same Lhlng buL reads beLLer ln cerLaln conLexLs.
My8aLls 3 - user Culde
1 March 2011 63
1o use Lhe SelecL8ullder as ln Lhe examples above, you slmply need Lo lmporL lL sLaLlcally as follows:
import static org.mybatis.jdbc.SelectBuilder.*;
Cnce Lhls ls lmporLed, Lhe class you're worklng wlLhln wlll have all of Lhe SelecL8ullder meLhods
avallable Lo lL. 1he compleLe seL of meLhods ls as follows:
Method Descr|pt|on
8LCln() / 8LSL1() 1hese meLhods clear Lhe 1hreadLocal sLaLe of Lhe SelecL8ullder class, and
prepare lL for a new sLaLemenL Lo be bullL. 8LCln() reads besL when
sLarLlng a new sLaLemenL. 8LSL1() reads besL when clearlng a sLaLemenL
ln Lhe mlddle of execuLlon for some reason (perhaps lf Lhe loglc demands
a compleLely dlfferenL sLaLemenL under some condlLlons).
SLLLC1(SLrlng) SLarLs or appends Lo a SLLLC1 clause. Can be called more Lhan once, and
parameLers wlll be appended Lo Lhe SLLLC1 clause. 1he parameLers are
usually a comma separaLed llsL of columns and allases, buL can be
anyLhlng accepLable Lo Lhe drlver.
SLLLC1_ulS1lnC1(SLrlng) SLarLs or appends Lo a SLLLC1 clause, also adds Lhe ulS1lnC1" keyword Lo
Lhe generaLed query. Can be called more Lhan once, and parameLers wlll
be appended Lo Lhe SLLLC1 clause. 1he parameLers are usually a comma
separaLed llsL of columns and allases, buL can be anyLhlng accepLable Lo
Lhe drlver.
l8CM(SLrlng) SLarLs or appends Lo a l8CM clause. Can be called more Lhan once, and
parameLers wlll be appended Lo Lhe l8CM clause. arameLers are usually
a Lable name and an allas, or anyLhlng accepLable Lo Lhe drlver.
!Cln(SLrlng)
lnnL8_!Cln(SLrlng)
LLl1_Cu1L8_!Cln(SLrlng)
8lCP1_Cu1L8_!Cln(SLrlng)

Adds a new !Cln clause of Lhe approprlaLe Lype, dependlng on Lhe
meLhod called. 1he parameLer can lnclude a sLandard [oln conslsLlng of
Lhe columns and Lhe condlLlons Lo [oln on.
WPL8L(SLrlng) Appends a new WPL8L clause condlLlon, concaLenaLed by Anu. Can be
called mulLlple Llmes, whlch causes lL Lo concaLenaLe Lhe new condlLlons
each Llme wlLh Anu. use C8() Lo spllL wlLh an C8.
C8() SpllLs Lhe currenL WPL8L clause condlLlons wlLh an C8. Can be called
more Lhan once, buL calllng more Lhan once ln a row wlll generaLe erraLlc
SCL.
Anu() SpllLs Lhe currenL WPL8L clause condlLlons wlLh an Anu. Can be called
more Lhan once, buL calllng more Lhan once ln a row wlll generaLe erraLlc
SCL. 8ecause WPL8L and PAvlnC boLh auLomaLlcally concaLenaLe wlLh
Anu, Lhls ls a very uncommon meLhod Lo use and ls only really lncluded
for compleLeness.
C8Cu_8?(SLrlng) Appends a new C8Cu 8? clause elemenLs, concaLenaLed by a comma.
Can be called mulLlple Llmes, whlch causes lL Lo concaLenaLe Lhe new
condlLlons each Llme wlLh a comma.
PAvlnC(SLrlng) Appends a new PAvlnC clause condlLlon, concaLenaLed by Anu. Can be
called mulLlple Llmes, whlch causes lL Lo concaLenaLe Lhe new condlLlons
each Llme wlLh Anu. use C8() Lo spllL wlLh an C8.
My8aLls 3 - user Culde
1 March 2011 66
Method Descr|pt|on
C8uL8_8?(SLrlng) Appends a new C8uL8 8? clause elemenLs, concaLenaLed by a comma.
Can be called mulLlple Llmes, whlch causes lL Lo concaLenaLe Lhe new
condlLlons each Llme wlLh a comma.
SCL() 1hls reLurns Lhe generaLed SCL() and reseLs Lhe SelecL8ullder sLaLe (as lf
8LCln() or 8LSL1() were called). 1hus, Lhls meLhod can only be called
CnCL!

?@8<*&8/0$
Slmllarly Lo SelecL8ullder, My8aLls also lncludes a generallzed Sql8ullder. lL lncludes all Lhe meLhods for
SelecL8ullder, as well as meLhods for bulldlng lnserLs, updaLes, and deleLes. 1hls class can be useful
when bulldlng SCL sLrlngs ln a ueleLerovlder, lnserLrovlder, or updaLerovlder (as well as a
SelecLrovlder).
1o use Lhe Sql8ullder as ln Lhe examples above, you slmply need Lo lmporL lL sLaLlcally as follows:
import static org.mybatis.jdbc.SqlBuilder.*;
Sql8ullder conLalns all meLhods from SelecL8ullder, as well as Lhese addlLlonal meLhods:
Method Descr|pt|on
uLLL1L_l8CM(SLrlng) SLarLs a deleLe sLaLemenL and speclfles Lhe Lable Lo deleLe from. Cenerally
Lhls should be followed by a WPL8L sLaLemenL!
lnSL81_ln1C(SLrlng) SLarLs an lnserL sLaLemenL and speclfles Lhe Lable Lo lnserL lnLo. 1hls
should be followed by one or more vALuLS() calls.
SL1(SLrlng) Appends Lo Lhe seL" llsL for an updaLe sLaLemenL.
uuA1L(SLrlng) SLarLs an updaLe sLaLemenL and speclfles Lhe Lable Lo updaLe. 1hls should
be followed by one or more SL1() calls, and usually a WPL8L() call.
vALuLS(SLrlng, SLrlng) Appends Lo an lnserL sLaLemenL. 1he flrsL parameLer ls Lhe column(s) Lo
lnserL, Lhe second parameLer ls Lhe value(s).

Pere are some examples:
public String deletePersonSql() {
BEGIN(); // Clears ThreadLocal variable
DELETE_FROM("PERSON");
WHERE("ID = ${id}");
return SQL();
}

public String insertPersonSql() {
BEGIN(); // Clears ThreadLocal variable
INSERT_INTO("PERSON");
VALUES("ID, FIRST_NAME", "${id}, ${firstName}");
VALUES("LAST_NAME", "${lastName}");
return SQL();
}
My8aLls 3 - user Culde
1 March 2011 67

public String updatePersonSql() {
BEGIN(); // Clears ThreadLocal variable
UPDATE("PERSON");
SET("FIRST_NAME = ${firstName}");
WHERE("ID = ${id}");
return SQL();
}

C)''&%'
My8aLls provldes logglng lnformaLlon Lhrough Lhe use of an lnLernal log facLory. 1he lnLernal log facLory
wlll delegaLe logglng lnformaLlon Lo one of Lhe followlng log lmplemenLaLlons:
1. SLl4!
2. !akarLa Commons Logglng (!CL - nC1 !ob ConLrol Language!)
3. Log4!
4. !uk logglng
1he logglng soluLlon chosen ls based on runLlme lnLrospecLlon by Lhe lnLernal My8aLls log facLory. 1he
My8aLls log facLory wlll use Lhe flrsL logglng lmplemenLaLlon lL flnds (lmplemenLaLlons are searched ln
Lhe above order). lf My8aLls flnds none of Lhe above lmplemenLaLlons, Lhen logglng wlll be dlsabled.
Many envlronmenLs shlp !CL as a parL of Lhe appllcaLlon server classpaLh (good examples lnclude
1omcaL and WebSphere). lL ls lmporLanL Lo know LhaL ln such envlronmenLs, My8aLls wlll use !CL as Lhe
logglng lmplemenLaLlon. ln an envlronmenL llke WebSphere Lhls wlll mean LhaL your Log4! conflguraLlon
wlll be lgnored because WebSphere supplles lLs own proprleLary lmplemenLaLlon of !CL. 1hls can be very
frusLraLlng because lL wlll appear LhaL My8aLls ls lgnorlng your Log4! conflguraLlon (ln facL, My8aLls (#
lgnorlng your Log4! conflguraLlon because My8aLls wlll use !CL ln such envlronmenLs). lf your
appllcaLlon ls runnlng ln an envlronmenL where !CL ls lncluded ln Lhe classpaLh buL you would raLher use
one of Lhe oLher logglng lmplemenLaLlons you can selecL a dlfferenL logglng lmplemenLaLlon by calllng
one of Lhe followlng meLhods:
org.apache.lbaLls.logglng.LoglacLory.useSlf4[Logglng(),
org.apache.lbaLls.logglng.LoglacLory.useLog4!Logglng(),
org.apache.lbaLls.logglng.LoglacLory.use!dkLogglng(),
org.apache.lbaLls.logglng.LoglacLory.useCommonsLogglng(),
org.apache.lbaLls.logglng.LoglacLory.useSLdCuLLogglng(),

My8aLls 3 - user Culde
1 March 2011 68
lf you choose Lo call one of Lhese meLhods, you should do so before calllng any oLher My8aLls meLhod.
Also, Lhese meLhods wlll only swlLch Lo Lhe requesLed log lmplemenLaLlon lf LhaL lmplemenLaLlon ls
avallable on Lhe runLlme classpaLh. lor example, lf you Lry Lo selecL Log4! logglng and Log4! ls noL
avallable aL runLlme, Lhen My8aLls wlll lgnore Lhe requesL Lo use Log4! and wlll use lL's normal algorlLhm
for dlscoverlng logglng lmplemenLaLlons.
1he speclflcs of !akarLa Commons Logglng, Log4! and Lhe !uk Logglng Al are beyond Lhe scope of Lhls
documenL. Powever Lhe example conflguraLlon below should geL you sLarLed. lf you would llke Lo know
more abouL Lhese frameworks, you can geL more lnformaLlon from Lhe followlng locaLlons:
!akarLa Commons Logglng
hLLp://[akarLa.apache.org/commons/logglng/lndex.hLml
Log4!
hLLp://[akarLa.apache.org/log4[/docs/lndex.hLml
!uk Logglng Al
hLLp://[ava.sun.com/[2se/1.4.1/docs/gulde/uLll/logglng/
Log ConflguraLlon
My8aLls logs mosL of lLs acLlvlLy uslng log classes LhaL are noL ln Lhe My8aLls packages. 1o see My8aLls
logglng sLaLemenLs, you should enable logglng on classes ln Lhe [ava.sql package - speclflcally Lhe
followlng classes:
! [ava.sql.ConnecLlon
! [ava.sql.reparedSLaLemenL
! [ava.sql.8esulLseL
! [ava.sql.SLaLemenL
Agaln, how you do Lhls ls dependenL on Lhe logglng lmplemenLaLlon ln use. We'll show how Lo do lL wlLh
Log4!. Conflgurlng Lhe logglng servlces ls slmply a maLLer of lncludlng one or more exLra conflguraLlon
flles (e.g. log4[.properLles) and someLlmes a new !A8 flle (e.g. log4[.[ar). 1he followlng example
conflguraLlon wlll conflgure full logglng servlces uslng Log4! as a provlder. 1here are 2 sLeps.
SLep 1: Add Lhe Log4! !A8 flle
8ecause we're uslng Log4!, we'll need Lo ensure lLs !A8 flle ls avallable Lo our appllcaLlon. 1o use Log4!,
you need Lo add Lhe !A8 flle Lo your appllcaLlon classpaLh. ?ou can download Log4! from Lhe u8L above.
lor web or enLerprlse appllcaLlons you can add Lhe log4[.[ar Lo your WL8-lnl/llb dlrecLory, or for a
sLandalone appllcaLlon you can slmply add lL Lo Lhe !vM -classpaLh sLarLup parameLer.
My8aLls 3 - user Culde
1 March 2011 69
SLep 2: Conflgure Log4!
Conflgurlng Log4! ls slmple - you creaLe a flle called log4[.properLles and lL looks llke Lhe followlng:
log4[.properLles
# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
#log4j.logger.org.apache.ibatis=DEBUG
#log4j.logger.java.sql.Connection=DEBUG
#log4j.logger.java.sql.Statement=DEBUG
#log4j.logger.java.sql.PreparedStatement=DEBUG
#log4j.logger.java.sql.ResultSet=DEBUG
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

1he above flle ls Lhe mlnlmal conflguraLlon LhaL wlll cause logglng Lo only reporL on errors. Llne 2 of Lhe
flle ls whaL ls shown Lo be conflgurlng Log4! Lo only reporL errors Lo Lhe sLdouL appender. An appender
ls a componenL LhaL collecLs ouLpuL (e.g. console, flle, daLabase eLc.). 1o maxlmlze Lhe level of reporLlng,
we could change llne 2 as follows:
log4[.rooLLogger=uL8uC, sLdouL
8y changlng llne 2 as above, Log4! wlll now reporL on all logged evenLs Lo Lhe sLdouL' appender
(console). lf you wanL Lo Lune Lhe logglng aL a flner level, you can conflgure each class LhaL logs Lo Lhe
sysLem uslng Lhe SqlMap logglng conflguraLlon' secLlon of Lhe flle above (commenLed ouL ln llnes 4
Lhrough 8 above). So lf we wanLed Lo log reparedSLaLemenL acLlvlLy (SCL sLaLemenLs) Lo Lhe console aL
Lhe uL8uC level, we would slmply change llne 7 Lo Lhe followlng (noLlce lL's noL #commenLed ouL
anymore):
log4j.logger.java.sql.PreparedStatement=DEBUG
1he remalnlng conflguraLlon ln Lhe log4[.properLles flle ls used Lo conflgure Lhe appenders, whlch ls
beyond Lhe scope of Lhls documenL. Powever, you can flnd more lnformaLlon aL Lhe Log4! webslLe (u8L
above). Cr, you could slmply experlmenL wlLh lL Lo see whaL effecLs Lhe dlfferenL conflguraLlon opLlons
have.

You might also like