MyBatis学习总结(14)——Mybatis使用技巧总结
2019独角兽企业重金招聘Python工程师标准>>>
1、 区分 #{} 和 ${}的不同应用场景
1)#{} 会生成预编译SQL,会正确的处理数据的类型,而${}仅仅是文本替换。
对于SQL: select * from student where xCode = ‘S123456’;
如果使用#{}
那么生成的SQL为:
select * from student where xCode = ? 传的值为’S123456’;
如果使用${}
那么生成的SQL为:select * from student where xCode = S123456
如果xCode的数据类型为varchar,那么使用${}就会报错。
2)${}一般用在order by, limit, group by等场所。
假设我们使用#{} 来指定order by字段,比如
select * from student order by #{xCode},
那么产生的SQL为
select * from student order by ?, 替换值后为
select * from student order by ‘xCode’
Mybatis对xCode加了引号导致排序失败
2、Spring环境用Mybatis-Spring的接口而不是Mybatis的原生接口
在spring 环境使用mybatis-spring的好处有:
1)我们可以使用Sping的声明式事务处理模型(@Transactional),而不用手动回归事务。
2)mybatis-spring会优雅的关闭SqlSession,而不用手动关闭
3)可以将数据库连接池交给spring管理,当程序停止的时候,spring会合适的关闭连接
3、返回Map<ID, Entity>而不是List便于查找
有时太多的表连接(join)性能太差,我们会将该SQL拆为多个SQL,然后在代码中组装起来。比如学生表和班级表,需要查询的结果为”学号,班级,姓名”,我们可以先查询“学号,班级ID,姓名”以及“班级ID,班级名次”,我们可以在查询班级表的时候返回Map<班级ID, 班级>, 然后迭代学生表的结果集,用班级ID到Map<班级ID, 班级>中查找对应的班级信息,然后用班级名称替换班级ID。
接口声明为SqlSession.selectMap(String statement, String mapKey)
4、使用Map封装查询的结果
有时我们厌倦了为每个查询写一个Entity类,这时Map开始发挥它的功效。
对于要返回“学号,班级,姓名”结果的查询,可以这样写Mapper:
1
2
3
4
5
|
<select id="selectStudent">
select s.code as sNo , s.name as sName, c.name as cName
from xStudent s, xClass c
where s.cID = c.ID
</select>
|
如下声明我们的dao方法:
1
2
3
|
public List<Map<String, Object>> selectStudent(Map<String, Object> parameter) {
return getSqlSession().selectList(getStatement("selectStudent"), parameter);
}
|
如果要将该查询结果转为JSON字符串返回,那么我们就可以直接将List<Map<String, Object>转为JSON,逻辑层不需要任何代码。
如果返回的结果集需要按select中的字段顺序返回,那么将resultType=”java.util.HashMap” 换为resultType=”java.util.LinkedHashMap”
5、使用Map封装查询结果时注意数据的类型映射
对于如下的Mapper
1
2
3
4
|
<select id="selectStudent">
select s.code as sNo , concat(s.firstName, s.lastName) as sName
from xStudent s
</select>
|
Mybatis会傻傻的将sName的数据类型映射为byte[], 因为我们没有提供entity,mybatis也不知道我们想要什么类型,而sName是计算出来的值,mybatis也没有办法从数据库中获取字段的值,所以它就将其封装为byte[],解决办法很简单,加一个cast 函数
1
2
3
4
|
<select id="selectStudent">
select s.code as sNo , cast(concat(s.firstName, s.lastName) AS CHAR) as sName
from xStudent s
</select>
|
6、正确的配置Mybatis 的Log
1)一个应用一般会使用很多的jar,各个jar依赖的log 实现不一样,Mybatis查找Log的顺序为(SLF4J,Apache Commons Logging,Log4j 2,Log4j,JDK logging),如果classpath中有slf4j记得添加相应的桥接jar,比如slf4j-log4j。许多web 服务器的classpath 会含有Apache Commons Logging,因此如果要使用Log4j,要么使用SLF4J桥接Log4j,要么在配置中强制指定使用Log4J。
1
2
3
4
5
6
7
|
<configuration>
<settings>
...
<setting name="logImpl" value="LOG4J"/>
...
</settings>
</configuration>
|
7、警惕Mybatis的Foreach的的副作用
对于如下SQL:
假设有如下的mapper:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<select id=”testForeach” parameterType=”map” resultType=”Student”>
Select * from student
<where>
<if test=”ID != null and ID != ‘’ ”>
ID = #{ID}
</if>
<if test=” IDArr != null and IDArr.size()>0”>
And ID IN
<foreach collection="IDArr" open="("
separator="," close=")" item="ID">
${ID}
</foreach>
</if>
</where>
</select>
|
当我们传入的IDArr时,最后产生的SQL为:
Select * from student where ID = ‘998’ AND ID IN ( ‘123’, ’234’,…..,’998’)
解决办法:
解决办法有
1) 将红色的ID 换成别的名称,比如“item”。
2) 这两个if 是对同一个字段判断,改为choose… when 结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<select id=”testForeach” parameterType=”map” resultType=”Student”>
Select * from student
<where>
<choose>
<when test=”ID != null and ID != ‘’ ”>
ID = #{ID}
</when>
<when test=” IDArr != null and IDArr.size()>0”>
And ID IN
<foreach collection="IDArr" open="("
separator="," close=")" item="ID">
${ID}
</foreach>
</when>
</choose>
</where>
|
8、使用原生的SQL操作数据以提高效率
对于一次插入多条数据,将其组装成 insert into xxx values (), () ()格式一次插入多行数据往往能极大的提高性能。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public int execute(String sql) {
int affectedCount = 0;
Connection conn = null;
Statement stm = null;
try {
conn = getSqlSession().getConnection();
stm = conn.createStatement();
stm.execute(sql);
affectedCount = stm.getUpdateCount();
} catch (SQLException e) {
throw new RuntimeException(“execute[" + sql + "] failed”);
} finally {
try{
if(stm != null && !stm.isClosed()) {
stm.close();
}
//conn will be released by mybatis framework
} catch(SQLException e) {
}
}
return affectedCount;
}
|
9、警惕MyBatis封装数据时性能损耗
对于如下的mapper
1
2
3
4
5
6
7
|
<select id="test" resultType="Student">
select s.code, s.firstName,
s.lastName, s.birthDate, s.sex, s.checkIn, s.phoneNumber,
s.classNo
from student
where ...
</select>
|
在一个批处理程序中循环的调用了该方法250次,每次返回大概1w条记录,发现这个程序运行的很慢,用jrofiler 查看各个方法耗费的时间,居然80%的时间花在了student的setter上了,在这个过程中大概产生了250w个对象,而mybatis是利用发射封装Entity,代码大致如下:
1
2
3
4
5
6
|
Class c= Class.forName("cn.javacoder.testmybatis.Student");
Object o = c.newInstance();
for(each colum) {
Method m = c.getMethod("get" + colum);
m.invoke(o, value);
}
|
解决的办法是让返回的行数和返回的字段尽量的少。
转载于:https://my.oschina.net/zhanghaiyang/blog/606146
MyBatis学习总结(14)——Mybatis使用技巧总结相关推荐
- 【最全Mybatis学习笔记(导入mybatis相关jar包)】
目录 1. 什么是Mybatis 2. 如何引入Mybatis? 3.编写Mybatis工具类 4. 万能Map 5. 模糊查询怎么写? 6. 作用域(Scope)和生命周期SqlSessionFac ...
- Mybatis学习第一天——Mybatis的安装配置以及基本CURD操作
1.Mybatis下载 Mybatis是开源的持久层框架,能够度jdbc进行简单的封装,但其并不是完全的ORM(Object Relational Mapping,对象关系映射),无法脱离数据库进行适 ...
- Mybatis学习笔记(一) —— mybatis介绍
一.Mybatis介绍 MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名 ...
- 【MyBatis学习8】MyBatis中的二级缓存
1. 二级缓存的原理 前面介绍了,mybatis中的二级缓存是mapper级别的缓存,值得注意的是,不同的mapper都有一个二级缓存,也就是说,不同的mapper之间的二级缓存是互不影响的.为了更加 ...
- MyBatis学习总结(1)——MyBatis快速入门
2019独角兽企业重金招聘Python工程师标准>>> 一.Mybatis介绍 MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis消除了几乎所 ...
- MyBatis学习笔记(一)——MyBatis快速入门
转自孤傲苍狼的博客:http://www.cnblogs.com/xdp-gacl/p/4261895.html 一.Mybatis介绍 MyBatis是一个支持普通SQL查询,存储过程和高级映射的优 ...
- MyBatis研习录(14)——MyBatis逆向工程
C语言自学完备手册(33篇) Android多分辨率适配框架 JavaWeb核心技术系列教程 HTML5前端开发实战系列教程 MySQL数据库实操教程(35篇图文版) 推翻自己和过往--自定义View ...
- 【MyBatis学习13】MyBatis中的二级缓存
1. 二级缓存的原理 前面介绍了,mybatis中的二级缓存是mapper级别的缓存,值得注意的是,不同的mapper都有一个二级缓存,也就是说,不同的mapper之间的二级缓存是互不影响的.为了更加 ...
- MyBatis学习总结(七)——Mybatis缓存
一.MyBatis缓存介绍 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持 一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 Se ...
- 【mybatis学习记录】mybatis的各种查询 一对一关联查询(4种方式) 一对多(2种方式)
文章目录 一对一 方式一: 方式2 方式3 方式4 一对多查询(2种方式) 方式2 一对一 如:通过订单id查询订单的时候,将订单关联的用户信息也返回. 首先建库建表: 新建实体类: @Builder ...
最新文章
- python怎么玩pdf_最全总结!聊聊 python 操作PDF的几种方法
- R语言-安装使用指南
- 实例化Layout中的布局文件(xml)
- 【开发环境】戴尔电脑系统重装 ( 下载 Dell OS Recovery Tool 工具 | 使用 Dell OS Recovery Tool 工具制作 U 盘系统 | 安装系统 )
- DL之DNN优化技术:利用Batch Normalization(简介、入门、使用)优化方法提高DNN模型的性能
- 香农定理和奈奎斯特定理区别_这一切都从指数函数开始(4)——采样定理
- C语言求二个数的最大公约数gcd和最小公倍数lcm(附完整源码)
- 超线程cpu的寄存器_一文总结 CPU 基本知识
- 有监督学习和无监督学习举例_监督学习入门学习笔记
- RDBMS数据定时采集到HDFS
- 隐藏ASP.NET MVC版本
- 计算机图形学 opengl版本 第三版------胡事民 第四章 图形学中的向量工具
- java生成字符_java中随机生成字符串的方法(三种)
- 【TSP】基于matlab遗传和模拟退火算法求解旅行商问题【含Matlab源码 696期】
- netkeeper客户端_中国电信创翼客户端下载
- 如何搭建个人私有云盘
- linux动态库so更新
- python unpack_关于python中的struct.unpack()
- javafx 教程_何时使用JavaFX代替HTML
- acrobat PDF删除部分_PDF原来可以这么玩
热门文章
- 2678v3支持内存频率_电脑内存别乱加,不了解这些白花钱
- tf.keras.layers.Conv2D 示例
- 解决Python报错UnicodeDecodeError: 'gbk' codec can't decode byte 0x80 in position 658: illegal multibyte
- php mysql cms 商城,国内最常用的PHP+MySql免费CMS系统大全
- gcc c语言标准,GCC 7.1发布 支持当前所有的C ++ 17标准
- 查询距离两天的数据_一张图就可以管理城建数据?!实景城市三维平台来了
- html创建等边三角形,CSS3 等边三角形组成星形图案
- 三阶魔方还原步骤图_(六)最简单的三阶魔方入门教程——顶面还原
- NSURLCache
- Mac OS增删环境变量