这篇笔记主要记录如何使用MyBatis框架实现简单的单表增删改查,以及如何编写Mapper接口和XML映射配置。
这里我们还是使用MySQL数据库进行演示,我们使用的表t_role
如下。
create table t_role (
role_id bigint auto_increment primary key,
rolename varchar(255) not null
);
数据表对应的实体类如下。
Role.java
package com.gacfox.demomb.model;
import lombok.Data;
@Data
public class Role {
private Long roleId;
private String rolename;
}
我们这里现创建一个空的映射XML配置,后续介绍的XML配置都是基于该例子配置文件的。
RoleMapper.xml
<?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.gacfox.demomb.mapper.RoleMapper">
<!-- 具体的mapper方法实现会在后文介绍 -->
</mapper>
注意:namespace
属性对应接口的类全名。
查询单条结果我们的Mapper接口方法就要返回单个实体类对象,接口方法如下。
public Role queryRoleById(Long roleId);
对应XML配置如下。
<select id="queryRoleById" resultType="com.gacfox.demomb.model.Role">
select role_id as roleId, rolename
from t_role
where role_id = #{roleId}
</select>
该Mapper方法将查询单条记录,如果查询无结果返回null
,如果返回多条将抛出异常。如果我们不能保证SQL返回的结果是单条数据记录就应该使用查询多条的写法,即返回类型为List<Role>
。
这里我们注意以下几点:
select
的id
属性对应接口中的方法名resultType
对应实体类的类全名,这里Role
是该查询方法的返回值role_id as roleId
为查出的一个字段起了别名,这是为了和实体类的属性名对应,只有这两个名相同MyBatis才能自动映射(这是一种比较投机取巧的写法, 更好的方式是使用resultMap
映射配置,我们将在后文介绍)#{}
包裹,里面的参数名需要和方法声明中的参数名对应@param
注解标注(上面就是这样),如果有多个参数就必须用注解标注,我们将在后文介绍resultMap
手动映射查询结果之前的例子是MyBatis自动映射到Java实体类对象的,其中因为数据库中字段名是role_id
而实体类中对应属性名是roleId
,我们使用了as
指定别名MyBatis才能正常识别,除此之外更好的方式是使用resultMap
实现手动进行映射。
<resultMap id="roleMap" type="com.gacfox.demomb.model.Role">
<id property="roleId" column="role_id"/>
<result property="rolename" column="rolename"/>
</resultMap>
<select id="queryRoleById" resultMap="roleMap">
select role_id, rolename
from t_role
where role_id = #{roleId}
</select>
<resultMap>
中,id
用于映射主键,result
用于映射普通字段。除了上面介绍的用法,在关联查询中resultMap
还有级联查询相关的配置,我们将在后文介绍。
查询多条结果需要返回列表类型,Mapper接口方法定义例子如下。
public List<Role> queryAllRole();
Mapper对应XML配置如下。
<select id="queryAllRole" resultType="com.gacfox.demomb.model.Role">
select role_id as roleId, rolename
from t_role
</select>
这里SQL语句返回的可能是一条结果、多条结果或是没有结果。方法的返回值是一个List
,返回结果可能里面有多条、1条、或是0条数据。实际上,返回一个结果时,我们也可以使用List
接收返回结果(列表中仅有一条数据),然而如果不使用列表接收但返回了多条结果将抛出异常。
前面我们提到过,如果Mapper方法参数有多个,就必须用@Param
注解对参数起名。
public List<Role> queryRoleByPage(@Param("start_index") Integer startIndex, @Param("page_size") Integer pageSize);
对应XML配置如下,其中#{}
包裹的就是注解指定的参数名。
<select id="queryRoleByPage" resultType="com.gacfox.demomb.model.Role">
select role_id as roleId, rolename
from t_role
limit #{start_index},#{page_size}
</select>
这里我们传递了多个参数进行查询,注意参数需要用@param
进行标注,这个注解是org.apache.ibatis.annotations.Param
包的,不要和别的包弄混。只有一个参数时,@param
可以省略,SQL中的参数名是对应方法的参数名,当然,如果你有强迫症,那么所有Mapper方法参数都标注@param
也是完全可以的。
对于插入语句,我们需要传入包含数据的实体类对象,然后在Mapper映射XML中拼接INSERT插入语句。
public int insertRole(Role role);
对应XML配置如下。
<insert id="insertRole" useGeneratedKeys="true" keyProperty="roleId">
insert into t_role(rolename)
values (#{rolename})
</insert>
由于我们使用了MySQL的自增长主键,因此我们需要在插入后得知该条数据主键值,useGeneratedKeys="true"
表示插入时使用数据库提供的主键自增长功能,keyProperty
是实体类中主键对应的字段名。这里SQL中的参数字段对应实体类中的属性名,实际上这也是传入多个参数的一种方式。
注意MyBatis中执行插入操作,接口方法的返回值是受影响的行数,主键值在传入的对象中,如果我们需要获取插入后的主键值,可以使用如下写法。
Role role = new Role();
role.setRolename("新角色");
mapper.insertRole(role);
System.out.println("pk=" + role.getRoleId());
删除和插入类似,我们需要传入参数并拼接DELETE语句。
public int deleteRole(Long roleId);
对应XML配置如下。
<delete id="deleteRole">
delete
from t_role
where role_id = #{roleId}
</delete>
对于插入方法,Mapper接口返回值也是受影响的行数。
修改方法和插入、删除类似,我们需要传入参数拼接UPDATE语句。
public int updateRole(Role role);
对应XML配置如下。
<update id="updateRole">
update t_role
set rolename = #{rolename}
where role_id = #{roleId}
</update>
和之前一样,Mapper接口返回值也是受影响的行数。