本节主要讲解mybatis如下五个方面的内容:

  • foreach
  • 批量插入
  • 模糊查询like的写法
  • #{}和${}的区别
  • 解决实体类中的属性名和表中的字段名不一致问题

由于每次建立工程比较复杂,可以参考第一节:mybatis入门来搭建一个简单的工程,然后来测试本节内容。

1、foreach


foreach是一个动态sql标签,主要解决mapper接口方法的参数是集合数组时如何进行操作。比如根据传入的多个id进行查询,那么sql一般使用 in 关键字,但是多个id如何拼装成一条完整的sql语句?这就需要foreach来解决。

foreach的用途一:拼接in关键字后面的列表。 下面是mapper接口

  1. public interface PersonMapper
  2. {
  3. List<Person> getPersons(List<Integer> ids);
  4. }

下面是mapper接口的映射文件:

  1. <select id="getPersons" resultType="com.yefengyu.mybatis.entity.Person">
  2. select id, first_name firstName, last_name lastName, age, email, address from person where id in
  3. <foreach collection="list" item="result" index="index" open="(" close=")" separator=",">
  4. #{result}
  5. </foreach>
  6. </select>

属性解释:

collection:指定要遍历的集合: list类型的参数会特殊处理封装在map中,map的key就叫list

item:将当前遍历出的元素赋值给指定的变量

separator:每个元素之间的分隔符

open:遍历出所有结果拼接一个开始的字符

close:遍历出所有结果拼接一个结束的字符

index:索引 遍历list的时候index就是索引,item就是当前值;遍历map的时候index表示的就是map的key,item就是map的值

#{变量名}就能取出变量的值也就是当前遍历出的元素

从上面的属性解释可以看出:select标签中,首先是如下sql语句:

  1. select id, first_name firstName, last_name lastName, age, email, address from person where id in

假如我们调用List<Person> getPersons(List<Integer> ids)方法,传入的参数是【1,2】,那么foreach的功能就类似于:

先拼接一个 (     开始符open

再拼接一个  1     foreach循环取list的第一个元素

再拼接一个  ,    separator指定每个list里面每个元素的分隔符

再拼接一个  2     foreach循环取list的第二个元素

最后拼接一个)    结束符close

那么最终拼接字符串为 (1,2),加上foreach外部的sql片段,合成一条完整的sql语句:

  1. select id, first_name firstName, last_name lastName, age, email, address from person where id in (1,2)

foreach的用途二:批量插入

mysql数据库的多条数据可以在一条insert语句中执行,以减少和数据库的交互:

比如下面的两条插入语句

  1. insert into person(first_name,last_name,age,email,address) VALUES('Schmitt', 'Carine',25,null,'beijing');
  2. insert into person(first_name,last_name,age,email,address) VALUES('King', 'Jean',36,'Jean@163.com','beijing');

可以合成一条,使用逗号分隔

  1. insert into person(first_name,last_name,age,email,address) VALUES('Schmitt', 'Carine',25,null,'beijing'),('King', 'Jean',36,'Jean@163.com','beijing');

因此我们使用foreach完成类似的功能。

编写一个mapper接口:

  1. public interface PersonMapper
  2. {
  3. Integer insertPersons(List<Person> personList);
  4. }

编写对应的mapper映射文件,每一个循环体内使用括号括起来,每个括号使用逗号分隔,无需open和close.

  1. <insert id="insertPersons">
  2. insert into person(first_name,last_name,age,email,address) VALUES
  3. <foreach collection="list" item="person" separator=",">
  4. (#{person.firstName},#{person.lastName},#{person.age},#{person.email},#{person.address})
  5. </foreach>
  6. </insert>

此处实现了一种批量插入的功能,但是拼接sql,如果数据太长,某些数据库可能对sql语句的长度有限制。在一次只插入少量数据的情况下可以考虑这个方法。另外mybatis还有另一种批量插入的方式。

2、批量插入


这种插入和上面的不同,首先在接口方面,上面的接口直接传入一个list,而下面的方式中,一般只需要单个插入的接口:

  1. public interface PersonMapper
  2. {
  3. Integer insertPerson(Person person);
  4. }

单条数据插入的相关mapper映射文件就不必再展示。下面主要关注如何编写批量插入的代码:

  1. public static void main(String[] args)
  2. throws IOException
  3. {
  4. InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
  5. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
  6. //注意此处使用ExecutorType.BATCH进行批量插入
  7. SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
  8. try
  9. {
  10. PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
  11. for (int i = 0; i < 1000; i++)
  12. {
  13. mapper.insertPerson(new Person());//此处是真正插入的对象,只做展示,没有构造真实数据
  14. }
  15. sqlSession.commit();
  16. }
  17. finally
  18. {
  19. sqlSession.close();
  20. }
  21. }

批量插入的时候,在构造SqlSession的时候,使用ExecutorType.BATCH指定插入的模式。

总结:上面两种插入方式,使用foreach的时候,需要注意每次插入20-50条为好,一次性插入数据过多反而性能下降的比较厉害。使用BATCH插入,则一般不用关注这个问题,但是在插入的时候,最好也要关注for循环的次数,找出插入性能最好的循环次数。

3、模糊查询like的写法


  1. public interface PersonMapper
  2. {
  3. List<Person> getPersons(String lastName);
  4. }

我们使用lastName进行模糊匹配,一般sql查询中使用like的方式如下:

  1. select * from person where last_name like %tom%

在mapper映射文件中应该如何写呢?有两种方式:

1、直接拼接字符串:"%"#{person.lastName}"%"

  1. <select id="getPersons" resultType="com.yefengyu.mybatis.entity.Person">
  2. select id, first_name firstName, last_name lastName, age, email, address from person where last_name like "%"#{last_name}"%"
  3. </select>

注意:百分号要用双引号引起来,而不能使用单引号。

2、使用字符串拼接函数拼接:concat('%',#{lastName},'%')

  1. <select id="getPersons" resultType="com.yefengyu.mybatis.entity.Person">
  2. select id, first_name firstName, last_name lastName, age, email, address from person where last_name like concat('%',#{lastName},'%')
  3. </select>

注意:百分号要用双引号引起来,也可以使用单引号。

4、#{}和${}的区别


1、作用

#{}:可以获取map中的值或者pojo对象属性的值;

${}:可以获取map中的值或者pojo对象属性的值;

2、区别

#{}:是以预编译的形式,将参数设置到sql语句中的参数位置;PreparedStatement;防止sql注入

${}:取出的值直接拼装在sql语句中的任意位置;会有安全问题;

大多情况下,我们去参数的值都应该去使用#{};

3、为什么要使用$?

原生jdbc不支持占位符的地方我们就可以使用${}进行取值 ,比如分表、排序等。

  1. select * from ${year}_salary where xxx;
  2.  
  3. select * from person order by ${lastName}

5、解决实体类中的属性名和表中的字段名不一致问题


1、在sql中使用别名

  1. select id, first_name firstName, last_name lastName, age, email, address from person where id = #{id}

将数据库表的first_name映射为firstName,last_name映射为lastName,可以参考第一节:mybatis入门

2、如果数据库是使用下划线规则命名表字段,而实体是驼峰命名法,那么可以使用开启mybatis字段映射规则来解决映射问题。在全局配置文件加入:

  1. <settings>
  2. <setting name="mapUnderscoreToCamelCase" value="true"/>
  3. </settings>

mapUnderscoreToCamelCase:是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射,默认false。

3、使用resultMap标签

  1. <!--自定义某个javaBean的封装规则
  2. type:自定义规则的Java类型
  3. id:唯一id方便引用
  4. -->
  5. <resultMap id="person" type="com.yefengyu.mybatis.entity.Person">
  6. <!-- 指定主键列的封装规则
  7. id定义主键会底层有优化;
  8. column:指定哪一列
  9. property:指定对应的javaBean属性
  10. -->
  11. <id column="id" property="id"/>
  12.  
  13. <!-- 定义普通列封装规则 -->
  14. <result column="first_name" property="firstName"/>
  15. <result column="last_name" property="lastName"/>
  16.  
  17. <!-- 其他不指定的列会自动封装:我们只要写resultMap就最好把全部的映射规则都写上。 -->
  18. <result column="age" property="age"/>
  19. <result column="email" property="email"/>
  20. <result column="address" property="address"/>
  21. </resultMap>
  22.  
  23. <!-- resultMap:自定义结果集映射规则; -->
  24. <select id="getPersons" resultMap="person">
  25. select * from person where id = #{id}
  26. </select>

上面的映射文件中首先定义一个resultMap,然后在select中通过id来引用。resultMap主要把数据库的列和javaBean的属性对应上。现在只是展示result的简单映射功能,其实它还有更多高级功能,后面继续研究。

MyBatis中关于resultType和resultMap的区别:

MyBatis中在查询进行select映射的时候,返回类型可以用resultType,也可以用resultMap,resultType是直接表示返回类型的(对应着我们的model对象中的实体),而resultMap则是对外部ResultMap的引用(提前定义了db和model之间的隐射key-->value关系),但是resultType跟resultMap不能同时存在。在MyBatis进行查询映射时,其实查询出来的每一个属性都是放在一个对应的Map里面的,其中键是属性名,值则是其对应的值。
    1、当提供的返回类型属性是resultType时,MyBatis会将Map里面的键值对取出赋给resultType所指定的对象对应的属性。所以其实MyBatis的每一个查询映射的返回类型都是ResultMap,只是当提供的返回类型属性是resultType的时候,MyBatis对自动的给把对应的值赋给resultType所指定对象的属性。
    2、当提供的返回类型是resultMap时,因为Map不能很好表示领域模型,就需要自己再进一步的把它转化为对应的对象,这常常在复杂查询中很有作用。

mybatis小技巧的更多相关文章

  1. Java代码优化的30个小技巧

    前言 我之前写过两篇关于优化相关的问题:<聊聊sql优化的15个小技巧>和<聊聊接口性能优化的11个小技巧>,发表之后,在全网受到广大网友的好评.阅读量和点赞率都很高,说明了这 ...

  2. 前端网络、JavaScript优化以及开发小技巧

    一.网络优化 YSlow有23条规则,中文可以参考这里.这几十条规则最主要是在做消除或减少不必要的网络延迟,将需要传输的数据压缩至最少. 1)合并压缩CSS.JavaScript.图片,静态资源CDN ...

  3. Git小技巧 - 指令别名及使用Beyond Compare作为差异比较工具

    前言 本文主要写给使用命令行来操作Git的用户,用于提高Git使用的效率.至于使用命令还是GUI(Tortoise Git或VS的Git插件)就不在此讨论了,大家根据自己的的喜好选择就好.我个人是比较 ...

  4. 分享两个BPM配置小技巧

    1.小技巧 流程图修改后发布的话版本号会+1,修改次数多了之后可能会导致版本号很高,这个时候可以将流程导出,然后删除对应的流程包再导入,发布数据模型和流程图之后,版本清零 2.小技巧 有的同事入职后使 ...

  5. linux系统维护时的一些小技巧,包括系统挂载新磁盘的方法!可收藏!

    这里发布一些平时所用到的小技巧,不多,不过会持续更新.... 1.需要将history创建硬链接ln 全盘需要备份硬链接 ln /etc/xxx /home/xxx 2.root用户不可以远程 /et ...

  6. JS处理事件小技巧

    今天,就分享一下我自己总结的一些JS的小技巧: ①防止鼠标选中事件 <div class="mask" onselectstart="return false&qu ...

  7. iOS:小技巧(不断更新)

    记录下一些不常用技巧,以防忘记,复制用. 1.获取当前的View在Window的frame: UIWindow * window=[[[UIApplication sharedApplication] ...

  8. css小技巧(1)

    1.-webkit-overflow-scrolling: touch; 解决ios滑动时无缓冲问题 2.::-webkit-scrollbar 设置ios滑动时是否显示滚动条 3.::selecti ...

  9. 最强 Android Studio 使用小技巧和快捷键

    写在前面 本文翻译自 Android Studio Tips by Philippe Breault,一共收集了62个 Android Studio 使用小技巧和快捷键. 根据这些小技巧的使用场景,本 ...

随机推荐

  1. 攻防世界--dmd-50

    测试文件:https://adworld.xctf.org.cn/media/task/attachments/7ef7678559ea46cbb535c0b6835f2f4d 1.准备 获取信息 6 ...

  2. 微信小程序(13)--页面滚动到某个位置添加类效果

    微信小程序页面滚动到某个位置添加类,盒子置顶效果. <!-- vh,是指CSS中相对长度单位,表示相对视口高度(Viewport Height),1vh = % * 视口高度 --> &l ...

  3. ajax提交表单包括文件

    <script src="${pageContext.request.contextPath}/assets/js/jquery-1.8.3.js"></scri ...

  4. 非阻塞套接字与IO多路复用(转,python实现版)

    非阻塞:指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回.epoll工作在非阻塞模式时,才会发挥作用. 我们了解了socket之后已经知道,普通套接字实现的服务端的缺陷:一次只能服务一个 ...

  5. 【串线篇】Mybatis之缓存原理

    所谓二级缓存是名称空间级别的缓存,什么意思呢? TeacherDao.xml首行 <mapper namespace="com.atguigu.dao.TeacherDao" ...

  6. cassandra集群

    cassandra是分布式数据库属于nosql,用于处理大量商用服务器上的大量数据,提供高可用性,无单点故障. Cassandra在其节点之间具有对等分布式系统,并且数据分布在集群中的所有节点之间. ...

  7. Java Web 之HttpServletRequest对象初识

    通过request对象获得请求行 获得客户端请求方式:String getMethod(); 获得请求的资源: String getRequestURL(); String getQueryStrin ...

  8. IntelliJ IDEA 代码调式

    Mute Breakpoints: 保留所有断点,但是不执行(程序一次性执行). Condition: 条件触发 即当执行到i的值变为5的时候,在断点处暂停.

  9. Python中使用"subplot"在一张画布上显示多张图

    subplot(arg1, arg2, arg3) arg1: 在垂直方向同时画几张图 arg2: 在水平方向同时画几张图 arg3: 当前命令修改的是第几张图 t = np.arange(0,5,0 ...

  10. Python 递归算法指归

    1. 递归概述 递归( recursion)是一种编程技巧,某些情况下,甚至是无可替代的技巧.递归可以大幅简化代码,看起来非常简洁,但递归设计却非常抽象,不容易掌握.通常,我们都是自上而下的思考问题, ...