mybatis-mapper

Mybatis generic mapper plugin for solving most basic operations, simplifying sql syntax and improving dynamic execution efficiency

License

License

Categories

Categories

MyBatis Data ORM
GroupId

GroupId

com.viiyue.plugins
ArtifactId

ArtifactId

mybatis-mapper
Last Version

Last Version

1.3.6
Release Date

Release Date

Type

Type

jar
Description

Description

mybatis-mapper
Mybatis generic mapper plugin for solving most basic operations, simplifying sql syntax and improving dynamic execution efficiency
Project URL

Project URL

https://github.com/tangxbai/mybatis-mapper
Source Code Management

Source Code Management

https://github.com/tangxbai/mybatis-mapper.git

Download mybatis-mapper

How to add to project

<!-- https://jarcasting.com/artifacts/com.viiyue.plugins/mybatis-mapper/ -->
<dependency>
    <groupId>com.viiyue.plugins</groupId>
    <artifactId>mybatis-mapper</artifactId>
    <version>1.3.6</version>
</dependency>
// https://jarcasting.com/artifacts/com.viiyue.plugins/mybatis-mapper/
implementation 'com.viiyue.plugins:mybatis-mapper:1.3.6'
// https://jarcasting.com/artifacts/com.viiyue.plugins/mybatis-mapper/
implementation ("com.viiyue.plugins:mybatis-mapper:1.3.6")
'com.viiyue.plugins:mybatis-mapper:jar:1.3.6'
<dependency org="com.viiyue.plugins" name="mybatis-mapper" rev="1.3.6">
  <artifact name="mybatis-mapper" type="jar" />
</dependency>
@Grapes(
@Grab(group='com.viiyue.plugins', module='mybatis-mapper', version='1.3.6')
)
libraryDependencies += "com.viiyue.plugins" % "mybatis-mapper" % "1.3.6"
[com.viiyue.plugins/mybatis-mapper "1.3.6"]

Dependencies

compile (4)

Group / Artifact Type Version
org.mybatis : mybatis jar 3.5.0
mysql : mysql-connector-java jar 8.0.16
org.apache.commons : commons-lang3 jar 3.8
org.eweb4j : fel jar 0.8

Project Modules

There are no modules declared in this project.

MybatisMapper

mybatis-mapper maven central size license

项目简介

Mybatis通用Mapper插件,用于解决大多数基础CRUD,简化sql语法并提高动态执行效率,拥有更丰富的Api。用最少的配置,提供一个健全的使用体系。

注意:此项目是一款完全开源的项目,您可以在任何适用的场景使用它,商用或者学习都可以,如果您有任何项目上的疑问,可以在issue上提出您问题,我会在第一时间回复您,如果您觉得它对您有些许帮助,希望能留下一个您的星星(★),谢谢。


此项目遵照 Apache 2.0 License 开源许可

技术讨论QQ群:947460272

核心亮点

  • 无侵入:100%兼容mybatis,不与mybatis冲突,只添加功能,对现有程序无任何影响;
  • 配置少:所有配置均在原始mybatis的基础上读取,不增加额外配置消耗;
  • 无捆绑关系:与XML文件独立,有无独立XML均可;
  • 效率高:由Xml+OGNL模式转向Java+ExpressionEngine的模式,省去了XML的解析和OGNL解析的时间消耗;
  • 灵活的规则制定:灵活多元化的(表/列)规则制定,完美融合各种(名字/类型等)不统一的场景;
  • SQL模板语法:模板语法简单易掌握,一次开发,终生受用,避免因数据库变化而大量更改SQL语句的场景。表达式会在程序完全启动之前编译成完整的SQL,仅留下需要动态解析的表达式,对效率的影响微乎甚微;
  • CRUD增强:除了提供基础的CRUD外还提供一系列高级辅助方法(Example/ForUpdate/聚合函数/逻辑删除/回收站/乐观锁等);
  • 便捷的条件查询:更简单便捷的Example条件查询,提供符合SQL语义化的链式条件函数调用;
  • 支持多主键:支持多主键场景,CRUD中可选择特定主键进行操作;
  • 丰富的主键生成策略:支持JDBC自增主键、自定义主键SQL查询、雪花ID、UUID、自定义主键生成策略等;
  • 支持常量值:灵活化的常量值生成策略,可针对不同场景做不同操作,均支持雪花ID/UUID等内置生成器;
  • 可排序字段:可对SQL字段排列顺序进行干扰,简直是强迫症重度患者的福音啊;
  • 粘连性小:可以独立使用,纯Java环境/spring/springboot都提供了单独的组件。
  • 可扩展的开发模式:继承Marker/Mapper/BaseMapper即可继续增强基础CRUD。

关联文档

关于整合spring,请移步到:https://github.com/tangxbai/mybatis-mapper-spring

关于整合springboot,请移步到:https://github.com/tangxbai/mybatis-mapper-spring-boot

项目演示

功能列表

快速开始

Maven方式(推荐

<dependency>
	<groupId>com.viiyue.plugins</groupId>
	<artifactId>mybatis-mapper</artifactId>
	<version>[VERSION]</version>
</dependency>

如果你没有使用Maven构建工具,那么可以通过以下途径下载相关jar包,并导入到你的编辑器。

点击跳转下载页面

如何下载

如何获取最新版本?点击这里获取最新版本

如何使用

1、配置 mybatis.xml

这个文件具体如何配置不作过多说明,你可以拉取相关demo查看详细配置,在配置上也没有什么区别,需要注意的是 typeAliases(实体别名配置)一定要配置,不然插件可能无法正常工作。

2、配置数据库实体Bean

@Table( prefix = "t_" ) // 表名生成规则,可以配置更多详细说明
@NamingRule( NameStyle.UNDERLINE ) // 字段和数据库列之间的转换规则
@ValueRule( ValueStyle.SHORT ) // 值的生成规则,类似于:#{id}
@ExpressionRule( ExpressionStyle.SHORT ) // 表达式生成规则,类似于: id = #{id}
@DefaultOrderBy( "#pk" ) // #默认排序字段,"pk"为主键占位符,指向当前生效的主键字段,也可以直接写"id"
public class YourModelBean {

    @Id // 主键可以配置多个,但是只会有一个生效,Api方法中如果想要使用其他主键请指明所在下标位置
    @Index( Integer.MIN_VALUE )
    @GeneratedKey( useGeneratedKeys = true ) // JDBC支持的自增主键获取方式
    // @GeneratedKey( valueProvider = SnowFlakeIdValueProvider.class ) // 雪花Id,插件提供的两种主键生成策略之一
    // @GeneratedKey( statement = "MYSQL" ) // 枚举引用
    // @GeneratedKey( statement = "SELECT LAST_INSERT_ID()" ) // 自增主键SQL查询语句
    // @GeneratedKey( statementProvider = YourCustomStatementProvider.class ) // 通过Provider提供SQL语句
    private Long id;

    @Index( Integer.MAX_VALUE - 4 )
    @Column( jdcbType = Type.CHAR ) // 对字段进行详细描述
    @LogicallyDelete( selectValue = "Y", deletedValue = "N" ) // 开启逻辑删除支持,只能配置一次
    private Boolean display;

    @Index( Integer.MAX_VALUE - 3 )
    private Date createTime;

    @Index( Integer.MAX_VALUE - 2 )
    private Date modifyTime;

    @Version // 开启乐观锁支持,只能配置一次
    @Index( Integer.MAX_VALUE - 1 )
    @Column( insertable = false )
    private Long version;
    
    // setter/getter...
    
    // ----------------------------------------------------------------
    // @Index主要对字段出现顺序进行干扰,对字段进行干扰以后,输出的顺序大概是这样:
    // => id, ..., display, create_time, modify_time, version
    // 如果您未使用@Index注解,那么字段的原始顺序是这样的:
    // => id, display, create_time, modify_time, version, ...
    // 默认输出会将父类的字段排在最前面
    // ----------------------------------------------------------------  

}

3、Mapper接口需要继承 BaseMapper 或者 Mapper

// 继承Mapper
public interface YourMapper extends Mapper<YourModelBean, YourModelBeanDTO, Long> {
}
// 或者继承BaseMapper
public interface YourMapper extends BaseMapper<YourModelBean, YourModelBeanDTO, Long> {
}

4、使用方式

SqlSessionFactory factory = new MyBatisMapperFactoryBuilder().build( Resources.getResourceAsStream("your-mybatis.xml"));
SqlSession session = factory.openSession();
YourMapper mapper = session.getMapper(YourMapper.class);
mapper.xxx(...);
session.commit();

请注意:MyBatisMapperFactoryBuilder 是插件提供的一个 SqlSessionFactory 工厂构造器,这里我们需要用插件提供的MyBatisMapperFactoryBuilder替换mybatis原始的 SqlSessionFactoryBuilder 以启用插件相关Api功能。

配置注解

类型 注解 描述
类注解 @Table 配置表名生成规则
@ResultMap 自定义ResultMap,默认使用BaseResultMap
@Excludes 排除不需要的字段属性,一般用于子类排除父类某字段的场景
@DefaultOrderBy 默认排序字段,#pk内置占位符,隐式地指向当前生效的主键
规则注解 @NamingRule 配置字段名和数据库列的转换规则
@ValueRule 配置值的生成规则,类似:#{id, ...}
@ExpressionRule 配置表达式的生成规则,类似:id = #{id, ...}
以上两种类型的注解都只能配置在类上,主要用于描述数据库实体Bean的一些基础信息,通常建议配置在父类上,进而避免大量重复代码的产生。
成员注解 @Id 主键标识,默认使用第一个标注字段,否则使用primary为true的字段作为主键
@Index 干扰字段的排列顺序,默认按照Bean定义的顺序从父类到子类排列
@Column 显式地配置字段和数据库列的规则说明
@GeneratedKey 主键生成策略,必须和@Id组合使用,否则无效,且只能出现一次
@GeneratedValue 生成常量值,插件提供 SnowFlakeId/UUID,可自行拓展
@Conditional 条件表达式,默认使用 = 桥接前后条件,可更改条件规则
@LogicallyDelete 启用逻辑删除,只能出现一次
@Version 启用乐观锁,只能出现一次
成员注解主要是对实体字段的一些描述
标识注解 @EnableResultMap 标注在Mapper方法上,是否使用ResultMap结果映射
@Reference 标注在Mapper方法上,指向@XXXProvider(type)的其他非同名方法
标识注解主要用于扩展插件Api的时候用的场景多一些,你也可以在自己的Mapper上使用默认的ResultMap,申明一下即可。

偏好配置

属性说明

属性 描述 类型 默认
enableLogger 是否启用日志 Boolean true
enableMapperScanLog 是否开启Mapper扫描日志 Boolean true
enableRuntimeLog 是否开启实时日志 Boolean true
enableCompilationLog 是否开启编译日志 Boolean true
enableKeywordsToUppercase 关键字大小写转换 Boolean false
databaseColumnStyle 数据库列样式 String #

特别说明# 是一个占位符,代表据数据库中的列名,比如mysql中默认列使用 `column`,那么你可以这样配置 `#`,默认是没有任何样式修饰符的。

-- 默认样式 - #
select id, name, age, weight from ... where ...
-- Mysql样式 - `#`
select `id`, `name`, `age`, `weight` from ... where ...
-- Oracle - [#]
select [id], [name], [age], [weight] from ... where ...
-- 自定义样式 - L-#-R
select L-id-R, L-name-R, L-age-R, L-weight-R from ... where ...

配置方式

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <properties resource="jdbc.properties">
        <property name="enableLogger" value="true"/>
        <property name="enableRuntimeLog" value="true"/>
        <property name="enableCompilationLog" value="true"/>
        <property name="enableMapperScanLog" value="true"/>
        <property name="enableKeywordsToUppercase" value="true"/>
        <property name="databaseColumnStyle" value="`#`"/>
    </properties>
</configuration>

支持模板语法

以下是目前已经支持的模板语法,你可以在自定义 DynamicProvider 中无条件的使用它们,也可以开启XML模板语法支持并使用它。

  • @{expression} - 静态模板,会在程序启动过程中被解析成完整的文本。
  • %{expression} - 动态模板,会在SQL执行过程被解析成完整的文本,类似mybatis判断条件。
  • [kewords] - 关键字模板,会根据配置自动转换成大写或小写关键字。
  • {{value.expression}} - 取值表达式,可以获取执行方法的传入参数或程序上下文数据。
  • <error>message</error> - 错误信息,用于隐藏错误信息,不影响程序启动,但会在执行过程中抛出。

关于this关键字

可能你会在模板看到 this 字样的关键字,这个关键字默认指向当前Mapper对应的数据库Bean的 解析对象,如果你想在模板语法中使用其他Bean解析对象的话,请使用Mybatis提供的 类对象别名 进行调用,这将会类似于 @{this.table} 或者 @{user.table}/@{role.table}/@{xxx.table} 等。

this = EntityParser.getEntity(Bean.class);

特别说明

首先,插件分两部分,默认是不支持XML模板语法解析的,所以可以根据个人喜好,选择开启或者不使用它,插件的运行和XML没太大关系,基础功能是基于Mybatis内部的 @SelectProvider@UpdateProvider@InsertProvider@DeleteProvider 注解提供运行所需的 SqlSource,所以即使无任何XML文件也可正常工作,因为都是对单表的扩展Api,所以如果涉及一些任何复杂SQL,请添加XML文件并书写自己的SQL逻辑脚本。

开启XML模板语法

如果你需要在XML也使用这些模板语法,请配置解析XML的扩展 LanguageDriver,插件提供的扩展Driver是 MyBatisMapperLanguageDriver,Mybatis的LanguageDriver接口无任何限制,任何人都可以对其进行自定义更改,属于Mybatis的一种扩展机制,具体使用的话,可以在单个XML语句节点上配置 lang 属性来开启单个Statement支持,也可以覆盖Mybatis的默认 XMLLanguageDriver 解析驱动。

1、单个语句块,使用lang属性即可

<select id="xxx" lang="com.viiyue.plugins.mybatis.MyBatisMapperLanguageDriver">
    [select] @{this.columns} 
    [from] @{this.table} 
    [where] @{this.column.yourFieldName} = #{yourFieldName}
</select>

2、全局范围,需要覆盖mybatis默认语言驱动

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <settings>
        <setting name="defaultScriptingLanguage" value="com.viiyue.plugins.mybatis.MyBatisMapperLanguageDriver"/>
    </settings>
</configuration>

3、DynamicProvider无条件支持任何模板语法

public final class YourCustomProvider extends DynamicProvider {
    // 实现一
    // 方法名必须和你接口中定义的方法名一致
    public String selectAll( MappedStatement ms ) {
        return "[select] @{this.columns} [from] @{this.table}";
    }
    
    // 实现二
    // 两个参数,第二个为当前对应的Mapper数据库实体Class类型
    public String selectAll( MappedStatement ms, Class<?> yourModelBeanType ) {
        System.out.println(yourModelBeanType);
        return "[select] @{this.columns} [from] @{this.table}";
    }
}

接下来对每一种模板语法作一些详细说明,方便大家能更好的理解并熟练的使用它们。现在假设当前Mapper是下面这样的,那么 this 关键字会指向 User的解析对象,将从其中获取各种元数据信息。

// DO
// 省略各种注解配置
public class User {
    private Long id;
    private String name;
    private Integer age;
}

// Mapper
public interface UserMapper extends Mapper<User, UserDTO, Long> { 
}

// DO → User
// DTO → UserDTO
// PK → Long
// this → EntityParser.getEntity(User.class);

@{expression} - 静态模板

-- 关于表
-- @see com.viiyue.plugins.mybatis.template.builder.TableBuilder
@{this.table} → t_user
@{this.table.prefix("xxx")} → xxx.t_user
@{this.table.alias("t")} → t_user as 't'
@{this.table.prefix("xxx").alias("t")} → xxx.t_user as 't'

-- 关于单列
-- @see com.viiyue.plugins.mybatis.template.builder.ColumnBuilder
@{this.column.yourFieldName} → your_field_name
@{this.column.yourFieldName.prefix("a")} → a.your_field_name
@{this.column.yourFieldName.suffix("_suffix")} → your_field_name_suffix
@{this.column.yourFieldName.javaType} → Integer/Long/YourFieldType
@{this.column.yourFieldName.jdbcType} → INT/BIGINT/OTHERS
@{this.column.yourFieldName.property} → yourFieldName
@{this.column.yourFieldName.prefix("a").suffix("_suffix")} → a.your_field_name_suffix

-- 关于所有列
-- @see com.viiyue.plugins.mybatis.template.builder.ColumnsBuilder
@{this.columns} → id, name, age
@{this.columns.include("id,name")} → id, name
@{this.columns.exclude("id,age")} → name
@{this.columns.prefix("t")} → t.id, t.name, t.age
@{this.columns.prefix("t").include("id,name").exclude("id")} → t.name

-- 关于值
-- @see com.viiyue.plugins.mybatis.template.builder.ValuesBuilder
@{this.values} → #{id}, #{name}, #{age}
@{this.values.alias("user")} → #{user.id}, #{user.name}, #{user.age}
@{this.values.include("id,name")} → #{id}, #{name}
@{this.values.exclude("id,age")} → #{name}
@{this.values.alias("user").include("name,age")} → #{user.name}, #{user.age}

-- 关于默认排序(需要在类上配置@DefaultOrderBy)
-- 没有配置相关注解的话,表达式返回一段空白文本("")
-- @see com.viiyue.plugins.mybatis.template.builder.LogicallyDeleteBuilder
@{this.defaultOrderBy} → order by sorter desc
@{this.defaultOrderBy.desc} → order by sorter desc
@{this.defaultOrderBy.asc} → order by sorter asc
@{this.defaultOrderBy.prefix("t")} → order by t.sorter desc

-- 关于逻辑删除(需要在字段上配置@LogicallyDelete)
-- 没有配置相关注解的话,表达式返回一段空白文本("")
-- @see com.viiyue.plugins.mybatis.template.builder.LogicallyDeleteBuilder
@{this.tryLogicallyDelete} → deleted = 'N'
@{this.tryLogicallyDelete.prefix("t")} → t.deleted = 'N'
@{this.tryLogicallyDelete.useWhereQuery} → where deleted = 'N'
@{this.tryLogicallyDelete.useAndQuery} → and deleted = 'N'
@{this.tryLogicallyDelete.useOrQuery} → or deleted = 'N'
@{this.tryLogicallyDelete.useQueryValue} → or deleted = 'Y'
@{this.tryLogicallyDelete.useDeletedValue} → or deleted = 'N'

-- 关于乐观锁(需要在类上配置@Version)
-- 没有配置相关注解的话,表达式返回一段空白文本("")
-- @see com.viiyue.plugins.mybatis.template.builder.OptimisticLockBuilder
@{this.tryOptimisticLock} → version = #{version}
@{this.tryOptimisticLock.prefix("t")} → t.version = #{version}
@{this.tryOptimisticLock.useWhere} → where version = #{version}
@{this.tryOptimisticLock.useAnd} → and version = #{version}
@{this.tryOptimisticLock.useOr} → or version = #{version}

%{expression} - 动态模板

-- 关于列
-- $ 是当前传入的参数,如果单个参数,可以直接写 $ 符号,多参数使用 $.param 的形式。
-- 会筛选出Bean中所有non-null的属性,值得注意的是 @Column(nullable=true/false)
-- @see com.viiyue.plugins.mybatis.template.builder.ColumnBuilder
%{this.columns.dynamic($)} → id, name
%{this.columns.dynamic($).include("id,name")} → id, name
%{this.columns.dynamic($).exclude("id,age")} → name
%{this.columns.dynamic($).prefix("t")}t.id, t.name, t.age
%{this.columns.dynamic($).prefix("t").include("id,name").exclude("id")}t.name

-- 关于修改
-- 注意:如果开启了乐观锁的话,版本字段的取值不再和字段名一样,类似:next(?)Value
-- @see com.viiyue.plugins.mybatis.template.builder.UpdateSetBuilder
%{this.set} → id = #{id}, name = #{name}, version = #{nextVersionValue}
%{this.set.prefix("t")}t.id = #{id}, t.name = #{name}, t.age = #{age}
%{this.set.alias("user")} → id = #{user.id}, name = #{user.name}, age = #{user.age}
%{this.set.include("id,name")} → id = #{id}, name = #{name}
%{this.set.exclude("id,name")} → age = #{age}
%{this.set.dynamic($)} → name = #{name}
%{this.set.dynamic($.user).prefix("t").alias("user")}t.name = #{user.name}

-- 关于动态值
-- 构造器会自动筛选出所有non-null的属性,这里只是一个示例效果。
-- @see com.viiyue.plugins.mybatis.template.builder.ValuesBuilder
%{this.values.dynamic($)}#{id}, #{name}, #{age}
%{this.values.dynamic($).alias("user")}#{user.id}, #{user.name}, #{user.age}
%{this.values.dynamic($).include("id,name")}#{id}, #{name}
%{this.values.dynamic($).exclude("id,age")}#{name}
%{this.values.dynamic($).alias("u").include("name,age")}#{u.name}, #{u.age}

-- 关于Where条件
-- 构造器会自动筛选出所有non-null的属性,这里只是一个示例效果。
-- @see com.viiyue.plugins.mybatis.template.builder.WhereBuilder
%{this.where($)}where name = #{name} and age = #{age}
%{this.where($).prefix("t")}where t.name = #{name} and t.age = #{age}
%{this.where($).include("name")}where name = #{name}
%{this.where($).exclude("name")}where age = #{age}
%{this.where($).tryLogicallyDeleteQuery}where deleted = 'Y' and name = #{name}
%{this.where($).tryLogicallyDeleteQuery.useQueryValue}where deleted = 'Y' and name = #{name}
%{this.where($).tryLogicallyDeleteQuery.useDeletedValue}where deleted = 'N' and name = #{name}

[keywords] - 关键字转换

需要说明一下,如果不做偏好配置的话,插件默认全部转换为小写关键字,如果想使用大写关键字,请更改相关配置。

[select] * [from] t_user [where] name = #{name}
-- enableKeywordsToUppercase = true
SELECT * FROM t_user WHERE name = #{name}
-- enableKeywordsToUppercase = false / default
select * from t_user where name = #{name}

{{expression}} - 取值表达式

这种表达式主要是 Example 查询的时候用的相对多一些,其他情况你要使用也是可以的。此表达式不输出任何修饰符,大家使用的话记得添加修饰符,比如:引号。

-- Example
select {{$.example.columns}} from @{this.table} {{$.example.where}}

-- 获取系统值,表达式具体的值在运行时生效
-- 目前{{system.xxx}}仅支持下面四个属性
update @{this.table} set modify_time = {{system.now}} where ... -- Date
update @{this.table} set millis = {{system.systime}} where ... -- CurrentTimeMillis
update @{this.table} set order_code = '{{system.uuid}}' where ... -- UUID
update @{this.table} set sort_value = {{system.rundom.nexInt(5)}} where ... -- Number

-- 获取环境变量值,表达式具体的值在运行时生效
-- 更多属性调用请参照以下常量类的ENV_PROP_NAMES属性值
-- @see com.viiyue.plugins.mybatis.Constants#ENV_PROP_NAMES
insert into @{this.table} (name, text) values ('{{env.osName}', '{{env.osVersion}}')

<error>message</error> - 异常表达式

这种情况不要轻易写在SQL脚本中,如果你写在了自己的SQL脚本中,执行方法时会把标签内部的文本信息以 RuntimeException 的形式抛出来,目前也只是插件内部用来判断一些特殊情况时才会使用到。

回到顶部

支持SQL注释

众所周知,XML文件中的SQL脚本是不支持注释的,但是我们可以帮你实现在XML添加脚本注释,你可以直接从DB软件中整个复制过来,而不需要单独剔除你添加的注释,不要惊慌,多余的注释会在你程序启动过程中被移除掉,不会有任何效率上的影响,所以放心拥抱SQL注释吧。

<select id="xxx" resultMap="xxx">
    // 单行注释
    // 支持大小写关键字转换,凡是包裹在“[]”中的任何文本,都会被转换成全大写或全小写文本。
    [select]

    -- SQL注释
    -- 输出表的所有列
    -- 注意:注释不支持#注释,#会和mybatis的取值表达式冲突,所以不要使用#注释
    @{this.columns}
    [from]

    /* 单行文本注释 */
    /* 输出表名 */
    @{this.table} /* --- [where] --- */

    /**
     * 多行文本注释多行文本注释
     * 多行文本注释多行文本注释
     * 多行文本注释多行文本注释
     * 多行文本注释多行文本注释
     */

    // 所有程序通用的单行注释也是支持的
    // 内容可以直接写表达式,也可以结合mybatis的逻辑标签,没有任何限制。
    // @{this.column.loginName} = #{loginName}

    // 可以结合各种条件标签使用模板语法
    <trim prefix="[where]" prefixOverrides="and|AND">
        <if test="loginName != null">[and] @{this.column.xxx} = #{xxx}</if>
    </trim>

    <!-- 不影响原有XML注释 -->

    // 你也可以加入逻辑删除表达式
    @{this.tryLogicallyDelete.useAndQuery}
    
    // 或者使用乐观锁表达式
    @{this.tryOptimisticLock.useAndQuery}
</select>

回到顶部

支持各种主键生成策略

目前插件主要支持以下四种主键生成策略,使用 @Id 标识主键,然后使用 @GeneratedKey 对主键生成策略进行配置。

// 省略各种注解配置
public class YouBean {
    
    @Id
    // 1、使用JDBC的自增主键获取方式
    @GeneratedKey( useGeneratedKeys = true )
    
    // 2、直接生成主键值,插件提供两种默认主键值生成器(SnowFlakeId/UUID)
    // @GeneratedKey( valueProvider = SnowFlakeIdValueProvider.class )
    // @GeneratedKey( valueProvider = UUIDValuePrivoder.class )
    
    // 3、对于不支持JDBC获取自增主键值的数据库来说,可以像下面这样使用:
    // 具体参照com.viiyue.plugins.mybatis.enums.AutoIncrement里面的枚举值,
    // 里面预置了部分获取自增主键的SQL,可以直接写枚举名字,没有的话也可以自己写SQL脚本。
    // @GeneratedKey( statement = "MYSQL" ) // MYSQL是枚举名,通过枚举找到对应SQL脚本
    // @GeneratedKey( statement = "SELECT T_USER.YYYY()" ) // 直接写SQL脚本
    
    // 4、自定义自增主键SQL提供者
    // 如果枚举里面没有你需要的,可以通过statementProvider来提供你自己的SQL主键查询
    // @GeneratedKey( statementProvider = OracleAutoIncrementStatementProvider.class )
    private Long id;
    
}

// 自定义自增主键SQL脚本
public class OracleAutoIncrementStatementProvider implements AutoIncrementStatementProvider {
     @Override
     public String getAutoIncrementSqlStatement( GeneratedKeyInfo info ) {
         return "SELECT " + info.getTableName() + ".NEXTVAL FROM DUAL";
     }
}

回到顶部

支持多主键场景

Bean的定义

可以对多个主键字段进行 @Id 标注,没有特殊指明的话,默认会使用对象中第一个标注的主键,否则将会使用 @Id(primary=true) 的那一个主键。

// 省略各种注解配置
public class YouBean {

    @Id
    private Long id;

    @Id(primary = true)
    private Long id2;
    
}

使用上的区别

mapper.selectByPrimaryKey(PK); // 使用默认主键
mapper.selectByPrimaryKeyIndex(Index, PK); // 使用指定下标的主键,多主键顺序由实体Bean决定
mapper.selectByPrimaryKeyGroup(Pk...); // 使用默认主键
mapper.selectByPrimaryKeyGroupIndex(Index, PK...); // 使用指定下标的主键,多主键顺序由实体Bean决定

回到顶部

更方便快捷的条件查询

Example example = null;

// query
// 方法后面可以直接跟各种Where条件
example = Example.query(User.class).equal("id", 1L).lt("age", 60).xxx(...);

// select
// 该方法可以对列进行操作,条件筛选的话使用when()来桥接
example = Example.select(User.class).includes( "id", "loginName", "password" );
example.when().equal("id", 1L).lt("age", 60).xxx(...);

// update
// 使用set/values可以对单个字段进行设值,不支持乐观锁
example = Example.update(User.class).set(xx, yy, zz).values(XX, YY, ZZ);
example.when().equal("id", 1L).lt("age", 60).xxx(...);

// update
// 还可以绑定某个实体对象来修改
User user = null;
Example.update(User.class).bind(user).when().equal("id", 1L).xxx(...);

// 具体使用
mapper.selectByExample(example);
mapper.updateByExample(example);
mapper.deleteByExample(example);

回到顶部

支持聚合函数统计

Example example = null;

// 支持多字段统计,* 仅能在count函数中使用,其他函数使用会出现异常
example = Example.count(User.class, "*", ...); // 统计行数
example = Example.summation(User.class, "price", "num", ...); // 求和
example = Example.maximum(User.class, "price", "num", ...); // 求最大值
example = Example.minimum(User.class, "price", "num", ...); // 求最小值
example = Example.average(User.class, "price", "num", ...); // 求平均值

// 条件筛选
example.when().equal("id", 1L).lt("age", 60).xxx();

// 统计单个值,为了兼容不同的数据类型,统一使用BigDecimal接口,大家可自行转换成需要的数据类型
// 这种情况只能统计单列,如果统计多个字段,会出现SQL异常,此时请使用下面这种方式
BigDecimal result = mapper.selectStatisticByAggregateFunction(example);

// 统计多列,返回的是对应的实体对象,统计的字段值会自动封装到对象同名字段中
List<DTO> results = mapper.selectStatisticListByAggregateFunction(example);

回到顶部

支持数据库乐观锁

只需要在你的字段上标注 @Version 即可,乐观锁注解只能出现一次,默认为版本自增实现,数据类型支持 ShortIntegerLongTimestamp,还可以选择雪花版本值,甚至你可以自己实现版本值的获取,实现 NextVersionProvider 接口即可。

// 省略各种注解配置
public class User {
    @Version
    // 默认:DefaultNextVersionProvider.class
    // @Version(nextVersion = SnowFlakeIdNextVersionProvider.class)
    private Long version;
}

回到顶部

支持各种逻辑删除

逻辑删除需要配合 @LogicallyDelete 注解一起使用,如无任何注解配置,方法执行将会抛出异常,只可配置一次

// 逻辑删除所有
mapper.logicallyDeleteAll();

// 根据特定条件逻辑删除部分
mapper.logicallyDelete(Object);

// 通过主键逻辑删除指定数据
mapper.logicallyDeleteByPrimaryKey(PK);

// 通过主键数组逻辑删除特定数据
mapper.logicallyDeleteByPrimaryKeyGroup(Pk...);

// 多主键情况下,通过主键下标和主键值逻辑删除特定数据
mapper.logicallyDeleteByPrimaryKeyIndex(Integer, Pk);

// 多主键情况下,通过主键下标和主键数组逻辑删除特定数据
mapper.logicallyDeleteByPrimaryKeyIndexGroup(Index, Pk...);

// 通过自定义条件筛选逻辑删除特定数据
mapper.logicallyDeleteByExample(example);

回到顶部

支持逻辑删除数据的恢复

数据恢复也需要配合 @LogicallyDelete 注解一起使用,如无任何注解配置,方法执行将会抛出异常。

// 查询所有被逻辑删除过的数据
mapper.selectAllDeleted();

// 根据特定条件还原指定数据
mapper.restore(Object);

// 还原所有被逻辑删除过的数据
mapper.restoreAllDeleted();

// 通过主键还原指定Id的数据
mapper.restoreByPrimaryKey(Pk);

// 通过主键数组批量还原数据
mapper.restoreByPrimaryKeyGroup(PK...);

// 多主键的情况,通过指定主键下标和主键值还原特定数据
mapper.restoreByPrimaryKeyIndex(Integer, Pk);

// 多主键的情况,通过指定主键下标和主键数组还原特定数据
mapper.restoreByPrimaryKeyIndexGroup(Index, Pk...);

// 通过自定义条件筛选还原特定数据
mapper.restoreByExample(example);

回到顶部

支持查询自定义返回Bean类型

Mapper接口提供三个泛型参数,依次为<数据库实体类型,返回数据类型,主键类型>。对于返回数据类型你可以任意定义,但是 ResultMap 结果映射只会生成和 数据库实体 同名的匹配字段,其他不匹配的字段值将一直为 null

public class YourMapper extends Mapper<User, UserDTO, Long> {
    // 那么你的返回数据类型就是:UserDTO
}

回到顶部

支持零MapperXML配置文件

因为插件通过Mybatis的注解 @SelectProvider@UpdateProvider@InsertProvider@DeleteProvider 来提供基础 SqlSource ,所以即使你没有配置任何XML也是可以正常工作的。

回到顶部

扩展插件Api

Mybatis提供的注解SQL功能本身就是一种扩展机制,所以扩展就很好理解了,你可以写自己的@xxxProvider,也可以在插件的基础上实现 DynamicProvider 进而扩展插件的Api,这样的话你就可以在通用的Mapper上调用你自己的Api了。

接口定义,需要继承Marker

public interface Mapper<DO, DTO, PK extends Serializable> extends Marker<DO, DTO, PK> {
    @SelectProvider( type = YourProvider.class, method = DynamicProvider.dynamicSQL )
    List<DTO> selectCustomApi( @Param("param1") String param1, @Param("param2") String param2 );
}

具体实现,需要继承DynamicProvider

public final class YourProvider extends DynamicProvider {
    public String selectCustomApi( MappedStatement ms ) {
        return "[select] @{this.columns} [from] @{this.table} [where] @{this.column.name} = #{param1} [and] @{this.column.xxx} = #{param2}";
    }
}

回到顶部

提供各种场景的日志打印

编译日志,需要开启 enableCompilationLog 配置

... --------------------------------------------------------------------------------
... ----- Target: YourMapper( BaseSelectProvider )
... -- Namespace: xxx.xxx.xxx.YourMapper.selectAll
... Template SQL: [select] @{this.columns} [from] @{this.table} @{this.tryLogicallyDelete.useWhereQuery} @{this.defaultOrderBy}
... Compiled SQL: SELECT `id`, `name`, `version` FROM `t_user` WHERE deleted = 'N' ORDER BY `id` DESC
... ------- Time: 1ms
... --------------------------------------------------------------------------------

实时动态日志,需要开启 enableRuntimeLog 配置

... --------------------------------------------------------------------------------
... ==> Compile runtime SQL ...
... --------------------------------------------------------------------------------
... ==> - Template: SELECT `id`, `name`, `version` FROM `t_user` %{this.where($).tryLogicallyDeleteQuery} ORDER BY `id` DESC
... ==> - Compiled: SELECT `id`, `name`, `version` FROM `t_user` WHERE deleted = 'N' AND `name` = #{name} ORDER BY `id` DESC
... ==> Parameters: xxx.xxx.xxx.User@145eaa29
... <== ----- Time: 7ms
... --------------------------------------------------------------------------------
... ==>  Preparing: SELECT `id`, `name`, `version` FROM `t_user` WHERE delete = 'N' AND `name` = ? ORDER BY `id` DESC 
... ==> Parameters: xxx(String)
... <==      Total: 3
... --------------------------------------------------------------------------------

回到顶部

关于作者

Versions

Version
1.3.6
1.3.5
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.0
1.1.1
1.1.0