一、Mybatis简介
1.1 Mybatis是什么
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
1.2 为什么使用Mybatis
通俗的理解,一个接口映射一个数据库SQL。调用传参时,需要将Java类型转换为数据库类型;返回值时需要将数据库类型转换为Java类型。Mybatis简化一进一出的复杂类型转换。
1.3 Mybatis系列说明
虽然我们标题是Mybatis快速入门,但Mybatis框架已经很少再单一使用,通常会使用Mybatis-plus,同时结合SpringBoot一起使用。
它们之前关系是mybatis-plus-boot-starter将mybatis-plus注册到Springboot中,同时设置默认配置,保证最小设置即可启动。Mybatis-plus扩展了Mybatis的能力,通过IService<T>接口支持一系列默认的Curd操作,对于单表增删改成无需再编写接口和数据库SQL的映射;同时可以通过数据库表直接生成所有映射实体和接口。
二、mybatis-plus-boot-starter
2.1 Maven
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.1</version>
</dependency>
2.2 配置
#mybatis配置
mybatis-plus.type-aliases-package=com.startdt.teaching.data.model #支持的实体的扫描路径
mybatis-plus.mapper-locations=classpath*:mappers/**/*.xml #支持映射的XML路径
mybatis.configuration.map-underscore-to-camel-case=true #开启驼峰命名法
2.3 Mybatis-plus使用
通过Mybatis-plus映射生成以下实体和接口:
(1)Demo.java
说明:Demo.java是数据库表所对应的实体,其字段与数据库字段一般一一对应关系;同时将Demo.java对象放置在com.startdt.teaching.data.model目录下,确保可以扫描到该实体。
public class Demo implements Serializable {
}
(2)DemoMapper.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.startdt.teaching.data.repository.demo.mapper.DemoMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.startdt.teaching.data.repository.demo.dataobject.Demo">
<id column="id" property="id" />
<result column="name" property="name" />
<result column="datas" property="datas" />
<result column="data_type" property="dataType" />
<result column="user_id" property="userId" />
<result column="space_id" property="spaceId" />
<result column="create_time" property="createTime" />
<result column="modify_time" property="modifyTime" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, name, datas, data_type, user_id, space_id, create_time, modify_time
</sql>
</mapper>
(3)DemoMapper.java
public interface DemoMapper extends BaseMapper<Demo> {
}
(4)IDemoService.java
public interface IDemoService extends IService<Demo> {
}
(5)DemoServiceImpl.java
@Service
public class DemoServiceImpl extends ServiceImpl<DemoMapper,Demo> implements IDemoService {
}
2.4 CURD接口
/**
* 插入一条记录(选择字段,策略插入)
*
* @param entity 实体对象
*/
boolean save(T entity);
/**
* 插入(批量)
*
* @param entityList 实体对象集合
*/
@Transactional(rollbackFor = Exception.class)
default boolean saveBatch(Collection<T> entityList) {
return saveBatch(entityList, 1000);
}
/**
* 插入(批量)
*
* @param entityList 实体对象集合
* @param batchSize 插入批次数量
*/
boolean saveBatch(Collection<T> entityList, int batchSize);
/**
* 批量修改插入
*
* @param entityList 实体对象集合
*/
@Transactional(rollbackFor = Exception.class)
default boolean saveOrUpdateBatch(Collection<T> entityList) {
return saveOrUpdateBatch(entityList, 1000);
}
/**
* 批量修改插入
*
* @param entityList 实体对象集合
* @param batchSize 每次的数量
*/
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);
/**
* 根据 ID 删除
*
* @param id 主键ID
*/
boolean removeById(Serializable id);
/**
* 根据 columnMap 条件,删除记录
*
* @param columnMap 表字段 map 对象
*/
boolean removeByMap(Map<String, Object> columnMap);
/**
* 根据 entity 条件,删除记录
*
* @param queryWrapper 实体包装类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
*/
boolean remove(Wrapper<T> queryWrapper);
/**
* 删除(根据ID 批量删除)
*
* @param idList 主键ID列表
*/
boolean removeByIds(Collection<? extends Serializable> idList);
/**
* 根据 ID 选择修改
*
* @param entity 实体对象
*/
boolean updateById(T entity);
/**
* 根据 whereEntity 条件,更新记录
*
* @param entity 实体对象
* @param updateWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper}
*/
boolean update(T entity, Wrapper<T> updateWrapper);
/**
* 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
*
* @param updateWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper}
*/
default boolean update(Wrapper<T> updateWrapper) {
return update(null, updateWrapper);
}
/**
* 根据ID 批量更新
*
* @param entityList 实体对象集合
*/
@Transactional(rollbackFor = Exception.class)
default boolean updateBatchById(Collection<T> entityList) {
return updateBatchById(entityList, 1000);
}
/**
* 根据ID 批量更新
*
* @param entityList 实体对象集合
* @param batchSize 更新批次数量
*/
boolean updateBatchById(Collection<T> entityList, int batchSize);
/**
* TableId 注解存在更新记录,否插入一条记录
*
* @param entity 实体对象
*/
boolean saveOrUpdate(T entity);
/**
* 根据 ID 查询
*
* @param id 主键ID
*/
T getById(Serializable id);
/**
* 查询(根据ID 批量查询)
*
* @param idList 主键ID列表
*/
Collection<T> listByIds(Collection<? extends Serializable> idList);
/**
* 查询(根据 columnMap 条件)
*
* @param columnMap 表字段 map 对象
*/
Collection<T> listByMap(Map<String, Object> columnMap);
/**
* 根据 Wrapper,查询一条记录 <br/>
* <p>结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")</p>
*
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
*/
default T getOne(Wrapper<T> queryWrapper) {
return getOne(queryWrapper, true);
}
/**
* 根据 Wrapper,查询一条记录
*
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
* @param throwEx 有多个 result 是否抛出异常
*/
T getOne(Wrapper<T> queryWrapper, boolean throwEx);
/**
* 根据 Wrapper,查询一条记录
*
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
*/
Map<String, Object> getMap(Wrapper<T> queryWrapper);
/**
* 根据 Wrapper,查询一条记录
*
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
* @param mapper 转换函数
*/
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
/**
* 根据 Wrapper 条件,查询总记录数
*
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
*/
int count(Wrapper<T> queryWrapper);
/**
* 查询总记录数
*
* @see Wrappers#emptyWrapper()
*/
default int count() {
return count(Wrappers.emptyWrapper());
}
/**
* 查询列表
*
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
*/
List<T> list(Wrapper<T> queryWrapper);
/**
* 查询所有
*
* @see Wrappers#emptyWrapper()
*/
default List<T> list() {
return list(Wrappers.emptyWrapper());
}
/**
* 翻页查询
*
* @param page 翻页对象
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
*/
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
2.5 使用Mybatis
假如ISevice<T>中接口不符合我的要求,比如需要多表联合查询、主子表嵌套查询时怎么办?
(1)在DemoMapper.java中编写接口
public interface DemoMapper extends BaseMapper<Demo> {
List<Demo> selectUserJoin();
}
(2)在DemoMapper.xml中编写id为接口名的sql语句
<select id="selectUserJoin" resultType="com.startdt.teaching.data.repository.demo.dataobject.Demo">
SELECT * FROM user u JOIN group g on u.group_id = u.id
</select>
三、mybatis-plus原理
SqlSessionFacotry 中 → Configuration→ MappedStatements 每一个 mappedStatement 都表示 Mapper 接口中的一个方法与 Mapper 映射文件 中的一个 SQL。
MP 在启动就会挨个分析 xxxMapper 中的方法,并且将对应的 SQL 语句处理好,保存到 configuration 对象中的 mappedStatements 中。