Mybatis 使用技巧总结
2016-02-15 09:52
363 查看
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:
<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方法:
123 | publicList<Map<String,Object>>selectStudent(Map<String,Object>parameter){ returngetSqlSession().selectList(getStatement("selectStudent"),parameter); } |
如果返回的结果集需要按select中的字段顺序返回,那么将resultType=”java.util.HashMap” 换为resultType=”java.util.LinkedHashMap”
5、使用Map封装查询结果时注意数据的类型映射
对于如下的Mapper1 2 3 4 | <select id="selectStudent"> select s.code as sNo , concat(s.firstName, s.lastName) as sName from xStudent s </select> |
1234 | <selectid="selectStudent"> selects.codeassNo,cast(concat(s.firstName,s.lastName)ASCHAR)assName fromxStudents </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:
123456789101112131415 | <selectid=”testForeach” parameterType=”map” resultType=”Student”> Select*fromstudent <where> <iftest=”ID!=nullandID!=‘’”> ID=#{ID} </if> <iftest=”IDArr!=nullandIDArr.size()>0”> AndIDIN <foreachcollection="IDArr"open="(" separator=","close=")"item="ID"> ${ID} </foreach> </if> </where> </select> |
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 (), () ()格式一次插入多行数据往往能极大的提高性能。12345678910111213141516171819202122 | publicintexecute(Stringsql){ intaffectedCount=0; Connectionconn=null; Statementstm=null; try{ conn=getSqlSession().getConnection(); stm=conn.createStatement(); stm.execute(sql); affectedCount=stm.getUpdateCount(); }catch(SQLExceptione){ thrownewRuntimeException(“execute[" + sql + "]failed”); }finally{ try{ if(stm!=null&&!stm.isClosed()){ stm.close(); } //conn will be released by mybatis framework }catch(SQLExceptione){ } } returnaffectedCount; } |
9、警惕MyBatis封装数据时性能损耗
对于如下的mapper1 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> |
1 2 3 4 5 6 | Classc=Class.forName("cn.javacoder.testmybatis.Student"); Objecto=c.newInstance(); for(eachcolum){ Methodm=c.getMethod("get"+colum); m.invoke(o,value); } |
相关文章推荐
- IOS Core Animation Advanced Techniques的学习笔记(四)
- Python Elasticsearch api
- 10534 - Wavio Sequence
- 使用IVersionedWorkspace进行版本检测
- 关于编码-解码
- C++定义和强制转换
- 1035. 插入与归并
- IOS Core Animation Advanced Techniques的学习笔记(三)
- 请求天气
- 中层为什么难以培养?
- ImageLoader加载网络图片初始化类
- java ee 开发环境配置-跟我一起学
- 线程池
- 微信开发踩坑之旅 之 开发准备及服务器配置
- ViewPager 详解(三)---PagerTabStrip与PagerTitleStrip添加标题栏的异同
- IOS Core Animation Advanced Techniques的学习笔记(二)
- 【.Net设计模式系列】仓储(Repository)模式 ( 一 )
- 营销 - 思考
- oerr 工具使用汇总
- 最新的高效 易上手的app数据库realm 学习