1、select

我们基于这个持久层接口 GirlDao:
public interface GirlDao {

    List<Girl> findByAge(int age);

    Girl findById(long id);

    int insertGirl(Girl girl);

    int updateGirl(Girl girl);

    int deleteGirl(long id);
}
12
 
1
public interface GirlDao {
2

3
    List<Girl> findByAge(int age);
4

5
    Girl findById(long id);
6

7
    int insertGirl(Girl girl);
8

9
    int updateGirl(Girl girl);
10

11
    int deleteGirl(long id);
12
}

关于select,我们还是先使用最先提到的简单的mapper的一个例子:
<mapper namespace="dulk.learn.mybatis.dao.GirlDao">
<select id="findById" parameterType="long" resultType="dulk.learn.mybatis.pojo.Girl">
SELECT * FROM girl WHERE id = #{id}
</select>
</mapper>
5
 
1
<mapper namespace="dulk.learn.mybatis.dao.GirlDao">
2
    <select id="findById" parameterType="long" resultType="dulk.learn.mybatis.pojo.Girl">
3
        SELECT * FROM girl WHERE id = #{id}
4
    </select>
5
</mapper>

这里的 <select> 标签,即代表的是 select 操作,你应该可以联想到,我们当然还有 <insert>、<update>、<delete> 标签。纵观这段内容,需要提醒你知道的是:
  • select 标签的 id 属性用来标记和区别该 select,如果需要对应接口则 id 和接口方法名要一致
  • parameterType 表示输入参数的类型
  • resultType 表示输出结果的类型
  • #{ } 表示传入的动态参数的占位符

简单来说就是,这个语句叫 findById,接受long(或Long)类型参数(#{id} 则说明参数名为id),返回Girl类型的对象。其实这也相当于告诉MyBatis创建一个预处理语句对象,并传入相应的值,所以以上又相当于JDBC的如下操作:
String findById = "SELECT * FROM girl WHERE id = ?";
PreparedStatement ps = conn.prepareStatement(findById);
ps.setLong(1, id);
3
 
1
String findById = "SELECT * FROM girl WHERE id = ?";
2
PreparedStatement ps = conn.prepareStatement(findById);
3
ps.setLong(1, id);

1.1 输入参数 parameterType

在如上的示例中我们已经看到,输入参数的属性为 parameterType,其值是将会传入这条语句的参数类的 “完全限定名” 或 “别名”(还记得别名吗?参见mybatis-config.xml全局配置文件说明中的typeAliases)。

另外可喜的是,这个属性其实是可选的,因为 MyBatis 可以通过 TypeHandler 推断出具体传入语句的参数,所以这个属性的默认值是 unset,当然,往往我们在开发的时候还是主动进行了限定,因为很多时候我们传入的将会是一个封装了参数的类。

上面的含义是说,假如你传入的是一个自定义的对象,那么占位符的属性会在该对象属性中进行查找并赋值:
<insert id="insertUser" parameterType="User">
insert into users (id, username, password)
values (#{id}, #{username}, #{password})
</insert>
4
 
1
<insert id="insertUser" parameterType="User">
2
    insert into users (id, username, password)
3
    values (#{id}, #{username}, #{password})
4
</insert>

如上若 User 类型的参数对象传递到了语句中,id、username 和 password 属性将会被查找,然后将它们的值传入预处理语句的参数中。

1.2 输出结果 resultType / resultMap

输出结果有两种形式来进行限定,即你要么使用 resultType,要么使用 resultMap,两者不能同时出现在相同的语句标签中:
  • resultType - 返回的期望类型的类的完全限定名或别名(注:若是集合情形,那应该是集合可包含的类型,而不能是集合本身)
  • resultMap - 外部 resultMap 的命名引用

resultType很好理解,其实就和parameterType的使用性质是一样的。那么来简单说明一下这里的resultMap和其外部命名引用是什么意思。

其实在select标签之外,有一个同级的标签,也叫 resultMap(注意我们刚才提到的resultMap是作为select标签的属性出现的),该标签主要针对一些复杂的结果映射,用来 “描述语句和对象之间的映射关系”,你可以理解为我们手动地匹配查询出的列名和对象的属性之间的对应关系(注意是“查询出的列名”而非数据库原本的列名,这意味着你语句中是否有使用“AS”关键字会相应对该映射关系的描述造成影响)。

还是之前的mapper的例子,用resultMap来配置的话,就应该是如下面貌:
<mapper namespace="dulk.learn.mybatis.dao.GirlDao">
<!--定义resultMap-->
<resultMap id="girlResultMap" type="dulk.learn.mybatis.pojo.Girl">
<!--id表查询结果中的唯一标识-->
<id property="id" column="id" />
<!--result表示对普通列名的映射,propertyi表对象属性名,column表查询出的列名-->
<result property="age" column="age" />
</resultMap> <!--引用外部resultMap,即girlResultMap-->
<select id="findById" parameterType="long" resultMap="girlResultMap">
SELECT * FROM girl WHERE id = #{id}
</select>
</mapper>
14
 
1
<mapper namespace="dulk.learn.mybatis.dao.GirlDao">
2
    <!--定义resultMap-->
3
    <resultMap id="girlResultMap" type="dulk.learn.mybatis.pojo.Girl">
4
        <!--id表查询结果中的唯一标识-->
5
        <id property="id" column="id" />
6
        <!--result表示对普通列名的映射,propertyi表对象属性名,column表查询出的列名-->
7
        <result property="age" column="age" />
8
    </resultMap>
9

10
    <!--引用外部resultMap,即girlResultMap-->
11
    <select id="findById" parameterType="long" resultMap="girlResultMap">
12
        SELECT * FROM girl WHERE id = #{id}
13
    </select>
14
</mapper>

所以,如果你是使用ResultType作为输出映射,只有查询出来的列名和对象属性名一致才可映射成功。否则,你就需要定义一个resultMap来描述两者之间的关系。

另外值得一提的是,对于生成的结果是单个还是集合,往往是根据对应接口的返回值类型来确定的,假如 GirlDao 中 List<Girl> findByAge(int age),则返回集合(MyBatis内部调用selectList方法);而诸如 Girl findById(long id) 返回单个对象调用(MyBatis内部调用selectOne方法),所以哪怕你知道你sql会返回的是多个对象,你在 resultType 中也只需要定义的是单个元素的类型,而不是集合。

2、insert, update 和 delete

我们已经知道了<select>,举一反三来看,其实 <insert>、<update>、<delete> 也就不难使用了,如下例:
<!--使用了useGeneratedKeys和keyProperty来将生成的主键设置到对象属性中-->
<insert id="insertGirl" parameterType="dulk.learn.mybatis.pojo.Girl" useGeneratedKeys="true" keyProperty="id">
INSERT INTO girl (age)
VALUES (#{age})
</insert> <update id="updateGirl" parameterType="dulk.learn.mybatis.pojo.Girl">
UPDATE girl
SET age = #{age}
WHERE id = #{id}
</update> <delete id="deleteGirl" parameterType="long">
DELETE FROM girl
WHERE id = #{id}
</delete>
16
 
1
<!--使用了useGeneratedKeys和keyProperty来将生成的主键设置到对象属性中-->
2
<insert id="insertGirl" parameterType="dulk.learn.mybatis.pojo.Girl" useGeneratedKeys="true" keyProperty="id">
3
    INSERT INTO girl (age)
4
    VALUES (#{age})
5
</insert>
6

7
<update id="updateGirl" parameterType="dulk.learn.mybatis.pojo.Girl">
8
    UPDATE girl
9
    SET age = #{age}
10
    WHERE id = #{id}
11
</update>
12

13
<delete id="deleteGirl" parameterType="long">
14
    DELETE FROM girl
15
    WHERE id = #{id}
16
</delete>

只是需要注意的是:
  • insert / update / delete 都没有 resultType 或 resultMap,他们的返回值是受影响的行数
  • 若数据库支持自动生成主键,可设置 useGeneratedKeys 为 true,并使用 keyProperty 将生成的主键值设置到目标属性上(如上例的insert)

做了个单元测试如下:
public class Test {

    @org.junit.Test
public void testMyBatis() throws IOException {
//读取配置文件
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
//获取工厂类
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
//获取SqlSession数据库会话对象
SqlSession sqlSession = factory.openSession();
//获取Dao
GirlDao girlDao = sqlSession.getMapper(GirlDao.class); Girl girl = new Girl();
girl.setAge(18); //insert a girl with age 18
int resultInsert = girlDao.insertGirl(girl);
Assert.assertEquals(1, resultInsert);
Assert.assertEquals(18, girlDao.findById(girl.getId()).getAge()); //update girl's age from 18 to 20
girl.setAge(20);
int resultUpdate = girlDao.updateGirl(girl);
Assert.assertEquals(1, resultUpdate);
Assert.assertEquals(20, girlDao.findById(girl.getId()).getAge()); //delete girl
int resultDelete = girlDao.deleteGirl(girl.getId());
Assert.assertEquals(1, resultDelete);
Assert.assertNull(girlDao.findById(girl.getId()));
} }
34
 
1
public class Test {
2

3
    @org.junit.Test
4
    public void testMyBatis() throws IOException {
5
        //读取配置文件
6
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
7
        //获取工厂类
8
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
9
        //获取SqlSession数据库会话对象
10
        SqlSession sqlSession = factory.openSession();
11
        //获取Dao
12
        GirlDao girlDao = sqlSession.getMapper(GirlDao.class);
13

14
        Girl girl = new Girl();
15
        girl.setAge(18);
16

17
        //insert a girl with age 18
18
        int resultInsert = girlDao.insertGirl(girl);
19
        Assert.assertEquals(1, resultInsert);
20
        Assert.assertEquals(18, girlDao.findById(girl.getId()).getAge());
21

22
        //update girl's age from 18 to 20
23
        girl.setAge(20);
24
        int resultUpdate = girlDao.updateGirl(girl);
25
        Assert.assertEquals(1, resultUpdate);
26
        Assert.assertEquals(20, girlDao.findById(girl.getId()).getAge());
27

28
        //delete girl
29
        int resultDelete = girlDao.deleteGirl(girl.getId());
30
        Assert.assertEquals(1, resultDelete);
31
        Assert.assertNull(girlDao.findById(girl.getId()));
32
    }
33
    
34
}

3、sql

sql元素用来定义可重用的SQL代码片段,其他语句可以用过 <include> 标签来将之包含其中。看个例子就能明白了:
<mapper namespace="dulk.learn.mybatis.dao.GirlDao">

    <resultMap id="girlResultMap" type="dulk.learn.mybatis.pojo.Girl">
<id property="id" column="id" />
<result property="age" column="age" />
<result property="cupSize" column="cup_size" />
</resultMap> <!--定义可重用的sql片段-->
<sql id="girlColumn">
id, age
</sql> <select id="findById" parameterType="long" resultMap="girlResultMap">
<!--通过include引用外部sql片段-->
SELECT <include refid="girlColumn" />
FROM girl WHERE id = #{id}
</select> </mapper>
20
 
1
<mapper namespace="dulk.learn.mybatis.dao.GirlDao">
2

3
    <resultMap id="girlResultMap" type="dulk.learn.mybatis.pojo.Girl">
4
        <id property="id" column="id" />
5
        <result property="age" column="age" />
6
        <result property="cupSize" column="cup_size" />
7
    </resultMap>
8

9
    <!--定义可重用的sql片段-->
10
    <sql id="girlColumn">
11
      id, age
12
    </sql>
13

14
    <select id="findById" parameterType="long" resultMap="girlResultMap">
15
        <!--通过include引用外部sql片段-->
16
        SELECT <include refid="girlColumn" />
17
        FROM girl WHERE id = #{id}
18
    </select>
19

20
</mapper>


[03] mapper.xml的基本元素概述的更多相关文章

  1. mybatis自动生成model、dao及对应的mapper.xml文件

    背景: 日常开发中,如果新建表,手动敲写model.dao和对应的mapper.xml文件,费时费力且容易出错, 所以采用mybatis自动生成model.dao及对应的mapper.xml文件.代码 ...

  2. MyBatis Mapper.xml文件中 $和#的区别

    MyBatis Mapper.xml文件中 $和#的区别   网上有很多,总之,简略的写一下,作为备忘.例子中假设参数名为 paramName,类型为 VARCHAR . 1.优先使用#{paramN ...

  3. Mybatis学习错误之:重复加载mapper.xml

    学习mybatis的时候,突然遇到测试出错.测试mapper代理失败,现在钻研少了,不喜欢看未知的错误了,立即改正.错误打印说mapper.xml已经注册,仔细查看SQLMapConfig.xml发现 ...

  4. mybatis公用代码抽取到单独的mapper.xml文件

    同任何的代码库一样,在mapper中,通常也会有一些公共的sql代码段会被很多业务mapper.xml引用到,比如最常用的可能是分页和数据权限过滤了,尤其是在oracle中的分页语法.为了减少骨架性代 ...

  5. Mybatis学习--Mapper.xml映射文件

    简介 Mapper.xml映射文件中定义了操作数据库的sql,每个sql是一个statement,映射文件是mybatis的核心. 映射文件中有很多属性,常用的就是parameterType(输入类型 ...

  6. nested exception is java.lang.RuntimeException: Error parsing Mapper XML. Cause: java.lang.IllegalArgumentException: Result Maps collection already contains value for

    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'daoSupport': ...

  7. mybatis mapper.xml 配置文件问题(有的错误xml是不报的) 导致服务无法启动 。

    转载自 开源编程 一舟mybatsi xml编译报错,tomcat启动一直循环,导致内存溢出,启动失败 mapper.xml怎么知道有没有编译错误,哪个位置有错误 这应该是mybatis的一个bug, ...

  8. mybatis之mapper.xml分析

    select: id:方法名,在同一个mapper.xml中,要保持唯一 parameterType:指定输入的参数类型,不是必须的,如果不指定,mybatis会自动识别(推荐指定). resultT ...

  9. spring mybatis 整合问题Error parsing Mapper XML. Cause: java.lang.NullPointerException

    14:30:40,872 DEBUG SqlSessionFactoryBean:431 - Parsed configuration file: 'class path resource [myba ...

随机推荐

  1. vue.js及项目实战[笔记]— 02 vue.js基础

    一. 基础 1. 注册全局组件 应用场景:多出使用的公共性能组件,就可以注册成全局组件,减少冗余代码 全局APIVue.component('组件名','组件对象') 2.附加功能:过滤器&监 ...

  2. MySQL MySql连接数与线程池

    MySql连接数与线程池 by:授客 QQ:1033553122 连接数 1.  查看允许的最大并发连接数 SHOW VARIABLES LIKE 'max_connections'; 2.  修改最 ...

  3. 安卓开发_关于WebView加载页面空白问题

    依据我自己的测试,发现有时候用APP打开网页的时候,有的网页加载成功之前需要很久,有的一下就出来了(比如百度) 当加载时间过长的情况下,这时候显示的是空白界面,其实不是代码问题,只是要打开的这个网页太 ...

  4. Android jni c/c++线程通过CallVoidMethod调用java函数出现奔溃问题

    最近在移植网络摄像机里的p2p库到android平台,需要用到jni,最近在c线程了调用java函数的时候 出现一个问题,假如在同一个线程调用java函数是没问题的,但在一个c线程了调用java函数就 ...

  5. linux上用newman+postman进行自动化测试

    第一步:导出postman文件 Postman就是根据collection和enviroment这两个json文件来自动化运行的! 所以从Postman中导出collection和enviroment ...

  6. spring 引用Bean的属性值

    引用Bean的属性值 从Spring3.0开始,可以通过#{beanName.beanProp}的方式方便地引用另一个bean的属性值1.不需要使用PropertyPlaceholderConfigu ...

  7. Python:GUI之tkinter学习笔记2界面布局显示

    相关内容: pack 介绍 常用参数 使用情况 常用函数 grid 介绍 常用参数 使用情况 常用函数 place 介绍 常用参数 使用情况 常用函数 首发时间:2018-03-04 14:20 pa ...

  8. python并发编程之线程

    操作系统线程理论 参考资料:http://www.cnblogs.com/Eva-J/articles/8306047.html 线程和python 理论知识 全局解释器锁GIL Python代码的执 ...

  9. MySQL修改编码为UTF-8无效果解决办法

    本来这是一件很简单的事,有很多博客里都有教程,但却足足花了我半天的时间才解决问题. 可能是因为我的MySQL安装时没有选择默认路径的原因,按照网上的教程修改了下图中的my.ini配置文件后编码并没有发 ...

  10. python第七十九天--第十四周作业

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...