MyBatis框架
ORM框架概述
ORM框架的基本思想
无论是用过的hibernate,mybatis,你都可以法相他们有一个共同点:
- 从配置文件(通常是XML配置文件中)得到 sessionfactory.
- 由sessionfactory 产生 session
- 在session 中完成对数据的增删改查和事务提交等.
- 在用完之后关闭session 。
- 在java 对象和 数据库之间有做mapping 的配置文件,也通常是xml 文件。
mybatis简介
MyBatis 是一个可以自定义SQL、存储过程和高级映射的持久层框架。MyBatis 摒除了大部分的JDBC代码、手工设置参数和结果集重获。MyBatis 只使用简单的XML 和注解来配置和映射基本数据类型、Map 接口和POJO 到数据库记录。相对Hibernate和Apache OJB等“一站式”ORM解决方案而言,Mybatis 是一种“半自动化”的ORM实现。
MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs(Plan Old Java Objects,普通的Java对象)映射成数据库中的记录.
MyBatis架构图
MyBatis集成Spring
pom.xml配置dependency
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
</dependency>
<dependency>
<groupId>org.apache.ibatis</groupId>
<artifactId>ibatis-sqlmap</artifactId>
</dependency>
Spring配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="dataSource" class="..." init-method="init">
...
</bean>
<!-- TransactionManager定义。 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="transactionTemplate"
class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"/>
</bean>
<!-- 通过aop定义事务增强切面 -->
<aop:config>
<aop:pointcut id="serviceMethod" expression="execution(* com.alibaba.swork.info.common.service.*.*(..))"/>
<aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="find*" read-only="false"/>
<tx:method name="add*" rollback-for="Exception"/>
<tx:method name="new*" rollback-for="Exception"/>
<tx:method name="update*" rollback-for="Exception"/>
</tx:attributes>
</tx:advice>
<!-- MyBatis配置 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 自动扫描entity目录, 省掉Configuration.xml里的手工配置 -->
<property name="typeAliasesPackage" value="com.alibaba.swork.info.common.bean.model"/>
<!-- 显式指定Mapper文件位置 -->
<property name="mapperLocations"
value="classpath:/sqlmap/*Mapper.xml"/>
<property name="configLocation" value="classpath:/dal/sqlmap-config.xml"></property>
</bean>
<!-- 扫描basePackage下mapper接口 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"
p:basePackage="com.alibaba.swork.info.common.mapper"/>
</beans>
一个示例工程: https://github.com/universsky/SpringMVC-Spring-MyBatis
更多原理介绍参考: http://www.mybatis.org/mybatis-3/zh/getting-started.html
MyBatis自动生成model对象,mapper.java,mapper.xml代码
pom依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
</dependency>
java自动生成代码工具类
package com.alibaba.swork.info.common.generator;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* Created by jack on 2016/9/22.
*/
public class GenerateDaoCode {
public static void main(String[] args) throws Exception {
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;//是否覆盖原来的文件
File currentDir = new File(".");
System.out.println(currentDir.getAbsolutePath());
File configFile = new File("swork.info.common/src/main/resources/generatorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
}
}
配置文件generatorConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<classPathEntry
location="D:/swork-idea/swork.info/swork.info.server/target/swork-info/WEB-INF/lib/mysql-connector-java-5.1.30.jar"/>
<context id="mysql" defaultModelType="flat" targetRuntime="MyBatis3">
<!-- 自动识别数据库关键字,默认false,如果设置为true,根据SqlReservedWords中定义的关键字列表;
一般保留默认值,遇到数据库关键字(Java关键字),使用columnOverride覆盖
-->
<property name="autoDelimitKeywords" value="false"/>
<!-- 生成的Java文件的编码 -->
<property name="javaFileEncoding" value="UTF-8"/>
<!-- 格式化java代码 -->
<property name="javaFormatter" value="org.mybatis.generator.api.dom.DefaultJavaFormatter"/>
<!-- 格式化XML代码 -->
<property name="xmlFormatter" value="org.mybatis.generator.api.dom.DefaultXmlFormatter"/>
<!-- beginningDelimiter和endingDelimiter:指明数据库的用于标记数据库对象名的符号,比如ORACLE就是双引号,MYSQL默认是`反引号; -->
<property name="beginningDelimiter" value="`"/>
<property name="endingDelimiter" value="`"/>
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://127.0.0.1:3306/swork_info?allowMultiQueries=true"
userId="root" password="*********">
</jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<javaModelGenerator targetPackage="test.model"
targetProject="swork.info.common">
<property name="enableSubPackages" value="true"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<sqlMapGenerator targetPackage="test.sqlmap"
targetProject="swork.info.common">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<javaClientGenerator type="XMLMAPPER"
targetPackage="test.mapper" targetProject="swork.info.common">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<table tableName="%"
enableCountByExample="false"
enableDeleteByExample="false"
enableSelectByExample="false"
enableUpdateByExample="false">
<generatedKey column="id" sqlStatement="Mysql" identity="true"/>
</table>
</context>
</generatorConfiguration>
详细原理介绍参考:
http://www.mybatis.org/generator/
generatorConfiguration配置文件参考:
http://www.mybatis.org/generator/configreference/table.html
MyBatis动态 SQL
MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么痛苦。拼接的时候要确保不能忘了必要的空格,还要注意省掉列名列表最后的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。
通常使用动态 SQL 不可能是独立的一部分,MyBatis 当然使用一种强大的动态 SQL 语言来改进这种情形,这种语言可以被用在任意的 SQL 映射语句中。
动态 SQL 元素和使用 JSTL 或其他类似基于 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多的元素需要来了解。MyBatis 3 大大提升了它们,现在用不到原先一半的元素就可以了。MyBatis 采用功能强大的基于 OGNL 的表达式来消除其他元素。
if
choose (when, otherwise)
trim (where, set)
foreach
if
动态 SQL 通常要做的事情是有条件地包含 where 子句的一部分。比如:
<select id="findActiveBlogWithTitleLike"
resultType="Blog">
SELECT * FROM BLOG
WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
</select>
这条语句提供了一个可选的文本查找类型的功能。如果没有传入“title”,那么所有处于“ACTIVE”状态的BLOG都会返回;反之若传入了“title”,那么就会把模糊查找“title”内容的BLOG结果返回(就这个例子而言,细心的读者会发现其中的参数值是可以包含一些掩码或通配符的)。
如果想可选地通过“title”和“author”两个条件搜索该怎么办呢?首先,改变语句的名称让它更具实际意义;然后只要加入另一个条件即可。
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</select>
choose, when, otherwise
有些时候,我们不想用到所有的条件语句,而只想从中择其一二。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
还是上面的例子,但是这次变为提供了“title”就按“title”查找,提供了“author”就按“author”查找,若两者都没有提供,就返回所有符合条件的BLOG(实际情况可能是由管理员按一定策略选出BLOG列表,而不是返回大量无意义的随机结果)。
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
trim, where, set
前面几个例子已经合宜地解决了一个臭名昭著的动态 SQL 问题。现在考虑回到“if”示例,这次我们将“ACTIVE = 1”也设置成动态的条件,看看会发生什么。
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
WHERE
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</select>
如果这些条件没有一个能匹配上将会怎样?最终这条 SQL 会变成这样:
SELECT * FROM BLOG
WHERE
这会导致查询失败。如果仅仅第二个条件匹配又会怎样?这条 SQL 最终会是这样:
SELECT * FROM BLOG
WHERE
AND title like ‘someTitle’
这个查询也会失败。这个问题不能简单的用条件句式来解决,如果你也曾经被迫这样写过,那么你很可能从此以后都不想再这样去写了。
MyBatis 有一个简单的处理,这在90%的情况下都会有用。而在不能使用的地方,你可以自定义处理方式来令其正常工作。一处简单的修改就能得到想要的效果:
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
<where>
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</where>
</select>
where 元素知道只有在一个以上的if条件有值的情况下才去插入“WHERE”子句。而且,若最后的内容是“AND”或“OR”开头的,where 元素也知道如何将他们去除。
如果 where 元素没有按正常套路出牌,我们还是可以通过自定义 trim 元素来定制我们想要的功能。比如,和 where 元素等价的自定义 trim 元素为:
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
prefixOverrides 属性会忽略通过管道分隔的文本序列(注意此例中的空格也是必要的)。它带来的结果就是所有在 prefixOverrides 属性中指定的内容将被移除,并且插入 prefix 属性中指定的内容。
类似的用于动态更新语句的解决方案叫做 set。set 元素可以被用于动态包含需要更新的列,而舍去其他的。比如:
<update id="updateAuthorIfNecessary">
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio}</if>
</set>
where id=#{id}
</update>
这里,set 元素会动态前置 SET 关键字,同时也会消除无关的逗号,因为用了条件语句之后很可能就会在生成的赋值语句的后面留下这些逗号。
若你对等价的自定义 trim 元素的样子感兴趣,那这就应该是它的真面目:
<trim prefix="SET" suffixOverrides=",">
...
</trim>
注意这里我们忽略的是后缀中的值,而又一次附加了前缀中的值。
foreach
动态 SQL 的另外一个常用的必要操作是需要对一个集合进行遍历,通常是在构建 IN 条件语句的时候。比如:
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
foreach 元素的功能是非常强大的,它允许你指定一个集合,声明可以用在元素体内的集合项和索引变量。它也允许你指定开闭匹配的字符串以及在迭代中间放置分隔符。这个元素是很智能的,因此它不会偶然地附加多余的分隔符。
注意 你可以将任何可迭代对象(如列表、集合等)和任何的字典或者数组对象传递给foreach作为集合参数。当使用可迭代对象或者数组时,index是当前迭代的次数,item的值是本次迭代获取的元素。当使用字典(或者Map.Entry对象的集合)时,index是键,item是值。
到此我们已经完成了涉及 XML 配置文件和 XML 映射文件的讨论。下一部分将详细探讨 Java API,这样才能从已创建的映射中获取最大利益。
bind bind 元素可以从 OGNL 表达式中创建一个变量并将其绑定到上下文。比如:
<select id="selectBlogsLike" resultType="Blog"> <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" /> SELECT * FROM BLOG WHERE title LIKE #{pattern} </select>
Multi-db vendor support 一个配置了“_databaseId”变量的 databaseIdProvider 对于动态代码来说是可用的,这样就可以根据不同的数据库厂商构建特定的语句。比如下面的例子:
<insert id="insert"> <selectKey keyProperty="id" resultType="int" order="BEFORE"> <if test="_databaseId == 'oracle'"> select seq_users.nextval from dual </if> <if test="_databaseId == 'db2'"> select nextval for seq_users from sysibm.sysdummy1" </if> </selectKey> insert into users values (#{id}, #{name}) </insert>
动态 SQL 中可插拔的脚本语言 MyBatis 从 3.2 开始支持可插拔的脚本语言,因此你可以在插入一种语言的驱动(language driver)之后来写基于这种语言的动态 SQL 查询。
可以通过实现下面接口的方式来插入一种语言:
public interface LanguageDriver {
ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql);
SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType);
SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType);
}
一旦有了自定义的语言驱动,你就可以在 mybatis-config.xml 文件中将它设置为默认语言:
<typeAliases>
<typeAlias type="org.sample.MyLanguageDriver" alias="myLanguage"/>
</typeAliases>
<settings>
<setting name="defaultScriptingLanguage" value="myLanguage"/>
</settings>
除了设置默认语言,你也可以针对特殊的语句指定特定语言,这可以通过如下的 lang 属性来完成:
<select id="selectBlog" lang="myLanguage">
SELECT * FROM BLOG
</select>
或者在你正在使用的映射中加上注解 @Lang 来完成:
public interface Mapper {
@Lang(MyLanguageDriver.class)
@Select("SELECT * FROM BLOG")
List<Blog> selectBlog();
}
MyBatis处理集合、循环、数组和in查询等语句的使用
相信很多人可能都遇到过下面这些异常:
"Parameter 'xxx' not found. Available parameters are [...]"
"Could not get property 'xxx' from xxxClass. Cause:
"The expression 'xxx' evaluated to a null value."
"Error evaluating expression 'xxx'. Return value (xxxxx) was not iterable."
不只是上面提到的这几个,我认为有很多的错误都产生在和参数有关的地方。
想要避免参数引起的错误,我们需要深入了解参数。
想了解参数,我们首先看MyBatis处理参数和使用参数的全部过程。
参考文章: http://blog.csdn.net/isea533/article/details/44002219
MyBatis的传入参数parameterType类型
MyBatis的传入参数parameterType类型分两种:
(1) 基本数据类型:int,string,long,Date;
(2) 复杂数据类型:类和Map
如何获取参数中的值:
(1)基本数据类型:#{参数} 获取参数中的值
(2)复杂数据类型:#{属性名} ,map中则是#{key}
例子
基本数据类型
<sql id="Base_Column_List" >
id, car_dept_name, car_maker_name, icon,car_maker_py,hot_type
</sql>
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Long" >
select
<include refid="Base_Column_List" />
from common_car_make
where id = #{id,jdbcType=BIGINT}
</select>
复杂类型--map类型
<select id="queryCarMakerList" resultMap="BaseResultMap" parameterType="java.util.Map">
select
<include refid="Base_Column_List" />
from common_car_make cm
where 1=1
<if test="id != null">
and cm.id = #{id,jdbcType=DECIMAL}
</if>
<if test="carDeptName != null">
and cm.car_dept_name = #{carDeptName,jdbcType=VARCHAR}
</if>
<if test="carMakerName != null">
and cm.car_maker_name = #{carMakerName,jdbcType=VARCHAR}
</if>
<if test="hotType != null" >
and cm.hot_type = #{hotType,jdbcType=BIGINT}
</if>
ORDER BY cm.id
</select>
复杂类型--类类型
<update id="updateByPrimaryKeySelective" parameterType="com.epeit.api.model.CommonCarMake" >
update common_car_make
<set >
<if test="carDeptName != null" >
car_dept_name = #{carDeptName,jdbcType=VARCHAR},
</if>
<if test="carMakerName != null" >
car_maker_name = #{carMakerName,jdbcType=VARCHAR},
</if>
<if test="icon != null" >
icon = #{icon,jdbcType=VARCHAR},
</if>
<if test="carMakerPy != null" >
car_maker_py = #{carMakerPy,jdbcType=VARCHAR},
</if>
<if test="hotType != null" >
hot_type = #{hotType,jdbcType=BIGINT},
</if>
</set>
where id = #{id,jdbcType=BIGINT}
</update>
复杂类型--map中包含数组的情况
<select id="selectProOrderByOrderId" resultType="com.epeit.api.model.ProOrder" parameterType="java.util.HashMap" >
select sum(pro_order_num) proOrderNum,product_id productId,promotion_id promotionId
from pro_order
where 1=1
<if test="orderIds != null and orderIds.length > 0">
and
<foreach collection="orderIds" item="item" open="order_id IN(" separator="," close=")">
#{item,jdbcType=BIGINT}
</foreach>
</if>
GROUP BY product_id,promotion_id
</select>
foreach动态语句
在Mybatis的xml配置中使用集合,主要是用到了foreach动态语句。
foreach的参数:
foreach元素的属性主要有
item,index,collection,open,separator,close
item表示集合中每一个元素进行迭代时的别名.
index指 定一个名字,用于表示在迭代过程中,每次迭代到的位置.
open表示该语句以什么开始
separator表示在每次进行迭代之间以什么符号作为分隔符.
close表示以什么结束。
Mybatis生成select * from table where id in(1,2,...,n)语句的查询
我们一般的做法是在方法的参数处指定传入的参数名称,在xml中使用的时候,集合的名称要和方法的Param的名称一致,这样便于阅读和理解,然后是在对应的xml文件中使用foreach循环。
java代码如下:
public abstract List<Model> findByIds(@Param("ids")List<Integer> ids);
对应的xml代码如下:
select * from table
<where>
id in <foreach collection="ids" item="item" index="index"
open="(" separator="," close=")">#{item}</foreach>
</where>
Mybatis保存多条记录
我们同样是通过foreach的方法来实现,这里我们巧妙的利用了sql的语法规则用Mybatis的foreach动态语句来处理。
java代码:
public abstract void saves(@Param("tables")List<Model> tables);
xml代码:
insert into table(name,addtime) values
<foreach collection="tables" item="item" index="index" separator=",">
(#{item.name},#{item.addtime})
</foreach>
以上方法Mybatis会帮我们进行sql注入拦截,Mybatis如果采用#{xxx}的形式设置参数,Mybatis会进行sql注入的过滤。如果采用的是${xxx},Mybatis不会进行sql注入过滤,而是直接将参入的内容输出为sql语句。
判断集合是否有值
<if test="list!=null and list.size()>0"></if>
一个完整的例子
Mapper.java代码:
List<Employee> selectByWorkNos(@Param("workNos")String[] workNos);
Mapper.xml代码
<select id="selectByWorkNos" parameterType="java.lang.String" resultMap="BaseResultMap">
select
<include refid="Base_Column_List"/>
from employee
<where>
work_no
<choose>
<when test="workNos!= null and workNos.length > 0">
in
<foreach collection="workNos" item="workNo" open="(" close=")" separator=",">
#{workNo,jdbcType=VARCHAR}
</foreach>
</when>
<otherwise>
<![CDATA[
in (null)
]]>
</otherwise>
</choose>
</where>
</select>
mysql关联表查询
sql程序
SELECT
p.id,
p.name,
p.aone_product_id,
p.aone_deptartment_id,
p.aone_deptartment_name,
p.product_id,
p.kickoff_date,
p.goal_expect_date,
p.goal_actual_date,
p.expect_start_date,
p.goal,
p.bizvalue,
p.background,
p.recipients,
p.expect_end_date,
p.actual_start_date,
p.actual_end_date,
p.gmt_create,
p.gmt_modified,
p.ref_app,
p.workload_pd,
p.workload_uc,
p.workload_front,
p.workload_end,
p.workload_qa,
p.link_project_doc,
p.link_aone,
p.link_frd,
p.type,
p.status,
p.version,
p.parent_project_id,
p.deparmtent_id,
p.aone_project_id,
p.sponsor_workno,
p.role_bizside_workno,
p.role_pm_workno,
p.role_pd_workno,
p.role_dev_workno,
p.role_qa_workno,
p.role_architector_workno,
p.admins,
p.members,
pr.name AS product_name,
ps.status_detail AS status_detail,
pt.type_detail AS type_detail,
dept.name AS deparmtent_name
FROM
((((project p inner join product pr on pr.id = p.product_id)
inner join project_type pt on p.type = pt.id)
inner join project_status ps on p.status = ps.id)
inner join department dept on p.deparmtent_id = dept.dept_no)
WHERE p.type = #{type, jdbcType=INTEGER}
<?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.alibaba.swork.info.common.mapper.ProjectMapper">
<resultMap id="BaseResultMap" type="com.alibaba.swork.info.common.bean.model.Project">
<id column="id" jdbcType="INTEGER" property="id"/>
<result column="name" jdbcType="VARCHAR" property="name"/>
...
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="com.alibaba.swork.info.common.bean.model.Project">
<result column="sponsor_workno" jdbcType="LONGVARCHAR" property="sponsorWorkno"/>
<result column="background" jdbcType="LONGVARCHAR" property="background"/>
...
<result column="members" jdbcType="LONGVARCHAR" property="members"/>
<result column="admins" jdbcType="LONGVARCHAR" property="admins"/>
</resultMap>
<sql id="Base_Column_List">
id, name, ...
</sql>
<sql id="Blob_Column_List">
sponsor_workno, background, ...
members,admins
</sql>
<select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="ResultMapWithBLOBs">
select
<include refid="Base_Column_List"/>
,
<include refid="Blob_Column_List"/>
from project
where id = #{id,jdbcType=INTEGER}
</select>
...
<resultMap extends="ResultMapWithBLOBs" id="BaseVoResultMap" type="com.alibaba.swork.info.common.vo.ProjectVo">
<result column="product_name" jdbcType="VARCHAR" property="productName"/>
<result column="status_detail" jdbcType="VARCHAR" property="statusDetail"/>
<result column="type_detail" jdbcType="VARCHAR" property="typeDetail"/>
<result column="deparmtent_name" jdbcType="VARCHAR" property="deparmtentName"/>
</resultMap>
<select id="findVoByType" parameterType="java.lang.Integer" resultMap="BaseVoResultMap" resultOrdered="true">
SELECT
p.id,
p.name,
p.aone_product_id,
p.aone_deptartment_id,
p.aone_deptartment_name,
p.product_id,
p.kickoff_date,
p.goal_expect_date,
p.goal_actual_date,
p.expect_start_date,
p.goal,
p.bizvalue,
p.background,
p.recipients,
p.expect_end_date,
p.actual_start_date,
p.actual_end_date,
p.gmt_create,
p.gmt_modified,
p.ref_app,
p.workload_pd,
p.workload_uc,
p.workload_front,
p.workload_end,
p.workload_qa,
p.link_project_doc,
p.link_aone,
p.link_frd,
p.type,
p.status,
p.version,
p.parent_project_id,
p.deparmtent_id,
p.aone_project_id,
p.sponsor_workno,
p.role_bizside_workno,
p.role_pm_workno,
p.role_pd_workno,
p.role_dev_workno,
p.role_qa_workno,
p.role_architector_workno,
p.admins,
p.members,
pr.name AS product_name,
ps.status_detail AS status_detail,
pt.type_detail AS type_detail,
dept.name AS deparmtent_name
FROM
((((project p inner join product pr on pr.id = p.product_id)
inner join project_type pt on p.type = pt.id)
inner join project_status ps on p.status = ps.id)
inner join department dept on p.deparmtent_id = dept.dept_no)
WHERE p.type = #{type, jdbcType=INTEGER}
</select>
...
</mapper>
学习资料
MyBatis学习 之 一、MyBatis简介与配置MyBatis+Spring+MySql http://limingnihao.iteye.com/blog/781671
MyBatis学习 之 二、SQL语句映射文件(1)resultMap http://limingnihao.iteye.com/blog/781878
MyBatis学习 之 二、SQL语句映射文件(2)增删改查、参数、缓存 http://limingnihao.iteye.com/blog/781911
MyBatis学习 之 三、动态SQL语句 http://limingnihao.iteye.com/blog/782190
MyBatis学习 之 四、MyBatis配置文件 http://limingnihao.iteye.com/blog/1060764