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

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

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

1、foreach


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

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

public interface PersonMapper
{
List<Person> getPersons(List<Integer> ids);
}

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

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

属性解释:

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

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

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

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

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

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

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

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

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语句:

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

foreach的用途二:批量插入

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

比如下面的两条插入语句

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

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

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接口:

public interface PersonMapper
{
Integer insertPersons(List<Person> personList);
}

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

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

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

2、批量插入


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

public interface PersonMapper
{
Integer insertPerson(Person person);
}

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

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

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

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

3、模糊查询like的写法


public interface PersonMapper
{
List<Person> getPersons(String lastName);
}

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

select * from person where last_name like %tom%

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

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

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

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

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

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

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

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


1、作用

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

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

2、区别

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

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

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

3、为什么要使用$?

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

select * from ${year}_salary where xxx; 

select * from person order by ${lastName}

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


1、在sql中使用别名

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字段映射规则来解决映射问题。在全局配置文件加入:

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

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

3、使用resultMap标签

<!--自定义某个javaBean的封装规则
type:自定义规则的Java类型
id:唯一id方便引用
-->
<resultMap id="person" type="com.yefengyu.mybatis.entity.Person">
<!-- 指定主键列的封装规则
id定义主键会底层有优化;
column:指定哪一列
property:指定对应的javaBean属性
-->
<id column="id" property="id"/> <!-- 定义普通列封装规则 -->
<result column="first_name" property="firstName"/>
<result column="last_name" property="lastName"/> <!-- 其他不指定的列会自动封装:我们只要写resultMap就最好把全部的映射规则都写上。 -->
<result column="age" property="age"/>
<result column="email" property="email"/>
<result column="address" property="address"/>
</resultMap> <!-- resultMap:自定义结果集映射规则; -->
<select id="getPersons" resultMap="person">
select * from person where id = #{id}
</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. python 字符编码问题总结

    都是计算机存储是二进制0101之类的数字 最早计算机在美国开始的 所以数字和英文之类的占用八位 2的8次方 256可以存储对于英文和数字戳戳有余  每个国家都有自己的编码 中国 gb2312 gbk ...

  2. JS :Date日期格式化

    Date.prototype.format = function (formatStr) { var date = this; /* 函数:填充0字符 参数:value-需要填充的字符串, lengt ...

  3. JS继承——原型链

    许多OO语言支持两种继承:接口继承和实现继承.ECMAScript只支持实现继承,且继承实现主要依赖原型链实现. 原型链 基本思想:利用原型让一个引用类型继承另一个引用类型的属性和方法. 构造函数.原 ...

  4. tensorflow创建cnn网络进行中文手写文字识别

    数据集下载地址:http://www.nlpr.ia.ac.cn/databases/handwriting/download.html chinese_write_detection.py # -* ...

  5. 20180315-Python面向对象编程设计和开发

    1.在子类中调用父类的方法 在子类派生出的新方法中,往往需要重用父类的方法,我们有两种实现方式: 方式一:父类名.父类方法() Animal.__init__(self,name) 方式二:super ...

  6. 203-基于ARM和双TI DSP TMS320C6678的6UCPCI高清编解码处理平台

    基于ARM和双TI DSP TMS320C6678的6UCPCI高清编解码处理平台 1.产品简介 该板卡由我公司自主研发,以TI Cortex-A8.TI 双DSP TMS320C6678为设计核心, ...

  7. 12-低延迟、全接口(HMDI、DVI、YPb Pr、RGB)H.264全高清编码器解码器

    低延迟.全接口(HMDI.DVI.YPb Pr.RGB)H.264全高清编码器解码器 一.产品介绍  1.近零延时的H.264压缩到1920x1080p60  该产品提供分辨率为1920x1080p6 ...

  8. BZOJ 4034 树链剖分

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4034 题意:中文题面 思路:树链剖分入门题. 剖分后就是一个简单的区间更新和区间求和问题. ...

  9. 线程安全与非线程安全集合说一下,底层怎么实现的(hashmap,concurrenthashmap)

    Hashmap本质是数组加链表.根据key取得hash值,然后计算出数组下标,如果多个key对应到同一个下标,就用链表串起来,新插入的在前面. ConcurrentHashMap:在hashMap的基 ...

  10. Flutter-Text

    text的主要属性有:textAlign,maxLines,overflow等. Text( "hello flutter!", TextAlign:TextAlign.cente ...