MyBatis是什么?
Mybatis是一个开源的,支持自定义SQL,存储过程和高级映射的持久化框架
Mybatis官网(https://mybatis.org/mybatis-3/zh/index.html)
MyBatis和JDBC的对比
连接:(托管,编码实现)使用了Mybatis我们就不需要自己获取数据库连接了,而是使用mybatis托管,使用JDBC需要自己编码获取连接
SQL:(隔离集中,混合分散)Mybatis将sql语句集中到一起,但是对于不相关的两个DAO类又是相互隔离的,JDBC的Sql代码分散,混合。
缓存:(两级缓存,不支持)Mybatis会将查询结果加入缓存,加快了对于同一个sql语句的查询速度。jdbc不支持缓存
结果映射:(Mybatis为自动映射(编写mapper文件,通过名字自动映射),编码实现)Mybatis可以使用XML文件将查询结果映射为POJO类。
维护性:(高,低),Mybatis的Sql的隔离集中,以及结果映射等特点大大提高了维护性,JDBC难于维护
MyBatis的配置
1. 引入Mybatis依赖
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
2. Mybatis配置文件
Mybatis配置文件结构:
例子:
<configuration>
<environments default = "develop">
<environment id = "devolop">
// 配置事务
<transacationManager type = "JDBC">
</transacationManager>
// 配置数据源
<dataSource type = "">
</dataSource>
</environment>
</environments>
// Mapper文件
<mappers>
// 从外部引入Mapper文件
<mapper resource = "mapper/PersonMapper.xml"/>
// 将整个包导入,需要java的class文件和mapper.xml的路径一样
<mapper package = "com.leetp.dao"/>
</mappers>
</configuration>
3. 编写映射文件:PersonMapper.xml
...
4. 使用
Mybatis操作数据库是使用SqlSession,所以先获取SqlSession
SqlSessionFactory sqlSessionFac =
new SqlSessionFactoryBuilder().build(Resource.getResourceAsReader("Mybatis配置文件路径"))
SqlSession sqlSession = sqlSessionFac.openSession(true); // true表示自动提交事务。可以不写
Mapper mapper = sqlSession.getMapper(Mapper.class) // Mapper是DAO接口
// mapper调用方法
使用mapper调用相应方法即可操作数据库。
MyBatis的核心概念
作用域和生命周期:
SqlSessionFactoryBuilder:获取完SqlSessionFactory他就应该被销毁了,以后不会用到
SqlSessionFactory:存在于整个运行生命周期中。理论上一个应用程序只有一个SqlSessionFactory
SqlSession:作用域为方法,方法销毁,SqlSession销毁,不能被用于方法参数传递。
Mapper:和SqlSession一样,不能被用于方法参数传递。
MyBatis的Mapper映射:
Mapper映射也就是将数据库表中的字段和类的属性映射起来。
下面是一个Mapper文件中结果映射的例子:
使用结果映射的例子
Mybatis动态Sql
常用标签:
if:常见用法<if test="name!=null">xxx</if>
choose:从众多条件中选择满足要求的其中一个。通常和when,otherwise一起用。类似于switch语句。
when:相当于switch的case
otherwise:相当于switch的default
where:只有where语句中有判断才会插入where语句,没有的话就不会插入where例如以下代码,如果title==null的话where语句就不会出现
<select id="queryMemoInfoWithPrivacyAndLikeTitleAndBackground" resultMap="memoInfoMap">
select
id, group_id, title, content, is_protected, background, is_remind, remind_time,
created_time, modify_time
from memo_info
where is_protected = '1'
<if test="title!=null">
and title like #{title}
</if>
<if test="background!=null">
and background = #{background}
</if>
</select>
trim:相当于自定义标签,可以自己定义where的实现,用法如下。
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
prefixOverrides 属性会忽略通过管道分隔的文本序列(注意此例中的空格也是必要的)。它带来的结果就是所有 在 prefixOverrides 属性中指定的内容将被移除,并且插入 prefix 属性中指定的内容。
set:用于update中。例子如下:
<update id="updateMemoInfo">
update memo_info
<set>
<if test="title!=null">
title = #{title},
</if>
<if test="content!=null">
content = #{content},
</if>
<if test="privacy!=null">
is_protected = #{privacy},
</if>
<if test="background!=null">
background = #{background},
</if>
<if test="remind!=null">
is_remind = #{remind},
</if>
<if test="remindTime!=null">
remind_time = #{remindTime}
</if>
</set>
where id = #{id}
</update>
foreach
<!-- 映射接口 -->
List<MemoInfo> queryMemoInfoWithIdsList(List<Integer> ids);
<!-- 命令配置 -->
<select id="queryMemoInfoWithIdsList" parameterType="list" resultMap="memoInfoMap">
SELECT
id, group_id, title, content, is_protected, background, is_remind, remind_time,
created_time, modify_time
FROM memo_info
WHERE id in
<foreach item="item" index="index" collection="list" open="(" separator="," close=")">
#{item}
</foreach>
</select>
其他
#{id}和${id}的区别:
#{id}所处的地方在编译时会被替换成一个?,但是${id}是直接进行结果写入,所以${id}的会有SQL注入的问题。
resultType和resultMap的区别
resultType只能指定java的class类型或者typeAlias,resultMap用于指定mapper.xml中定义的resultMap,可以通过他来实现复杂关系映射
如何实现一对一(association),一对多(collection),多对多
在resultMap标签中添加<association>标签
<!-- 非常复杂的结果映射 -->
<resultMap id="detailedBlogResultMap" type="Blog">
<constructor>
<idArg column="blog_id" javaType="int"/>
</constructor>
<result property="title" column="blog_title"/>
<association property="author" 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" javaType="Author"/>
<collection property="comments" ofType="Comment">
<id property="id" column="comment_id"/>
</collection>
<collection property="tags" ofType="Tag" >
<id property="id" column="tag_id"/>
</collection>
<discriminator javaType="int" column="draft">
<case value="1" resultType="DraftPost"/>
</discriminator>
</collection>
</resultMap>