Why Mybatis
-It Eliminates a lot of JDBC boilerplate code
--MyBatis provides many other features that simplify the implementation of persistence logic
---It supports the mapping of complex SQL result set data to nested object graph structures
---It supports the mapping of one-to-one and one-to-many results to Java objects
---It supports building dynamic SQL queries based on the input data
-It has a low learning curve
-It works well with legacy databases
-It embraces SQL
-It provides support for integeration with Spring and Guice frameworks
-It porvides support for integeration with third-party cache libraries
-It induces better performance
--MyBatis supports database connection pooling that eliminates the cost of creating a database connection on demand for every request.
--Mybatis has an in-built cache mechanism which caches the results of SQL queries at the SqlSession level. That is, if you invoke the same mapped select query , then MyBatis returns the cached result instead of querying the database again.
--MyBatis doesn't use proxying heavily and hence yields better performance compared to other ORM frameworks that use proxies extensively.
Best Practice
-
-There should be only one instance of SqlSessionFactory per database environment , so we have used a singleton pattern to have only one instance of SqlSessionFactory.
-
-Instances of SqlSession objects are not thread safe and should not be shared.So the best scope for SqlSession is the method scope.From a web application perpective,SqlSession should have a request scope.
Configuration MyBatis using XML
Environment:
If your application needs to connect to multiple database, you'll need to configure each database as a separate environment and create a separate SqlSessionFactory object for each other.
DataSource:
The dataSource type can be one of the built-in types sucn as 'UNPOOLED','POOLED','JNDI'
-If you set the type to UNPOOLED,MyBatis will open a new connection and close that connection for every database operation. This method can be used for simple applications that have a small number of concurrent users.
-If you set the type to POOLED,MyBatis will create a pool of database connections,and one of these conncetions will be used for the database operation.Once this is complete,MyBatis will return the connection to the pool.This is a commonly used method for developing/testing environment.
-If you set the type to JNDI,MyBatis will get the connection from the JNDI dataSource that has typically been configured in the application server.
TransactionManager
MyBatis supports two types of transaction managers:JDBC and MANAGED
-The JDBC transaction manager is used where the application is responsible for managing the connection life cycle,that is,commit,rollback,and so on.When you set the TransactionManager property to JDBC,behind the scenes MyBatis uses the JdbcTransactionFactory class to create TransactionManager.For example,an application deployed onApache Tomcat should manage the transactions by itself.
-The MANAGED transaction manager is used where the application server is responsible for managing the connection life cycle.When you set the TransactionManager property to MANAGED,behind the scenes MyBatis used the ManagedTransactionFactory class to create TransactionManager.For example,a JavaEE application deployed on anserver,such as JBoss,WebLogic,or GlassFish,can leverage the application server's transaction management capabilities using EJB.In these managed environments,you can use the MANAGED transaction manager.
typeAliases
Instead of typing the fully qualified names everywhere, we can give the alias names and use these alias names in all the other places where we need to give the fully qualified names.
you can also give the package name where MyBatis can scan and register aliases using uncapitalized nonqualifiedcalss names of the bean.
There is another way of aliasing JavaBeans , using the @Alias annotation
The @Alias annotation overrides the <typeAliases> configuration.
typeHandlers
To let MyBatis understand how to handle custom Java object types,we can extend abstract class BaseTypeHandler<T> to create custom type handlers.
Once the custom type handler is implemented , we need to register it in mybatis-comfig.xml
Settings
The default MyBatis global setting, which can be overridden to better suit application-specific needs,are as fllows:
Mappers
We need to configure the locations of the SQL Mapper files mybatis-config.xml
-The attribute resource can be used to point to a mapper file that is in the classpath
-The attribute url can be used to point to a mapper file by its fully qualified filesystem path or web URL
-The attribute class can be used to point to a Mapper interface
-The package element can be used to point to a package name where Mapper interfaces can be found.
Customizing MyBatis logging
MyBatis uses its internal LoggerFactory as a facade to actual logging libraries.The internal LoggerFactory will delegate the logging task to one of the following actual logger implementations,with the priority decreasing from top to buttom in the given order:
If MyBatis finds none of ther previous implementations , logging will be disabled.
You also can make MyBatis to use a specific logging implementation.
Mapper XMLs and Mapper interfaces
Autogenerated keys
We can use the useGeneratedKeys and keyProperty attributes to let the database generate the auto_increment column value and set that generated value into one of the input object properties as follows:
Here the STUD_ID column value will be autogenerated by MySQL database,and the generated value will be set to the studId property of the student object.
Some databases such as Oracle dont't support AUTO_INCREMENT columns and use SEQUENCE to generated th primary key values.
Here we used the <selectKey> subelement to generate the primary key value and stored it in the studId property of the Student object.The attribute order='BEFORE' indicates that MyBatis will get the primary key value,that is,the next value from the sequence and store it in the studId property before executing the INSERT query.[Like ORACLE]
We can also set the primary key value using a trigger where we will obtain the next value from the sequence and set it as the primary key column value before executing the INSERT query.[LIKE MYSQL]
Simple ResultMaps
resultMap can be a map type(we will get a Map<key_column,Object>)
or we will get List<HashMap<key_column,Object>>
Extending ResultMaps
We can extends one <resultMap> query from another <resultMap> query,thereby inheriting the column to do property mappings from the one that is being extended.
One-to-one mapping
-
We can set the properties of a nested object using the dot notation
2.The <association>element can be used to load the has-one type of association.In the preceding eample,we usedthe <association>element,referencing another <resultMap> that is declared in the same XML flee
We can also use <association> with an inline resultMap query as follows:
Using the nested ResultMap approach , the association data will be loaded using a single query(along with joins ifrequired)
3.One-to-one mapping using nested Select
One-to-many mapping
1、One-to-many mapping with nested ResultMap
2.One-to-many mapping with nested select
A nested select approach may result in N+1 select problems.First, the main query will be excuted(1),and for every row returned by the first query,another select query will be executed(N queries for N rows).For large datasets,this could result in poor performance.
Dynamic SQL
-
The If condition
2.The choose,when,and otherwise conditions
--MyBatis evaluates the <choose> test conditions and uses the clause with the first condition that evaluates to TRUE.If none of the conditions are true,the <otherwise> clause will be used.
3.The<where>element inserts WHERE only if any content is returned by the inner conditional tags.Also,it removes the AND or OR prefixs if the WHERE clause begins with AND or OR.
4.The <trim>element works similar to <where> but provides additional flexibility on what prefix/suffix needs to be prefixed/suffixed and what prefix/suffix needs to be stripped off.
Here <trim> will insert WHERE if any of the <if> conditions are true and remove the AND or OR prefixes just after WHERE.
5.The foreach loop
6.The set condition
The <set> element is similar to the <where> element and will insert SET if any content is returned by the inner conditions.
Here,<set>inserts the SET keyword if any of the <if> conditions return text and also strips out the tailing commas at the end.
MyBatis Recipes
Handling enumeration types
By default,MyBatis uses EnumTypeHandler to handle enum type Java properties and stores the name of the enum value.You don't need any extra configuration to do this.You can use enum type properties just like primitive type properties.
If you want to store the ordinal position of the enum instead of the enum name,you will need to explicitly configure it.You'll to register EnumOrdinalTypeHandler in the mybatis-config.xml file.
[Be careful to use ordinal values to store in the DB.Ordinal values are assigned to enum values based on their order of declaration. If you change the declaration order in enum,the data in the database and ordinal values will be mismatched]
Handling the CLOB/BLOB types
By default, MyBatis maps CLOB type columns to the java.lang.String type and BLOB type columns to the byte[] type.
to
Passing multiple input parameters
-
We can put all the input parameters in a HashMap and pass it to that mapped statement.
-
MyBatis provides another way of passing multiple input parameters to a mapped statement.
MyBatis supports passing multiple input parameters to a mapped statement and referencing them using the ${param} syntax.
Here #{param1} refers to the first parameter and #{param2} refers to the second parameter
Multiple results as a map
If we have a mapped statement that returns multiple rows and we want the results in a HashMap with some property value as the key and the resulting object as the value,we can use sqlsession.selectMap() as fllows:
Here studentMap will contain studId values as keys and Student objects as values.
Paginated ResultSets using RowBounds
MyBatis can load table data page by page using RowBounds.The RowBounds object can be constructed using th offset and limit parameters.The parameter offset refers to the starting position and limit refers to the number of records.
To display the second page,use offset=25 and limit=25;for third page,use offset=50 and limit=25
Custom ResultSet processing using ResultSetHandler
MyBatis provides ResultHandler plugin that enables the processing of the ResultSet in whatever way we like.
As the handleResult() method will be called for every row returned by the query,we are extracting the studId and name values from the Student object and populating the map.
Cache
By default,the first-level cache is enabled;this means that if you'll invoke the same SELECT statement within the same sqlSession interface,results will be fetched from the cache instead of the database.
We can add global second-level cacahes by adding the <cache/> element in SQL Mapper XML files.
When you'll add the <cache/> element the following will occur:
-
All results from the <select> statements in the mapped statement file will be cached
-
All the <insert>、<update>、and <delete> statements in the mapped statement file will flush the cache.
-
The cache will use a Least Recently Used(LRU) algorithm for eviction
-
The cache will not flush on any sort of time-based schedule(no Flush Interval)
-
The cache will store 1024 references to lists or objects(whatever the query method returns)
-
The cache will be treated as a read/write;this means that the objects retrieved will not be shared and can safely be modified by the caller without it interfering with other potential modifications by other callers or threads
You can also customize this behavior by overriding the default attribute values as follows:
A description for each of the attributes is as follow:
A cache configuration and cache instance are bound to the namespaces of the SQL Mapper file,so all the statements in the same namespace table as the cache are bound
The default cache configuration for a mapped statement is :
You can override this default behavior for any specific mapped statements;for example , by not using a chache for a select staement by setting the useCache='false" attribute.
In addition to in-built Cache support,MyBatis provides support for integration with popular third-party Cache libraries,such as Ehcache,OSCache,and Hazelcast.
SQL Mappers Using Annotations
@Insert
1.We can use the useGeneratedKeys and keyProperty attributes of the @Options annotation to let the database server generate the auto_increment column value and set that generated value as one of the input object properties.
Here the STUD_ID column value will be autogenerated by MySQL database and the generated value will be set to the studId property of the student object.
2.We can use the @SelectKey annotation to specify any SQL statement that will give the primary key value , which can be used as the primary key column value
Here we have used @SelectKey to generate the primary key value and store it in the studId property of the Student object using the keyProperty attribute. This gets executed before executing the INSERT statement,because we specified it via the before=true attribute.[Oracle]
If we are setting the primary key value through triggers using SEQUENCE, we can obtain the database-generated primary key value from sequence_name.vurrval after the INSERT statement is executed.[MySQL]
Result maps
1.We can map query results to JavaBean properties using inline aliases or using an explict @Result annotation.
The @Result annotation is a couterpart of the Mapper XML element <resultMap>.However,as of MyBatis3.2.2 we can't give an ID for the @Result annotation.So unlike the <resultMap> XML element,we can't reuse the @Results declaration across different mapped statements.What this means is that you need to duplicate the @Results configuration even though it is the same.
Here the @Results configuration is same for both the statements,but we need to duplicate it.There is also a work around for this problem.We can create a Mapper XML file and configure the <resultMap>element and reference that resultMap using the @ResultMap annotation.
One-to-one mapping
1.MyBatis provides the @one annotation to load a one-to-one association using a Nested-Select statement
2.we can load a one-to-one association using nested ResultMap using XML-base Mapper configuration.But as of MyBatis-3.2.2,there is no annotation-based counterpart for this kind of mapping.However,we can define <resultMap> in Mapper XML file and reference it
One-to-many mapping
1.MyBatis provides the @many annotation to load a one-to-many association using a Nested-Select statement.
2.Using an XML-based Mapper configuration , we can load a one-to-many association using a nested ResultMap.As of MyBatis 3.2.2,there is no annotation-based counterpart for this kind of mapping.But we can define the <resultmap> in the Mapper XML file and reference it using the @ResultMap annotaion.
Dynamic SQL
Sometimes we may need to build queries dynamically based on input criteria.MyBatis provides various annotations such as @InsertProvider,@UpdateProvider,@DeleteProvider,and @SelectProvider,which facilitates building dynamic queries and lets MyBatis execute those queries.
-
@SelectProvider
The SQL utility providers various methods to perform JOINS,ORDER_BY,GROUP_BY,and so on
2.@InsertProvider
3.@UpdateProvider
4.@DeleteProvider
该系列文章参考如下书籍及文章:
《Java Persistence with MyBatis 》
《http://www.cnblogs.com/hzhuxin/p/3349836.html》
《http://www.iteye.com/topic/1112327》
《http://www.iteye.com/blogs/subjects/mybatis_internals》
《http://denger.me/2011/05/mybatis-and-spring-interface-integrated/》