第六节:mybatis小技巧

本节主要讲解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,‘[email protected]‘,‘beijing‘);

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

insert into person(first_name,last_name,age,email,address) VALUES(‘Schmitt‘, ‘Carine‘,25,null,‘beijing‘),(‘King‘, ‘Jean‘,36,‘[email protected]‘,‘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不能很好表示领域模型,就需要自己再进一步的把它转化为对应的对象,这常常在复杂查询中很有作用。

原文地址:https://www.cnblogs.com/ye-feng-yu/p/11020511.html

时间: 2024-10-29 10:33:57

第六节:mybatis小技巧的相关文章

第二节 MyBatis的技巧优化

MyBatis的技巧优化 2016年3月2日 星期三 09:13 ?配置日志文件 ?练习 作业: 请分别查询 姓为林的数据  LIKE 3种 Select * from sys_user where user_name like '林%' 关于结果集合多个参数传递数据 特殊字符的处理 核心配置文件,加载jdbc.properties的属性文件 封装工具类

HDU 5895 Mathematician QSC(矩阵乘法+循环节降幂+除法取模小技巧+快速幂)

传送门:HDU 5895 Mathematician QSC 这是一篇很好的题解,我想讲的他基本都讲了http://blog.csdn.net/queuelovestack/article/details/52577212 [分析]一开始想简单了,对于a^x mod p这种形式的直接用欧拉定理的数论定理降幂了 结果可想而知,肯定错,因为题目并没有保证gcd(x,s+1)=1,而欧拉定理的数论定理是明确规定的 所以得另谋出路 那么网上提供了一种指数循环节降幂的方法 具体证明可以自行从网上找一找 有

Chrome 开发者工具的六个小技巧

下面是特邀Umar Hansa做的一篇文章.Umar有一个新闻组,我是他的粉丝,他很亲切地应我们要求把这篇约稿写成了新闻组的形式.我将让他介绍一下他自己. 嘿,我是Umar.我喜欢在Twitter(@umaar)上分享web开发相关的小技巧,同时也喜欢通过Dev Tips以gif的形式分享开发的小技巧.Dev Tips是开发者的一个新闻组.现在,它主要是Chrome开发工具相关的内容.开始之前,感谢CSS-Tricks给我机会为自己喜欢的一个组织做点贡献. 这篇文章将涵盖Chrome开发工具的六

思科命令配置小技巧六:default inter

在配置命令,特别是做实验的时候,经常在一个接口下配置了大量的命令 而在做另外一个实验的时候,又要清除接口的大部分或者全部配置 suzhouxiaoniu#show run inter s1/1Building configuration... Current configuration : 242 bytes!interface Serial1/1 description suzhouxiaoniu bandwidth 512 ip address 8.8.8.8 255.255.255.0 e

关于导航栏的六个小技巧

UINavigationBar和UINavigationItem是iOS开发中常用的控件.今天给大家介绍一下六个关于导航栏的小技巧. 1.设置导航栏标题 self.title = @"iOS开发:iOSDevTip"; 2.设置导航栏样式 设置方法: [self.navigationController.navigationBar setBarStyle:UIBarStyleBlack]; UIBarStyle的样式: typedef NS_ENUM(NSInteger, UIBarS

第八十四节,css布局小技巧

css布局小技巧 图片鼠标放上去遮罩效果,显示文字 当鼠标放上去时 /*最外层div*/ .a{ width: 384px; height: 240px; background-color: #ff4e37; position: relative; } /*插入图片的div*/ .b{ width: 384px; height: 240px; background-color: #ff4e37; overflow: hidden; } /*遮罩层div*/ .c{ width: 384px; h

css学习の第六弹—样式设置小技巧

一.css样式设置小技巧>>1.行内元素水平居中是通过给父元素设置 text-align:center 来实现的.html代码:<body> <div class="txtCenter">我想要在父容器中水平居中显示.</div></body> css代码:<style> .txtCenter{ text-align:center; }</style>>>2.块状元素(定宽)通过设置&quo

205. jetcache:你需要知道的小技巧

[视频&交流平台] àSpringBoot视频:http://t.cn/R3QepWG à SpringCloud视频:http://t.cn/R3QeRZc à Spring Boot源码:https://gitee.com/happyangellxq520/spring-boot à Spring Boot交流平台:http://412887952-qq-com.iteye.com/blog/2321532 à Spring Boot Shiro视频:http://t.cn/R3QDMbh

移动端样式小技巧

平时在移动端开发拼页面的过程中总会遇到一些问题,主要是各手机webview样式显示效果不一致造成的.以下总结了一些常见坑和一些小技巧,希望对看官有所帮助! 本文只针对两大手机阵营 Android和IOS 中的魅蓝metal 和 iPhone6进行样式对比. 一.line-height line-height经常用于文字居中,当然也有小伙伴会用上下padding去写.but!不管你用padding还是line-height,不同手机显示效果还是-不一样. 一般会这样写 .demo{ height: