mybatis-plus从入门到入土(三):持久层接口之IService
大家好,之前两周一直没有更新博客,主要因为最近回了趟老家,处理了一些事情。好了,今天我们开始更新第三篇持久层接口
。首先先看持久层的IService
接口。
官方文档
https://baomidou.com/guides/data-interface/#get
IService相关方法
IService
是我们工作中最长用到的类,这里面的方法主要就是增删改查,我们先来看几个方法。
增
// 插入一条记录(选择字段,策略插入)
boolean save(T entity);
// 插入(批量)
boolean saveBatch(Collection<T> entityList);
// 插入(批量)
boolean saveBatch(Collection<T> entityList, int batchSize);
关于增,也就是插入记录,在这个接口里主要提供了单条插入
和批量插入
方法,关于saveBatch
的两个方法需要说一下,虽然一个带有batchSize
,一个不带,但是最终都是走的带batchSize
的方法。如果不指定batchSize
,则batchSize
为1000。有兴趣的可以看下源码。
删
// 根据 queryWrapper 设置的条件,删除记录
boolean remove(Wrapper<T> queryWrapper);
// 根据 ID 删除
boolean removeById(Serializable id);
// 根据 columnMap 条件,删除记录
boolean removeByMap(Map<String, Object> columnMap);
// 删除(根据ID 批量删除)
boolean removeByIds(Collection<? extends Serializable> idList);
关于删,有根据id删除,也有根据条件删除,总体都比较简单就不赘述了。
改
// 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
boolean update(Wrapper<T> updateWrapper);
// 根据 whereWrapper 条件,更新记录
boolean update(T updateEntity, Wrapper<T> whereWrapper);
// 根据 ID 选择修改
boolean updateById(T entity);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList, int batchSize);
关于改,其他几个方法也没啥,可以单条更新,可以批量更新,UpdateWrapper
说一下,这是个更新包装器,可以用来组装更新的字段和条件等,这个后面会讲到。
查
--------------------------GET 单条查询-----------------------------------------------------------------------
// 根据 ID 查询
T getById(Serializable id);
// 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")
T getOne(Wrapper<T> queryWrapper);--------------------------LIST 集合查询-----------------------------------------------------------------------
// 查询所有
List<T> list();
// 查询列表
List<T> list(Wrapper<T> queryWrapper);
// 查询(根据ID 批量查询)
Collection<T> listByIds(Collection<? extends Serializable> idList);
// 查询(根据 columnMap 条件)
Collection<T> listByMap(Map<String, Object> columnMap);--------------------------PAGE 分页查询-----------------------------------------------------------------------
// 无条件分页查询
IPage<T> page(IPage<T> page);
// 条件分页查询
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);--------------------------COUNT 数量查询-----------------------------------------------------------------------
// 查询总记录数
long count();
// 根据 Wrapper 条件,查询总记录数
long count(Wrapper<T> queryWrapper);
关于查,分为单条查询
,集合查询
,分页查询
和数量查询
;这几个API用法也比较简单,这里简单列举了一些,但是不全;建议去看下官方文档的描述。
以上就是增删改查的部分API,大家可能感到很无语,我基本上只是把方法贴上去了,但是确实没啥可讲的,对着官方文档的例子,大家自己测试下就好了,当然我还省略了saveOrUpdate
方法,这个主要是根据主键来判断是更新还是删除。下面我们分析下IService的继承结构,这块是我重点想讲的,对这些了解了,才是对大家真正的有帮助。
IService相关类结构
从上面图中,可以看出,IService
继承自IRepository
,然后IRepository
还有个抽象实现类AbstractRepository
,以及CrudRepository
,最后呢有一个ServiceImpl
继承了CrudRepository
还实现了IService
接口。是不是听晕了,没关系,我们挨个来看下。
IRepository
IRepository
作为顶层接口,它实现了增删改查里面的比较基础的方法,比如save
,deleteById
等,但是涉及到批量操作的或者需要一些逻辑判断的是交给实现类去实现的。如下图所示在IRepository
接口中只实现了save
方法,但是save
方法的getBaseMapper
也没有实现,也就是说getBaseMapper
也是需要实现类去定义逻辑的。
/*** 插入一条记录(选择字段,策略插入)** @param entity 实体对象*/default boolean save(T entity) {return SqlHelper.retBool(getBaseMapper().insert(entity));}/*** 插入(批量)** @param entityList 实体对象集合* @param batchSize 插入批次数量*/boolean saveBatch(Collection<T> entityList, int batchSize);/*** 批量修改插入** @param entityList 实体对象集合* @param batchSize 每次的数量*/boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);...省略其他方法.../*** 获取对应 entity 的 BaseMapper** @return BaseMapper*/BaseMapper<T> getBaseMapper();
AbstractRepository
AbstractRepository
作为抽象类,在IRepository
的基础上填充了不少的方法逻辑,比如批量操作的一些方法,还有saveOrUpdate
以及getOne
这类的方法也是在AbstractRepository
中实现的,从这一点可以看出来,作者设计的时候把IRepository
作为绝对的顶层接口,只实现非常简单单一的增删改查。
...省略其他方法...
@Override
public boolean saveOrUpdate(T entity) {return getBaseMapper().insertOrUpdate(entity);
}@Override
public T getOne(Wrapper<T> queryWrapper, boolean throwEx) {return getBaseMapper().selectOne(queryWrapper, throwEx);
}
CrudRepository
CrudRepository
最重要的点,就是在这个类里面实现了getBaseMapper
,也就意味着之前IRepository
和AbstractRepository
一直缺少的BaseMapper
,终于有了,就是相当于之前都是定义了一些逻辑和规则,但缺少真正的引擎啊,好了,CrudRepository
是真真正正的能执行的个体了。
/*** IService 实现类( 泛型:M 是 mapper 对象,T 是实体 )** @author hubin* @since 2018-06-23*/
public abstract class CrudRepository<M extends BaseMapper<T>, T> extends AbstractRepository<M, T> {@Autowiredprotected M baseMapper;@Overridepublic M getBaseMapper() {Assert.notNull(this.baseMapper, "baseMapper can not be null");return this.baseMapper;}...省略其他方法...
}
IService
好了,我们再看下IService
这个接口的意义是什么,我们之前已经看到了从IRepository
一直到CrudRepository
,这之间从单一的增删改查到批量操作以至最后的装上引擎,这已经够了啊,那IService
是干什么的呢?
IService
中只定义了下面这四个方法,都是关于批量操作的,但是方法内的逻辑还是直接调用了IRepository
的对应方法,唯一的区别就是他把这四个方法都加上了事务注解,这也就是这个接口为什么叫做IService
的原因,这是真正贴合实际开发中需要的MVC
三层架构中Service
服务的接口,他对于批量的操作进行了事务控制,正如咱们平时开发的时候需要在Service
类中加事务注解一样,从这可以看出MybatisPlus
的作者在类的设计上还是很讲究的奥。
public interface IService<T> extends IRepository<T> {/*** 插入(批量)** @param entityList 实体对象集合*/@Transactional(rollbackFor = Exception.class)default boolean saveBatch(Collection<T> entityList) {return saveBatch(entityList, DEFAULT_BATCH_SIZE);}/*** 批量修改插入** @param entityList 实体对象集合*/@Transactional(rollbackFor = Exception.class)default boolean saveOrUpdateBatch(Collection<T> entityList) {return saveOrUpdateBatch(entityList, DEFAULT_BATCH_SIZE);}/*** 批量删除(jdbc批量提交)** @param list 主键ID或实体列表(主键ID类型必须与实体类型字段保持一致)* @return 删除结果* @since 3.5.0*/@Transactional(rollbackFor = Exception.class)default boolean removeBatchByIds(Collection<?> list) {return removeByIds(list);}/*** 根据ID 批量更新** @param entityList 实体对象集合*/@Transactional(rollbackFor = Exception.class)default boolean updateBatchById(Collection<T> entityList) {return updateBatchById(entityList, DEFAULT_BATCH_SIZE);}
}
ServiceImpl
好了,轮到最后的重头戏了,就是ServiceImpl
类,这个类没有任何的方法,但是他继承了CrudRepository
并且实现了IService
接口,从这个类的定位来说,首先他实现IService
接口,证明他是用于提供Service服务层级的实现类,然后继承CrudRepository
呢,是为了获取CrudRepository
中一些已经实现的功能。话说是不是有个什么设计模式和这很像来着??
/*** IService 实现类( 泛型:M 是 mapper 对象,T 是实体 )** @author hubin* @since 2018-06-23*/
public class ServiceImpl<M extends BaseMapper<T>, T> extends CrudRepository<M, T> implements IService<T> {}
什么设计模式和这很像来着??**
/*** IService 实现类( 泛型:M 是 mapper 对象,T 是实体 )** @author hubin* @since 2018-06-23*/
public class ServiceImpl<M extends BaseMapper<T>, T> extends CrudRepository<M, T> implements IService<T> {}
好了,朋友们,今天先讲到这里吧。想必经过今天的讲解大家对IService这个接口的理解更加深了吧,我们下周再会!