Xbatis 是一个 SpringBoot 应用环境中使用的数据管理框架,它基于 MyBatis 实现,支持 MySQL,可以使用更加 Java 的方式实现业务逻辑中的 CRUD 操作。

安装

下载源码

git clone https://github.com/njdi/durian.git

编译源码

cd durian/

切换至最新版本(Tag),如:0.4,

git checkout 0.4

编译安装至本地 Maven 仓库:

mvn clean package

添加依赖

SpringBoot 项目使用 Xbatis 时,需要在 Maven pom.xml 中添加:

<dependency>
<groupId>io.njdi</groupId>
<artifactId>durian-xbatis</artifactId>
<version>${version}</version>
</dependency>

${version} 替换为具体的版本号,如:0.4。

数据表

数据表 mytable 包含 3 个字段:id、col1 和 col2,

CREATE TABLE `mytable` (
`id` int NOT NULL AUTO_INCREMENT,
`col1` varchar(45) COLLATE utf8mb4_unicode_ci NOT NULL,
`col2` varchar(45) COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

其中,字段 id 是主键,且支持自增。

Xbatis 中每一张数据表都要求必须包含一个整数类型的主键字段,名称为 id,且支持自增。

数据源

Xbatis 运行时需要使用 SpringBoot 提供的数据源(DataSource),需要在 application.yml 中添加:

spring:
application:
name: sample
datasource:
url: jdbc:mysql://${host}:${port}/${db}?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
username: ${user}
password: ${passwd}
hikari:
keepaliveTime: 30000
maxLifetime: 600000
maximumPoolSize: 30

${...} 替换为具体的数据库信息:

  • ${host}:MySQL 实例地址;
  • ${port}:MySQL 实例端口;
  • ${db}:数据库名称;
  • ${user}:用户名;
  • ${passwd}:密码;

Xbatis

Xbatis 是基于 MyBatis 实现的,运行时相关实例需要以 Bean 的形式注入到 Spring 容器,为保证 Spring 可以正常扫描且实例化这些 Bean,需要作如下配置:

Main

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan; @SpringBootApplication
@ComponentScan({"io.njdi.durian.sample.xbatis", "io.njdi.durian.xbatis"})
@MapperScan(basePackages = {"io.njdi.durian.xbatis.core"})
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}

Main 是 SpringBoot 应用的入口类,@ComponentScan 用于指定“去哪里”扫描 Xbatis 的 Bean,“io.njdi.durian.sample.xbatis” 是示例项目的 Bean,“io.njdi.durian.xbatis” 是 Xbatis 项目的 Bean;@MapperScan 用于指定“去哪里”扫描 MyBatis 的 Mapper。

application.xml

mybatis:
mapper-locations: classpath:xbatis.xml

mybatis.mapper-locations 用于指定“去哪里”加载 MyBatis 的配置文件。

XbatisManager

XbatisManager 是数据管理器实例,用以完成 CRUD 相关的具体操作,可以在 ServiceDao 层注入此实例:

@Autowired
private XbatisManager xbatisManager;

Database/Table/Column

Xbatis 中也有数据库(Database)、数据表(Table)和数据列(Column)的概念,它们是 业务逻辑 中的库/表/列,相较于 MySQL 中的 物理 库/表/列,它们拥有更多的业务属性。

Column

Column 用于定义 ,它对应着 MySQL 中的一列,包含以下属性:

name

列名称,指 业务逻辑 中列的名称;如果 业务逻辑 中列的名称与 MySQL 中对应列的名称不一致,则需要使用列别名(alias)指定。

alias

列别名,指 MySQL 中列的名称;仅列名称与列别名不一致时需要指定。

type

列类型,指 业务逻辑 中列的数据类型,支持数值和字符串类型,默认为字符串类型(String)。

implicit

列默认查询标识,查询数据表时,如果没有指定需要查询具体哪些列,会使用默认查询列替代,默认为 true。

create

列允许插入标识,指列是否支持插入,默认为 true。

select

列允许查询标识,指列是否支持查询,默认为 true。

update

列允许更新标识,指列是否支持更新,默认为 false。

Column 实例支持通过 Builder 模式进行创建:

Column id = Column.builder().name(COLUMN_MYTABLE_ID).type(Integer.class).create(false).build();
Column colOne = Column.builder().name("colOne").alias("col1").build();
Column colTwo = Column.builder().name("colTwo").alias("col2").build();

其中,id 可使用 type() 指定类型为整数,使用 create() 指定不允许插入;colOne 和 colTwo 可使用 alias() 分别指定别名 col1 和 col2。

Table

Table 用于定义 ,它对应着 MySQL 中的一张表,包含以下属性:

name

表名称,指 业务逻辑 中表的名称;如果 业务逻辑 中表的名称与 MySQL 中对应表的名称不一致,则需要使用表别名(alias)指定。

alias

表别名,指 MySQL 中表的名称;仅表名称与表别名不一致时需要指定。

columns

列集合,指 某表的多个列(Column)。

limit

查询某表时,最多可以返回的记录数目,默认为整数最大值(Integer.MAX_VALUE),即不限制。

create

表允许插入标识,默认为 true。

delete

表允许删除标识,默认为 true。

page

表允许(分页)查询标识,默认为 true。

update

表允许更新标识,默认为 true。

deleteMustHaveWhere

表删除时,必须指定过滤条件标识,默认为 true。

pageMustHaveWhere

表查询时,必须指定过滤条件标识,默认为 true。

updateMustHaveWhere

表更新时,必须指定过滤条件标识,默认为 true。

Table 实例支持通过 Builder 模式进行创建:

Table myTable = Table.builder()
.name("myTable")
.alias("mytable")
.column(id)
.column(colOne)
.column(colTwo)
.build();

使用 alias() 可指定表别名(注意 myTablemytable 的区别);使用 column() 可添加多个列。

Database

Database 用于定义 ,它对应着 MySQL 中的一个数据库,仅包含一个属性:

tables

表集合,指库的多张表(Table)。

Database 实例支持通过 Builder 模式进行创建:

Database database = Database.builder()
.table(myTable)
.build();

使用 table() 可添加多张表。

Database(库) 实例可以包含多个 Table(表) 实例;Table 实例可以包含多个 Column(列)实例。其中,Database 实例创建完成以后,需要以 Bean 的形式注入 Spring 容器:

import io.njdi.durian.xbatis.model.schema.Column;
import io.njdi.durian.xbatis.model.schema.Database;
import io.njdi.durian.xbatis.model.schema.Table;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; @Configuration
public class DbConfigurer {
public static final String TABLE_MYTABLE = "myTable"; public static final String COLUMN_MYTABLE_ID = "id";
public static final String COLUMN_MYTABLE_COL_ONE = "colOne";
public static final String COLUMN_MYTABLE_COL_TWO = "colTwo"; public Table createTable() {
Column id = Column.builder().name(COLUMN_MYTABLE_ID).type(Integer.class).create(false).build();
Column colOne = Column.builder().name(COLUMN_MYTABLE_COL_ONE).alias("col1").build();
Column colTwo = Column.builder().name(COLUMN_MYTABLE_COL_TWO).alias("col2").build(); return Table.builder()
.name(TABLE_MYTABLE)
.alias("mytable")
.column(id)
.column(colOne)
.column(colTwo)
.build();
} @Bean
public Database createDatabase() {
Table myTable = createTable(); return Database.builder()
.table(myTable)
.build();
}
}

注意 @Configuration@Bean 两个注解的使用。其中,业务逻辑 中的表名和列名 均使用 公共静态常量(public/static/final) 进行声明,方便业务代码引用。

Create/Creates

Create 用于描述 插入 操作,每一个 Create 实例对应着一条 Insert 语句,如下:

INSERT INTO mytable (col1, col2) VALUES('a', 'b')

Insert 语句包含两部分重要内容:键值对和表名。键值对即列名和列值,如:

col1 -> a
col2 -> b

Pair

在 Xbatis 中键值对是使用 Pair 表示的,每一个 Pair 实例表示一组列名和列值;其中,列名使用属性 name 表示,列值使用属性 value 表示,如:

Pair<String> colOne = Pair.<String>builder()
.name(DbConfigurer.COLUMN_MYTABLE_COL_ONE)
.value("a")
.build();
Pair<String> colTwo = Pair.<String>builder()
.name(DbConfigurer.COLUMN_MYTABLE_COL_TWO)
.value("b")
.build();

创建一个 Create 实例表示一条 Insert 语句:

String table = DbConfigurer.TABLE_MYTABLE;

Pair<String> colOne = Pair.<String>builder()
.name(DbConfigurer.COLUMN_MYTABLE_COL_ONE)
.value("a")
.build();
Pair<String> colTwo = Pair.<String>builder()
.name(DbConfigurer.COLUMN_MYTABLE_COL_TWO)
.value("b")
.build(); Create create = Create.builder()
.pair(colOne)
.pair(colTwo)
.table(table)
.build();

创建 Create 实例时,使用了 DbConfigurer 中表名和列名的公共静态常量。

id

id 是 Create 中一个很重要的属性,它要求 MySQL 数据表中的主键字段名称为 id,且必须是自增的;使用 XbatisManager 执行插入操作后,可以获取已插入记录的主键值:

int id = xbatisManager.create(create);
log.info("id: {}", id);

也可以通过 Create 实例获取主键值:

log.info("id: {}", create.getId());

Creates

Creates 实例内部可以添加多个 Create 实例,用于表示多条记录的插入操作。

Creates creates = Creates.builder()
.create(create)
.create(create2)
.build(); List<Integer> ids = xbatisManager.creates(creates);
log.info("ids: {}", ids);

Delete/Deletes

Delete 用于描述 删除 操作,每一个 Delete 实例对应着一条 Delete 语句,如下:

DELETE FROM mytable WHERE col1 = 'a'

Delete 语句包含两部分重要内容:表名和过滤条件(可选)。

Where

Xbatis 中过滤条件使用 Where 表示,每一个 Where 实例表示一个过滤条件。Where 有四种实现:

  • Filter(基本过滤器)
  • OrFilter(逻辑或过滤器)
  • AndFilter(逻辑与过滤器)
  • NotFilter(逻辑非过滤器)

Filter

Filter 是基本过滤器的实现,它含有三个属性:

name

列名称。

operator

操作符,支持:EQ(=), NE(!=), GT(>), LT(<), GE(>=), LE(<=), BETWEEN(between ... and ...), LIKE(like), IN(in), NOT_IN(not in), IS_NULL(is null), IS_NOT_NULL(is not null)。

values

值列表,根据操作符的不同,可能是零个、一个或多个值。

创建 Filter 实例:

// col1 = 'a'
Filter eq = Filter.builder()
.name(DbConfigurer.COLUMN_MYTABLE_COL_ONE)
.operator(Filter.Operator.EQ)
.value("a")
.build(); // id between 1 and 10
Filter between = Filter.builder()
.name(DbConfigurer.COLUMN_MYTABLE_ID)
.operator(Filter.Operator.BETWEEN)
.value(1)
.value(10)
.build(); // col2 is not null
Filter isNotNull = Filter.builder()
.name(DbConfigurer.COLUMN_MYTABLE_COL_TWO)
.operator(Filter.Operator.IS_NOT_NULL)
.build();

Delete、Page 和 Update 实例均可以添加多个 Filter(Where) 实例,多个 Filter 之间的逻辑关系是 And(与)。

OrFilter

OrFilter 逻辑非过滤器,用于表示多个 Filter 之间的逻辑或(Or)关系。

假设需要表示过滤:

col1 = 'a' || col2 is not null

使用 OrFilter:

// col1 = 'a'
Filter eq = Filter.builder()
.name(DbConfigurer.COLUMN_MYTABLE_COL_ONE)
.operator(Filter.Operator.EQ)
.value("a")
.build(); // col2 is not null
Filter isNotNull = Filter.builder()
.name(DbConfigurer.COLUMN_MYTABLE_COL_TWO)
.operator(Filter.Operator.IS_NOT_NULL)
.build(); // col1 = 'a' or col2 is not null
OrFilter orFilter = OrFilter.builder()
.filter(eq)
.filter(isNotNull)
.build();

AndFilter

AndFilter 逻辑与过滤器,用于表示多个 Filter 之间的逻辑与(And)关系,使用场景较少。

NotFilter

NotFilter 逻辑非过滤器,用于表示多个 Filter 之间的逻辑非(Not)关系,使用场景较少。

使用 Where 创建 Delete 实例:

String table = DbConfigurer.TABLE_MYTABLE;

Filter colOne = Filter.builder()
.name(DbConfigurer.COLUMN_MYTABLE_COL_ONE)
.operator(Filter.Operator.EQ)
.value("a")
.build(); Delete delete = Delete.builder()
.table(table)
.where(colOne)
.build();

可以使用 Delete where() 添加多个 Where 实例,它们之间的逻辑关系是与(And)。

执行删除操作:

int rows = xbatisManager.delete(delete);
log.info("rows: {}", rows);

XbatisManager delete() 会返回执行删除操作后所影响的记录行数,也可以使用 Deletes 执行多个删除操作。

Page

Page 用于描述 查询 操作,每一个 Page 实例对应着一条 Select 语句,它是 Xbatis 中最复杂的结构,包含若干组成部分:

  • Field(查询字段)
  • Where(过滤)
  • Group(分组)
  • Having(分组过滤)
  • Order(排序)
  • limit/offset(分页)

Field

Field 用于描述 查询字段 部分:

SELECT

    select_expr [, select_expr] ...
FROM
table

select_expr 就是查询字段,每一个 Field 实例对应着一个 查询字段,它包含两个属性:

name

列名称。

alias

列别名,如果需要为查询的列起一个其它的名称,可以使用列别名指定。

创建 Field 实例:

Field field = Field.builder()
.name(DbConfigurer.COLUMN_MYTABLE_COL_ONE)
.alias("mycol")
.build();

翻译成 SQL 片段:

SELECT
col1 AS mycol
FROM
table

Where

SELECT
select_expr [, select_expr] ...
FROM
table
WHERE
where_condition

详细内容参考 Delete Where。

Group

列名称集合,每一个列名称表示一个分组字段,直接使用字符串表示。

SELECT
select_expr [, select_expr] ...
FROM
table
WHERE
where_condition
GROUP BY
col_name [, col_name] ...

Having

SELECT
select_expr [, select_expr] ...
FROM
table
WHERE
where_condition
GROUP BY
col_name [, col_name] ...
HAVING
where_condition

详细内容参考 Delete Where。

Order

Order 用于描述 排序字段 部分:

SELECT
select_expr [, select_expr] ...
FROM
table
WHERE
where_condition
GROUP BY
col_name [, col_name] ...
HAVING
where_condition
ORDER BY order_expr [, order_expr] ...

order_expr 就是排序字段,每一个 Order 实例对应着一个 排序字段,它包含两个属性:

name

列名称。

sort

排序,升序(ASC)或降序(DESC)。

创建 Order 实例:

Order order = Order.builder()
.name(DbConfigurer.COLUMN_MYTABLE_COL_ONE)
.sort(Order.Sort.DESC)
.build();

翻译成 SQL 片段:

ORDER BY col1 DESC

limit/offset

limit 用于限制查询返回的记录行数,offset 用于指定记录偏移量,两者结合可实现分页。

SELECT
select_expr [, select_expr] ...
FROM
table
WHERE
where_condition
GROUP BY
col_name [, col_name] ...
HAVING
where_condition
ORDER BY order_expr [, order_expr] ...
LIMIT limit
OFFSET offset

创建 Page 实例:

Page page = Page.builder()
.field(...)
.table(table)
.where(...)
.group(...)
.having(...)
.order(...)
.limit(...)
.offset(...)
.build();

其中,field()、where()、group()、having()、order() 均可以使用多次。

执行查询操作:

List<Map<String, Object>> rows = xbatisManager.page(page);
log.info("rows: {}", rows);

XbatisManager page() 会返回一个记录集合,使用 List 表示;每一个记录使用一个 Map 表示,Key(String)代表列名称,Value(Object)代表列值。

XbatisManager page() 有一个重载方法,可以直接以 对象集合 的形式返回查询结果:

public class MyRow {
private Integer id;
private String colOne;
private String colTwo;
} List<MyRow> rows = xbatisManager.page(page, MyRow.class);
log.info("rows: {}", rows);

每一个 MyRow 实例表示一行记录。注意,MyRow 属性名称及类型必须与列名称及类型一一对应。

id/ids

使用 ID 查询记录是很常见的需求,Xbatis 直接支持这样的查询请求。ID 可以有两种解读:

  • MySQL 数据表记录中的自增 id
  • 业务逻辑中的唯一记录标识

对于第一种情况:

String table = DbConfigurer.TABLE_MYTABLE;

int id = 106;

MyRow myRow = xbatisManager.id(table, id, MyRow.class);
log.info("id: {}", myRow);

直接使用 id 值查询对应的记录。

对于第二种情况:

String table = DbConfigurer.TABLE_MYTABLE;

String name = "id";
Integer value = 106; MyRow myRow = xbatisManager.id(table, name, value, MyRow.class);
log.info("id: {}", myRow);

需要特别指定唯一记录标识列的名称 name。

此外,id() 也支持返回 Map 类型的记录。

ids() 可以查询 ID 集合(多个ID)的记录列表。如果 ID 集合中存在 重复 的 ID,返回的记录列表也会包含 重复 的记录。

Update/Updates

Update 用于描述 更新 操作,每一个 Update 实例对应着一条 Update 语句,如下:

UPDATE
mytable
SET
col2 = 'b'
WHERE
col1 = 'a'

Update 语句包含三部分重要内容:表名,键值对(Pair)和过滤条件(Where);其中,Pair 请参考 Create Pair,Where 请参考 Delete Where。

创建 Update 实例:

String table = DbConfigurer.TABLE_MYTABLE;

Filter filter = Filter.builder()
.name(DbConfigurer.COLUMN_MYTABLE_COL_ONE)
.operator(Filter.Operator.EQ)
.value("a")
.build(); Pair<String> pair = Pair.<String>builder()
.name(DbConfigurer.COLUMN_MYTABLE_COL_TWO)
.value("c")
.build(); Update update = Update.builder()
.table(table)
.pair(pair)
.where(filter)
.build();

执行更新操作:

int rows = xbatisManager.update(update);
log.info("rows: {}", rows);

XbatisManager update() 会返回执行更新操作后所影响的记录行数,也可以使用 Updates 执行多个删除操作。

自定义列名称

一般情况下,Field.nameFilter.nameOrder.name 只能使用已经定义的列名称 Column.name。如果需要使用自定义的列名称,则需要通过 expr 属性额外指定。

以 Field 为例,假设需要查询列 colOne 大写之后的值:

Field field = Field.builder()
.name("UPPER(col1)")
.alias("colOne")
.expr(true)
.build();

注意,使用自定义列名称时,只能引用 MySQL 数据表中的列名,如:col1。

示例

Xbatis:SpringBoot 数据管理框架的更多相关文章

  1. SpringBoot数据访问之Druid启动器的使用

    数据访问之Druid启动器的使用 承接上文:SpringBoot数据访问之Druid数据源的自定义使用 官方文档: Druid Spring Boot Starter 首先在在 Spring Boot ...

  2. SpringBoot数据访问之整合mybatis注解版

    SpringBoot数据访问之整合mybatis注解版 mybatis注解版: 贴心链接:Github 在网页下方,找到快速开始文档 上述链接方便读者查找. 通过快速开始文档,搭建环境: 创建数据库: ...

  3. Springboot数据访问,棒棒哒!

    Springboot对数据访问部分提供了非常强大的集成,支持mysql,oracle等传统数据库的同时,也支持Redis,MongoDB等非关系型数据库,极大的简化了DAO的代码,尤其是Spring ...

  4. SpringBoot学习笔记(6) SpringBoot数据缓存Cache [Guava和Redis实现]

    https://blog.csdn.net/a67474506/article/details/52608855 Spring定义了org.springframework.cache.CacheMan ...

  5. springBoot数据校验与统一异常处理

    概念 异常,在程序中经常发生,如果发生异常怎样给用户一个良好的反馈体验就是我们需要处理的问题.以前处理异常信息,经常都是给前端一个统一的响应,如数据错误,程序崩溃等等.没办法指出哪里出错了,这是一种对 ...

  6. springboot 数据访问【转】【补】

    六.SpringBoot与数据访问 1.JDBC pom.xml配置 <dependencies> <dependency> <groupId>org.spring ...

  7. Springboot数据校验

    SpringBoot中使用了Hibernate-validate校验框架 1.在实体类中添加校验规则 校验规则: @NotBlank: 判断字符串是否为null或者是空串(去掉首尾空格).@NotEm ...

  8. SpringBoot数据访问(一) SpringBoot整合Mybatis

    前言 SpringData是Spring提供的一个用于简化数据库访问.支持云服务的开源框架.它是一个伞形项目,包含了大量关系型数据库及非关系型数据库的数据访问解决方案,其设计目的是为了使我们可以快速且 ...

  9. SpringBoot数据访问(二) SpringBoot整合JPA

    JPA简介 Spring Data JPA是Spring Data大家族的一部分,它可以轻松实现基于JPA的存储库.该模块用于增强支持基于JPA的数据访问层,它使我们可以更加容易地构建使用数据访问技术 ...

随机推荐

  1. ssm项目中常用的上传文件

    在项目中,上传文件一般是必不可少的,所以今天学到新的上传方式,就干脆将学习过的上传方式记录一下 一.表单直接上传图片 表单头要设置 <form action="" metho ...

  2. CF916A Jamie and Alarm Snooze 题解

    Content 令一个时间为幸运时间,当且仅当该时间中包含数字 \(7\). 小 J 很懒,他决定在 \(h\) 时 \(m\) 分起床,于是他将闹钟设定在一个很幸运的时间,并通过按一次按钮以多睡 \ ...

  3. LuoguB2103 图像相似度 题解

    Content 给定两个 \(m\times n\) 的矩阵 \(A,B\),求 \(A,B\) 两个矩阵的相似度,精确到小数点后 \(2\) 位. 定义两个矩阵的相似度为两个矩阵对应相同元素个数占矩 ...

  4. redis集群搭建,使用注意

    https://www.cnblogs.com/vieta/p/11192137.html https://blog.csdn.net/qq_42815754/article/details/8291 ...

  5. JAVA调用微信接口实现页面分享功能(分享到朋友圈显示图片,分享给朋友)

    钉钉提供的内网穿透之HTTP穿透:https://www.cnblogs.com/pxblog/p/13862376.html 网页分享到微信中如何显示标题图,如果自定义标题图,描述,显示效果如下 官 ...

  6. Lucene 基础类型

    Lucene 索引文件中,用一下基本类型来保存信息:1. Byte:是最基本的类型,长 8 位(bit).2. UInt32:由 4 个 Byte 组成.3. UInt64:由 8 个 Byte 组成 ...

  7. Exploration(hdu5222)

    Exploration  Accepts: 190  Submissions: 976  Time Limit: 30000/15000 MS (Java/Others)  Memory Limit: ...

  8. TensorFlow.NET机器学习入门【4】采用神经网络处理分类问题

    上一篇文章我们介绍了通过神经网络来处理一个非线性回归的问题,这次我们将采用神经网络来处理一个多元分类的问题. 这次我们解决这样一个问题:输入一个人的身高和体重的数据,程序判断出这个人的身材状况,一共三 ...

  9. 亲测:三个值得练手的Java实战项目

    测试奇谭,BUG不见. 大家好,我是谭叔. 一提到编码,很多小伙伴便感到头疼,特别是半路转行的小伙伴或者没有系统学习过计算机基础的小伙伴. 对于想学而不知道怎么学的小伙伴,我可以分享下我的策略: 刷一 ...

  10. VAE with a VampPrior

    目录 概 主要内容 分级的VAE 代码 Tomczak J. & Welling M. VAE with a VampPrior. In International Conference on ...