Ibatis Presentation - Changed
Ibatis Presentation - Changed
Ibatis Presentation - Changed
December, 2006
What is iBATIS ?
Commercial in Confidence 2
Don'ts
Commercial in Confidence 3
Does
Commercial in Confidence 4
Architecture
Commercial in Confidence 5
How it Works ?
Data Mapper provides a very simple framework for using XML descriptors to
map Java Beans, Map implementations, primitive wrapper types (String,
Integer…) and even XML documents to an SQL statement. The following is a
high level description of the lifecycle:
1. Provide an object as a parameter (either a JavaBean, Map or primitive
wrapper).
The parameter object will be used to set input values in an update
statement, or where clause values in a query, ...
2. Execute the mapped statement.
This step is where the magic happens. The Data Mapper framework will
create a PreparedStatement instance, set any parameters using the provided
parameter object, execute the statement and build a result object from the
ResultSet.
3. In the case of an update, the number of rows effected is returned. In the case of
a query, a single object, or a collection of objects is returned. Like parameters,
result objects can be a JavaBean, a Map, a primitive type wrapper or XML.
Commercial in Confidence 6
Installing iBatis.
Commercial in Confidence 7
SqlMapConfig.xml
Commercial in Confidence 8
</sqlMapConfig>
typeAlias Element
<SqlMapConfig.xml>
Commercial in Confidence 9
sqlMap Element
Commercial in Confidence 10
SQL Map XML File
Commercial in Confidence 11
Statement Element
<statement> <delete>
<insert> <update>
<select> <procedure>
Commercial in Confidence 12
parameterMap
Commercial in Confidence 13
parameterMap Ext
nullValue –The null attribute is used to specify an outgoing null value replacement. What this means
is that when the value is detected in the JavaBeans property, a NULL will be written to the database.
typeHandler-- This attribute is used to specify a custom type handler that will be used for this
property instead of the default iBATIS type system. If specified, this value should be the fully
qualified name of a class that implements either the com.ibatis.sqlmap.engine.type.TypeHandler
interface or the com.ibatis.sqlmap.client.extensions.TypeHandlerCallback interface. This value
overrides any global type handler that might otherwise be applied to this property.
Eg:
<parameterMap class="com.firstapex.demo.vo.AddressVO" id="customerDetailsParameterMap" >
<parameter property="custNo" javaType="int" jdbcType="NUMBER"/>
<parameter property="custName" javaType="String" jdbcType="VARCHAR" nullValue="-999"/>
<parameter property="job" javaType="String" jdbcType="VARCHAR" nullValue="-999"/>
<parameter property="ssn" javaType="String" jdbcType="VARCHAR" nullValue="-999"/>
<parameter property="licensed" nullValue="-999" typeHandler="booleanHandler"/>
<parameter property="licencseNo" javaType="String" jdbcType="VARCHAR" nullValue="-
999"/>
<parameter property="rentalID" javaType="String" jdbcType="VARCHAR" nullValue="-999"/>
</parameterMap>
Commercial in Confidence 14
parameterMap Ext
Eg:
<parameterMap class="rental" id="rentalParameterMap" >
<parameter property="rentalID" javaType="string" jdbcType="VARCHAR" />
<parameter property="vehicalType" javaType="string" jdbcType="VARCHAR" nullValue="-
999"/>
<parameter property="vehicleNo" javaType="string" jdbcType="VARCHAR" nullValue="-999"/>
<parameter property="fromDate" jdbcType='DATE' nullValue="-999"/>
<parameter property="toDate" jdbcType='DATE' nullValue="-999"/>
</parameterMap>
Usage:
<insert id="insertRentalByMap" parameterMap="rentalParameterMap" >
INSERT INTO RENTAL_DETAILS
(RENTALID,VEHICLETYPE,VEHICLENO,FROMDATE,TODATE)
VALUES(?,?,?,?,?)
</insert>
In the above example, the JavaBeans properties will be applied to the parameters of the Mapped
Statement insertRentalByMap in the order they are listed.
Commercial in Confidence 15
InLine ParameterMap
Eg:
<insert id="insertRental" parameterClass="rental" >
INSERT INTO RENTAL_DETAILS
(RENTALID,VEHICLETYPE,VEHICLENO,FROMDATE,TODATE)
VALUES
(#rentalID:VARCHAR:-999#,#vehicalType:VARCHAR:-999#,
#vehicleNo:VARCHAR:-999#,#fromDate:DATE#,#toDate:DATE#)
</insert>
• When using inline parameters, you cannot specify the null value replacement without also specifying
the type. You must specify both due to the parsing order.
Commercial in Confidence 16
Primitive Type Parameter
•Here #value# will be substituted by the value of the string that is being passed by the ibatis.
•Primitive types are aliased for more concise code.
• For example, “int” can be used in place of “java.lang.Integer”.
“string” in place of “java.lang.String”
Commercial in Confidence 17
Map Type Parameters
• Map must contain keys named rentalID and type. The values referenced by those keys would be of the
appropriate type, such as Integer and String .
Commercial in Confidence 18
resultMap
Commercial in Confidence 20
ResultMap Example
<resultMap class="rental" id="rentalResultMap" >
<result property="rentalID" column="RENTALID" />
<result property="vehicalType" column="RENTALID" />
<result property="vehicleNo" column="VEHICLENO" />
<result property="fromDate" column="FROMDATE" />
<result property="toDate" column="TODATE" />
<result property="customer" column="RENTALID" select="customer.getCustomerForRentalId" />
</resultMap>
<select id="getRentalVO" parameterClass="String" resultMap="rentalResultMap">
select * from RENTAL_DETAILS where RENTALID = #value#
</select>
<resultMap class="customerVO" id="customerVOResultMap">
<result property="custNo" column="CUSTNO"/>
<result property="custName" column="CUSTNAME"/>
<result property="job" column="JOB"/>
<result property="ssn" column="SSN"/>
<result property="licensed" column="LICENSED" typeHandler="booleanHandler"/>
<result property="licencseNo" column="LICENSENO"/>
<result property="address" column="CUSTNO" select="address.getAddressByID"/>
<result property="rentalID" column="RENTALID"/>
</resultMap>
<select id="getCustomerForRentalId" resultMap="customerVOResultMap" parameterClass=“string">
select * from CUSTOMER_DETAILS where RENTALID = #value#
</select>
<N+1 Problem>
Commercial in Confidence 21
Implicit Result Maps
If you have a very simple requirement ,there is a quick way to implicitly specify a result map by setting a resultClass
attribute of a mapped statement. The trick is that you must ensure that the result set returned has column names
(or labels/aliases) that match up with the write-able property names of your JavaBean.
Eg:
<select id="getRentalVOUsingResultClass" resultClass="rental" parameterClass="string">
select RENTALID as rentalID,VEHICLETYPE as vehicalType,VEHICLENO as vehicalNo ,
FROMDATE as fromDate,TODATE as toDate from RENTAL_DETAILS where RENTALID = #value#
</select>
Commercial in Confidence 22
Map Results
Result Maps can also conveniently populate a Map instance such as HashMap or TreeMap. Collections of
such objects (e.g. Lists of Maps) can also be retrieved using the APIs (Like queryForList()).
Map types are mapped exactly the same way as a JavaBean, but instead of setting JavaBeans properties, the
keys of the Map are set to reference the values for the corresponding mapped columns.
Eg:
<resultMap id="rentalResultHashMap" class="java.util.HashMap">
<result property="rentalID" column="RENTALID" />
<result property="vehicalType" column="VEHICLETYPE" />
<result property="vehicleNo" column="VEHICLENO" />
<result property="fromDate" column="FROMDATE" />
<result property="toDate" column="TODATE" />
</resultMap>
Commercial in Confidence 23
SQL
• The problem with this solution is, that whenever a rental object is loaded, 2 SELECT’s in total
are executed.
• 1 to retrieve the rental details (main query)
• 1 queries to retrieve the related complex property customer details.
• seems trivial when loading a single rental object.
• if the query was run to load 10 rental objects , 1 additional queries would be executed for each
rental object
• 1 * 10 = 10 additional queries => N+1 or in this case 10 + 1 = 11.
This problem can be addressed using another query approach.
<Example>
Commercial in Confidence 25
Solution For Problem
<resultMap class="rental" id="rentalResultMap" >
<result property="rentalID" column="RENTALID" />
<result property="vehicalType" column="RENTALID" />
<result property="vehicleNo" column="VEHICLENO" />
<result property="fromDate" column="FROMDATE" />
<result property="toDate" column="TODATE" />
<!--<result property="customer" column="RENTALID" select="customer.getCustomerForRentalId" />-->
<result property="customer" column="RENTALID" resultMap="customer.customerVOResultMap"/>
</resultMap>
<resultMap class="customerVO" id="customerVOResultMap">
<result property="custNo" column="CUSTNO"/>
<result property="custName" column="CUSTNAME"/>
<result property="job" column="JOB"/>
<result property="ssn" column="SSN"/>
<result property="licensed" column="LICENSED" typeHandler="booleanHandler"/>
<result property="licencseNo" column="LICENSENO"/>
<result property="address" column="CUSTNO" select="address.getAddressByID"/>
<result property="rentalID" column="RENTALID"/>
</resultMap>
<select id="getRentalVOByJoin" parameterClass="String" resultMap="rentalResultMap">
select * from RENTAL_DETAILS , CUSTOMER_DETAILS
Where
RENTAL_DETAILS.RENTALID = CUSTOMER_DETAILS.RENTALID and
RENTAL_DETAILS.RENTALID = #value#
</select>
Commercial in Confidence 26
Lazy Loading vs. Joins
• Currently lazy loading can only be set on the whole SQL Map config
Commercial in Confidence 27
Mapping Results to XML document
<select id="getAddressXml" resultClass="xml" xmlResultName=“ADDRESS"
parameterClass="String">
select CUSTNO AS "CUSTOMER NO", PURPOSE AS "PURPOSE" LINE1 as "Addressline1" ,
LINE2as "Addressline2" ,LINE3 as "Addressline3" , LINE4 as "Addressline4" ,STATE
as "state" ,COUNTRY as "country" , PIN as "PIN NUMBER" from ADDRESS_DETAILS Where
CUSTNO = #customerID#;
</select>
Result:
<ADDRESS>
<CUSTOMER NO></CUSTOMER NO>
<PURPOSE></PURPOSE>
<Addressline1></Addressline1>
<Addressline2></Addressline2>
<Addressline3></Addressline3>
<Addressline4></Addressline4>
…..
</Address>
Commercial in Confidence 28
TypeHandlerCallback
Commercial in Confidence 29
TypeHandlerCallback - Example
public class BooleanHandler implements TypeHandlerCallback {
private static final String YES = "Y";
private static final String NO = "N";
public Object getResult(ResultGetter getter) throws SQLException {
String s = getter.getString();
if (YES.equalsIgnoreCase(s)) {
return new Boolean(true);
} else if (NO.equalsIgnoreCase(s)) {
return new Boolean(false);
} else {
throw new SQLException("Unexpected value " + s + " found where "+ YES + " or " + NO + " was expected.");
}
}
public void setParameter(ParameterSetter setter, Object parameter) throws SQLException {
boolean b = ((Boolean) parameter).booleanValue();
if (b) {
setter.setString(YES);
} else {
setter.setString(NO);
}
}
public Object valueOf(String arg0) {
// TODO Auto-generated method stub
return null;
Commercial in Confidence 30
}
}
Dynamic Mapped Statement
• A very common problem with working directly with JDBC is dynamic SQL
• normally very difficult to work with SQL statement
• that change not only the values of parameters
• but which parameters and columns are included at all
• The typical solution is usually a mess of conditional if-else statements and string
concatenations
• The Data Mapper API provides an elegant solution that can be applied to any mapped statement
element
Eg:
<select id=“dynamicGetRentalVO” resultMap = “rentalParameterMap”>
select * from RENTAL_DETAILS
<dynamic prepend=“WHERE”>
<isNotNull prepend=“AND” property=“vehicalType”>
VEHICLETYPE = # vehicalType #
</isNotNull>
<isGreaterThan prepend="and" property=“rentalID" compareValue="0">
RENTALID = #rentalID#
</isGreaterThan>
<dynamic>
order by rentalID
</select>
Commercial in Confidence 31
Binary Conditional Attributes
Commercial in Confidence 32
Caching Mapped Statement Results
The results from a Query Mapped Statement can be cached simply by specifying the cacheModel
parameter
The cache model is configured within the SQL map using the cacheModel element cache model
uses a pluggable framework
• MEMORY – uses reference type to manage the cache behavior
• LRU – uses a Least Recently Used algorithm
• FIFO – uses a First In First Out algorithm
• OSCACHE – uses the OSCache 2.0 caching engine
Eg:
<cacheModel id=“rental-cache" type =“MEMORY" readOnly=”true” serialize=”false”>
<flushInterval hours="24"/>
<flushOnExecute statement="insertRental"/>
<flushOnExecute statement=“updateRental”/>
<property name=”cache-size” value=”1000” />
<property name="reference-type" value="WEAK"/>
</cacheModel
Commercial in Confidence 33
Programming with the DataMapper:
insert(), update(), delete(): These methods are specifically meant for DML Operations.
public Object insert(String statementName, Object parameterObject) throws SQLException
public Object insert(String statementName) throws SQLException
public int update(String statementName, Object parameterObject) throws SQLException
public int update(String statementName) throws SQLException
public int delete(String statementName, Object parameterObject) throws SQLException
public int delete(String statementName) throws SQLException
Query:
queryForObject():There are three versions of queryForObject(), one that returns a newly allocated object,
and another that uses a pre-allocated object that is passed in as a parameter. The latter is useful for objects
that are populated by more than one statement.
public Object queryForObject(String statementName,Object parameterObject) throws
SQLException
public Object queryForObject(String statementName) throws SQLException
public Object queryForObject(String statementName, Object parameterObject, Object
resultObject) throws SQLException
Commercial in Confidence 34
API
queryForList(): There are four versions of queryForList().
The first executes a query and returns all of the results from that query.
The second is like the first, but does not accept a parameter object.
The third allows for specifying a particular number of results to be skipped (i.e. a starting point) and also the
maximum number of records to return. This is valuable when dealing with extremely large data sets
The fourth is like the third, but does not accept a parameter object.
This method will be called on the RowHandler for each row returned from the database.
queryForMap(): This method provides an alternative to loading a collection of results into a list. Instead it loads the
results into a map keyed by the parameter passed in as the keyProperty.
public Map queryForMap (String statementName, Object parameterObject, String keyProperty) throws
SQLException
public Map queryForMap (String statementName, Object parameterObject, String keyProperty, String
valueProperty) throws SQLException
flushDataCache(): These methods provide a programmatic way of flushing the data caches. The method without
arguments will flush all data caches.The no-argument method clears all the the data Cache.
public void flushDataCache()
public void flushDataCache(String cacheId)
Commercial in Confidence 36
Spring DAO Support
•The DAO (Data Access Object) support in Spring is primarily aimed at making it easy to work with
different data access technologies (like JDBC, Hibernate, EJB3 or iBATIS) in a standardized way.
• This allows to switch between them fairly easily and to code without worrying about catching exceptions
that are specific to each technology.
• replaces DAOFactory classes with configurations and dependency injection
• easy configuration of DAO using dependency injection
• base DaoSupport classes for popular persistence frameworks JDBC, iBATIS, Hibernate, Toplink, EJB3,
…
Commercial in Confidence 37
Spring Integration
• converts exceptions to a common exception hierarchy
• template classes reduce redundant code
• opens and closes necessary resources (such as database connections)
Eg:
<!-- Web SqlMap setup for iBATIS Database Layer -->
<bean id="sqlMapConfig" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="configLocation">
<value>/WEB-INF/sqlMapConfig.xml</value>
</property>
</bean>
<!-- iBatis DAO using the JNDI DataSource -->
<bean id=“rentalQueryDao" class="com.firstapex.demo.dao.ibatis. RentalDAOImpl">
<property name="dataSource" ref="dataSource"/>
<property name="sqlMapClient" ref="sqlMapConfig"/>
</bean>
public class RentalDAOImpl extends SqlMapClientDaoSupport implements IRentalDAO {
public RentalVO getRentalVO(String id) {
return (RentalVO) getSqlMapClientTemplate().queryForObject("getRentalVO", id);
}Commercial in Confidence 38
Settings Element
• The <settings> elements allows to configure various options and optimizations for the SqlMapClient instance
• The <settings> element and all its attribute are optional Always refer to mapped statements by a fully qualified
name (combination of the sqlMap name and the statement name)
maxRequests maximum number of threads that can execute an SQL statement at a time
maxSessions number of sessions (or clients) that can be active at a given time
maxTransactions Maximum number of threads that can enter a transaction at a time
cacheModelsEnabled Globally enables or disables caching
lazyLoadingEnabled Globally enables or disables lazy loading
enhancementEnabled Enables runtime bytecode enhancements
useStatementNamespaceAlways refer to mapped statements by a fully qualified name (combination of the sqlMap name and the statement name)
<sqlMapConfig.xml>
Commercial in Confidence 39
Transaction Manager and Data Source
Commercial in Confidence 41