【一】、简介
Mybatis源于Apache的一个开源项目iBatis。2020年iBatis这个项目,Apache Software Foundation迁移到了Google Code,并改名为Mybatis,2013年11月迁移到Github。Mybatis是一个基于Java的支持普通SQL查询,存储过程和高级映射的优秀持久框架。Mybatis使用简单的XML或注解,用于配置和原始映射,将接口和Java的POJO(普通的Java对象)映射成数据库的记录。
【二】、原理
Mybatis应用程序大都使用SqlSessionFactory实例,SqlSessionFactory实例可以通过SqlSessionFactoryBuilder获得,而SqlSessionFactoryBuilder则可以从一个XML的配置文件或者一个预定义的配置类的实例中获得。
【三】、基础知识
1.设置namespace命名空间,是为了绑定DAO接口的,即面向接口编程。
2.结果集resultMap对象的ORM(Object Relational Mapping 对象关系映射),一般如果数据库中的字段和实体类的属性命名不一致,就会采用resultMap进行映射。
- 主键为<id column="person_id" property="personId"/>
- 普通字段<result column="person_name" property="personName">
- 在结果集中,常用的两个属性分别为:
- property,表示实体类的属性
- column,表示数据表的字段
- 额外的两个属性为:
- javaType属性对应实体类的类型,如int,Integer...
- jdbcType属性对应数据库的类型,如varchar...
<resultMap id="PersonDO" type="main.java.com.mybatisstudy.entity.PersonDO"> <result column="id" property="id"/> <result column="person_name" property="personName"></result> <result column="sex" property="sex"></result> <result column="phone" property="phone"></result> </resultMap>
3.在映射文件中,常用的标签有四个,分别为select、insert、update、delete
- id属性,一般它的值对应mapper接口中的方法,保证同一个mapper.xml中id不会重复。
- parameterType表示传入参数的类型,eg:int,Integer...
- 返回值resultType用于表示该sql语句返回的数据类型(与java类型对应)
- 返回值resultMap用于返回复杂的类型
当参数和返回值为集合时,resultType和parameterType声明为集合中的元素类型
例如:
<insert id="insertPerson" parameterType="main.java.com.mybatisstudy.entity.PersonDO"> insert into person (id,person_name,sex,phone) values (#{id},#{personName},#{sex},#{phone}); </insert>
5.参数传参为:字段名=#{属性名},eg:person_name=#{personName};SQL语句不区分大小写,它默认使用PrepareStatment预编译,可以防止SQL注入。
6.sql标签
当多处调用相同的字段时,可以使用sql标签,完成底层的字符串拼接,例如: <sql id="xxx"> id,name,age </sql> <select> select <include refid="xxx"> from perpson </select>
7.赋别名
在mapper.xml文件中,<insert id="insert" parameterType="PersonDO"> 在sqlMapConfig.xml文件中先定义别名 <typeAliases> <typeAlias type="com.mybatisstudy.entity,PersonDO" alias="personDO"/> </typeAliases>
8.动态sql标签总结
- if标签用于条件判断,test属性中写条件,条件体内可以省略逗号
- where标签来输出条件完成判断,可以胜率多余的and和逗号
- set标签完成修改操作,当字段值为null时,不参与到sql语句中
- foreach标签中,collection属性表示传入的参数集合,如果传入单参数且为List集合,则写成collection="list";如果传入单参数且为array数组,collection="array";如果传入多个参数,则我们需要封装成一个map集合,collection="map"
- item表示该循环体中每隔元素变量的名称
- open表示该循环体开始之前外围放置的开始符号,一般都是“(”
- close表示结束字符,一般都是“)”
- separator表示分隔符,一般都是“,”
- index表示索引。index指定一个名字,用于表示在迭代的过程中,每次迭代到的位置。遍历list,index就是索引,遍历map,index就是map的key,item就是map的值
choose标签是按顺序判断其内部when标签中的test条件出否成立,如果有一个成立,则 choose 结束。当 choose 中所有 when 的条件都不满则时,则执行 otherwise 中的sql。类似于Java 的 switch 语句,choose 为 switch,when 为 case,otherwise 则为 default。 <!-- choose(判断参数) - 按顺序将实体类 User 第一个不为空的属性作为:where条件 --> <select id="getUserListChoose" resultMap="resultMapUser" parameterType="User"> SELECT * FROM User u <where> <choose> <when test="username !=null "> u.username LIKE CONCAT(CONCAT('%', #{username, jdbcType=vaechar}),'%') </when > <when test="sex != null and sex != '' "> AND u.sex = #{sex, jdbcType=integer} </when > <when test="birthday != null "> AND u.birthday = #{birthday, jdbcType=date} </when > <otherwise> </otherwise> </choose> </where> </select>
类似于Java 的 switch 语句,choose 为 switch,when 为 case,otherwise 则为 default。
- trim标签可以替代where/set标签
trim 是更灵活用来去处多余关键字的标签,它可以用来实现 where 和 set 的效果。 <!-- 使用 if/trim 代替 where(判断参数) - 将 User 类不为空的属性作为 where 条件 --> <select id="getUsertList_if_trim" resultMap="resultMap_User"> SELECT * FROM user u <trim prefix="WHERE" prefixOverrides="AND|OR"> <if test="username !=null "> u.username LIKE CONCAT(CONCAT('%', #{username, jdbcType=VARCHAR}),'%') </if> <if test="sex != null and sex != '' "> AND u.sex = #{sex, jdbcType=INTEGER} </if> <if test="birthday != null "> AND u.birthday = #{birthday, jdbcType=DATE} </if> </trim> </select> trim 代替 set <!-- if/trim代替set(判断参数) - 将 User 类不为空的属性更新 --> <update id="updateUser_if_trim" parameterType="com.yiibai.pojo.User"> UPDATE user <trim prefix="SET" suffixOverrides=","> <if test="username != null and username != '' "> username = #{username}, </if> <if test="sex != null and sex != '' "> sex = #{sex}, </if> <if test="birthday != null "> birthday = #{birthday}, </if> </trim> WHERE user_id = #{user_id}
trim 元素的主要功能是可以在自己包含的内容前加上某些前缀,也可以在其后加上某些后缀,与之对应的属性是 prefix 和 suffix;可以把包含内容的首部某些内容覆盖,即忽略,也可以把尾部的某些内容覆盖,对应的属性是 prefixOverrides 和 suffixOverrides;正因为 trim 有这样的功能,所以我们也可以非常简单的利用 trim 来代替 where 元素的功能。
需要注意的是在增加,更改,删除的时候需要调用 session.commit()
来提交事务,这样才会真正对数据库进行操作提交保存,否则操作没有提交到数据中。
【四】注解映射
除了xml格式,还有比这更简单的方法,使用合理描述参数和SQL语句返回值的接口。
增加:Insert;InsertProvider
删除:Delete;DeleteProvider
修改:Update;UpdateProvider
查询:Select;SelectProvider
Provider类中常用来创建含有动态的sql。
//PersonMapper(interface)中的代码
@Select("select * from person")
List<PersonDO> listPerson();
@SelectProvider(type = PersonProvider.class, method = "findAuditPlanByTime")
PersonDO getPersonByNameOrPhone(String personName,String phone);
//PersonProvider(class)中的代码
public String getPersonByNameOrPhone(String personName, String phone) {
return new SQL() {
{
SELECT("*");
FROM("person");
if (personName != null && personName != "") {
WHERE("person_name=#{personName}");
}
if (phone != null && phone != "") {
WHERE("phone=#{phone}");
}
}
}.toString();
}
【五】项目练习
mybatis表一对一:MyBatis表关联一对一简单项目练习
mybatis表一对多:MyBatis表关联一对多简单项目练习
mybatis表多对一:MyBatis表关联多对一简单项目练习
mybatis表多对多:MyBatis表关联多对多简单项目练习
【六】mybatis常见异常