Java后台面试--MyBatis核心知识集锦

Java后台面试--MyBatis核心知识集锦

2288发表于2016-11-10

1、${}与#{}区别

默认情况下,使用#{}格式的语法会导致MyBatis创建预处理语句属性并以它为背景设置安全的值(比如?)。这样做很安全,很迅速,也是首选的做法,有时你只是想直接在SQL语句中插入一个不改变的字符串。比如,像ORDER BY,你可以这样来使用:
ORDER BY ${columnName}

这里MyBatis不会修改或转义字符串。

重要:

接受从用户输出的内容并提供给语句中不变的字符串,这样做是不安全的。这会导致潜在的sql注入攻击,因此你不应该允许用户输入这些字段,或者通常自行转义并检查。


2、自定义主键,通过其他表的数据来生成

1、

<selectKey keyProperty="id" resultType="int" order="BEFORE">
</selectKey>


3、sql结点作用

这个元素可以被用来定义可重用的SQL代码段,可以包含在其他语句中。比如:
<sql id=”userColumns”> id,username,password </sql>

这个SQL片段可以被包含在其他语句中,例如:
<select id=”selectUsers” parameterType=”int” resultType=”hashmap”>
select <include refid=”userColumns”/>
from some_table
where id = #{id}
</select>

数据库列存的整数1,2,3,对应类对象枚举类型或者字符串
<discriminator javaType="int" column="draft">
<case value="1" resultType="DraftPost"/>
</discriminator>

2、N+1的问题及如何避免

什么时候问题严重?
列表的时候

一、关联的嵌套查询

<resultMap id=”blogResult” type=”Blog”>
<association property="author" column="blog_author_id"
javaType="Author" select=”selectAuthor”/>
</resultMap>
<select id=”selectAuthor” parameterType=”int” resultType="Author">
SELECT * FROM AUTHOR WHERE ID = #{id}
</select>

我们有两个查询语句:一个来加载博客,另外一个来加载作者,而且博客的结果映射描
述了“selectAuthor”语句应该被用来加载它的author属性。
其他所有的属性将会被自动加载,假设它们的列和属性名相匹配。
这种方式很简单,但是对于大型数据集合和列表将不会表现很好。问题就是我们熟知的
“N+1查询问题”。概括地讲,N+1查询问题可以是这样引起的:
 你执行了一个单独的SQL语句来获取结果列表(就是“+1”)。
 对返回的每条记录,你执行了一个查询语句来为每个加载细节(就是“N”)。
这个问题会导致成百上千的SQL语句被执行。这通常不是期望的。
MyBatis能延迟加载这样的查询就是一个好处,因此你可以分散这些语句同时运行的消
耗。然而,如果你加载一个列表,之后迅速迭代来访问嵌套的数据,你会调用所有的延迟加
载,这样的行为可能是很糟糕的。

所以还有另外一种方法。


二、关联的嵌套结果

select id="selectBlog" parameterType="int" resultMap="blogResult">
select
B.id as blog_id,
B.title as blog_title,
B.author_id as blog_author_id,
A.id as author_id,
A.username as author_username,
A.password as author_password,
A.email as author_email,
A.bio as author_bio
From Blog B left outer join Author A on B.author_id = A.id
where B.id = #{id}
</select>

注意:

这个联合查询,以及采取保护来确保所有结果被唯一而且清晰的名字来重命名。这

使得映射非常简单。现在我们可以映射这个结果:
<resultMap id="blogResult" type="Blog">
<id property=”blog_id” column="id" />
<result property="title" column="blog_title"/>
<association property="author" column="blog_author_id"
javaType="Author" resultMap=”authorResult”/>
</resultMap>
<resultMap id="authorResult" type="Author">
<id property="id" column="author_id"/>
<result property="username" column="author_username"/>
<result property="password" column="author_password"/>
<result property="email" column="author_email"/>
<result property="bio" column="author_bio"/>
</resultMap>

用户对应角色(多对多):

<select id="selectUserByID" parameterType="int" resultMap="userResult">
select a.*,c.id as roleID,c.`name` from sys_userinfo a
left join sys_user_role b on a.ID=b.userID
left join sys_role c on b.roleID=c.id
where a.`id` = #{id}
</select>
<resultMap id="userResult" type="VSysUserInfo">
<id property="id" column="id"/>
<result property="loginName" column="loginName"/>
<result property="trueName" column="trueName"/>
<result property="phoneNo" column="phoneNo"/>
<result property="qq" column="qq"/>
<result property="email" column="email"/>
<result property="enabled" column="enabled"/>
<result property="createTime" column="createTime"/>
<collection property="roles" ofType="Role">
<id property="id" column="roleID"/>
<result property="name" column="name"/>
</collection>
</resultMap>

3、分页是怎么做的?

PageHelper插件的形式(mybatis配置文件plugins 结点)
PageHelper.startPage(p, 10);
dao.
...

4、怎么避免数据库链接泄露

try 

finnaly

session.close()
模板模式
或者用spring template

resultMap使用:

<resultMap id="detailedBlogResultMap" type="Blog">
<constructor>
<idArg column="blog_id" javaType="int"/>
</constructor>
<result property="title" column="blog_title"/>
<association property="author" column="blog_author_id" javaType="Author">
<id property="id" column="author_id"/>
<result property="username" column="author_username"/>
<result property="password" column="author_password"/>
<result property="email" column="author_email"/>
<result property="bio" column="author_bio"/>
<result property="favouriteSection" column="author_favourite_section"/>
</association>
<collection property="posts" ofType="Post">
<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>
<association property="author" column="post_author_id"
javaType="Author"/>
<collection property="comments" column="post_id" ofType=" Comment">
<id property="id" column="comment_id"/>
</collection>
<collection property="tags" column="post_id" ofType=" Tag" >
<id property="id" column="tag_id"/>
</collection>
<discriminator javaType="int" column="draft">
<case value="1" resultType="DraftPost"/>
</discriminator>
</collection>
</resultMap>


动态sql---if:

<select id=”findActiveBlogLike”
parameterType=”Blog” resultType=”Blog”>
SELECT * FROM BLOG
WHERE
<if test=”state != null”>
state = #{state}
</if>
<if test=”title != null”>
AND title like #{title}
</if>
<if test=”author != null and author.name != null”>
AND title like #{author.name}
</if>
</select>

---choose... when (case )

<select id=”findActiveBlogLike”
parameterType=”Blog” resultType=”Blog”>
SELECT * FROM BLOG WHERE state ='ACTIVE'
<choose>
<when test=”title != null”>
AND title like #{title}
</when>
<when test=”author != null and author.name != null”>
AND title like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>

---where

<select id=”findActiveBlogLike”
parameterType=”Blog” resultType=”Blog”>
SELECT * FROM BLOG
<where>
<if test=”state != null”>
state = #{state}
</if>
<if test=”title != null”>
AND title like #{title}
</if>
<if test=”author != null and author.name != null”>
AND title like #{author.name}
</if>
</ where >
</select>

如果where元素没有做出你想要的,你可以使用trim 元素来自定义。比如,和where元素相等的trim 元素是:
<trim prefix="WHERE" prefixOverrides="AND |OR ">
…
</trim>

---set动态更新列

和动态更新语句相似的解决方案是set。set元素可以被用于动态包含更新的列,而不包
含不需更新的。比如:
<update id="updateAuthorIfNecessary"
parameterType="domain.blog.Author">
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio}</if>
</set>
where id=#{id}
</update

如果你对和这相等的trim 元素好奇,它看起来就是这样的:
<trim prefix="SET" suffixOverrides=",">
…
</trim>

注意这种情况下我们覆盖一个后缀,而同时也附加前缀。


---foreach

另外一个动态SQL通用的必要操作是迭代一个集合,通常是构建在IN条件中的。比如:
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreac h ite m="ite m" inde x="index" c ollection="list"
open="(" separator="," close=")">
#{item}
</fore ach>
</select>

foreach 元素是非常强大的,它允许你指定一个集合,声明集合项和索引变量,它们可
以用在元素体内。它也允许你指定开放和关闭的字符串,在迭代之间放置分隔符。这个元素
是很智能的,它不会偶然地附加多余的分隔符。



小编蓝狐