持久框架Mybatis的应用

对于持久层框架,我们比较熟悉的是Hibernate,这是一款功能非常强大的持久框。除此之外,还有一款比较流行的框架 - Mybatis

什么是Mybatis?

mybatis是数据映射器(数据映射器层:用于在对象和数据库之间搬运数据,同时保证对象、数据库和数据映射器层本身相对独立。Martin Fowler 《企业应用架构模式》) mybatis不是直接把类映射为数据库表,而是把sql语句的参数与结果(即输入与输出)映射为类。为如何在类和数据库间建立映射带来了更大的灵活性。同时也更好的隔离了数据库设计和应用程序中使用的对象模型。

从以上描述上可以很容易的看出Mybatis是将结果集映射成类,这种半自动化持久框架的最大特点就是具有很强的灵活性。何为半自动化,就是相对于Hibernate的全自动而言的,因为Mybatis需要为每一个持久层的接口定义一个sql语句,接口的执行,就是执行这些sql,每一个持久层方法都需要手动设置sql语句,所以更加灵活

对于Mybatis更多的介绍请参阅黎明你好的技术博客博主的博客http://limingnihao.iteye.com/blog/781671,比较基础和详细。

可以看出mybatis持久框架主要涉及到了三个类,分别是Model模型,是要将结果集映射成的数据模型,Mapper 接口文件,对应持久层的接口;还有一个xml配置文件,用sql语句实现Mapper的接口。以下给出三种文件的例子:

Domain.java

  public class Domain {

    private String id;
    private String name;
    private String domainCode; // 

    // 省略getter setter
}

DomainMapper.java:

public interface DomainMapper {

public Domain findByID(String domainID);

public List<Domain> findAll();

public void add(Domain domain);

public void merge(Domain domain);

public void delete(String domainID);

}

DomainMapper.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="com.test.pojo.domain.DomainMapper">  

<resultMap type="Domain" id="DomainResultMap">  
    <id property="id" column="ID"/ jdbctype=VARCHAR>  
    <result property="name" column="Name"/ jdbctype=VARCHAR> 
    <result property="domainCode" column="DomainCode"/ jdbctype=VARCHAR>  
</resultMap>  

<!-- 查询域,根据id -->  
<select id="findByID" parameterType="String" resultMap="DomainResultMap">  
    <![CDATA[ 
        SELECT * from Domain D 
            WHERE D.ID = #{doaminID}  
    ]]>   
</select>  

<select id="findAll" resultMap="DomainResultMap">
    <![CDATA[
        SELECT * from Domain
    ]]>
</select>

<insert id="add" parameterType="Domain">  
    <![CDATA[
        INSERT INTO DOMAIN         (ID,  
                                 NAME, DomainCode)  
          VALUES   (  #{id},  
                      #{name}, #{domainCode})  
    ]]>
</insert>  

<update id="merge" parameterType="Domain">
    <![CDATA[
        UPDATE DOMAIN
            SET NAME = #{name}
            WHERE ID = #{id}
    ]]>
</update>

<delete id="delete" parameterType="String">
    <![CDATA[
        DELETE DOMAIN
            WHERE ID = #{domainID}
    ]]>
</delete>

</mapper> 

[CDATA]是保证里面的内容当成语句执行,可以不加,不加的时候注意一些关键字,比如User ,要写成‘User’格式

Mapper.java与Mapper.xml的方法一一对应,而且方法名必须一致
namespace指向Mapper.java文件,resultMap 是结果集映射,type是映射到的实体类,这里之所以没有写全路径,是因为Mybatis配置文件里可以对实体类定义别名。

mybatis-config.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="Domain" type="com.shenj.teworks.pojo.domain.Domain"/>  
  </typeAliases>  
<mappers>  
    <mapper resource="com/shenj/teworks/pojo/domain/DomainMapper.xml" />
 </mappers>  
</configuration> 

所有的Mapper.xml文件都要在上面这个文件做一个声明;

在spring中定义datasource:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="net.sourceforge.jtds.jdbc.Driver">
    </property>
    <property name="url" value="jdbc:jtds:sqlserver://localhost:1433/Test">
    </property>
    <property name="username" value="sa"></property>
    <property name="password" value="sa"></property>
</bean>

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

然后Mapper就可以在Spring里声明了,持久层接口就实现了。

应用Mybatis,最经常出现问题的就是xml配置文件:

ResultType取值
可以是一个对象,或者基本类型如,java.lang.Strin,java.lang.Integer
JDBCType是字段对应的数据库类型,取值如下:
BIT,NVACHAR,BIT,TIMESTAMP…

注意

  1. 对于可能为空的字段,进行赋值的时候必须指明jdbcType
  2. 对于有些数据库的nvarchar类型,jdbcType指定为NVARCHAR会报错,请改为VARCHAR即可

Mapper参数设置:
如果只有一个参数,可以这样赋值

ID = #{id , jdbcType=VARCHAR}

或者使用编号,代表第几个参数

ID = #{0}

如果存在不同类型的参数,在xml方法里就不能指明parameterType,
设置参数的时候有两种选择

1 接口

pulic User find(Strig id , String year);

xml中使用序号获取参数 如

where ID = #{0} and Year = #{1}

2 map,在server中将所有参数,封装成map
接口如下:

public User find(Map map);

Map map = new Map();
map.set("id", id);
map.set("year" ,year);

在xml中使用的时候直接用key

where ID = #{id} and
Year = #{year}

此处名称id,year就是map设置的key,必须保持一致

association:

外键映射成对象,比如Schedule 表中有外键Creator 连接到表User表, Schedule对象中有User类型的creator属性,此时就要用association.
有两种方法:

1.用select ,如下

<association property="creator" column="Creator" javaType="User"  
        select="com.test.pojo.user.UserMapper.findByI    D"/> 

此时在获取Schedule对象的时候,根据外键Creator调用userMapper的select方法(UserMapper里事先已经实现了该方法),相当于再去User表中查询一次。

2.用resultMap,如下

<association property="creator" column="Creator" javaType="User"  
        resultMap="com.test.pojo.user.UserMapper.UserResultMap"/> 

此时相当于把UserResultMap集成到ScheduleResulMap中,然后在获取的时候 将两张表连接在一起(此处保证UserMapper下的UserResultMap已经定义了)

select * from Schedule left join User on Creator = UserID

在此需要保证Schedule和User的字段都不一样,否则ResultMap也不知道究竟映射哪一个了,第一种方法没有这种要求

从速度上来说,第一种方法做了两次查询,后一种方法只做了一次查询,因此速度更快,不过一定要保证两张表的字段不能重复,如果不能保证,还是保险一点使用第一种方法吧,如果对于性能要求比较高,再进行优化。

Collection

当处理一对多关系时,映射的是一个关系表中的数据集合,跟association一样,也有两种方法

1.用select

<collection property="appointmentParticipants" column="ID" ofType="User"
      select="com.test.pojo.schedule.AppointmentParticipantMapper.findParticipantByAppointment">
    </collection>

同理,进行两次查询, 只不过这个查询的结果是一个集合,通过ofType制定元素的类型

2.用ResultMap

<collection property="appointmentParticipants" column="ID" ofType="User"
      ResultMap="com.test.pojo.schedule.AppointmentParticipantMapper.UserResultMap">
    </collection>

表连接的方式进行一次查询。

本站总访问量