QuickBatis
介绍
QuickBatis是一个自动化生成DAO层代码的工具,它使用Java注解配置来生成Mybatis的Mapper,SQL实现以及Param对象等。通过此工具,应用系统可以快速开发、迭代和维护,从而提高开发效率和质量。QuickBatis项目的灵感来源于AliGenerator,但相比于后者,QuickBatis采用Java Annotation Processing技术,在构建应用程序时通过扫描注解上的配置来生成代码,从而减少人工操作。生成的代码不可修改,符合软件设计的开闭原则,避免了人为修改自动化代码带来的一系列问题,如漏改、错改、排查问题成本、合并代码成本等。总之,QuickBatis可以帮助开发者更好地实现自动化代码生成,提高开发效率和代码质量。
项目价值
QuickBatis的主要优势体现在两个方面:提高生产效率和降低开发成本。首先,它实现了代码生成全配置化和全自动化,从而减少了重复的人工操作,提高了生产效率。其次,由于生成的代码不可修改,遵循开闭原则,因此避免了人为修改和版本不一致导致的问题,减少了排查问题、合并代码和回归验证等方面的时间和精力成本。总之,QuickBatis可以显著地提高开发效率和降低开发成本。
快速开始
1、依赖
添加类库依赖,以 maven 为例
xxxxxxxxxx
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>com.dzg.fastbatis</groupId>
<artifactId>quickbatis-core</artifactId>
<version>${quickbatis.version}</version>
</dependency>
<dependency>
<groupId>com.dzg.fastbatis</groupId>
<artifactId>quickbatis-auto</artifactId>
<version>${quickbatis.version}</version>
</dependency>
其中,quickbatis-core
包含需要用到的注解。quickbatis-auto
是自动生成代码的实现。最新的版本是 1.0.0
。
2、建模
实现数据模型,并添加注解
xxxxxxxxxx
package com.dzg.xxx;
name = "t_article") (
public class Contact {
id = true, autoIncrement = true) (
private Long id;
updatable = false) (
private Date gmtCreate;
private Date gmtModified;
private String author;
private String title;
blob = true) (
private String content;
private Long version = 1L;
private Integer delState = 0;
// 省略 getter 和 setter
}
FastBatis 会根据 [@Table]注解生成对应的 ArticleParam,ArticleMapper,ArticleSqlProvider 的代码到 com.dzg.xxx.auto
包下。
3、集成
生成的代码位于 ${当前包}.auto
包下,需要把 auto 包的代码集成到应用里去。
例如 Spring Boot 应用可以通过 [@MapperScan]快速完成。
xxxxxxxxxx
basePackages = {"com.dzg.xxx.auto"}) (
public class Application {
...
}
4、构建
FastBatis 在构建时生成自动化代码。因此新增或改动的数据模型后,只需要对相应的 module 执行 mvn clean install
即可得到新的代码。
使用详解
@Table
@Table 注解用于标记类型。FastBatis 通过 @Table 注解来生成代码。该注解的具体选项如下:
属性 | 默认值 | 说明 |
---|---|---|
name | "" | 指定表名,默认根据类名完成映射,也可自行指定 |
schema | "" | 指定表的 schema,不常用,除非你知道是干嘛 |
queryable | true | 指定是否在 mapper 中生成 select 接口 |
insertable | true | 指定是否在 mapper 中生成 insert 接口 |
updatable | true | 指定是否在 mapper 中生成 update 接口 |
deletable | true | 指定是否在 mapper 中生成 delete 接口 |
@Column
[@Column]注解用于标记字段,以此来实现对字段进行特殊处理。
例如 FastBatis 默认会将 camelCase 的字段名称自动映射成 snake_case 的列名(如 gmtCreate 字段映射成列名则是 gmt_create),但某些特殊情况需要显式指定列名,这时可以通过 name
指定。
属性 | 默认值 | 说明 |
---|---|---|
name | "" | 指定列名,默认根据命名规则完成映射,也可自行指定 |
jdbcType | UNDEFINED | 指定数据库类型,默认不需要,由 mybatis 完成类型映射 |
id | false | 标记字段为 id(PrimaryKey),生成 selectByPrimaryKey,updateByPrimaryKey,deleteByPrimaryKey 等接口 |
autoIncrement | false | 配合 id 属性使用,在 mapper 中生成 insertAutoIncrement 和 batchInsertAutoIncrement 接口,在插入时使用数据库自增 id,并回填到传入的 DataObject 里 |
insertable | true | 指定字段是否在 insert 时写入,设为 false 会在所有 insert 接口中排查该字段 |
updatable | true | 指定字段是否在 update 时更新,设为 false 会在所有 update 接口中排除该字段 |
blob | false | 标记字段为 blob 字段,在 mapper 中生成 selectByParamWithBlobs,updateByParamWithBlobs,updateByPrimaryKeyWithBlobs 等接口,在这些接口中实现对 blob 字段的查询和更新 |
接口说明
下表为生成的 mapper 接口:
接口方法名 | 用法说明 | 生成条件 |
---|---|---|
countByParam | 按参数 count | 默认生成 |
selectOneByParam | 按参数 select 第一条数据 | @Table(queryable = true) |
selectByParam | 按参数 select all,不返回 blob 字段 | @Table(queryable = true) |
selectByParamWithBlobs | 按参数 select all,并返回 blob 字段 | @Table(queryable = true) 且有字段标记为 blob,即 @Column(blob = true) |
selectByPrimaryKey | 按 id 进行 select,并返回所有字段 | @Table(queryable = true) 且有字段标记为 id,即 @Column(id = true) |
insert | 插入一条数据,需要指定 id | @Table(insertable = true) |
batchInsert | 插入多条数据,需要指定 id | @Table(insertable = true) |
insertAutoIncrement | 插入一条数据,使用自增 id,id 在插入后会回填到数据模型上 | @Table(insertable = true) 且有字段标记为 auto increment id,即 @Column(id = true, autoIncrement = true) |
实验性功能
得益于注解的灵活性,FastBatis 整合了一些常用的设计模式到自动化代码中,避免重复建设。
@LogicalDelete
@LogicalDelete 注解用于标记字段,表示逻辑删除状态,以实现逻辑删除功能。
标记字段后在 mapper 中生成以下接口:
接口方法名 | 用法说明 | 生成条件 |
---|---|---|
deleteByParamLogically | 按参数删除数据(逻辑删除) | @Table(deletable = true) 且有删除状态字段,即标记为 @LogicalDelete |
deleteByPrimaryKeyLogically | 按id删除数据(逻辑删除) | @Table(deletable = true) 且有 id 字段 @Column(id = true) 和删除状态字段 @LogicalDelete |
这两个接口实际上执行的是 update 操作。此外还会在所有 select 接口中排除逻辑删除状态的数据。
@Version
@Version 注解用于标记字段,表示一条记录的版本号。该注解会重写 updateByPrimaryKey 和 updateByPrimaryKeyWithBlobs 方法的逻辑,在更新数据时自动加入版本号的校验逻辑(where version = 传入的 version)和更新逻辑(set version = version + 1),来提供一个简易的乐观锁实现。
@ShardingKey
@ShardingKey 注解用于标记字段,表示分片键,适用于分库分表的场景。
使用时会在 selectByPrimaryKey
,deleteByPrimaryKey
,deleteByPrimaryKeyLogically
这几个方法的参数中加入 shardingKey 参数,并作为查询条件的一部分添加到 where 子句里。
对于更新操作,updateByPrimaryKey
,updateByPrimaryKeySelective
,updateByPrimaryKeyWithBlobs
这几个方法里将不对 shardingKey 字段进行更新,而是作为查询条件的一部分添加到 where 子句里。
@UpdateOnDuplicated
@UpdateOnDuplicated 注解用于标记字段,用于控制在 Id 或 UK 冲突的情况下,字段的更新策略。用法如下。
xxxxxxxxxx
class Foo {
id = true) (
private String key;
private Date gmtCreate;
// 冲突时更新为最新时间
"NOW()") (
private Date gmtModified;
// 冲突时更新为传入的值
private String value;
// 冲突时自增
"version + 1") (
private Long version = 1L;
}
复制
规划中
@UniqueKey - 提供唯一键相关的接口
@TypeConvert - 类型转换机制
进阶用法
Script DSL
FastBatis 不生成 xml 文件,而是采用 mybatis 的 SqlProvider 机制来实现 mapper。为此 FastBatis 建立了 Script DSL 来实现 dynamic-sql。当自动化代码不足以满足需求时,可以通过 Script DSL + SqlProvider 来定制 mapper 的实现。
xxxxxxxxxx
public interface ScriptDemoMapper {
ScriptDemoSqlProvider.class) (
List<DataModel> getData( ("id") Collection<Long> id);
}
// SQL Provider
public class ScriptDemoSqlProvider implements ProviderMethodResolver {
public static String getData() {
return SCRIPT(
SELECT("*"),
FROM("t_demo"),
WHERE(
LITERAL("id IN"),
FOREACH("id")
.item("it").separator(",").open("(").close(")")
.inner("#{it}")
)
).toString();
}
}
Debug
要对特定 mapper 进行 debug,可通过修改 logback-spring 配置把 debug 信息打印到日志里,调用时可以看到生成的 SQL Statement 和传入的参数。
x
<logger name="com.dzg.quickbatis.demo.ScriptDemoMapper" level="DEBUG">
<appender-ref ref="CONSOLE" />
</logger>