前面三篇博客我们已经多次涉及到映射器的使用了,增删查基本上都用过一遍了,但是之前我们只是介绍了基本用法,实际上mybatis中映射器可以配置的地方还是非常多,今天我们就先来看看映射器还有哪些需要配置的地方,用好这些配置,可以让我们的mybatis变得非常灵活。如果小伙伴对于mybatis尚不了解可以先参考前面三篇博客(初识mybatis/初识mybatis(二)/mybatis常用配置)否则小伙伴可能不太容易理解本文的内容,老司机请略过。

映射器中的元素还是非常多的,比如select、insert、update、delete、parameterMap、sql、resultMap、cache、cache-ref等,本文我们先来说其中比较重要,也是非常常用的几个元素。

select中字段的映射问题

select元素用来执行一条查询语句,Select可以算作是最常用,最复杂的元素之一,我们在使用Select的时候可以自定义元素自定义结果集等,非常灵活,OK,在说Select强大的一面之前,我们先来看看我们在前面几篇博客中是怎么使用Select的:

<select id="getUser" resultType="user" parameterType="Long">
        select * from user where id = #{id}
    </select>

我们直接从user表中查询一条数据出来,查询的结果是一个user对象,即mybatis会自动帮我们把查询的结果转为一个user对象,那么mybatis在转化的过程中怎么知道数据库的哪个字段对应JavaBean中的哪个属性呢?很简单,只要两者的名称一样,系统就能就能自动识别出来,我们在前面博客中在数据库中创建的user表的字段分别为id,username,password,address这四个,实体类的属性也是这四个一模一样,所以系统会自动将查询结果给我们转为User对象,那么在实际开发中,JavaBean中的属性命名我们习惯于驼峰命名法,在数据库中我们更常用下划线命名法,比如我现在创建一个新的实体类User:

public class User {
    private Long id;
    private String userName;
    private String password;
    private String address;
    //省略getter/setter
}

然后创建一个user表,如下:



小伙伴们注意这个表中有一个字段和实体类的属性名称不一样,就是数据库的user_name字段对应了实体类的userName属性,这样的话,在Select查询结果中,mybatis就没法帮我们自动将查询结果转为user对象了。对于这种非常常见的需求,我们有三种不同的解决方案,分别如下:

使用SQL语句中的别名功能

我们可以在查询的时候自动将相关的列名进行修改,如下:

<select id="getUser" resultType="u" parameterType="Long">
        select id,user_name as userName,password,address from user2 where id = #{id}
    </select>

使用SQL语句中的别名功能,这样查询的结果实际又变为了id、userName、password、address这样几个字段,这样mybatis就知道哪个字段对应哪个属性了,就能成功转化了。

使用mapUnderscoreToCamelCase属性

在mybatis的配置文件中,有一个settings节点,该节点中都是setting节点,setting节点有一个属性叫做mapUnderscoreToCamelCase,该属性表示是否开启自动驼峰命名规则映射,即从经典的数据库列名A_COLUMN到经典Java属性名aColumn的映射,这种方式要求我们的数据库字段命名和JavaBean属性命名都要非常规范才能实现。这个属性的开启也是非常容易的,在mybatis的配置文件中,我这里实在mybatis-conf.xml文件中,添加如下代码即可 :

<settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

开启了这个之后,在Select节点中我们就不需要使用别名这种方式了,直接像下面这样写就行了,如下:

<select id="getUser" resultType="u" parameterType="Long">
        select * from user2 where id = #{id}
    </select>

OK,其实只要我们在开发中遵守命名规范,这个问题其实很好解决的。

使用resultMap来解决

resultMap算是这个问题的一个终极解决方案了,当然resultMap的意义不局限于此,我们这里先说resultMap的这个功能,resultMap可以用来描述从数据库结果集中来加载对象,有的时候映射过于复杂,我们可以在Mapper中定义resultMap来解决映射问题,比如还是上面那个问题,我可以在userMapper中这样来定义一个resultMap:

<resultMap id="userMap" type="org.sang.bean.User">
        <id property="id" column="id" javaType="long" jdbcType="NUMERIC"/>
        <result property="userName" column="user_name" javaType="string" jdbcType="VARCHAR"/>
        <result property="password" column="password" javaType="string" jdbcType="VARCHAR"/>
        <result property="address" column="address" javaType="string" jdbcType="VARCHAR"/>
    </resultMap>

关于这个resultMap,我说如下几点:

1.首先我们给resultMap去了一个id,这个id是resultMap的唯一标识符,我们在后面引用这个resultMap的时候就是通过这个id来引用,然后还定义了type属性,type属性指明了这个resultMap它对应的是哪个JavaBean。

2.在resultMap节点中,id表示哪个字段代表这主键,result节点定义了普通的映射关系,这里的property表示JavaBean中的属性名称,column表示数据库中的字段名称,javaType代表JavaBean中该属性的类型,jdbcType则表示数据库中该字段的类型,

OK ,如此定义之后,我们只需要在select查询的时候指定resultMap即可,如下:

<select id="getUser" resultMap="userMap" parameterType="Long">
        select * from user2 where id = #{id}
    </select>

select多条件查询

之前我们举的几个例子查询的时候都是只有一个查询条件,真正开发中多条件查询也是非常常见的需求,对于多条件查询mybatis也给我们提供了相应的方式,我们来看一下:

使用Map集合传递参数

我们可以将参数装入Map集合中传入,使用Map集合传递参数的话需要我在UserMapper接口中定义方法的时候参数就先设置为Map,如下:

public ArrayList<User> getUserByAddressAndName2(Map<String,String> map);

然后在userMapper.xml中将map中的数据提取出来:

<select id="getUserByAddressAndName2" resultMap="userMap">
        SELECT * FROM user2 WHERE address=#{address} AND user_name LIKE concat(#{username},'%')
    </select>

提取的方式还是通过#{XXX},只不过这里XXX代表map中数据的key。然后在使用的时候组装map集合数据,如下:

    @Test
    public void test3() {
        SqlSession sqlSession = null;
        try {
            sqlSession = DBUtils.openSqlSession();
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            Map<String, String> map = new HashMap<String, String>();
            map.put("address", "长沙");
            map.put("username", "赵");
            List<User> list = userMapper.getUserByAddressAndName2(map);
            for (User user : list) {
                System.out.println(user);
            }
            sqlSession.commit();
        } catch (Exception e) {
            e.printStackTrace();
            sqlSession.rollback();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }

    }

构造map传入即可,但是在开发中一般我们不推荐这种方式,因为key容易写错,这种方式也不直观,采用较多的还是后面两种方式。

使用@Param注解

@Param注解可以把问题进一步简化,如下,首先在UserMapper这个接口中定义相关的方法:

public List<User> getUserByAddressAndName(@Param("username") String username, @Param("address") String address);

在数据提交的过程中,mybatis会以@Param提供的名称为准,如此,我们在userMapper.xml中可以这样来定义(注意我们我们不再需要指定参数类型):

<select id="getUserByAddressAndName" resultMap="userMap">
        SELECT * FROM user2 WHERE address=#{address} AND user_name LIKE concat(#{username},'%')
    </select>

这样的话参数的传递就更直观一些,使用方式如下:

@Test
    public void test2() {
        SqlSession sqlSession = null;
        try {
            sqlSession = DBUtils.openSqlSession();
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            List<User> list = userMapper.getUserByAddressAndName("赵", "长沙");
            for (User user : list) {
                System.out.println(user);
            }
            sqlSession.commit();
        } catch (Exception e) {
            e.printStackTrace();
            sqlSession.rollback();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }

    }

这种方式是我们推荐的一种方式,参数传递很直观,不必像map那样还要去考虑key到底是什么。

使用JavaBean

第二种方式按说已经很完美了,但是还有一种情况就是如果参数特别多的话,这样写起来也是非常麻烦的一件事,所以mybatis支持我们在传参的时候可以直接传入对象,传入对象的话需要我们先创建对象类,如下:

public class UserParams {
    private String username;
    private String address;

    //省略getter/setter
}

然后在UserMapper中定义方法,如下:

public ArrayList<User> getUserByAddressAndName3(UserParams params);

最后在userMapper.xml文件中我们直接设置parameterType为UserParams,然后引用UserParams中的属性即可,如下:

<select id="getUserByAddressAndName3" resultMap="userMap" parameterType="org.sang.bean.UserParams">
        SELECT * FROM user2 WHERE address=#{address} AND user_name LIKE concat(#{username},'%')
    </select>

使用方式如下:

    @Test
    public void test6() {
        SqlSession sqlSession = null;
        try {
            sqlSession = DBUtils.openSqlSession();
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            UserParams userParams = new UserParams("赵", "长沙");
            List<User> list = userMapper.getUserByAddressAndName3(userParams);
            for (User user : list) {
                System.out.println(user);
            }
            sqlSession.commit();
        } catch (Exception e) {
            e.printStackTrace();
            sqlSession.rollback();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }

    }

第二种和第三种是我们在开发中常用的传参方式,小伙伴们在开发中根据实际情况选择合适的方式即可。

insert中的主键回填

可能有小伙伴不理解什么是主键回填,我这里简单解释下,比如我们在创建表的时候设置了表的id为自增长字段,我在Java代码中存储一条数据时先构建了一个JavaBean,这个JavaBean的id属性是为null,因为id不需要插入到数据库中去 ,那么当我将数据插入成功之后系统会自动给该对象的id属性赋值,值为刚刚插入那条数据的id,这就称作主键回填。这个在我们开发中也是非常常见的需求,我可能希望知道刚刚插入成功的数据的id是多少,而很多时候id可能都是按照某种既定规则去生成,我们在插入之前并不知晓,这种时候就可以使用主键回填。实际上想配置主键回填很简单,我们先来看看UserMapper中的方法:

public int insertUser(User user);

这个方法就是普普通通的UserMapper中的方法,再来看看userMapper.xml中是怎么定义的:

<insert id="insertUser" parameterType="u" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO user2(user_name,password,address) VALUES (#{userName},#{password},#{address})
    </insert>

这个里边比我们在初识mybatis(二)这篇博客中介绍的insert节点多了一点东西,其实就多了两个东西,首先keyProperty属性指定了哪个是主键字段,useGeneratedKeys的含义则是告诉mybatis这个主键是否使用数据库内置的策略生成,OK,这样写了之后,我们再向数据库插入一条数据,如下:

    @Test
    public void test7() {
        SqlSession sqlSession = null;
        try {
            sqlSession = DBUtils.openSqlSession();
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            User user = new User(null, "奥巴牛", "123456", "米国");
            int i = userMapper.insertUser(user);
            System.out.println("i:"+i+";id:"+user.getId());
            sqlSession.commit();
        } catch (Exception e) {
            e.printStackTrace();
            sqlSession.rollback();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }

    }

注意,这里的i表示受影响的行数,在这里就是插入的行数,我们在构造User对象的时候id是为null,数据插入成功之后再来打印id属性,我们来看看结果:



插入成功之后mybatis已经给id属性赋值了,值即为刚刚插入数据。当然这种我们是按照数据库的规则自动生成id,有的时候生成id的规则需要我们自定义,当然,mybatis也给我们提供了相应的方式。

insert中主键自定义

假设有这样一种需求,当我往数据库中插入一条数据的时候,如果此时表为空,则这条数据的id我设置为1,如果表不为空,那我找到表中最大的id,然后给其加2作为即将添加数据的id,这种也算是较常见的需求,我们来看看怎么实现吧。

先在UserMapper中定义相关方法:

public int insertUser2(User user);

这个方法很普通,没啥特殊的地方,然后在userMapper.xml中定义insert节点,如下:

<insert id="insertUser2" parameterType="u" useGeneratedKeys="true" keyProperty="id">
      <selectKey keyProperty="id" resultType="long" order="BEFORE">
          SELECT if(max(id) is null,1,max(id)+2) as newId FROM user3
      </selectKey>
        INSERT INTO user3(id,user_name,password,address) VALUES (#{id},#{userName},#{password},#{address})
    </insert>

这里我们使用了selectKey来进行了简单的处理。selectKey中的keyProperty属性表示selectKey中的sql语句的查询结果应该被设置的目标属性,我们这里当然是要设置为id了,然后我在下文好使用这个id,selectKey的resultType属性表示查询结果的返回类型,注意这个类型要和User类中id的类型一致,selectKey中的order=”BEFORE”表示在插入操作之前选择主键,order的另一个取值AFTER表示执行完插入操作之后再选择主键,关于这一块小伙伴可以参考这篇博客Mybatis 示例之 SelectKey。OK,最后我们来看看调用:

    @Test
    public void test8() {
        SqlSession sqlSession = null;
        try {
            sqlSession = DBUtils.openSqlSession();
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            User user = new User(null, "米歇尔", "222222", "米国");
            int i = userMapper.insertUser2(user);
            System.out.println("i:"+i+";id:"+user.getId());
            sqlSession.commit();
        } catch (Exception e) {
            e.printStackTrace();
            sqlSession.rollback();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }

    }

OK,以上就是select和insert的一些配置细则,剩下的update和delete和这两个差不多,我就不再赘述。

本文案例下载:

本文案例GitHub地址https://github.com/lenve/JavaEETest/tree/master/Test27-mybatis5

以上。

参考资料:

1.Mybatis 示例之 SelectKey

2.《深入浅出MyBatis 技术原理与实战 》第四章

mybatis映射器配置细则的更多相关文章

  1. mybatis中resultMap配置细则

    resultMap算是mybatis映射器中最复杂的一个节点了,能够配置的属性较多,我们在mybatis映射器配置细则这篇博客中已经简单介绍过resultMap的配置了,当时我们介绍了resultMa ...

  2. Mybatis映射器接口代理对象的方式 运行过程

    查询一张表的所有数据. 环境: 使用工具IntelliJ IDEA 2018.2版本. 创建Maven工程不用骨架 1.pom.xml <?xml version="1.0" ...

  3. Mybatis 映射器接口实现类的方式 运行过程debug分析

    查询一张表的所有数据. 环境: 使用工具IntelliJ IDEA 2018.2版本. 创建Maven工程不用骨架 <?xml version="1.0" encoding= ...

  4. MyBatis映射器(转载)

    什么是MyBatis映射器? MyBatis框架包括两种类型的XML文件,一类是配置文件,即mybatis-config.xml,另外一类是映射文件,例如XXXMapper.xml等.在MyBatis ...

  5. MyBatis映射器(一)--多参数传递方式

    在mybatis映射器的接口中,一般在查询时需要传递一些参数作为查询条件,有时候是一个,有时候是多个.当只有一个参数时,我们只要在sql中使用接口中的参数名称即可,但是如果是多个呢,就不能直接用参数名 ...

  6. MyBatis映射器元素

     映射器是MyBatis最强大的工具,也是我们使用MyBatis时用的最多的工具,映射器中主要有增删改查四大元素,来满足不同场景的需要: 下面是主要元素的介绍:         select:查询语句 ...

  7. mybatis 映射器(mappers) 配置说明 加载映射文件方式

    映射器(mappers) 既然 MyBatis 的行为已经由上述元素配置完了,我们现在就要定义 SQL 映射语句了.但是首先我们需要告诉 MyBatis 到哪里去找到这些语句. Java 在自动查找这 ...

  8. mybatis 映射器

    1 映射器 Mapper 是由java接口和 XML 文件共同组成.它的作用如下 1)定义参数类型 2)描述缓存 3)描述 SQL 语句 4)定义查询结果和POJO的映射关系 2 SqlSession ...

  9. 【长文】Spring学习笔记(七):Mybatis映射器+动态SQL

    1 概述 本文主要讲述了如何使用MyBatis中的映射器以及动态SQL的配置. 2 MyBatis配置文件概览 MyBatis配置文件主要属性如下: <settings>:相关设置,键值对 ...

随机推荐

  1. HTML的各种基本标签

      一 .head中的各种标签                1.       <!DOCTYPE html><html>文档类型声明   声明当前文件是一个HTML5文件文档 ...

  2. JDK安装、变量、变量的分类

    Lesson One 2018-04-17  19:50:35 JAVA语言特点: 编译型.强类型语言. 纯面向对象的语言,所有的代码都必须包含在class中的方法中 配置JAVA环境变量 1.安装J ...

  3. git中的merge与rebase

    之前一直对git的merge与rebase很困惑,而且一般也只使用merge而不是使用rebase.今天受高人指点理清了两者的区别. 首先对于两者而言,他们的结果是一样的,差异在于合并的方式(产生的结 ...

  4. jQuery中的事件监听小记

    一,一个事件监听的简便写法 最近发现一个jQuery中事件监听的简洁写法,感觉方便好多.同时也深感自己基础薄弱,好多东西竟然都模棱两可.因此,记录的同时,也对jQuery事件监听做个小的总结 原文链接 ...

  5. java面试3-对于java中值传递的理解(Hollis)

    这是根据Hollis的直面java内容习得(有兴趣的可以加他微信公众号) 对于初学者来说,要理解java中的值传递很难理解,为什么说java只有值传递?那引用传递呢? java中的错误理解: 错误理解 ...

  6. python3+dlib人脸识别及情绪分析

    一.介绍 我想做的是基于人脸识别的表情(情绪)分析.看到网上也是有很多的开源库提供使用,为开发提供了很大的方便.我选择目前用的比较多的dlib库进行人脸识别与特征标定.使用python也缩短了开发周期 ...

  7. 有效防止softmax计算时上溢出(overflow)和下溢出(underflow)的方法

    <Deep Learning>(Ian Goodfellow & Yoshua Bengio & Aaron Courville)第四章「数值计算」中,谈到了上溢出(ove ...

  8. Mac 下升级 vim 并自己配置 vim 的过程

    1.升级 vim 我自己 MacBook Pro 的系统还是 10.11 ,其自带的 vim 版本为 7.3 ,我们将其升至最新版: 使用 homebrew : brew install vim -- ...

  9. [ZJOI 2012]灾难

    Description 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的生态灾难. 学过生 ...

  10. [USACO08JAN]haybale猜测Haybale Guessing

    题目描述 The cows, who always have an inferiority complex about their intelligence, have a new guessing ...