本文为作者自己做的笔记,如果有什么地方写错了,望指出
我们在了解MyBatis接口的映射文件之前,先来看一下,什么是MyBatis?
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(实体类)映射成数据库中的记录。
每个MyBatis应用程序主要都是使用SqlSessionFactory实例的,一个SqlSessionFactory实例可以通过SqlSessionFactoryBuilder获得。SqlSessionFactoryBuilder可以从一个xml配置文件或者一个预定义的配置类的实例获得。
MyBatis有许多优点:
简单易学:本身很小且简单,没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
提供映射标签,支持对象与数据库的orm字段关系映射
提供对象关系映射标签,支持对象关系组建维护
提供xml标签,支持编写动态sql。
接下来解析配置文件,如下代码:
POJO实体类:
package cn.xhc.springboot.model;
import java.io.Serializable;
import java.math.BigDecimal;
public class User implements Serializable {
private Integer id;
private String userName;
private String userCard;
private Integer userAge;
private String userEmail;
private String userCompany;
private BigDecimal userWages;
private String userAddress;
private static final long serialVersionUID = 1L;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserCard() {
return userCard;
}
public void setUserCard(String userCard) {
this.userCard = userCard;
}
public Integer getUserAge() {
return userAge;
}
public void setUserAge(Integer userAge) {
this.userAge = userAge;
}
public String getUserEmail() {
return userEmail;
}
public void setUserEmail(String userEmail) {
this.userEmail = userEmail;
}
public String getUserCompany() {
return userCompany;
}
public void setUserCompany(String userCompany) {
this.userCompany = userCompany;
}
public BigDecimal getUserWages() {
return userWages;
}
public void setUserWages(BigDecimal userWages) {
this.userWages = userWages;
}
public String getUserAddress() {
return userAddress;
}
public void setUserAddress(String userAddress) {
this.userAddress = userAddress;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getClass().getSimpleName());
sb.append(" [");
sb.append("Hash = ").append(hashCode());
sb.append(", id=").append(id);
sb.append(", userName=").append(userName);
sb.append(", userCard=").append(userCard);
sb.append(", userAge=").append(userAge);
sb.append(", userEmail=").append(userEmail);
sb.append(", userCompany=").append(userCompany);
sb.append(", userWages=").append(userWages);
sb.append(", userAddress=").append(userAddress);
sb.append(", serialVersionUID=").append(serialVersionUID);
sb.append("]");
return sb.toString();
}
}
user数据库表:
Mapper接口层接口:
package cn.xhc.springboot.mapper;
import cn.xhc.springboot.model.User;
import cn.xhc.springboot.model.UserExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface UserMapper {
long countByExample(UserExample example);
int deleteByExample(UserExample example);
int deleteByPrimaryKey(Integer id);
int insert(User record);
int insertSelective(User record);
List<User> selectByExample(UserExample example);
User selectByPrimaryKey(Integer id);
int updateByExampleSelective(@Param("record") User record, @Param("example") UserExample example);
int updateByExample(@Param("record") User record, @Param("example") UserExample example);
int updateByPrimaryKeySelective(User record);
int updateByPrimaryKey(User record);
}
配置文件及解析:
<?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:用来使与之对应的Java关于数据库的操作的接口做联系。
属性:
namespace:接口所在的位置
-->
<mapper namespace="cn.xhc.springboot.mapper.UserMapper">
<!--
标签:
resultMap:用来配置数据库中指定表的字段与自己的POJO(实体)属性的联系的
属性:
id:resultMap的标识符
type:POJO(实体类)所在的路径
-->
<resultMap id="BaseResultMap" type="cn.xhc.springboot.model.User">
<!--
标签:
id:是为了配置数据库中表的主键标识符与自己的POJO属性的关联
result:是为了配置数据库中表的字段与自己的POJO属性的关联
属性:
column:数据库中表的字段名
jdbcType:数据库库中表的字段的类型
property:POJO中属性的名字
-->
<id column="id" jdbcType="INTEGER" property="id" />
<result column="user_name" jdbcType="VARCHAR" property="userName" />
<result column="user_card" jdbcType="VARCHAR" property="userCard" />
<result column="user_age" jdbcType="INTEGER" property="userAge" />
<result column="user_email" jdbcType="VARCHAR" property="userEmail" />
<result column="user_company" jdbcType="VARCHAR" property="userCompany" />
<result column="user_wages" jdbcType="DECIMAL" property="userWages" />
<result column="user_address" jdbcType="VARCHAR" property="userAddress" />
</resultMap>
<!-- Sql -->
<sql id="Example_Where_Clause">
<!--
where 元素知道只有在一个以上的if条件有值的情况下才去插入“WHERE”子句。
而且,若最后的内容是“AND”或“OR”开头的,where 元素也知道如何将他们去除。
-->
<where>
<!--
标签:
foreach:当传入参数为数组或者集合时需要通过<foreach></foreach>标签进行遍历
属性:
collection:指定输入对象中的集合属性名
item:每次遍历生成的对象名
separator:表示在每次进行迭代之后以什么符号作为分隔符(查出来一个数据应该以此作为分隔符,才能开始下一项查询)
-->
<foreach collection="oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<!--
标签:
trim
属性:
prefix="(":前缀为左括号
prefixOverrides="and":去掉sql语句的第一个AND连接符
suffix=")":后缀为右括号
open:值为开始遍历时候拼接的字符串
close:值为结束遍历时拼接的字符串
-->
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<!--
choose和when标签相当于Java中的Switch case标签,就是说那个when的标签成立,
就执行此when标签中的sql语句。
属性:
test:相当与Java中每个case中的条件
-->
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Update_By_Example_Where_Clause">
<where>
<foreach collection="example.oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<!--
标签:
sql:是用来将数据库中表的字段封装起来,以便以后使用的时候直接引用就行。
属性:
id:sql标签的标识符,以便于以后根据标识符来引用。
-->
<sql id="Base_Column_List">
id, user_name, user_card, user_age, user_email, user_company, user_wages, user_address
</sql>
<!--
标签:
select:用来根据条件对数据库中表数据的查询操作
属性:
id:要与Java程序数据库接口层的方法名称保持一致
parameterType:是Java程序数据库接口层方法的参数类型
resultMap:是Java程序数据库接口层方法的返回值类型,该值为我们的resultMap标签的id值
-->
<select id="selectByExample" parameterType="cn.xhc.springboot.model.UserExample" resultMap="BaseResultMap">
select
<!--
标签:
if:该标签是用来判断的条件是否成立的,如果条件成立(true),则执行if标签内的sql语句
属性:
test:是if标签的判断条件
-->
<if test="distinct">
distinct
</if>
<!--
标签:
include:是用来引用sql标签所封装的数据库表的字段
属性:
refid:该值与sql标签的id值应保持一致。
-->
<include refid="Base_Column_List" />
from user
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from user
<!--
#{id,jdbcType=INTEGER}
id:是Java程序的接口层方法的参数名字
jdbcType:是数据库中表对应该参数的字段的数据类型
-->
where id = #{id,jdbcType=INTEGER}
</select>
<!--
标签:
delete:用来对数据库中表数据的删除操作
属性:
id:要与Java程序数据库接口层的方法名称保持一致
parameterType:是Java程序数据库接口层方法的参数类型
-->
<delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
delete from user
where id = #{id,jdbcType=INTEGER}
</delete>
<delete id="deleteByExample" parameterType="cn.xhc.springboot.model.UserExample">
delete from user
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<!--
标签:
insert:用来对数据库中表数据的新增操作
属性:
id:要与Java程序数据库接口层的方法名称保持一致
parameterType:是Java程序数据库接口层方法的参数类型
-->
<insert id="insert" parameterType="cn.xhc.springboot.model.User">
<!--
数据库主键包括自增和非自增,有时候新增一条数据不仅仅知道成功就行了,
后边的逻辑可能还需要这个新增的主键,这时候再查询数据库就有点耗时耗力,
我们可以采用selectKey标签来帮助我们获取新增的主键。
标签:
selectKey:该标签的作用是将 LAST_INSERT_ID() 的结果放到我们的POJO(实体类)的主键里面。
属性:
keyProperty:对应POJO里的主键的属性名,这里对应我们User的id属性。
order:
AFTER:表示 SELECT LAST_INSERT_ID() 是在insert(插入数据)之后执行,多用于自增主键。
BEFORE:表示 SELECT LAST_INSERT_ID () 是在insert(插入数据)之前执行,但是就拿不到主键了,这种用于主键不是增的类型。
resultType:表示POJO中与数据库中表的主键对应的属性类型。
-->
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
SELECT LAST_INSERT_ID()
</selectKey>
insert into user (user_name, user_card, user_age,
user_email, user_company, user_wages,
user_address)
values (#{userName,jdbcType=VARCHAR}, #{userCard,jdbcType=VARCHAR}, #{userAge,jdbcType=INTEGER},
#{userEmail,jdbcType=VARCHAR}, #{userCompany,jdbcType=VARCHAR}, #{userWages,jdbcType=DECIMAL},
#{userAddress,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="cn.xhc.springboot.model.User">
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
SELECT LAST_INSERT_ID()
</selectKey>
insert into user
<!--
标签:
trim:
属性:
prefix="(":前缀左括号
suffix=")":后缀右括号
suffixOverrides=",":去掉sql语句的最后一个逗号
prefixOverrides="AND":去掉sql语句的第一个AND连接符
-->
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="userName != null">
user_name,
</if>
<if test="userCard != null">
user_card,
</if>
<if test="userAge != null">
user_age,
</if>
<if test="userEmail != null">
user_email,
</if>
<if test="userCompany != null">
user_company,
</if>
<if test="userWages != null">
user_wages,
</if>
<if test="userAddress != null">
user_address,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="userName != null">
#{userName,jdbcType=VARCHAR},
</if>
<if test="userCard != null">
#{userCard,jdbcType=VARCHAR},
</if>
<if test="userAge != null">
#{userAge,jdbcType=INTEGER},
</if>
<if test="userEmail != null">
#{userEmail,jdbcType=VARCHAR},
</if>
<if test="userCompany != null">
#{userCompany,jdbcType=VARCHAR},
</if>
<if test="userWages != null">
#{userWages,jdbcType=DECIMAL},
</if>
<if test="userAddress != null">
#{userAddress,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<!--
我们有时候会纠结select标签中的属性是resultMap还是resultType:
只要我们记住,Java程序数据库接口层方法的返回值如果是一个POJO,就用resultMap属性,
如果Java程序数据库接口层方法的返回值是其他类型(包括基本类型),就用resultType属性。
-->
<select id="countByExample" parameterType="cn.xhc.springboot.model.UserExample" resultType="java.lang.Long">
select count(*) from user
<!-- _parameter可以用来代表Java程序数据库接口层方法的参数,但是有一个局限性,就是方法参数只能有一个。 -->
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<!--
标签:
update:用来对数据库中表数据的部分修改操作。
属性:
id:要与Java程序数据库接口层的方法名称保持一致
parameterType:是Java程序数据库接口层方法的参数类型(我们可以使用简略模式,就像下面的map一样,也可以使用全路径java.util.Map)
-->
<update id="updateByExampleSelective" parameterType="map">
update user
<!--
set 标签元素主要是用在更新操作的时候,它的主要功能和 where 标签其实是差不多的,
主要是在包含的语句前输出一个 set,然后如果包含的sql语句是以逗号结束的话将会把该逗号忽略,
如果 set 包含的内容为空的话则会出错。有了 set 元素就可以动态的更新那些修改了的字段。
-->
<set>
<!-- record是该方法的实体类参数,record.id是用来获取该实体类的id-->
<if test="record.id != null">
id = #{record.id,jdbcType=INTEGER},
</if>
<if test="record.userName != null">
user_name = #{record.userName,jdbcType=VARCHAR},
</if>
<if test="record.userCard != null">
user_card = #{record.userCard,jdbcType=VARCHAR},
</if>
<if test="record.userAge != null">
user_age = #{record.userAge,jdbcType=INTEGER},
</if>
<if test="record.userEmail != null">
user_email = #{record.userEmail,jdbcType=VARCHAR},
</if>
<if test="record.userCompany != null">
user_company = #{record.userCompany,jdbcType=VARCHAR},
</if>
<if test="record.userWages != null">
user_wages = #{record.userWages,jdbcType=DECIMAL},
</if>
<if test="record.userAddress != null">
user_address = #{record.userAddress,jdbcType=VARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<!--
标签:
update:用来对数据库中表数据的全部修改操作。
属性:
id:要与Java程序数据库接口层的方法名称保持一致
parameterType:是Java程序数据库接口层方法的参数类型(我们可以使用简略模式,就像下面的map一样,也可以使用全路径java.util.Map)
-->
<update id="updateByExample" parameterType="map">
update user
set id = #{record.id,jdbcType=INTEGER},
user_name = #{record.userName,jdbcType=VARCHAR},
user_card = #{record.userCard,jdbcType=VARCHAR},
user_age = #{record.userAge,jdbcType=INTEGER},
user_email = #{record.userEmail,jdbcType=VARCHAR},
user_company = #{record.userCompany,jdbcType=VARCHAR},
user_wages = #{record.userWages,jdbcType=DECIMAL},
user_address = #{record.userAddress,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<!--
标签:
update:根据主键来对数据库中表数据的部分修改操作。
属性:
id:要与Java程序数据库接口层的方法名称保持一致
parameterType:是Java程序数据库接口层方法的参数类型
-->
<update id="updateByPrimaryKeySelective" parameterType="cn.xhc.springboot.model.User">
update user
<set>
<if test="userName != null">
user_name = #{userName,jdbcType=VARCHAR},
</if>
<if test="userCard != null">
user_card = #{userCard,jdbcType=VARCHAR},
</if>
<if test="userAge != null">
user_age = #{userAge,jdbcType=INTEGER},
</if>
<if test="userEmail != null">
user_email = #{userEmail,jdbcType=VARCHAR},
</if>
<if test="userCompany != null">
user_company = #{userCompany,jdbcType=VARCHAR},
</if>
<if test="userWages != null">
user_wages = #{userWages,jdbcType=DECIMAL},
</if>
<if test="userAddress != null">
user_address = #{userAddress,jdbcType=VARCHAR},
</if>
</set>
where id = #{id,jdbcType=INTEGER}
</update>
<!--
标签:
update:根据主键来对数据库中表数据的全部修改操作。
属性:
id:要与Java程序数据库接口层的方法名称保持一致
parameterType:是Java程序数据库接口层方法的参数类型)
-->
<update id="updateByPrimaryKey" parameterType="cn.xhc.springboot.model.User">
update user
set user_name = #{userName,jdbcType=VARCHAR},
user_card = #{userCard,jdbcType=VARCHAR},
user_age = #{userAge,jdbcType=INTEGER},
user_email = #{userEmail,jdbcType=VARCHAR},
user_company = #{userCompany,jdbcType=VARCHAR},
user_wages = #{userWages,jdbcType=DECIMAL},
user_address = #{userAddress,jdbcType=VARCHAR}
where id = #{id,jdbcType=INTEGER}
</update>
</mapper>
配置文件标签解析都在配置文件代码中!