Mybatis 的配置和使用
- Introduction
Mybatis 是一个支持sql查询,存储过程等的持久层框架,和hibernate作用基本相同,主要通过配置简单的xml,将java的接口和pojo类映射到数据库。 - Mybatis setup
我做测试的时候使用的是maven工程,可以用maven mybatis去google搜索,就可以看到dependency了。
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.1</version>
</dependency>
2.1 Mybatis without Spring
在src/main/resource下面创建一个配置文件mybatis-config.xml,里面配置pojo类的别名,之后访问这个别名就可以了。再要配置data source,接着就是配置mappers文件。mapper是一个xml文件,里面配置了需要执行的sql语句
<?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="CustomerDetail" type="com.data.account.po.CustomerDetail"/>
</typeAliases>
<environments default="development ">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="your db driver"/>
<property name="url" value="your db url" />
<property name="username" value="your account"/>
<property name="password" value="password"/>
</dataSource>
</environment>
</environments>
<mappers >
<mapper resource="com/data/account/mybatis/Customer.xml"/>
</mappers>
</configuration>
Customer.xml定义了一些sql语句,namespace是定义mapper的package,mapper是一个interface,select语句中id必须和接口中的方法名一致。
<?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.data.account.mybatis.CustomerDetailMapper">
<select id="getAccountsByCustomerId" resultType="CustomerDetail">
select * from CUSTOMER_DETAIL where CustomerId =#{id}
</select>
</mapper>
java部分,和hibernate一样,读入配置文件,创建session, open session, 执行sql语句,接着是close session。一说,下面这个调用方式,实际上不必创建CustomerDetailMapper java 接口,只要在Customer.xml配置了namespace, 就可以通过namepace+id执行sql了。
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder ().build(reader);
SqlSession session = sqlSessionFactory.openSession ();
User user = (User) session.selectOne ("com.data.account.mybatis.CustomerDetailMapper.getAccountsByCustomerId"
session.close ();
现在为了更好的符合java编程,mybatis可以使用接口方式,这时就要创建CustomerDetailMapper java 接口了。里面的方法名要和xml配置的id一致。
CustomerDetailMapper cdMapper=session.getMapper(CustomerDetailMapper.class);
CustomerDetail user = cdMapper.getAccountsByCustomerId(1);
2.2 mybatis with spring
将mybatis集成到spring当中,可以用以下的配置,这里的datasource的配置就不post了。文件名为Context.xml
<bean id='mybatisSessionFactory' class="org.mybatis.spring.SqlSessionFactoryBean ">
<property name="configLocation " value="classpath:mybatis-config.xml"></property>
<property name="dataSource" ref="dataSource "></property>
</bean>
<bean id ="customerMapper" class = "org.mybatis.spring.mapper.MapperFactoryBean" >
<property name="mapperInterface" value="com.data.account.mybatis.CustomerDetailMapper"></property>
<property name="sqlSessionFactory" ref="mybatisSessionFactory"></property>
</bean>
java(Junit test)
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.data.account.mybatis.CustomerDetailMapper;
import com.data.account.po.CustomerDetail;
import com.google.common.collect.Lists;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:Context.xml" })
public class MyBatisTest {
@Autowired
private CustomerDetailMapper customerMapper;
@Test
public void test(){
CustomerDetail customer = customerMapper.getAccountsByCustomerId("1");
System.out.println(customer);
}
}
如果在mybatis-config.xml中配置mappers,每一个po的mapper都要配置一个<mapper>,这是不希望的,我们可以将mapper的配置放到SqlSessionFactory中。注释掉mybatis-config.xml中的<mapper>
<bean id='mybatisSessionFactory' class = "org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<property name="dataSource" ref="dataSource"></property>
<property name="mapperLocations" value="com/data/account/mybatis/*.xml"></property>
</bean>
如果为每一个mapper都要配置一个bean的话,如上面的<bean id=”customerMapper”>也是不好的,我们可以用MapperScannerConfiger来扫描mapper接口。CustomerDetailMapper 就是一个普通的interface,无须加任何注解。Junit test和上面的一样。
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.data.account.mybatis" />
</bean>
至此mybatis的setup就结束了。
Spring是这样实现mybatis的,首先根据配置的SqlSessionFactoryBean,创建sqlSessionTemplate,它会创建一个sqlSessionImterceptor,getMapper(sqlSessionTemplate)为注册的mapper创建MapperProxy,MapperProxy的execute方法会执行insert,update,delete,select等方法,它调用的实际就是sqlSessionInterceptor,它完成了opensession,execute sql , close session。
Tips:select实际有selectList, selectOne,selectMap, selectCursor四种,根据方法的返回值类型决定用哪一种,比如是List,Array都是selectList, 单一对象就是selectOne, map就是selectMap,后两者不太懂,没有实际验证。
- Mybatis的使用
3.1 动态sql语句的拼装
支持mybatis 组成动态sql的,通常是以下几个标签
<if test=”account!=null”> and account = #{account} </if>
<if>标签指示条件,满足条件时,才会拼接
<where ><if test=”account!=null”> and account = #{account} </if></where>
<where>标签用于<select>生成where条件语句,如果出现where and|or,那么and|or会自动忽略掉。
<trim prefix="where" prefixOverrides="and |or" ><if test=’**’>…</if></trim>
<trim>可以实现<where>功能, prefix表示以什么为开头,这里举例为where,prefixOverrides表示prefix后面是prefixOverrides指定的字符串的话就省略。
<choose ><when test=”title! =null”> and title=#{title} </when> <when>…</when> <otherwise>…</otherwise></choose>
<choose>标签和java的switch-case-default一样,每次只会匹配一个条件。
<foreach collection=”list” item=”item” index=”i” open=”(” separator=”,”, close=”)”>#{item}</foreach>
<foreach>标签循环迭代collection,item是collection的一个元素,index是迭代的次数,递增,open以什么为开头,close以什么为结尾,separator是item间的分隔符
<update id=””><set ><if test=”**”>…</if></set></update>
<set>标签用于<update>语句,生成set语句。
3.2 Mybatis的resultType、resultMap
当用select的时候,会有一个返回类型,resultType通常用于单表的情况,返回的值会自动填充对象。resultMap通常用于多表的情况。都用resultMap也可以的。
CustomerDetail里面有一个对象是List<TopCustomerRelation> topCustomerRelation
<resultMap type="CustomerDetail" id="oneToMany"><!-- use 子查询 -->
<collection property="topCustomerRelation" select = "getAccountsBySubCustomerId" column = "customerId" ofType="TopCustomerRelation"></collection>
</resultMap>
<collection>标签是一对多,property为CustomerDetail(子)中的字段,select为主查询(多)语句的id,column为主查询和子查询关联column,ofType就是主查询(多)的对象啦。这是子查询的写法。接口方法是这样子的
public CustomerDetail getAccountsByCustomerId(@Param("id") String id)
下面是使用表关联查询,接口方法是这样子的,因为表关联查询会查出来很多条(你可以在db中执行以下语句),所以方法必须是返回List,Set之类的。
public List<TopCustomerRelation> getAccountInfoByCustomerId(@Param("id") String id);
多对一的情况,我们使用<association>来表示,下面的是配置,其中TopCustomerRelation对象中含有属性CustomerDetail customerDetail。我使用的多表关联查询。<association>中的resultMap也要写<result>哦。
<resultMap type="TopCustomerRelation" id="top"> <!--use 表关联 -->
<result property = 'topCustomerId' column="TopCustomerId"></result>
<result property = "subCustomerId" column="SubCustomerId"/>
<association property="customerDetail" javaType="CustomerDetail" resultMap="excustomerMap"></association>
</resultMap>
有的人也许会发现为什么有的时候用<result>标签明确指出property和column之间的关系呢?经过测试,当时多表关联查询的时候,必须指出property和column之间的关系,子查询,由于每次都是单表查询就不必加了。这也很好理解,多表查询会查不多个表的字段,当然要指定一下哪个对象的哪个property对应哪个column才好。
4.和Hibernate的区别
a. 对于用惯sql编程的人来说,无疑mybatis更容易上手,因为hibernate要创建criteria和Hql,调试起来挺麻烦,我在实际项目中遇到用hql写的,我想调试,还需要自己拼接,更重要的是我想在DB中run一下,我还要替换table和column
b. 分页,我没深入研究,但是简单的,它肯定是和数据库相关,比如Oracle,你要用rownum,Mysql, 你要用limit等,我下面参考的一篇blog,说是写一个plugin.我没有深入研究。Hiberate配置dialect就可以了,而且分页也支持
c.对于复杂对象,字段较多,要是用mybatis进行多表连接查询,由于要写resultMap,比较麻烦,hiberate就好多了。
以上是我在实际工作中的一些感受,高层次的差别,比如性能呀优化呀。请参考连接
完结!
参考
[http://blog.csdn.net/kutejava/article/details/9164353#t6]
[http://www.zhihu.com/question/21104468]