目前mybatis-plus事实上成为国内ORM框架的标准,开箱即用,中文支持,社区活跃度高,丰富的代码注释。适合中国人的习惯。
# mybatis-plus优点 | Advantages
# 优点 | Advantages
- **无侵入**:Mybatis-Plus 在 Mybatis 的基础上进行扩展,只做增强不做改变,引入 Mybatis-Plus 不会对您现有的 Mybatis 构架产生任何影响,而且 MP 支持所有 Mybatis 原生的特性
- **依赖少**:仅仅依赖 Mybatis 以及 Mybatis-Spring
- **损耗小**:启动即会自动注入基本CURD,性能基本无损耗,直接面向对象操作
- **通用CRUD操作**:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
- **多种主键策略**:支持多达4种主键策略(内含分布式唯一ID生成器),可*配置,完美解决主键问题
- **支持ActiveRecord**:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可实现基本 CRUD 操作
- **支持代码生成**:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用(. 比 Mybatis 官方的 Generator 更加强大!)
- **支持自定义全局通用操作**:支持全局通用方法注入( Write once, use anywhere )
- **内置分页插件**:基于Mybatis物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于写基本List查询
- **内置性能分析插件**:可输出Sql语句以及其执行时间,建议开发测试时启用该功能,能有效解决慢查询
- **内置全局拦截插件**:提供全表 delete 、 update 操作智能分析阻断,预防误操作
MybatisPlus 支持 SQL 方法
/**
* MybatisPlus 支持 SQL 方法
*
* @author hubin
* @since 2016-01-23
*/
public enum SqlMethod {
/**
* 插入
*/
INSERT_ONE("insert", "插入一条数据(选择字段插入)", "<script>\nINSERT INTO %s %s VALUES %s\n</script>"),
UPSERT_ONE("upsert", "Phoenix插入一条数据(选择字段插入)", "<script>\nUPSERT INTO %s %s VALUES %s\n</script>"),
/**
* 删除
*/
DELETE_BY_ID("deleteById", "根据ID 删除一条数据", "<script>\nDELETE FROM %s WHERE %s=#{%s}\n</script>"),
DELETE_BY_MAP("deleteByMap", "根据columnMap 条件删除记录", "<script>\nDELETE FROM %s %s\n</script>"),
DELETE("delete", "根据 entity 条件删除记录", "<script>\nDELETE FROM %s %s %s\n</script>"),
DELETE_BATCH_BY_IDS("deleteBatchIds", "根据ID集合,批量删除数据", "<script>\nDELETE FROM %s WHERE %s IN (%s)\n</script>"),
/**
* 逻辑删除
*/
LOGIC_DELETE_BY_ID("deleteById", "根据ID 逻辑删除一条数据", "<script>\nUPDATE %s %s WHERE %s=#{%s} %s\n</script>"),
LOGIC_DELETE_BY_MAP("deleteByMap", "根据columnMap 条件逻辑删除记录", "<script>\nUPDATE %s %s %s\n</script>"),
LOGIC_DELETE("delete", "根据 entity 条件逻辑删除记录", "<script>\nUPDATE %s %s %s %s\n</script>"),
LOGIC_DELETE_BATCH_BY_IDS("deleteBatchIds", "根据ID集合,批量逻辑删除数据", "<script>\nUPDATE %s %s WHERE %s IN (%s) %s\n</script>"),
/**
* 修改
*/
UPDATE_BY_ID("updateById", "根据ID 选择修改数据", "<script>\nUPDATE %s %s WHERE %s=#{%s} %s\n</script>"),
UPDATE("update", "根据 whereEntity 条件,更新记录", "<script>\nUPDATE %s %s %s %s\n</script>"),
/**
* 逻辑删除 -> 修改
*/
LOGIC_UPDATE_BY_ID("updateById", "根据ID 修改数据", "<script>\nUPDATE %s %s WHERE %s=#{%s} %s\n</script>"),
/**
* 查询
*/
SELECT_BY_ID("selectById", "根据ID 查询一条数据", "SELECT %s FROM %s WHERE %s=#{%s} %s"),
SELECT_BY_MAP("selectByMap", "根据columnMap 查询一条数据", "<script>SELECT %s FROM %s %s\n</script>"),
SELECT_BATCH_BY_IDS("selectBatchIds", "根据ID集合,批量查询数据", "<script>SELECT %s FROM %s WHERE %s IN (%s) %s </script>"),
@Deprecated
SELECT_ONE("selectOne", "查询满足条件一条数据", "<script>%s SELECT %s FROM %s %s %s\n</script>"),
SELECT_COUNT("selectCount", "查询满足条件总记录数", "<script>%s SELECT COUNT(%s) AS total FROM %s %s %s\n</script>"),
SELECT_LIST("selectList", "查询满足条件所有数据", "<script>%s SELECT %s FROM %s %s %s %s\n</script>"),
SELECT_PAGE("selectPage", "查询满足条件所有数据(并翻页)", "<script>%s SELECT %s FROM %s %s %s %s\n</script>"),
SELECT_MAPS("selectMaps", "查询满足条件所有数据", "<script>%s SELECT %s FROM %s %s %s %s\n</script>"),
SELECT_MAPS_PAGE("selectMapsPage", "查询满足条件所有数据(并翻页)", "<script>\n %s SELECT %s FROM %s %s %s %s\n</script>"),
SELECT_OBJS("selectObjs", "查询满足条件所有数据", "<script>%s SELECT %s FROM %s %s %s %s\n</script>");
private final String method;
private final String desc;
private final String sql;
SqlMethod(String method, String desc, String sql) {
= method;
= desc;
= sql;
}
public String getMethod() {
return method;
}
public String getDesc() {
return desc;
}
public String getSql() {
return sql;
}
}
核心的BaseMapper,继承Mapper接口
/**
* Mapper 继承该接口后,无需编写 文件,即可获得CRUD功能
* <p>这个 Mapper 支持 id 泛型</p>
*
* @author hubin
* @since 2016-01-23
*/
public interface BaseMapper<T> extends Mapper<T> {
/**
* 插入一条记录
*
* @param entity 实体对象
*/
int insert(T entity);
/**
* 根据 ID 删除
*
* @param id 主键ID
*/
int deleteById(Serializable id);
/**
* 根据实体(ID)删除
*
* @param entity 实体对象
* @since 3.4.4
*/
int deleteById(T entity);
/**
* 根据 columnMap 条件,删除记录
*
* @param columnMap 表字段 map 对象
*/
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
/**
* 根据 entity 条件,删除记录
*
* @param queryWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
*/
int delete(@Param() Wrapper<T> queryWrapper);
/**
* 删除(根据ID或实体 批量删除)
*
* @param idList 主键ID列表或实体列表(不能为 null 以及 empty)
*/
int deleteBatchIds(@Param() Collection<?> idList);
/**
* 根据 ID 修改
*
* @param entity 实体对象
*/
int updateById(@Param() T entity);
/**
* 根据 whereEntity 条件,更新记录
*
* @param entity 实体对象 (set 条件值,可以为 null)
* @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
*/
int update(@Param() T entity, @Param() Wrapper<T> updateWrapper);
/**
* 根据 ID 查询
*
* @param id 主键ID
*/
T selectById(Serializable id);
/**
* 查询(根据ID 批量查询)
*
* @param idList 主键ID列表(不能为 null 以及 empty)
*/
List<T> selectBatchIds(@Param() Collection<? extends Serializable> idList);
/**
* 查询(根据 columnMap 条件)
*
* @param columnMap 表字段 map 对象
*/
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
/**
* 根据 entity 条件,查询一条记录
* <p>查询一条记录,例如 ("limit 1") 限制取一条记录, 注意:多条数据会报异常</p>
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
default T selectOne(@Param() Wrapper<T> queryWrapper) {
List<T> list = (queryWrapper);
// 抄自 DefaultSqlSession#selectOne
if (() == 1) {
return (0);
} else if (() > 1) {
throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + ());
} else {
return null;
}
}
/**
* 根据 Wrapper 条件,判断是否存在记录
*
* @param queryWrapper 实体对象封装操作类
* @return 是否存在记录
*/
default boolean exists(Wrapper<T> queryWrapper) {
Long count = (queryWrapper);
return null != count && count > 0;
}
/**
* 根据 Wrapper 条件,查询总记录数
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
Long selectCount(@Param() Wrapper<T> queryWrapper);
/**
* 根据 entity 条件,查询全部记录
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List<T> selectList(@Param() Wrapper<T> queryWrapper);
/**
* 根据 Wrapper 条件,查询全部记录
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List<Map<String, Object>> selectMaps(@Param() Wrapper<T> queryWrapper);
/**
* 根据 Wrapper 条件,查询全部记录
* <p>注意: 只返回第一个字段的值</p>
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List<Object> selectObjs(@Param() Wrapper<T> queryWrapper);
/**
* 根据 entity 条件,查询全部记录(并翻页)
*
* @param page 分页查询条件(可以为 )
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
<P extends IPage<T>> P selectPage(P page, @Param() Wrapper<T> queryWrapper);
/**
* 根据 Wrapper 条件,查询全部记录(并翻页)
*
* @param page 分页查询条件
* @param queryWrapper 实体对象封装操作类
*/
<P extends IPage<Map<String, Object>>> P selectMapsPage(P page, @Param() Wrapper<T> queryWrapper);
}
MybatisPlusAutoConfiguration的sqlSessionFactory方法
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
// TODO 使用 MybatisSqlSessionFactoryBean 而不是 SqlSessionFactoryBean
MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
(dataSource);
();
if ((())) {
((()));
}
applyConfiguration(factory);
if (() != null) {
(());
}
if (!()) {
();
}
if ( != null) {
();
}
if ((())) {
(());
}
if (() != null) {
(());
}
if ((())) {
(());
}
if (!()) {
();
}
if (!(())) {
(());
}
// TODO 修改源码支持定义 TransactionFactory
(, factory::setTransactionFactory);
// TODO 对源码做了一定的修改(因为源码适配了老旧的mybatis版本,但我们不需要适配)
Class<? extends LanguageDriver> defaultLanguageDriver = ();
if (!()) {
();
}
(defaultLanguageDriver).ifPresent(factory::setDefaultScriptingLanguageDriver);
applySqlSessionFactoryBeanCustomizers(factory);
// TODO 此处必为非 NULL
GlobalConfig globalConfig = ();
// TODO 注入填充器
(, globalConfig::setMetaObjectHandler);
// TODO 注入参与器
(, globalConfig::setPostInitTableInfoHandler);
// TODO 注入主键生成器
(, i -> ().setKeyGenerators(i));
// TODO 注入sql注入器
(, globalConfig::setSqlInjector);
// TODO 注入ID生成器
(, globalConfig::setIdentifierGenerator);
// TODO 设置 GlobalConfig 到 MybatisSqlSessionFactoryBean
(globalConfig);
return ();
}
sql保留关键字
/**
* SQL 保留关键字枚举
*
* @author hubin
* @since 2018-05-28
*/
@AllArgsConstructor
public enum SqlKeyword implements ISqlSegment {
AND("AND"),
OR("OR"),
NOT("NOT"),
IN("IN"),
NOT_IN("NOT IN"),
LIKE("LIKE"),
NOT_LIKE("NOT LIKE"),
EQ(),
NE("<>"),
GT(StringPool.RIGHT_CHEV),
GE(">="),
LT(StringPool.LEFT_CHEV),
LE("<="),
IS_NULL("IS NULL"),
IS_NOT_NULL("IS NOT NULL"),
GROUP_BY("GROUP BY"),
HAVING("HAVING"),
ORDER_BY("ORDER BY"),
EXISTS("EXISTS"),
NOT_EXISTS("NOT EXISTS"),
BETWEEN("BETWEEN"),
NOT_BETWEEN("NOT BETWEEN"),
ASC("ASC"),
DESC("DESC");
private final String keyword;
@Override
public String getSqlSegment() {
return ;
}
}
一个SqlSessionFactory 测试类
@SpringBootApplication
public class ApplicationTestStartSuccess {
public static void main(String[] args) {
ConfigurableApplicationContext context = (, args);
SqlSessionFactory bean = ();
Configuration configuration = ();
GlobalConfig config = (configuration);
assertThat(()).isNotNull();
}
}
深刻阅读源代码对理解框架有好处,对开发也有帮助。