目录
文章目录
MyBatis
MyBatis 是轻量级持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
快速入门
安装
-
导入mybatis jar包
https://github.com/mybatis/mybatis-3/releases
-
maven项目添加依赖
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>x.x.x</version> </dependency>
核心架构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uhIMXxA2-1609347007799)(D:\0000note\4框架note\img\mybatis核心.png)]
SqlSessionFactory
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的,SqlSessionFactory 它是个单个数据库映射关系经过编译后的内存镜像
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession
SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。
try (SqlSession session = sqlSessionFactory.openSession()) {
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);
}
XML映射文件
用来定义SQL映射语句,包内的映射器接口实现全部注册为映射器(接口既绑定映射文件)
-
通过xml配置映射器
https://mybatis.org/mybatis-3/zh/configuration.html#mappers
-
在映射文件里绑定接口
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 对应接口的类路径 -->
<mapper namespace="com.cy.pj.sys.dao.xxMapper">
</mapper>
顶级元素
- cache – 该命名空间的缓存配置。
- cache-ref – 引用其它命名空间的缓存配置。
- resultMap – 描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。
sql
– 可被其它语句引用的可重用语句块。insert
– 映射插入语句。update
– 映射更新语句。delete
– 映射删除语句。- select – 映射查询语句。
select
这个语句名为 selectPerson,接受一个 int(或 Integer)类型的参数,并返回一个 HashMap 类型的对象,其中的键是列名,值便是结果行中的对应值。
<select id="selectPerson" parameterType="int" resultType="hashmap">
SELECT * FROM PERSON WHERE ID = #{id}
</select>
select元素属性
属性 | 描述 |
---|---|
id | 对应映射器中的方法 |
parameterType | 将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。 |
resultType | 期望从这条语句中返回结果的类全限定名或别名。 注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。 resultType 和 resultMap 之间只能同时使用一个。 |
resultMap | 对外部 resultMap 的命名引用。结果映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂的映射问题都能迎刃而解。 resultType 和 resultMap 之间只能同时使用一个。 |
timeout | 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。 |
insert, update 和 delete
数据变更语句 insert,update 和 delete 的实现非常接近:
<insert id="insertAuthor">
insert into Author (id,username,password,email,bio)
values (#{id},#{username},#{password},#{email},#{bio})
</insert>
<update id="updateAuthor">
update Author set
username = #{username},
password = #{password},
email = #{email},
bio = #{bio}
where id = #{id}
</update>
<delete id="deleteAuthor">
delete from Author where id = #{id}
</delete>
如果你的数据库支持自动生成主键的字段(比如 MySQL 和 SQL Server),那么你可以设置 useGeneratedKeys=”true”,然后再把 keyProperty 设置为目标属性就会把自增的id回显给pojo
<insert id="insertAuthor" useGeneratedKeys="true"
keyProperty="id">
insert into Author (username,password,email,bio)
values (#{username},#{password},#{email},#{bio})
</insert>
SQL
这个元素可以用来定义可重用的 SQL 代码片段,以便在其它语句中使用。 参数可以静态地(在加载的时候)确定下来,并且可以在不同的 include 元素中定义不同的参数值。
-
定义 (取参用 ‘$’)
<sql id="sqltest"> ${alias}.id,${alias}.username,${alias}.password </sql>
-
使用 (include标签 的 refid属性关联< sql>)
<select id="selectUsers" resultType="map"> select <include refid="userColumns"><property name="alias" value="t1"/></include>, <include refid="userColumns"><property name="alias" value="t2"/></include> from some_table t1 cross join some_table t2 </select>
resultMap 结果映射
resultMap 元素是 MyBatis 中最重要最强大的元素。ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。
隐式resultMap
<select id="selectUsers" resultType="map">
select *
from some_table
</select>
上述语句只是简单地将所有的列映射到 HashMap
的键上,这由 resultType
属性指定。虽然在大部分情况下都够用,但是 HashMap 并不是一个很好的领域模型。
你的程序更可能会使用 JavaBean 或 POJO(Plain Old Java Objects,普通老式 Java 对象)作为领域模型。MyBatis 对两者都提供了支持。
显式resultMap
定义< resultMap>然后在引用它的语句中设置 resultMap 属性就行了(注意去掉了 resultType 属性)。
<resultMap id="userResultMap" type="User">
<id property="id" column="user_id" />
<result property="username" column="user_name"/>
<result property="password" column="hashed_password"/>
</resultMap>
<select id="selectUsers" resultMap="userResultMap">
select user_id, user_name, hashed_password
from some_table
where id = #{id}
</select>
高级结果映射
<!-- 非常复杂的结果映射 -->
<!-- property bean的字段或属性
column 数据库中的列名
javaType java类的全限定名
-->
<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>
- constructor 用于在实例化类时,注入结果到构造方法中
- idArg id参数
- arg 将被注入到构造方法的一个普通结果
- id id结果
- result 注入到字段或 JavaBean 属性的普通结果
- association 一个复杂类型的关联;许多结果将包装成这种类型
- 嵌套结果映射 – 关联可以是 resultMap 元素,或是对其它结果映射的引用
- collection 一个复杂类型的集合
- 嵌套结果映射 – 集合可以是 resultMap 元素,或是对其它结果映射的引用
- discriminator 使用结果值来决定使用哪个 resultMap
- case 基于某些值的结果映射
- 嵌套结果映射 case 也是一个结果映射,因此具有相同的结构和元素;或者引用其它的结果映射
- case 基于某些值的结果映射
动态SQL
- if 条件元素
- choose(when,otherwise) 选择元素(like switch in java)
- trim(where,set)
- foreach
if
if提供了可选的xx功能,传入
<select id="find" resultType="pojo">
SELECT * FROM table
WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like concat('%',#{title},'%') <!-- '%${title}%' 也可,但会引发sql注入问题-->
</if>
</select>
choose ,when ,otherwise
如果传入title 则按title查找 ,传入author 就按author查找
<select id="find" resultType="pojo">
SELECT * FROM table
WHERE
<choose>
<when test="title != null">
column=#{title}
</when>
<when test="author != null and author.name != null">
column=#{author.name}
</when>
<otherwise>
column = -1
</otherwise>
</choose>
</select>
where
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或
“OR”,where 元素也会将它们去除。
<select id="find" resultType="pojo">
SELECT * FROM table
<where>
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
</where>
</select>
<!-- 注意和if标签配合使用: 不加if 则 相当于 where state=null 进行查询 -->
set
set 元素可以用于动态包含需要更新的列,而忽略其它不更新的列。若结尾有 ‘,’ 会自动去除.
<update id="update">
update teble
<set>
<if test="username!=null">username=#{username},</if>
<if test="password!=null">password=#{password}</if>
</set>
where id = #{id}
</update>
trim
属性
属性 | 描述 |
---|---|
prefix | 若sql有效,拼接前缀 |
suffix | 若sql有效,拼接后缀 |
prefixOverrides | 去除sql语句前面的关键字或者字符,该关键字或者字符由prefixOverrides属性指定,假设该属性指定为"AND",当sql语句的开头为"AND",trim标签将会去除该"AND" |
suffixOverrides | 去除sql语句后面的关键字或者字符,该关键字或者字符由suffixOverrides属性指定 |
<!-- preficOverrides 参数用 ' |' 分隔 -->
<trim prefix="WHERE" prefixOverrides="AND |OR ">
<!-- 等价于where标签-->
</trim>
<trim prefix="SET" suffixOverrides=",">
<!-- 等价于set 标签-->
</trim>
foreach
对集合进行遍历
<delete id="delete" resultType="pojo">
delete
from teble
<where>
<if test="ids!=null">
id in
<!-- mapper接口参数; 下标 前缀 后缀 分隔符-->
<foreach collection="ids" item="id" index="index" open="(" close=")" separator=",">
#{id}
</foreach>
</if>
</where>
</delete>