欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Mybatis 学习笔记

程序员文章站 2024-01-21 16:10:34
...

resultSets在学习Mybatis的过程中,应该或多或少的都会遇到一些问题,先整理如下。

Mybatis是什么,为什么使用?

答:MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。MyBatis 使用简单的 XML 或注解用于配置和原始映射,将接口和 Java 的 POJOs映射成数据库中的记录。使用的原因因为流行、简单、易维护优化、提高开发效率、开源、性能不错。

 

什么是N+1问题,如何解决?

 使用Mapper XML配置的时候,查询一个list的结果集,需要执行N+1次SQL进行查询,如果数据量大的话,会带来很大的性能问题。

举例:

<resultMap id="blogResult" type="Blog">
  <association property="author" column="author_id" javaType="Author" select="selectAuthor"/>
</resultMap>

<select id="selectBlog" resultMap="blogResult">
  SELECT * FROM BLOG WHERE ID = #{id}
</select>

<select id="selectAuthor" resultType="Author">
  SELECT * FROM AUTHOR WHERE ID = #{id}
</select>

 Blog的结果集中需要执行selectAuthor来获取Author的属性。假设BLOG表有10条记录,每条记录对应AUTHOR表也有10条记录,那么执行blogResult查询,需要进行了1+10次查询。简而言之,原因是:

  • 你执行一个SQL语句来获取结果(“+1”)的列表;
  • 对于返回的每条记录,你执行了一个查询语句来为每个加载细节(在“N”);

解决办法:

  • SQL使用连接查询;
  • Mybatis在3.2.3以后,可以使用Association关联多个ResultSet;

例如:

定义存储过程如下

 

SELECT * FROM BLOG WHERE ID = #{id}

SELECT * FROM AUTHOR WHERE ID = #{id}
 Mapper XML的配置中增加resultSets,如下
<select id="selectBlog" resultSets="blogs,authors" resultMap="blogResult">
  {call getBlogsAndAuthors(#{id,jdbcType=INTEGER,mode=IN})}
</select>
配置resultMap的地方可以引用resultSets中的内容,如下
<resultMap id="blogResult" type="Blog">
  <id property="id" column="id" />
  <result property="title" column="title"/>
  <association property="author" javaType="Author" resultSet="authors" column="author_id" foreignColumn="id">
    <id property="id" column="id"/>
    <result property="username" column="username"/>
    <result property="password" column="password"/>
    <result property="email" column="email"/>
    <result property="bio" column="bio"/>
  </association>
</resultMap>
如何处理“is-a”、“has-a”关系?

extends处理is-a;

association处理has-a;

collection处理has-many;

 

在Nested Select解决has-many的情况下,collection标签中,各个字段的理解?

<collection property="Java属性名" ofType="另一Java类名" javaType="ArrayList" column="关联主键ID(用于嵌套查询SQL语句传入参数,多个用逗号分开,必须和数据库列对应)" select="另一个select映射SQL的ID"/>
<select parameterType="int" resultType="另一Java类名" id="另一个select映射SQL的ID">

例如:

<resultMap type="org.demo.mybatis.po.Deptartment" id="deptResultMap">
		<id column="dept_id" property="deptId" javaType="int" />
		<result column="dept_name" property="deptName" javaType="string" />
		<result column="dept_address" property="deptAddress" javaType="string" />
		<!-- column是必填的,同时必须是数据库的列,关联SQL中的入参-->
		<collection property="employees" column="dept_id" ofType="org.demo.mybatis.po.Employee" select="selectEmployeeForDept" />
	</resultMap>
	
	<!-- 嵌套的SQL语句将被多次执行 -->
	<select id="selectEmployeeForDept" resultType="org.demo.mybatis.po.Employee">
		select
			e_id,
			dept_id,
			e_name
		from employee
		<!--any的值可以随意填写,但是必须写,同时不能使用${}取代,最好使用和colum对应的property,这里使用deptId提高可读性 -->
		where dept_id = #{any}
	</select>

 

 

#{..} vs ${...}?

#{…}是一个参数标记,而${…}只是简单的字符串替换。一般而言,为避免SQL注入攻击,传递参数应使用#{…}方式,因为这样MyBatis会处理好特殊字符转义的问题;但在SQL语句的某些地方,又不能使用#{…}方式。上述文档举出的例子是不能用这种方式指定表名,而根据我们的经验,在order by子句中也不能用这种方式。从中我们可以总结出:对于诸如表名、字段名(如order by子句后的排序字段)这些表本身或其字段的名字,和SQL关键字(如order by子句后的asc关键字),是不能使用#{…}方式的,而只能使用字符串替换的${…}方式。

官网:http://code.google.com/p/mybatis/wiki/faq

相关标签: FAQ