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. 利用火车头采集A67手机电影教程一

    今天将讲述:利用火车头采集A67手机电影,并导入到网站中,如果你要更多更快的教程,请访问:http://www.it28.cn/category-191.html 现在以A67中的电影中的动作片为例: ...

  2. Python Python中的反射机制

    Python中的反射机制 by:授客 QQ:1033553122 概念 借用java中的定义:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方 ...

  3. Ubuntu16.04升级 Ubuntu18.04

    1.更新资源 $ sudo apt-get update $ sudo apt-get upgrade $ sudo apt dist-upgrade 2.安装update-manager-core ...

  4. Android清单文件合并的那些事

    APK文件只能包含一个AndroidManifest.xml文件,但Android Studio项目可以包含多个文件(通过buildSrc.导入的库引入).因此,在构建应用时,Gradle构建会将所有 ...

  5. python自动发送测试报告(五)

    python实现自动发送邮件具体步骤参考笔者的另一篇博文,python实现邮件的发送 本次只展示发送附件的代码,MIMEApplication支持常用格式文档(.jpg..mp3.zip等)当做附件上 ...

  6. sql 查询表格中多列重复的数据并显示该表的其他列

    我们一般情况下通过分组函数group by来查询重复的列 ) R 但是查询出的结果不能显示该表的其他列 想要查询一张表中有多个列重复的数据且也要显示该表的其他列 SELECT M.* FROM [db ...

  7. Visual Stuido插件大全

    JS Enhancements 使用JS能像C#代码一样折叠成块 Code Compare Code Compare is a powerful file and folder comparison ...

  8. Java的学习路线建议(转)

    https://www.cnblogs.com/huaxingtianxia/p/5724093.html

  9. mysql5.7如何修改密码以及密码如何忘记无密码登陆

    今天买了一台阿里云服务器,Centos7.3系统,环境是LAMP.学生价9.8元是真的很实惠了.然后想修改一下mysql服务器的密码(mysql版本5.7),结果操作失误,密码给忘记了,导致新旧密码都 ...

  10. 设计 MySQL 数据表的时候一般都有一列为自增 ID,这样设计原因是什么,有什么好处?

    知乎采集: MyISAM/InnoDB默认用B-Tree索引(可理解为"排好序的快速查找结构"). InnoDB中,主索引文件上直接存放该行数据,称为聚簇索引.次索引指向对主键的引 ...