• Mybatis 使用技巧总结


        <div class="postdetails" style="background-color: rgb(204, 232, 207);">
            <i class="fa fa-calendar"></i> 9月 11, 2014 | 
            <i class="fa fa-user"></i> <a href="http://www.javacoder.cn/?author=1" title="由Nix.Huang发布" rel="author">Nix.Huang</a>            
       
    	            
        </div>
    
    <p>目录:<br>
    

    1、区分 #{} 和 ${}的不同应用场景

    2、spring环境用mybatis-spring 的接口而不是Mybatis的原生接口

    3、返回Map<ID, Entity>而不是List便于查找

    4、使用Map封装查询的结果

    5、使用Map封装查询结果时注意数据的类型映射

    6、正确的配置Mybatis 的Log

    7、警惕Mybatis的foreach的的副作用

    8、使用原生的SQL操作数据以提高效率

    9、警惕MyBatis封装数据时性能损耗

    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方法:

    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

    <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 函数

    <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。

    <configuration>
    <settings>
    ...
    <setting name="logImpl" value="LOG4J"/>
    ...
    </settings>
    </configuration>

    7、警惕Mybatis的foreach的的副作用

    对于如下SQL:
    假设有如下的mapper:

    <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 结构

    <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 (), () ()格式一次插入多行数据往往能极大的提高性能。

    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

    <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,代码大致如下:

    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);
    }
    

    解决的办法是让返回的行数和返回的字段尽量的少。

    <p>
        Posted in: <a href="http://www.javacoder.cn/?cat=4" rel="category">Mybatis practise</a>          | <i class="fa fa-tags"></i> Tags: <a href="http://www.javacoder.cn/?tag=mybatis" rel="tag">mybatis</a>    </p>
    
    <div class="clear"></div>
    
  • 相关阅读:
    ORACLE常用SQL(session&badSql)
    归档日志满解决方法
    SPRING MVC总结
    Java中分割字符串
    无废话ExtJs 入门教程二十一[继承:Extend]
    无废话ExtJs 入门教程二十[数据交互:AJAX]
    WAMP 80端口被Microsoft-HTTPAPI/2.0占用的解决办法
    WampServer安装图解教程
    vmware tools安装程序无法继续,Microsoft Runtime DLL安装程序未能完成安装。的解决方法
    WordPress添加网站图标
  • 原文地址:https://www.cnblogs.com/jpfss/p/7601065.html
Copyright © 2020-2023  润新知