iBatis与MyBatis了解

iBatis 到 MyBatis区别

iBatis 框架的主要优势主要体现在如下几个方面:

首先,iBatis 封装了绝大多数的 JDBC 样板代码,使得开发者只需关注 SQL 本身,而不需要花费精力去处理例如注册驱动,创建 Connection,以及确保关闭 Connection 这样繁杂的代码。

其次,iBatis 可以算是在所有主流的持久层框架中学习成本最低,最容易上手和掌握的框架。虽说其他持久层框架也号称门槛低,容易上手,但是等到你真正使用时会发现,要想掌握并用好它是一件非常困难的事。在工作中我需要经常参与面试,我曾听到过很多位应聘者描述,他们所在的项目在技术选型时选择 Hibernate,后来发现难以驾驭,不得不将代码用 JDBC 或者 iBatis 改写。

iBatis 自从在 Apache 软件基金会网站上发布至今,和他的明星兄弟们(Http Server,Tomcat,Struts,Maven,Ant 等等)一起接受者万千 Java 开发者的敬仰。然而在今年六月中旬,几乎是发布 3.0 版本的同时,iBatis 主页上的一则 “Apache iBATIS has been retired” 的声明在社区引起了一阵不小的波澜。在 Apache 寄居六年之后,iBatis 将代码托管到 Google Code。在声明中给出的主要理由是,和 Apache 相比,Google Code 更有利于开发者的协同工作,也更能适应快速发布。于此同时,iBatis 更名为 MyBatis。

从 iBatis 到 MyBatis,不只是名称上的变化,MyBatis 提供了更为强大的功能,同时并没有损失其易用性,相反,在很多地方都借助于 JDK 的泛型和注解特性进行了简化。iBatis 确实该退休了,因为一个更为出色的继任者经过 10 个 Beta 版本的蜕变已然出现在我们的面前。

本文将主要针对 MyBatis 和 iBatis 的变化之处进行讨论,以便于读者顺利从 iBatis 向 MyBatis 过渡。

由一个 MyBatis 示例开始

如果读者接触过一些常用的 Java EE 框架,应该都知道这些框架需要提供一个全局配置文件,用于指定程序正常运行所需的设置和参数信息。而针对常用的持久层框架而言(Hibernate、JPA、iBatis 等),则通常需要配置两类文件:一类用于指定数据源、事务属性以及其他一些参数配置信息(通常是一个独立的文件,可以称之为全局配置文件);另一类则用于指定数据库表和程序之间的映射信息(可能不止一个文件,我们称之为映射文件)。MyBatis 也不例外,虽然其中的一部分可以通过注解的形式进行,但是这两部分内容本身仍是必不可少的。

根据 iBatis 的习惯,我们通常把全局配置文件命名为 sqlMapConfig.xml,文件名本身并没有要求,在 MyBatis 中,也经常会将该文件命名为 Configuration.xml (读完全文后读者也许会发现,在 iBatis 中经常出现的 “sqlMap” 在 MyBatis 中被逐渐淡化了,除了此处,还比如 iBatis 配置文件的根元素为 <sqlMapConfig>,指定映射文件的元素为 <sqlMap>,以及 SqlMapClient 等等,这个变化正说明,iBatis 仅是以 SQL 映射为核心的框架,而在 MyBatis 中多以 Mapper、Session、Configuration 等其他常用 ORM 框架中的名字代替,体现的无非是两个方面:首先是为了减少开发者在切换框架所带来的学习成本;其次,MyBatis 充分吸收了其他 ORM 框架好的实践,MyBatis 现在已不仅仅是一个 SQL 映射框架了)。在全局配置文件中可以配置的信息主要包括如下几个方面:

properties --- 用于提供一系列的键值对组成的属性信息,该属性信息可以用于整个配置文件中。
settings --- 用于设置 MyBatis 的运行时方式,比如是否启用延迟加载等。
typeAliases --- 为 Java 类型指定别名,可以在 XML 文件中用别名取代 Java 类的全限定名。
typeHandlers --- 在 MyBatis 通过 PreparedStatement 为占位符设置值,或者从 ResultSet 取出值时,特定类型的类型处理器会被执行。
objectFactory --- MyBatis 通过 ObjectFactory 来创建结果对象。可以通过继承 DefaultObjectFactory 来实现自己的 ObjectFactory 类。
plugins --- 用于配置一系列拦截器,用于拦截映射 SQL 语句的执行。可以通过实现 Interceptor 接口来实现自己的拦截器。
environments --- 用于配置数据源信息,包括连接池、事务属性等。
mappers --- 程序中所有用到的 SQL 映射文件都在这里列出,这些映射 SQL 都被 MyBatis 管理。
上面提及的大多数元素都不是必需的,通常 MyBatis 会为没有显式设置的元素提供缺省值。一个简单的全局配置文件示例如下:


清单 1. 简单的全局配置文件示例
    
 <?xml version="1.0" encoding="UTF-8" ?>
 <!--iBatis 和 MyBatis 的全局配置文件使用不同的 DTD 约束,在将应用由
 iBatis 升级至 MyBatis 时需要注意(两者的映射文件 DTD 约束也不相同)-->
 <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
 <configuration>
 <!-- 配置数据源相关的信息 -->
 <environments default="demo">
 <environment id="demo">
 <transactionManager type="JDBC"/>
 <dataSource type="POOLED">
 <property name="driver" value= … />
 <property name="url" value= … />
 <property name="username" value="root"/>
 <property name="password" value="root"/>
 </dataSource>
 </environment>
 </environments>
 <!-- 列出映射文件 -->
 <mappers>
 <mapper resource="footmark/mybatis/demo/UserInfoMapper.xml"/>
 </mappers>
 </configuration>
 


有了这些信息,MyBatis 便能够和数据库建立连接,并应用给定的连接池信息和事务属性。MyBatis 封装了这些操作,最终暴露一个 SqlSessionFactory 实例供开发者使用,从名字可以看出来,这是一个创建 SqlSession 的工厂类,通过 SqlSession 实例,开发者能够直接进行业务逻辑的操作,而不需要重复编写 JDBC 相关的样板代码。根据全局配置文件生成 SqlSession 的代码如下:

 Reader reader = Resources.getResourceAsReader("Configuration.xml");
 SqlSessionFactory sqlSessionFactory =
 new SqlSessionFactoryBuilder().build(reader);
 SqlSession sqlSession = sqlSessionFactory.openSession();
 


可以把上面的三行代码看做是 MyBatis 创建 SqlSession 的样板代码。其中第一行代码在类路径上加载配置文件,Resources 是 MyBatis 提供的一个工具类,它用于简化资源文件的加载,它可以访问各种路径的文件,不过最常用的还是示例中这种基于类路径的表示方式。如果读者对 Hibernate 有所了解,一定会发现 MyBatis 不论是使用风格还是类名都和 Hibernate 非常相像,笔者曾今多次在国内外 Java 社区看到有人说 MyBatis 在向 Hibernate/JPA 靠拢。暂且不论这是否属实,持久化技术在经过一番蓬勃的竞争和发展,最终在社区形成统一的认识并被广泛接受,这对开发者而言未必不是一件好事,MyBatis 在这一点上只是向事实上的标准靠近了一步。

在完成全局配置文件,并通过 MyBatis 获得 SqlSession 对象之后,便可以执行数据访问操作了。对于 iBatis/MyBatis 而言,要执行的操作其实就是在映射文件中配置的 SQL 语句。两者的配置基本相同,如下所示:


清单 2. 在映射文件中配置 SQL 语句
    
 <?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="mybatis.demo.UserInfoMapper">
 <select id="selectUser" parameterType="int"
 resultType="mybatis.demo.UserInfo">
 select * from UserInfo where userid =#{userid}
 </select>
 </mapper>
 


在 iBatis 中,namespace 不是必需的,且它的存在没有实际的意义。在 MyBatis 中,namespace 终于派上用场了,它使得映射文件与接口绑定变得非常自然。关于接口绑定,后面会有篇幅专门描述。使用 SqlSession 执行 SQL 的方式如下:


清单 3. 使用 SqlSession 执行映射文件中配置的 SQL 语句
    
 try
 {
 UserInfo userinfo = (UserInfo) sqlSession.selectOne
 ("mybatis.demo.UserInfoMapper.getUser", 2);
 System.out.println(userinfo);
 } finally
 {
 sqlSession.close();
 }
 


需要注意的是,SqlSession 的使用必需遵守上面的格式,即在 finally 块中将其关闭。以保证资源得到释放,防止出现内存泄露!

以上就是一个简单而完整的 MyBatis 程序。其中涉及了全局配置文件,映射文件,构建 SqlSession 对象,执行数据访问操作等四个步骤。下面将针对除构建 SqlSession 对象之外的三块内容进行分解。

MyBatis 全局配置文件的改变

MyBatis 全局配置文件的各主要元素基本和 iBatis 相同,只是在用法和个别名称上做了调整。元素的意义就不再描述,下面主要讲述针对 iBatis 和 MyBatis 配置文件的主要区别之处。

首先,两个版本的 DTD 约束不同,MyBatis 的 DTD 文件已经包含在发布包下的 mybatis-3.0.x.jar 包中。这直接影响到的是,iBatis 配置文件的根元素是 <sqlMapConfig>,而 MyBatis 使用的是 <configuration>。

其次,<settings> 的用法发生了改变,之前的格式为:


清单 4. 在 iBatis 中设置属性的方式
    
 <settings props1="value1" props2="value2"… />
 


要设置的属性直接以键值对的形式作为 <settings> 的属性。而在 MyBatis 中调整为略显复杂但却更有条理的方式:


清单 5. 在 MyBatis 中设置属性的方式
    
 <settings>
 <setting name="props1" value="value1"/>
 <setting name="props2" value="value2"/>
……
 </settings>
 


另外,之前配置事务管理器和数据源的方式如下:


清单 6. 在 iBatis 中配置事务管理器和数据源的方式
    
 <transactionManager type="JDBC" >
 <dataSource type="SIMPLE">
 <property name="JDBC.Driver" value="${driver}"/>
 <!-- 其他数据源信息省略 -->
 </dataSource>
 </transactionManager>
 


在 MyBatis 中调整为如下的方式:


清单 7. 在 MyBatis 中配置事务管理器和数据源的方式
    
 <environments default="demo">
 <environment id="demo">
 <transactionManager type="JDBC"/>
 <dataSource type="POOLED">
 <property name="JDBC.Driver" value="${driver}"/>
 <!-- 其他数据源信息省略 -->
 </dataSource>
 </environment>
 </environments>
 


通过 <environments> 来进行数据源管理,主要是为了简化在多套数据源配置之间的切换,比如开发和发布使用不同的配置。

最后,在 iBatis 中指定映射文件的方式如下:


清单 8. 在 iBatis 中指定映射文件的方式
    
 <sqlMap resource=... />
 <sqlMap resource=... />
 <sqlMap resource=... />
 


在 MyBatis 中调整为如下方式:


清单 9. 在 MyBatis 中指定映射文件的方式
    
 <mappers>
 <mapper resource=... />
 <mapper resource=... />
 </mappers>
 


上面的这些调整,主要出发点其实并不是使得 MyBatis 功能更为强大,而是使配置更为合理,让开发者更容易阅读和理解。

到目前为止,我们主要讨论了 XML 形式的全局配置,其实这也不是唯一选择,MyBatis 还提供了通过代码来进行配置的方式:


清单 10. 在 MyBatis 中使用代码进行配置
    
 DataSource ds = …… // 获取一个 DataSource
 TransactionFactory txFactory = new JdbcTransactionFactory();
 Environment env = new Environment("demo", txFactory, ds);
 Configuration cfg = new Configuration(env);
 cfg.addMapper(UserInfoMapper.class);
 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(cfg);
 


结合前面的配置文件,很容易理解这段代码的意思,故不再赘述。不过,需要注意的是 Configuration 的 addMapper() 方法,该方法的参数通常是一个接口,可以在接口里面定义若干方法,在方法上使用注解来指定映射的 SQL 语句。一个典型的接口定义以及对应的数据访问方法如下:


清单 11. 将映射的 SQL 语句与接口中的方法绑定
    
 // 映射 SQL 绑定接口
 public interface UserInfoMapper
 {
 @Select("select * from userinfo where userid = #{userid}")
 public UserInfo getUserInfo(int userid);
 }
 // 接口绑定对应的数据访问方法
 try
 {
 //UserInfo userinfo = (UserInfo) sqlSession.selectOne
 ("mybatis.demo.UserInfoMapper.selectUser", 2);
 UserInfoMapper userinfoMapper =
 sqlSession.getMapper(UserInfoMapper.class);
 UserInfo userinfo = userinfoMapper.getUserInfo(1);
 System.out.println(userinfo);
 } finally
 {
 sqlSession.close();
 }
 

MyBatis 映射文件的改变

MyBatis 针对映射文件进行格式调整的地方很多,但大部分仅仅只是名称上的变化,现代的 IDE 都支持联想功能,可以很方便的获取到当前位置可以有哪些元素、哪些属性等。所以这基本不会给开发者造成什么麻烦。

针对映射文件,首先是一系列的属性名称的改变,这些仅仅是名称的改变,用法和含义并没有发生变化:

和全局配置文件一样,由于 DTD 约束发生变化,根元素也由原来的 <sqlMap> 调整为 <mapper>。
<select> 等元素的 parameterClass 属性改为了 parameterType 属性。
<select> 等元素的 resultClasss 属性改为了 resultType 属性。
<parameterMap> 等元素的 class 属性改为了 type 属性。
<result> 元素的 columnIndex 属性被移除了。
嵌套参数由 #value# 改为了 #{value}。
<parameter> 等元素的 jdbcType 属性取值中,原来的 "ORACLECURSOR" 取值改为了现在的 "CURSOR","NUMBER" 取值改为了 "NUMERIC"。
iBatis/MyBatis 对存储过程的支持一直是值得称道的。之前通过使用 <procedure> 元素进行存储过程的定义,示例如下:


清单 12. iBatis 中调用存储过程的方式
    
 <procedure id="getValues" parameterMap="getValuesPM">
    { ? = call pkgExample.getValues(p_id => ?) }
 </procedure>
 


在 MyBatis 中,<proccedure> 元素已经被移除,通过 <select>、<insert> 和 <update> 进行定义:


清单 13. MyBatis 中调用存储过程的方式
    
 <select id="getValues" parameterMap="getValuesPM" statementType="CALLABLE">
    { ? = call pkgExample.getValues(p_id => ?)}
 </select>
 

如上所示,通过 statementType 属性将该语句标识为存储过程而非普通 SQL 语句。

代码层面的改变
通过前面的示例可以看出,MyBatis 在编码中的最大的改变就是将一个最常用的 API 由 SqlMapClient 改为了 SqlSessionFactory。另外,类型处理器接口也由原来的 TypeHandlerCallback 改为了 TypeHandler。最后 DataSourceFactory 也进行了调整,移动到 org.apache.ibatis.datasource 包下,其中的方法也作了微调。总之,代码层面公开的部分改动较少,不会给开发者造成较大的移植成本。

 

MyBatis入门

所需要jar包:mybatis-3.x.x.jar 、如果需要和spring整合,还需要加入相关的包

1:看项目目录 红颜色不要关心

 

2:按照步骤:

1:加入jar包

2:创建数据源(configuration.xml)创建数据库(此处省略)
<?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> 
    <typeAliases> 
        <!--给实体类起一个别名 user --> 
        <typeAlias type="com.forum.po.User" alias="User" /> 
    </typeAliases> 
    <!--数据源配置  这块用 BD2数据库 --> 
    <environments default="development"> 
        <environment id="development"> 
            <transactionManager type="jdbc" /> 
            <dataSource type="POOLED"> 
                <property name="driver" value="com.ibm.db2.jcc.DB2Driver" /> 
                <property name="url" value="jdbc:db2://localhost:50000/forum" /> 
                <property name="username" value="DB2ADMIN" /> 
                <property name="password" value="admin" /> 
            </dataSource> 
        </environment> 
    </environments> 
    <mappers> 
        <!--userMapper.xml装载进来  同等于把“dao”的实现装载进来 --> 
        <mapper resource="myBatis/userMapper.xml" /> 
    </mappers> 
</configuration>

3:创建实体类USER
package com.forum.po; 
 
/**
 * 用户类
 * 
 * @author db2admin
 * 
 */ 
public class User extends Entity { 
    private String name; 
    private Integer age; 
    public String getName() { 
        return name; 
    } 
    public void setName(String name) { 
        this.name = name; 
    } 
    public Integer getAge() { 
        return age; 
    } 
    public void setAge(Integer age) { 
        this.age = age; 
    } 
    public User() { 
    } 
 
}

4:创建dao接口、可以说是Mapper接口:UserMapper
package com.forum.dao; 
 
import com.forum.po.User; 
 
public interface UserMapper { 
    public User findById(String Id); 
}

5:创建dao的实现,不同于hibernarte的此处的实现为一个xml文件,也就是userMapper.xml
<?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"> 
    <!--这块等于dao接口的实现  namespace必须和接口的类路径一样--> 
<mapper namespace="com.forum.dao.UserMapper"> 
    <!-- findById必须和接口中的方法名一样  返回一个User  就是刚才的别名  如果不弄别名要连类路径一起写 麻烦--> 
    <select id="findById" parameterType="HashMap" resultType="User"> 
        select 
        * from butone.student where id=#{id} 
    </select> 
</mapper>

6:测试类,MyBatisTest
package com.forum.test; 
 
import java.io.IOException; 
 
import org.apache.ibatis.io.Resources; 
import org.apache.ibatis.session.SqlSession; 
import org.apache.ibatis.session.SqlSessionFactory; 
import org.apache.ibatis.session.SqlSessionFactoryBuilder; 
 
import com.forum.dao.UserMapper; 
import com.forum.po.User; 
 
/**
 * myBatis数据库连接测试
 * 
 * @author db2admin
 * 
 */ 
public class MyBatisTest { 
    /**
     * 获得MyBatis SqlSessionFactory  
     * SqlSessionFactory负责创建SqlSession,一旦创建成功,就可以用SqlSession实例来执行映射语句,commit,rollback,close等方法。
     * @return
     */ 
    private static SqlSessionFactory getSessionFactory() { 
        SqlSessionFactory sessionFactory = null; 
        String resource = "configuration.xml"; 
        try { 
            sessionFactory = new SqlSessionFactoryBuilder().build(Resources 
                    .getResourceAsReader(resource)); 
        } catch (IOException e) { 
            // TODO Auto-generated catch block 
            e.printStackTrace(); 
        } 
        return sessionFactory; 
    } 
 
    public static void main(String[] args) { 
        SqlSession sqlSession = getSessionFactory().openSession(); 
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 
        User user = userMapper.findById("1"); 
        System.out.println(user.getName()); 
 
    } 
 
}

 

从iBATIS 2.x到MyBatis的变化

 

This page provides some information that is useful when migrating a project from iBatis 2 to MyBatis 3. It is probably not 100% complete.

Conversion Tool
There is a tool available in the downloads section that will help you to convert your iBATIS 2.x sqlmap files into MyBatis 3.x xml mapper files.

Get it from http://mybatis.googlecode.com/files/ibatis2mybatis.zip

The tool is designed around an xslt transformation and some text replacements packaged in an ant task and tries to deliver a good starting point before the more complex work begins.

New DTDs
New sqlMapConfig.xml DTD:

<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">New sqlMap (*.map.xml) DTD:

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> Configuration
Root configuration tag <sqlMapConfig> is now <configuration>
Settings
Within the root configuration tag:

<settings x="y" foo="bar"/>is now:

<settings>
    <setting name="x" value="y"/>
    <setting name="foo" value="bar"/>
</settings>and

<settings useStatementNamespaces="true"/>can be removed, since the use of namespaces has become mandatory.

<typeAlias>
<typeAlias> must be moved out of the <sqlMap> element to <configuration><typeAliases></typeAliases></configuration>

<configuration>
    <settings>
    ...
    </settings>
    <typeAliases>
        <typeAlias ... />
    </typeAliases>
</configuration><transactionManager> and <dataSource>
<transactionManager type="JDBC" commitRequired="false">
    <dataSource type="your.package.CustomDataSourceFactory" />
</transactionManager>is now:

<environments default="env">
    <environment id="env">
        <transactionManager type="JDBC">
            <property name="commitRequired" value="false"/>
        </transactionManager>
        <dataSource type="your.package.CustomDataSourceFactory" />
    </environment>
</environments><sqlMap>
<sqlMap resource=... />
<sqlMap resource=... />
<sqlMap resource=... />is now:

<mappers>
    <mapper resource=... />
</mappers>Mapping
The root element <sqlMap> is now <mapper>
The attribute parameterClass should be changed to parameterType
The attribute resultClass should be changed to resultType
The attribute class should be changed to type
the columnIndex attribute does not exist anymore for the <result> tag
The groupBy attribute has been eliminated. Here is an example of groupBy from a 2.x sqlMap:

<resultMap id="productRM" class="product" groupBy="id">
    <result property="id" column="product_id"/>
    <result property="name" column="product_name"/>
    <result property="category" column="product_category"/>
    <result property="subProducts" resultMap="Products.subProductsRM"/>
</resultMap>New:

<resultMap id="productRM" type="product" >
    <id property="id" column="product "/>
    <result property="name " column="product_name "/>
    <result property="category " column="product_category "/>
    <collection property="subProducts" resultMap="Products.subProductsRM"/>
</resultMap>Nested resultMaps
These should now be specified using the <association> tag.

<resultMap ...>
    <result property="client" resultMap="Client.clientRM"/>
    ...
</resultMap>is now:

<resultMap ...>
    <association property="client" resultMap="Client.clientRM"/>
    ...
</resultMap><parameterMap>
Although this tag is deprecated, it can be used as in iBatis 2. However for versions up to 3.0.3 there is a bug when using type="map" and not specifying javaType for a parameter. This will result in

There is no getter for property named '...' in 'interface java.util.Map'   
This should be solved in MyBatis 3.0.4. For versions 3.0.3 and earlier the workaround is to explicitly specify javaType.
Inline parameters
#value#is now:

#{value}jdbcType changes
jdbcType="ORACLECURSOR"is now:

jdbcType="CURSOR"and

jdbcType="NUMBER"is now:

jdbcType="NUMERIC"Stored procedures
the <procedure> tag doesn't exist anymore. Use <select>, <insert> or <update>.
<procedure id="getValues" parameterMap="getValuesPM">
    { ? = call pkgExample.getValues(p_id => ?) }
</procedure>is now:

<select id="getValues" parameterMap="getValuesPM" statementType="CALLABLE">
    { ? = call pkgExample.getValues(p_id => ?)}
</select>If you're calling an insert procedure that returns a value, you can use <select> instead of <insert>, but make sure to specify useCache="false" and flushCache="true". You'll also have to force a commit.

for stored procedures that return a cursor, there is a bug (see  issue 30 ) when using nested result maps (i.e. the output parameter's resultMap contains an <association> tag with the resultMap attribute). As long as the issue is not fixed, you have to specify the resultMap of the output parameter on the statement itself as well, or the nested resultMap will not be populated.
Caching

<cacheModel id="myCache" type="LRU">
    <flushInterval hours="24"/>
    <property name="size" value="100" />
</cacheModel>is now:

<cache flushInterval="86400000" eviction="LRU"/>Note: you can omit eviction="LRU" since it is the default.

the <flushOnExecute> tag is replaced by the flushCache attribute for the statements and the cache will be used by all select statements by default.
Dynamic SQL
The most common dynamic SQL in my project is isNotNull. Here is an example replacement regex:

Pattern:

<isNotNull.*?property=\"(.*?)\">
</isNotNull>Replacement:

<if test="$1 != null">
</if>Also common is the use of isEqual, you can replace this by a similar <if> tag.

Java code
SqlMapClient
This class doesn't exist anymore. Use SqlSessionFactory instead (see User Guide).

Custom type handler
Replace interface TypeHandlerCallback with TypeHandler. It has slightly different but similar methods.

Custom data source factory
Old interface:

com.ibatis.sqlmap.engine.datasource.DataSourceFactoryNew interface:

org.apache.ibatis.datasource.DataSourceFactoryReplace method

public void initialize(Map properties)with

public void setProperties(Properties props)

 

 MyBatis整合Spring


说白了其实就想使用Spring提供的服务,比如Spring的事务管理、Spring的IOC对Bean进行管理等。
Mybatis怎么整合Spring?
由于目前Spring官方还没有出整合Mybatis的特性,所以这里在Spring框架和MyBatis框架上再添加用于整合的框架“mybatis-spring-1.0.2.jar” (该框架时MyBatis官方自己出的)。
(1)新建一个Web工程,名称为MybatisSpring。
(2)将Spring3.0.3、Mybatis3.0.6、Mybatis-Spring1.0.2、log4j、Oracle驱动和DBCP连接池的JAR包放到Web工程的lib下面,具体的JAR包如下:
classes12.jar      
log4j-1.2.16.jar      
mybatis-3.0.6.jar      
mybatis-spring-1.0.2.jar      
org.springframework.aop-3.0.3.RELEASE.jar      
org.springframework.asm-3.0.3.RELEASE.jar      
org.springframework.aspects-3.0.3.RELEASE.jar      
org.springframework.beans-3.0.3.RELEASE.jar      
org.springframework.context-3.0.3.RELEASE.jar      
org.springframework.context.support-3.0.3.RELEASE.jar      
org.springframework.core-3.0.3.RELEASE.jar      
org.springframework.expression-3.0.3.RELEASE.jar      
org.springframework.jdbc-3.0.3.RELEASE.jar      
org.springframework.transaction-3.0.3.RELEASE.jar      
org.springframework.web-3.0.3.RELEASE.jar      
commons-logging-1.1.1.jar      
commons-dbcp-1.2.jar      
commons-pool-1.4.jar 

(3)在src下面新建log4j.properties文件,该文件的内容如下:
log4j.appender.stdout=org.apache.log4j.ConsoleAppender      
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout      
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] -%m%n      
log4j.logger.com.ibatis=debug      
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=debug      
log4j.logger.com.ibatis.common.jdbc.ScriptRunner=debug      
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=debug      
log4j.logger.java.sql.Connection=debug      
log4j.logger.java.sql.Statement=debug      
log4j.logger.java.sql.PreparedStatement=debug,stdout  

(4)在Oracle数据库执行以下SQL,创建一个USER_INFO的表:
-- Create table      
create table USER_INFO      
(      
  ID          NUMBER(12) not null,      
  NAME        VARCHAR2(50)      
);      
      
--Insert data      
insert into USER_INFO(ID,NAME) values(1,'张三'); 

(5)新建一个Java类UserInfo.java,该类的内容如下:
package com.user;      
      
public class UserInfo {      
    private int id;      
    private String name;      
      
    public UserInfo() {      
    }      
      
    public UserInfo(String name) {      
        this(0, name);      
    }      
      
    public UserInfo(int id, String name) {      
        this.id = id;      
        this.name = name;      
    }      
      
    public int getId() {      
        return id;      
    }      
      
    public void setId(int id) {      
        this.id = id;      
    }      
      
    public String getName() {      
        return name;      
    }      
      
    public void setName(String name) {      
        this.name = name;      
    }      
      
    @Override      
    public String toString() {      
        return "ID: " + id + ", Name: " + name;      
    }      
}    

(6)在com.user.sqlmap下面新建UserInfo.xml文件,该文件的内容如下:
<?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="User">      
    <select id="selectUser" parameterType="int" resultType="UserInfo">      
    <![CDATA[     
        select * from user_info where id = #{id}     
    ]]>      
    </select>      
</mapper>  

(7)在src下面新建mybatis.cfg.xml文件,该文件的内容如下:
<?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>      
    <typeAliases>      
        <typeAlias alias="UserInfo" type="com.user.UserInfo" />      
    </typeAliases>      
          
    <mappers>      
        <mapper resource="com/user/sqlmap/UserInfo.xml" />      
    </mappers>      
</configuration> 

(8)新建一个Java类UserService.java,该类的内容如下:
package com.user;      
      
import org.mybatis.spring.SqlSessionTemplate;      
      
public class UserService {      
    private SqlSessionTemplate  sqlSession;      
          
    public SqlSessionTemplate getSqlSession() {      
        return sqlSession;      
    }      
      
    public void setSqlSession(SqlSessionTemplate sqlSession) {      
        this.sqlSession = sqlSession;      
    }      
          
    public UserInfo selectUser(){      
          UserInfo user = null;      
          try {      
                          user = (UserInfo) sqlSession.selectOne("User.selectUser", "1");      
                    } catch (Exception e) {      
                          e.printStackTrace();      
                    }      
              
                   return user;      
             }      
}     

(9)在src下面新建applicationContext.xml文件,该文件的内容如下:
<?xml version="1.0" encoding="UTF-8"?>      
<beans xmlns="http://www.springframework.org/schema/beans"      
    default-autowire="byName"      
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"      
    xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd">      
      
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">      
        <property name="driverClassName" value="oracle.jdbc.OracleDriver" />      
        <property name="url" value="jdbc:oracle:thin:@localhost:1521:SID" />      
        <property name="username" value="xxxx" />      
        <property name="password" value="xxxx" />      
        <property name="maxActive" value="100"></property>      
        <property name="maxIdle" value="30"></property>      
        <property name="maxWait" value="500"></property>      
        <property name="defaultAutoCommit" value="true"></property>      
    </bean>      
          
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">      
        <property name="configLocation" value="classpath:mybatis.cfg.xml"></property>      
        <property name="dataSource" ref="dataSource" />      
    </bean>      
          
    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">      
        <constructor-arg index="0" ref="sqlSessionFactory" />      
    </bean>      
          
    <bean id="userService" class="com.user.UserService">      
       <property name="sqlSession" ref="sqlSessionTemplate" />      
    </bean>      
      
</beans>  

(10)新建一个测试Java类UserInfoTest.java,该类的具体内容如下:
package com.user;      
      
import java.io.IOException;      
      
import org.springframework.context.ApplicationContext;      
import org.springframework.context.support.ClassPathXmlApplicationContext;      
      
      
      
public class UserInfoTest {      
      
    /**   
     * @param args   
     * @throws IOException    
     */      
    public static void main(String[] args) throws IOException {      
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");      
        UserService userService = (UserService)context.getBean("userService");      
        UserInfo userInfo = userService.selectUser();      
        System.out.println(userInfo);      
      
    }      
      
}      

(11)右键UserInfoTest 类,选择Run As Application,运行MyBaits操作数据库。

 

Mybatis从配置读取到打开连接的源码分析

1. 准备工作

编写测试代码(具体请参考《Mybatis入门示例》),设置断点,以Debug模式运行,具体代码如下:
String resource = "mybatis.cfg.xml";    
Reader reader = Resources.getResourceAsReader(resource);
SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(reader); 
SqlSession session = ssf.openSession(); 

 

Properties properties //这里可以从专门的属性文件把数据源相关的属性(比如用户名,密码,驱动,URL等)读出来.特别是密码,一般在属性文件中的密码是加密过的.此时读进来,可以把密码还原回来,重新设置到对象properties中.比如:
String oldpass = properties.getPproperty("password");
String newpass = 通过解密方法得到原始密码.
properties.setPproperty(newpass);
SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(reader,properties);  //即读入配置文件后,会把属性文件中的内容设置到进去,与直接写到配置文件中是一样的. 2.XX的版本也有这个功能.

2.源码分析

我们此次就对上面的代码进行跟踪和分析,let's go。

首先我们按照顺序先看看第一行和第二行代码,看看它主要完成什么事情:
String resource = "mybatis.cfg.xml";      
      
Reader reader = Resources.getResourceAsReader(resource);  

读取Mybaits的主配置配置文件,并返回该文件的输入流,我们知道Mybatis所有的SQL语句都写在XML配置文件里面,所以第一步就需要读取这些XML配置文件,这个不难理解,关键是读取文件后怎么存放。

我们接着看第三行代码(如下),该代码主要是读取配置文件流并将这些配置信息存放到Configuration类中。
SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(reader); 
SqlSessionFactoryBuilder的build的方法如下:
public SqlSessionFactory build(Reader reader) {      
    return build(reader, null, null);      
  }  

其实是调用该类的另一个build方法来执行的,具体代码如下:
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {      
      
    try {      
      
      XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);      
      
      return build(parser.parse());      
      
    } catch (Exception e) {      
      
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);      
      
    } finally {      
      
      ErrorContext.instance().reset();      
      
      try {      
      
        reader.close();      
      
      } catch (IOException e) {      
      
        // Intentionally ignore. Prefer previous error.      
      
      }      
      
    }      
      
  }   

我们重点看一下里面两行:
//创建一个配置文件流的解析对象XMLConfigBuilder,其实这里是将环境和配置文件流赋予解析类       
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);      
      
// 解析类对配置文件进行解析并将解析的内容存放到Configuration对象中,并返回SqlSessionFactory       
return build(parser.parse()); 

这里的XMLConfigBuilder初始化其实调用的代码如下:
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {      
    super(new Configuration());      
      
    ErrorContext.instance().resource("SQL Mapper Configuration");      
      
    this.configuration.setVariables(props);      
      
    this.parsed = false;      
      
    this.environment = environment;      
      
    this.parser = parser;       
      
  } .

private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {      
    super(new Configuration());      
      
    ErrorContext.instance().resource("SQL Mapper Configuration");      
      
    this.configuration.setVariables(props);      
      
    this.parsed = false;      
      
    this.environment = environment;      
      
    this.parser = parser;       
      
  }

XMLConfigBuilder的parse方法执行代码如下:
public Configuration parse() {      
      
    if (parsed) {      
      
      throw new BuilderException("Each MapperConfigParser can only be used once.");      
      
    }      
      
    parsed = true;      
      
    parseConfiguration(parser.evalNode("/configuration"));      
      
    return configuration;      
      
  } .

析的内容主要是在parseConfiguration方法中,它主要完成的工作是读取配置文件的各个节点,然后将这些数据映射到内存配置对象Configuration中,我们看一下parseConfiguration方法内容:
private void parseConfiguration(XNode root) {      
      
    try {      
      
      typeAliasesElement(root.evalNode("typeAliases"));      
      
      pluginElement(root.evalNode("plugins"));      
      
      objectFactoryElement(root.evalNode("objectFactory"));      
      
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));      
      
      propertiesElement(root.evalNode("properties"));      
      
      settingsElement(root.evalNode("settings"));      
      
      environmentsElement(root.evalNode("environments"));      
      
      typeHandlerElement(root.evalNode("typeHandlers"));      
      
      mapperElement(root.evalNode("mappers"));      
      
    } catch (Exception e) {      
      
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);      
      
    }      
      
  }    

最后的build方法其实是传入配置对象进去,创建DefaultSqlSessionFactory实例出来. DefaultSqlSessionFactory是SqlSessionFactory的默认实现.
public SqlSessionFactory build(Configuration config) {      
    return new DefaultSqlSessionFactory(config);      
}

最后我们看一下第四行代码:
SqlSession session = ssf.openSession(); 

通过调用DefaultSqlSessionFactory的openSession方法返回一个SqlSession实例,我们看一下具体是怎么得到一个SqlSession实例的。首先调用openSessionFromDataSource方法。
public SqlSession openSession() {      
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);      
}

下面我们看一下openSessionFromDataSource方法的逻辑:
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {      
    Connection connection = null;      
      
try {      
      
//获取配置信息里面的环境信息,这些环境信息都是包括使用哪种数据库,连接数据库的信息,事务       
final Environment environment = configuration.getEnvironment();      
      
//根据环境信息关于数据库的配置获取数据源       
final DataSource dataSource = getDataSourceFromEnvironment(environment);      
      
//根据环境信息关于事务的配置获取事务工厂       
TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);      
      
      connection = dataSource.getConnection();      
      
      if (level != null) {      
      
        //设置连接的事务隔离级别       
      connection.setTransactionIsolation(level.getLevel());      
      }      
      
      //对connection进行包装,使连接具备日志功能,这里用的是代理。       
      connection = wrapConnection(connection);      
      
      //从事务工厂获取一个事务实例       
      Transaction tx = transactionFactory.newTransaction(connection, autoCommit);      
      
      //从配置信息中获取一个执行器实例       
      Executor executor = configuration.newExecutor(tx, execType);      
      
      //返回SqlSession的一个默认实例       
      return new DefaultSqlSession(configuration, executor, autoCommit);      
      
    } catch (Exception e) {      
      
      closeConnection(connection);      
      
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);      
      
    } finally {      
      
      ErrorContext.instance().reset();      
      
    }      
      
  }     

传入参数说明:

(1)ExecutorType:执行类型,ExecutorType主要有三种类型:SIMPLE, REUSE, BATCH,默认是SIMPLE,都在枚举类ExecutorType里面。

(2)TransactionIsolationLevel:事务隔离级别,都在枚举类TransactionIsolationLevel中定义。

(3)autoCommit:是否自动提交,主要是事务提交的设置。

 

DefaultSqlSession是SqlSession的实现类,该类主要提供操作数据库的方法给开发人员使用。

 

这里总结一下上面的过程,总共由三个步骤:

步骤一:读取Ibatis的主配置文件,并将文件读成文件流形式(InputStream)。

 

步骤二:从主配置文件流中读取文件的各个节点信息并存放到Configuration对象中。读取mappers节点的引用文件,并将这些文件的各个节点信息存放到Configuration对象。

 

步骤三:根据Configuration对象的信息获取数据库连接,并设置连接的事务隔离级别等信息,将经过包装数据库连接对象SqlSession接口返回,DefaultSqlSession是SqlSession的实现类,所以这里返回的是DefaultSqlSession,SqlSession接口里面就是对外提供的各种数据库操作。

 

Mybatis调用存储过程

1.在数据库中创建以下的存储过程:
create or replace procedure pro_hello(p_user_name in varchar2,p_result out varchar2) is    
begin    
  p_result := 'hello,' || p_user_name;    
end; 

2.编写SQL映射文件mapper.xml:
<select id="proHello" statementType="CALLABLE">    
<![CDATA[   
    {call pro_hello (#{p_user_name,mode=IN,jdbcType=VARCHAR},#{result,mode=OUT,jdbcType=VARCHAR})}   
]]>    
</select>   

3.编写JAVA代码调用存储过程
public class ProcedureTest {    
            
         public static void main(String[] args) throws IOException {    
            String resource = "mybatis.cfg.xml";    
            Reader reader = Resources.getResourceAsReader(resource);    
            SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(reader);    
           
            SqlSession session = ssf.openSession();    
           
           try {    
                 Map<String, String> param = new HashMap<String, String>();    
                 param.put("p_user_name", "zhangsan");    
                 String returnValue = (String) session.selectOne("User.proHello", param);    
                 System.out.println("message=" + param.get("p_user_name"));    
                 System.out.println("result=" + param.get("result"));    
                 System.out.println("returnValue=" + returnValue);    
     
           } catch (Exception e) {    
                e.printStackTrace();    
           } finally {    
              session.close();    
          }    
       }    
}   

 

MyBatis主配置文件

在定义sqlSessionFactory时需要指定MyBatis主配置文件:
 

Xml代码 
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 
    <property name="configLocation" value="classpath:mybatis-config.xml" /> 
    <property name="dataSource" ref="dataSource" /> 
</bean> 
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="configLocation" value="classpath:mybatis-config.xml" /> <property name="dataSource" ref="dataSource" /></bean>
 

MyBatis配置文件中大标签configuration下子标签包括(<environments>标签一定要放到<typeAliases> 标签后面,否则解析配置文件时会出错。):

configuration

|--- properties

|--- settings

|--- typeAliases

|--- typeHandlers

|--- objectFactory

|--- plugins

|--- environments

|--- |--- environment

|--- |--- |--- transactionManager

|--- |--- |__ dataSource

|__ mappers

 

 

 

4.1 properties属性
 

    properties和java的.properties的配置文件有关。配置properties的resource指定.properties的路径,然后再在properties标签下配置property的name和value,则可以替换.properties文件中相应属性值。

 

Xml代码 
    <!-- 属性替换 --> 
<properties resource="mysql.properties"> 
    <property name="jdbc.driverClassName" value="com.mysql.jdbc.Driver"/> 
    <property name="jdbc.url" value="jdbc:mysql://localhost:3306/student_manager"/> 
    <property name="username" value="root"/> 
    <property name="password" value="limingnihao"/> 
</properties> 
 <!-- 属性替换 --><properties resource="mysql.properties"> <property name="jdbc.driverClassName" value="com.mysql.jdbc.Driver"/> <property name="jdbc.url" value="jdbc:mysql://localhost:3306/student_manager"/> <property name="username" value="root"/> <property name="password" value="limingnihao"/></properties> 
 

4.2 settings设置
 

    这是MyBatis 修改操作运行过程细节的重要的步骤。下方这个表格描述了这些设置项、含义和默认值。

设置项

描述

允许值

默认值

cacheEnabled

对在此配置文件下的所有cache 进行全局性开/关设置。

true | false

true

lazyLoadingEnabled

全局性设置懒加载。如果设为‘false’,则所有相关联的都会被初始化加载。

true | false

true

aggressiveLazyLoading

当设置为‘true’的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载。

true | false

true

multipleResultSetsEnabled

允许和不允许单条语句返回多个数据集(取决于驱动需求)

true | false

true

useColumnLabel

使用列标签代替列名称。不同的驱动器有不同的作法。参考一下驱动器文档,或者用这两个不同的选项进行测试一下。

true | false

true

useGeneratedKeys

允许JDBC 生成主键。需要驱动器支持。如果设为了true,这个设置将强制使用被生成的主键,有一些驱动器不兼容不过仍然可以执行。

true | false

false

autoMappingBehavior

指定MyBatis 是否并且如何来自动映射数据表字段与对象的属性。PARTIAL将只自动映射简单的,没有嵌套的结果。FULL 将自动映射所有复杂的结果。

NONE,

PARTIAL,

FULL

PARTIAL

defaultExecutorType

配置和设定执行器,SIMPLE 执行器执行其它语句。REUSE 执行器可能重复使用prepared statements 语句,BATCH执行器可以重复执行语句和批量更新。

SIMPLE

REUSE

BATCH

SIMPLE

defaultStatementTimeout

设置一个时限,以决定让驱动器等待数据库回应的多长时间为超时

正整数

Not Set

(null)

 

例如:
Xml代码 
<settings> 
    <setting name="cacheEnabled" value="true" /> 
    <setting name="lazyLoadingEnabled" value="true" /> 
    <setting name="multipleResultSetsEnabled" value="true" /> 
    <setting name="useColumnLabel" value="true" /> 
    <setting name="useGeneratedKeys" value="false" /> 
    <setting name="enhancementEnabled" value="false" /> 
    <setting name="defaultExecutorType" value="SIMPLE" /> 
</settings> 
<settings> <setting name="cacheEnabled" value="true" /> <setting name="lazyLoadingEnabled" value="true" /> <setting name="multipleResultSetsEnabled" value="true" /> <setting name="useColumnLabel" value="true" /> <setting name="useGeneratedKeys" value="false" /> <setting name="enhancementEnabled" value="false" /> <setting name="defaultExecutorType" value="SIMPLE" /></settings> 
 

4.3 typeAliases类型别名

类型别名是Java 类型的简称。

它仅仅只是关联到XML 配置,简写冗长的JAVA 类名。例如:
 

Xml代码 
<typeAliases> 
    <typeAlias alias="UserEntity" type="com.manager.data.model.UserEntity" /> 
    <typeAlias alias="StudentEntity" type="com.manager.data.model.StudentEntity" /> 
    <typeAlias alias="ClassEntity" type="com.manager.data.model.ClassEntity" /> 
</typeAliases> 
<typeAliases> <typeAlias alias="UserEntity" type="com.manager.data.model.UserEntity" /> <typeAlias alias="StudentEntity" type="com.manager.data.model.StudentEntity" /> <typeAlias alias="ClassEntity" type="com.manager.data.model.ClassEntity" /></typeAliases> 


    使用这个配置,“StudentEntity”就能在任何地方代替“com.manager.data.model.StudentEntity”被使用。

      对于普通的Java类型,有许多内建的类型别名。它们都是大小写不敏感的,由于重载的名字,要注意原生类型的特殊处理。

别名

映射的类型

_byte

byte

_long

long

_short

short

_int

int

_integer

int

_double

double

_float

float

_boolean

boolean

string

String

byte

Byte

long

Long

short

Short

int

Integer

integer

Integer

double

Double

float

Float

boolean

Boolean

date

Date

decimal

BigDecimal

bigdecimal

BigDecimal

object

Object

map

Map

hashmap

HashMap

list

List

arraylist

ArrayList

collection

Collection

iterator

Iterator

4.4 typeHandlers类型句柄

无论是MyBatis在预处理语句中设置一个参数,还是从结果集中取出一个值时,类型处理器被用来将获取的值以合适的方式转换成Java类型。下面这个表格描述了默认的类型处理器。

类型处理器

Java类型

JDBC类型

BooleanTypeHandler

Boolean,boolean

任何兼容的布尔值

ByteTypeHandler

Byte,byte

任何兼容的数字或字节类型

ShortTypeHandler

Short,short

任何兼容的数字或短整型

IntegerTypeHandler

Integer,int

任何兼容的数字和整型

LongTypeHandler

Long,long

任何兼容的数字或长整型

FloatTypeHandler

Float,float

任何兼容的数字或单精度浮点型

DoubleTypeHandler

Double,double

任何兼容的数字或双精度浮点型

BigDecimalTypeHandler

BigDecimal

任何兼容的数字或十进制小数类型

StringTypeHandler

String

CHAR和VARCHAR类型

ClobTypeHandler

String

CLOB和LONGVARCHAR类型

NStringTypeHandler

String

NVARCHAR和NCHAR类型

NClobTypeHandler

String

NCLOB类型

ByteArrayTypeHandler

byte[]

任何兼容的字节流类型

BlobTypeHandler

byte[]

BLOB和LONGVARBINARY类型

DateTypeHandler

Date(java.util)

TIMESTAMP类型

DateOnlyTypeHandler

Date(java.util)

DATE类型

TimeOnlyTypeHandler

Date(java.util)

TIME类型

SqlTimestampTypeHandler

Timestamp(java.sql)

TIMESTAMP类型

SqlDateTypeHandler

Date(java.sql)

DATE类型

SqlTimeTypeHandler

Time(java.sql)

TIME类型

ObjectTypeHandler

Any

其他或未指定类型

EnumTypeHandler

Enumeration类型

VARCHAR-任何兼容的字符串类型,作为代码存储(而不是索引)。

 

你可以重写类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型。要这样做的话,简单实现TypeHandler接口(org.mybatis.type),然后映射新的类型处理器类到Java类型,还有可选的一个JDBC类型。然后再typeHandlers中添加这个类型处理器。

新定义的类型处理器将会覆盖已经存在的处理Java的String类型属性和VARCHAR参数及结果的类型处理器。要注意MyBatis不会审视数据库元信息来决定使用哪种类型,所以你必须在参数和结果映射中指定那是VARCHAR类型的字段,来绑定到正确的类型处理器上。这是因为MyBatis直到语句被执行都不知道数据类型的这个现实导致的。

Java代码 
public class LimingStringTypeHandler implements TypeHandler {  
 
    @Override 
    public void setParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {  
        System.out.println("setParameter - parameter: " + ((String) parameter) + ", jdbcType: " + jdbcType.TYPE_CODE);  
        ps.setString(i, ((String) parameter));  
    }  
 
    @Override 
    public Object getResult(ResultSet rs, String columnName) throws SQLException {  
        System.out.println("getResult - columnName: " + columnName);  
        return rs.getString(columnName);  
    }  
 
    @Override 
    public Object getResult(CallableStatement cs, int columnIndex) throws SQLException {  
        System.out.println("getResult - columnIndex: " + columnIndex);  
        return cs.getString(columnIndex);  
    }  

public class LimingStringTypeHandler implements TypeHandler { @Override public void setParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {  System.out.println("setParameter - parameter: " + ((String) parameter) + ", jdbcType: " + jdbcType.TYPE_CODE);  ps.setString(i, ((String) parameter)); } @Override public Object getResult(ResultSet rs, String columnName) throws SQLException {  System.out.println("getResult - columnName: " + columnName);  return rs.getString(columnName); } @Override public Object getResult(CallableStatement cs, int columnIndex) throws SQLException {  System.out.println("getResult - columnIndex: " + columnIndex);  return cs.getString(columnIndex); }} 
 

在配置文件的typeHandlers中添加typeHandler标签。
 

Xml代码 
<typeHandlers> 
    <typeHandler javaType="String" jdbcType="VARCHAR" handler="liming.student.manager.type.LimingStringTypeHandler"/> 
</typeHandlers> 
<typeHandlers> <typeHandler javaType="String" jdbcType="VARCHAR" handler="liming.student.manager.type.LimingStringTypeHandler"/></typeHandlers>

 
4.5 ObjectFactory对象工厂
 

每次MyBatis 为结果对象创建一个新实例,都会用到ObjectFactory。默认的ObjectFactory 与使用目标类的构造函数创建一个实例毫无区别,如果有已经映射的参数,那也可能使用带参数的构造函数。

如果你重写ObjectFactory 的默认操作,你可以通过继承org.apache.ibatis.reflection.factory.DefaultObjectFactory创建一下你自己的。

ObjectFactory接口很简单。它包含两个创建用的方法,一个是处理默认构造方法的,另外一个是处理带参数构造方法的。最终,setProperties方法可以被用来配置ObjectFactory。在初始化你的ObjectFactory实例后,objectFactory元素体中定义的属性会被传递给setProperties方法。


Java代码 
public class LimingObjectFactory extends DefaultObjectFactory {  
 
    private static final long serialVersionUID = -399284318168302833L;  
 
    @Override 
    public Object create(Class type) {  
        return super.create(type);  
    }  
 
    @Override 
    public Object create(Class type, List<Class> constructorArgTypes, List<Object> constructorArgs) {  
        System.out.println("create - type: " + type.toString());  
        return super.create(type, constructorArgTypes, constructorArgs);  
    }  
 
    @Override 
    public void setProperties(Properties properties) {  
        System.out.println("setProperties - properties: " + properties.toString() + ", someProperty: " + properties.getProperty("someProperty"));  
        super.setProperties(properties);  
    }  
 

public class LimingObjectFactory extends DefaultObjectFactory { private static final long serialVersionUID = -399284318168302833L; @Override public Object create(Class type) {  return super.create(type); } @Override public Object create(Class type, List<Class> constructorArgTypes, List<Object> constructorArgs) {  System.out.println("create - type: " + type.toString());  return super.create(type, constructorArgTypes, constructorArgs); } @Override public void setProperties(Properties properties) {  System.out.println("setProperties - properties: " + properties.toString() + ", someProperty: " + properties.getProperty("someProperty"));  super.setProperties(properties); }} 
 


配置文件中添加objectFactory标签

Xml代码 
<objectFactory type="liming.student.manager.configuration.LimingObjectFactory"> 
    <property name="someProperty" value="100"/> 
</objectFactory> 
<objectFactory type="liming.student.manager.configuration.LimingObjectFactory"> <property name="someProperty" value="100"/></objectFactory> 
 

4.6 plugins插件
 

MyBatis允许你在某一点拦截已映射语句执行的调用。默认情况下,MyBatis允许使用插件来拦截方法调用:

Executor(update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
ParameterHandler(getParameterObject, setParameters)
ResultSetHandler(handleResultSets, handleOutputParameters)
StatementHandler(prepare, parameterize, batch, update, query)
 

这些类中方法的详情可以通过查看每个方法的签名来发现,而且它们的源代码在MyBatis的发行包中有。你应该理解你覆盖方法的行为,假设你所做的要比监视调用要多。如果你尝试修改或覆盖一个给定的方法,你可能会打破MyBatis的核心。这是低层次的类和方法,要谨慎使用插件。

使用插件是它们提供的非常简单的力量。简单实现拦截器接口,要确定你想拦截的指定签名。

 
 

4.7 environments环境
MyBatis 可以配置多个环境。这可以帮助你SQL 映射对应多种数据库等。
 

4.8 mappers映射器
这里是告诉MyBatis 去哪寻找映射SQL 的语句。可以使用类路径中的资源引用,或者使用字符,输入确切的URL 引用。

例如:

Xml代码 
<mappers> 
    <mapper resource="com/manager/data/maps/UserMapper.xml" /> 
    <mapper resource="com/manager/data/maps/StudentMapper.xml" /> 
    <mapper resource="com/manager/data/maps/ClassMapper.xml" /> 
</mappers> 
<mappers> <mapper resource="com/manager/data/maps/UserMapper.xml" /> <mapper resource="com/manager/data/maps/StudentMapper.xml" /> <mapper resource="com/manager/data/maps/ClassMapper.xml" /></mappers>

 

MYBATIS注意事项


1。<environments>标签一定要放到<typeAliases> 标签后面,否则解析配置文件时会出错

2。MYBATIS日志记录时,需要在配置文件中增加<setting name="logImpl" value="LOG4J"/>
另外记得加入LOG4J的包以及LOG4J的属性文件放到SRC目录下


3。Mybatis 3.2.2 log4j.xml 没输出问题解决:

 spring sts 默认的mvc工程目录下的log4jx.xml 配置如下

<root>
<priority value="warn" />
<appender-ref ref="console" />
</root>
修改为
<root>
<priority value="debug" />
<appender-ref ref="console" />
</root>
问题搞定。

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值