Beetlsql自学笔记

自用为主,beetlsql是现在实习公司里用的,官网的文档有点乱。。然后找到了个比较好的文档,大部分来源于那篇文档,不过这里也加入了一些我自己的理解

1、简介

BeetlSql是一个数据访问框架,目标是提供开发敏捷,维护边界,运行告诉的数据库访问框架,目标是代替传统的JPA、Mybatis、Hibernate

  • 传统数据库:MySQL,MariaDB,Oralce,Postgres,DB2,SQL Server,H2,SQLite,Derby,神通,达梦,华为高斯,人大金仓,PolarDB,万里开源GreatSQL,南大通用GBase8s等

  • 大数据:HBase,ClickHouse,Cassandar,Hive

  • 物联网时序数据库:Machbase,TD-Engine,IotDB

  • SQL查询引擎:Drill,Presto,Druid

  • 内存数据库:ignite,CouchBase

2、特点

  • 派别:SQL为中心

  • 内置常见增删改查功能,节省项目50%工作量

  • 强化SQL管理,通过md文件管理sql,使用Beetl模板编写复杂sql

  • 简单SQL可以通过Query类链式API完成

  • 全面支持跨数据库平台

  • 支持NOSQL,如ClickhHouse,Elastic,Hive等

  • 支持SQL查询引擎,如Apache Drill,Presto等

  • 支持一对一,一对多等常见的映射。

  • 可以使用约定习俗映射,复杂查询结果支持通过json配置映射到POJO

  • 提供idea插件

  • 其他

  • 具备代码生成功能,提供代码生成框架

  • 最大程度减少数据库重构对项目造成的影响

  • 最大程度减少数据库切换对项目造成的影响

  • 支持多数据源,数据源包含传统数据库,NOSQL,SQL查询引擎,且可以根据规则使用数据源

  • 内置主从支持

  • 提供丰富的扩展功能,80%的功能都可以自行扩展,打造自己个性化的数据库发访问框架,扩展适应新的数据库&NOSQL&查询引擎

2-1、其他数据库工具的痛点

  • 开发效率低,如mybatis,还需要搭配plus工具才能提高开发效率,而JOOQ这样的又不适合复杂访问

  • 无SQL管理,遇到复杂的sql特别难维护,比如在Java里拼写sql,遇到调整就麻烦

  • 跨数据库平台,即使Hibernate,也完全做不到跨数据库

  • 缺少数据库和NOSQL无缝切换很难,比如一部分业务要无缝切换到NOSQL上

  • 数据库重构对代码影响非常大,数据库列修改,增加要改很多代码

  • 难以调试数据库访问代码

3、快速开始

3.1添加依赖

<!-- beetlsql-starter -->
<dependency>
    <groupId>com.ibeetl</groupId>
    <artifactId>sql-springboot-starter</artifactId>
    <version>3.9.0-RELEASE</version>
</dependency>
​
<!-- JDBC -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- 数据库驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
​
<!-- 引入数据库连接池 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.6</version>
</dependency>

3.2创建表

CREATE TABLE `user` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(64) DEFAULT NULL,
      `age` int(4) DEFAULT NULL,
      `create_date` datetime NULL DEFAULT NULL,
      PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

3.3编写一个与数据库表对应的 User 类(或者可以通过 SQLManager 的 gen 方法生成此类,参考一下节)

/**
* 与数据库 user 表对应的 POJO
*/
@Data
public class User  {
    private Integer id ;
​
    private Integer age ;
​
    private String name ;
​
    private Date createDate ;
}

3.3.1 Entity

最常用实体类,基本和数据表一一对应,一个实体一张表。

3.3.2 Pojo类

Pojo“Plain Old Java Object” 简单的Java对象。

纯的传统意义的java对象,最基本的Java Bean只有属性加上属性的get和set方法

3.3.3 DTO(data transfer object)

代表数据传输对象的意思

是一种设计模式之间传输数据的软件应用系统,数据传输目标往往是数据访问对象从数据库中检索数据

数据传输对象与数据交互对象或数据访问对象之间的差异是一个以不具任何行为除了存储和检索的数据(访问和存取器)

简而言之,就是接口之间传递的数据封装

表里面有十几个字段:id,name,gender(M/F),age……

页面需要展示三个字段:name,gender(男/女),age

DTO由此产生,一是能提高数据传输的速度(减少了传输字段),二能隐藏后端表结构

3.3.4 Vo(value object)

代表值对象的意思,通常用于业务层之间的数据传递,由new创建,由GC回收。 主要体现在视图的对象,对于一个WEB页面将整个页面的属性封装成一个对象,然后用一个VO对象在控制层与视图层进行传输交换。

3.3.5Po(persistant object)

代表持久层对象的意思,对应数据库中表的字段,数据库表中的记录在java对象中的显示状态,最形象的理解就是一个PO就是数据库中的一条记录。

好处是可以把一条记录作为一个对象处理,可以方便的转为其它对象。Vo和Po,都是属性加上属性的get和set方法;表面看没什么不同,但代表的含义是完全不同的。

3.3.6 Bo(business object)

代表业务对象的意思,Bo就是把业务逻辑封装为一个对象(注意是逻辑,业务逻辑),这个对象可以包括一个或多个其它的对象。通过调用Dao方法,结合Po或Vo进行业务操作。

形象描述为一个对象的形为和动作,当然也有涉及到基它对象的一些形为和动作。比如处理一个人的业务逻辑,该人会睡觉,吃饭,工作,上班等等行为,还有可能和别人发关系的行为,处理这样的业务逻辑时,我们就可以针对BO去处理。

再比如投保人是一个Po,被保险人是一个Po,险种信息也是一个Po等等,他们组合起来就是一张保单的B o。

3.3.7 Dao(data access object)

代表数据访问对象的意思,是sun的一个标准j2ee设计模式的接口之一,负责持久层的操作 。这个基本都了解,Dao和上面几个O区别最大,基本没有互相转化的可能性和必要,主要用来封装对数据的访问,注意,是对数据的访问,不是对数据库的访问。

3.3.8 Controller

代表数据访问对象的意思,是sun的一个标准j2ee设计模式的接口之一,负责持久层的操作 。这个基本都了解,Dao和上面几个O区别最大,基本没有互相转化的可能性和必要,主要用来封装对数据的访问,注意,是对数据的访问,不是对数据库的访问。

3.3.9 View

代表视图层的意思,主要是指由JSP、HTML等文件形成的显示层。

所以实际项目中,一般都是这样应用的: 控制层(controller-action),业务层/服务层( bo-manager-service),实体层(po-entity),dao(dao),视图对象(Vo-),视图层(view-jsp/html)

4、BaseMapper用法

mapper继承BaseMapper<T>

例子:

public interface UserMapper extends BaseMapper<User> {
    
}

UserMapper的关系

BaseMapper 具备很多内置的 CRUD 方法,因此有了 UserMapper 后,同样可以不写任何 SQL,可以轻易的完成常用操作 我们可以将UserMapper注入,然后调用它的方法完成 CRUD

下面列举几个常用方法:

方法说明
void insert(T entity)通用插入,插入一个实体对象到数据库
void insertTemplate(T entity)插入实体到数据库,对于 null 值不做处理
int updateById(T entity)据主键更新对象,所以属性都参与更新
boolean upsert(T entity)按照主键更新更新或插入,自增或者序列 id 自动赋值给 entity
int deleteById(Object key)根据主键删除对象,如果对象是复合主键,传入对象本生即可
T single(Object key)根据主键获取对象,如果对象不存在,返回 null
还有更多...更多 BaseMapper 内置方法使用参见 BaseMapper.java 

5、LambdaQuery 用法

注意:使用LamdbaQuery(推荐) 必须使用 Java8 及以上版本。

查询

获取 Query 查询器

我们继续以 user 表为例

取得Query有多种方式

// 方式一:注入 mapper 后用 mapper 获取
userMapper.createLambdaQuery();
​
// 方式二:注入 sqlManage 后用 sqlmanage 获取 (指定类型)
Query<User> query = sqlManage.lambdaQuery(User.class);
​
// 方式三:注入 sqlManage 后用 sqlmanage 获取 (指定类型)
Query<User> query = sqlManager.query(User.class);

查询模糊查询用户名包含"t",delete_time 不为空的数据,按照 id 倒序

// 代码中直接使用 userMapper 查询
List<User> userList = userMapper.createLambdaQuery()
    .andLike(User::getName,"%t%")
    .andIsNotNull(User::getDeleteTime)
    .desc(User::getId)
    .select();

从上面的例子可以看出,Query 是使用链式调用,看起来就像一个完整的 sql 一般,使用方式遵从用户平时 SQL 编写习惯。

所有的条件列完之后,再调用操作方法(要执行的方法:selectinsertupdatepage, count 等等)

查询指定字段

如果我们只要查询表其中的几个字段怎么办?如我只要 name 和 id 字段:

// 用法一 (推荐)
userMapper.createLambdaQuery()
    .select(User::getName,User::getId);
​
// 用法二
userMapper.createLambdaQuery()
    .select("name","id");

复杂的条件查询

要进行一条复杂的条件查询 SQL,需要用到 query.condition() 方法,产生一个新的条件,比如我们要查询下面这条 SQL

SELECT * FROM `user` 
WHERE ( `id` IN( 100 , 101 , 102 ) 
AND `name` LIKE '%t%' ) OR ( `id` = 10086 )
userMapper.createLambdaQuery()
    .or(query.condition()
    .andIn("id", Arrays.asList(100, 101, 102))
    .andLike("name", "%t%"))
    .or(query.condition().andEq("id", 10086))
    .select();

查询字段智能判断是否为空

我们开发中,经常会遇到前端传过来一些搜索条件,后端根据搜索条件进行判断,不为空时加入查询条件。 例如前端一个用户列表,有一个根据用户名进行查询的搜索框,我们一般会这么写。

public User findUser(String userName){
    LambdaQuery<User> query = sqlManager.lambdaQuery(User.class);
    query.andEq(User::getDeleteFlag,0);
    if(StringUtil.isNotEmpty(userName)) {
        query.andEq(User::getUserName,userName);
    }
    return query.single();
}

如果有很多个这样的字段查询,会显得比较臃肿,beetlsql 很好的解决了这个问题。

Query 工具中内置了两个过滤值的静态方法,filterEmptyfilterNull,这两个方法返回了一个StrongValue对象。

filterEmpty方法主要作用是,当一个字段为空时不把他加入查询条件,当字段不为空时才加入查询条件。

为空的判断标准:

  1. 当字段为 String 类型,会判断空字符串以及 NULL。

  2. 当字段为 Collection 类型以及其子类时,会调用 isEmpty 方法判断,以及 NULL。

  3. 当字段为其他对象时,仅仅会判断 NULL。

要实现上面的代码,我们只要下面这样写就行了:

public User findUser(String userName){
    LambdaQuery<User> query = sqlManager.lambdaQuery(User.class);
    return query.andEq(User::getDeleteFlag,0)
    .andEq(User::getUserName,Query.filterEmpty(userName))
    .single();
}

如果 userName 有值的情况下,例如等于"myName",将会生成下面的语句:

select * from user where delete_flag = 0 
and user_name = "myName" 
limit 0,1

当 userName 为空字符串或者 NULL 的时候,user_name 将不会参与条件查询:

select * from user where delete_flag = 0 
limit 0,1

filterNull 方法的作用也是类似的,但是此方法只会判断对象是否等于 NULL

自定义实现

但是业务场景往往是复杂的,BeetSql 也提供了非常好的拓展性,filterEmpty,filterNull可以 自定义实现

插入

全量插入

User record = new User();
record.setName("new name");
Query<User> query = sqlManager.lambdaQuery(User.class);
int count = query.insert(record);

全量插入,会对所有的值进行插入,即使这个值是 NULL;返回影响的行数

选择字段插入

User record = new User();
record.setName("new name2");
record.setCreateTime(new Date());
Query<User> query = sqlManager.lambdaQuery(User.class);
int count = query.insertSelective(record);

insertSelective方法,对 null 值的字段不插入;返回影响的行数

更新操作

update 和 insert 类似,有全量更新和选择列更新的方法;

全量更新 update 方法

User record = new User();
record.setName("new name");
Query<User> query = sqlManager.query(User.class);
int count = query.andEq("id", 1637)
    .andLess("create_time", new Date())
    .andEq("name", "test")
    .update(record);

全量更新,会对所有的值进行更新,即使这个值是 null;返回影响的行数;

选择更新

User record = new User();
record.setName("new name");
Query<User> query = sqlManager.query(User.class);
int count = query.andEq("id", 1637)
    .andLess("create_time", new Date())
    .andEq("name", "test")
    .updateSelective(record);

updateSelective方法,对 user 进行了一次有选择性的更新。非 null 值更新,null 值不更新;返回影响的行数;

删除操作

Query<User> query = sqlManager.query(User.class);
int count = query.andEq("id", 1642)
                 .delete();

delete 操作非常简单,拼接好条件,调用 delete 方法即可;返回影响的行数。

single 和 unique

在 beetlSql 中还提供了两个用来查询单条数据的方法,single 和 unique;

single 单条查询

single 查询,查询出一条,如果没有,返回 null;

Query<User> query = sqlManager.query(User.class);
User user = query.andEq("id", 1642).single();

unique 单条查询

unique 查询和 single 稍微不同,只能查询一条,如果没有或者有多条,抛出异常

Query<User> query = sqlManager.query(User.class);
User user = query.andEq("id", 1642).single();

如果存在多条,或者没有则抛出异常:org.beetl.sql.core.BeetlSQLException

COUNT 查询

count 查询主要用于统计行数,如下面的 SQL:

SELECT COUNT(1) FROM `user` WHERE `name` = 'myName' OR `id` = 1637 limit 0 , 10

Query<User> query = sqlManager.query(User.class);
long count = query.andEq("name", "new name")
             .orEq("id", 1637).limit(1, 10)
             .count();

拼接条件,调用 count 方法,返回总行数。

GROUP 分组查询和 Having 子句

有时候我们要进行分组查询,如以下 SQL:

SELECT * FROM `user` WHERE `id` IN(1637, 1639, 1640 ) GROUP BY name 

在 BeetlSql 中直接拼条件调用 group 方法,传入字段即可:

Query<User> query = sqlManager.query(User.class);
List<User> list = query
    .andIn("id", Arrays.asList(1637, 1639, 1640))
    .groupBy("name")
    .select();

在分组查询之后,我们可能还要进行 having 筛选,只需要在后面调用 having 方法,传入条件即可。

SELECT * FROM `user` WHERE `id` IN( 1637, 1639, 1640 ) GROUP BY name HAVING `create_time` IS NOT NULL 

Query<User> query = sqlManager.query(User.class);
List<User> list = query
    .andIn("id", Arrays.asList(1637, 1639, 1640))
    .groupBy("name")
    .having(query.condition().andIsNotNull("create_time"))
    .select();

ORDER BY 排序

进行排序查询时,只要调用 orderBy 方法,传入要排序的字段以及排序方式即可。

SELECT * FROM `user` WHERE `id` BETWEEN 1 AND 1640 
AND `name` LIKE '%t%' 
AND `create_time` IS NOT NULL ORDER BY id desc 

Query<User> query = sqlManager.query(User.class);
List<User> list = query.andBetween("id", 1, 1640)
    .andLike("name", "%t%")
    .andIsNotNull("create_time")
    .orderBy("id desc").select();

总结

query 接口分为两类

查询和更新操作

  • select 触发查询,返回指定的对象列表

  • single 触发查询,返回一个对象,如果没有,返回 null

  • unique 触发查询,返回一个对象,如果没有,或者有多个,抛出异常

  • count 对查询结果集求总数

  • delete 删除符合条件的结果集

  • update 全部字段更新,包括更新 null 值

  • updateSelective 更新选中的结果集(null 不更新)

  • insert 全部字段插入,包括插入 null 值

  • insertSelective 有选择的插入,null 不插入

各种条件

标准 sql 操作符and 操作or 操作
==,!=andEq,andNotEqorEq,orNotEq
>,>=andGreat,andGreatEqorGreat,orGreatEq
<,<=andLess,andLessEqorLess,orLessEq
LIKE,NOT LIKEandLike,andNotLikeorLike,orNotLike
IS NULL,IS NOT NULLandIsNull,andIsNotNullorIsNull,orIsNotNull
IN,NOT INandIn ,andNotInorIn,orNotIn
BETWEEN ,NOT BETWEENandBetween,andNotBetweenorBetween,orNotBetween
AND( .....)and or
标准 sqlQuery 方法
限制结果结范围,依赖于不同数据库翻页limit (默认从 1 开始,会自动处理)
ORDER BYorderBy, desc,asc
GROUP BYgroupBy
HAVINGhaving

6、#SQL的用法

使用@sql注解提供一个Sql语句

使用示例

public interface UserMapper extends BaseMapper<User> {
​
    @Sql("select * from sys_user where id = ?")
    User queryUserById(Integer id);
    
    @Sql("update sys_user set name=? where id = ?")
    @Update
    int updateName(String name,Integer id);//更新方法
}

在UserMapper中定义了queryUserById方法,并且使用@sql提供一个sql语句 那么我们可以在注入UserMapper后调用此方法

@Autowired
UserMapper userMapper;
    
@RequestMapping("test")
public String test() {
    User user = userMapper.queryUserById(100);
}

需要显示的使用@Update注解表明是一个更新或删除类的 sql,@BatchUpdate注解表明是一个批量更新 sql

使用@Select注解表明是一个查询 Sql(默认行为,所以可省略)

@Sql注解的方法参数返回值取决于于 sql 查询结果,不限定于 Mapper 定义的泛型,可以是任意 POJO

7、#Template注解用法

使用@Template注解和@Sql类似

使用方法:

public interface UserMapper extends BaseMapper<User> {
​
    @Template("select * from sys_user where id = #{id}")
    User queryUserById(Integer id);
}
/**
*@Sql占位符是 ?
​
@Template占位符是 #{}
*/

调用方法

@Autowired
UserMapper userMapper;
    
@RequestMapping("test")
public String test() {
    User user = userMapper.queryUserById(100);
}

@Template注解的方法参数返回值取决于于 sql 查询结果,不限定于 Mapper 定义的泛型,可以是任意 POJO

8、Marmdown用法

使用 Markdown 文件组织 sql 方式和注解相同的地方都是在 Mapper 里定义方法,方法上不加@Sql@Template即可 所有 Markwown 的 sql 文件默认位于 classpath 的 sql 目录下。一个 sql 文件里可以写多个 sql 片段

优点:

  • XML 格式过于复杂,书写不方便

  • XML 格式有保留符号,写 SQL 的时候不方便,如常用的< 符号 必须转义

  • md 格式本身就是一个文档格式,容易通过浏览器和各种开发工具阅读和编辑维护

  • md 中的 sql 语句是一个整体,可以直接复制出来执行,XML 无法做到

使用方法:

public interface UserMapper extends BaseMapper<User> {
​
    // 定义方法,不加 @Sql 或 @Template 注解,BeetlSQL 就会去 markdown 文件查找 sql
    User queryUserById(Integer id);
}

resources/sql/文件夹下新建 user.md 写 sql

使用===作为分隔,===上方是 sql 片段名称 (要与 mapper 中的方法名相同),===下方是 sql 语句,切记名称后不要有空格或者任何不可见的符号,否则 BeetlSQL 找不到

md结构示例

SQL 名称
===
以 * 开头的注释
SQL 语句
​
SQL 名称 2
===
SQL 语句 2
​
​
queryUserById
===
```sql
select * from sys_user where id = #{id}
```
markdown 中使用```sql是可选的,好处在于帮助 IDE 或者其他工具能对 sql 进行 ==高亮== 和语法校验

POJO,mapper 接口,markdown 之间的关系如下图所示

9、配置

beetlsql: 
  # sqlManage,可以配置多个,用逗号隔开
  sqlManagers: sqlManager1,sqlManager2
  # sqlManage1 的配置
  sqlManager1: 
    # 数据源名称
    ds: dataSource
    # 指明 mapper 类的结尾,扫描到以 Mapper 结尾的类会为其自动生成代理类,注册为 Spring 的 Bean
    # 默认扫描 Mapper 结尾,可不配置。如果你不是 xxxMapper 这样以 Mapper 结尾的,则需要配置
    daoSuffix: Dao
    # 要扫描 Mapper 的包名
    basePackage: com.compamny.xxxx
    # POJO 和数据表列的名称转换,如驼峰 userName 转换为下划线的 user_name
    nameConversion: org.beetl.sql.core.UnderlinedNameConversion
    # 数据库方言
    dbStyle: org.beetl.sql.core.db.MySqlStyle
    # 是否是开发模式
    dev: true
    # 存放 sql 文件的根目录,默认就是 resources/sql/下,所以可以不配置,
    sqlPath: sql
    # sql 文件编码
    sqlFileCharset: utf-8
  sqlManager2:
    同上,省略...

dbStyle 可配置值

数据库配置值
Mysqlorg.beetl.sql.core.db.MySqlStyle
Oracleorg.beetl.sql.core.db.OracleStyle
Postgresorg.beetl.sql.core.db.PostgresStyle
SqlServerorg.beetl.sql.core.db.SqlServerStyle
SQLiteorg.beetl.sql.core.db.SQLiteStyle
ShenTongSqlorg.beetl.sql.core.db.ShenTongSqlStyle
PolarDBorg.beetl.sql.core.db.PolarDBStyle
OpenGaussorg.beetl.sql.core.db.OpenGaussStyle
Kingbaseorg.beetl.sql.core.db.KingbaseStyle
H2org.beetl.sql.core.db.H2Style
DB2Sqlorg.beetl.sql.core.db.DB2SqlStyle

nameConversion 可配置值

可选值说明
org.beetl.sql.core.UnderlinedNameConversion默认值,下划线命名转换,数据库 Sys_User,对应类 SysUser,列 user_Id,对应属性 userId
org.beetl.sql.core.DefaultNameConversion数据库命名完全按照 java 风格来,数据库表 SysUser,对应类 SysUser,列 userId,对应属性 userId

sqlManage 配置

在 Spring Boot 中sqlManage由 starter 装配,我们可以通过SQLManagerCustomize接口来修改

比如修改默认的日志拦截器

@Configuration
public class BeeConfig {
​
    @Bean
    public SQLManagerCustomize sqlManagerCustomize() {
        return (sqlManagerName, manager) -> {
            // 设置 sql 拦截器
            manager.setInters(new Interceptor[]{new Slf4JLogInterceptor()});
        };
    }
}

10、POJO 相关注解

@Table

@Table 注解用在 POJO 上,用于数据库表名和 POJO 名称不一致的情况

例如表名为tb_user, POJO 为User,则添加@Table(name = "tb_user")注解,将表tb_userUser对应

@Data
@Table(name = "tb_user")
public class User  {
    private Integer id ;
​
    private Integer age ;
​
    private String name ;
​
    private Date createDate ;
}

@AutoID,@AssignID,SeqID

用于在 POJO 中指定数据库主键类型

注解说明
@AutoID作用于属性字段或者 getter 方法,告诉 beetlsql,这是自增主键,对应于数据自增长
@AssignID作用于属性字段或者 getter 方法,告诉 beetlsql,这是程序指定主键
@SeqID作用于 getter 方法,告诉 beetlsql,这是序列主键
@Data
public class User  {
    @AutoID // 指明表的 id 列是自增
    private Integer id ;
​
    private Integer age ;
​
    private String name ;
​
    private Date createDate ;
}

@AssignID代码设定主键可以传入 id 的生成策略以自动生成序列

beetl 默认提供了 snowflake 算法,一个用于分布式环境的 id 生成器

@AssignID("simple")
public Long getId() {
    return id;
}

simple 是 beetlsql 提供的一个默认的 snowflake 实现,你可以通过 sqlManager 自己注册 id 生成器

sqlManager.addIdAutonGen("uuid2", new IDAutoGen(){
    @Override
    public Object nextID(String params) {
        return "hi"+new Random().nextInt(10000);
    }
});
​
@AssignID("uuid2")
public Long getId() {
    return id;
}

@Column

通常数据库列名和实体类对应关系已经由 NameConversion 转化好了,如果你有特殊的命名需求,可以使用此注解

@Data
public class User  {
    @AutoID // 指明表的 id 列是自增
    private Integer id ;
​
    @Colum("my_age")
    private Integer age ;
​
    private String name ;
​
    private Date createDate ;
}

使用@Colum("my_age")age字段可以对应到 user 数据表中的my_age

Mapper 相关注解

@SqlResource

@SqlResource注解在 Mapper 上,指明 sql 片段所在的文件,如没有使用此注解,则会默认通过泛型类来查找,规则是泛型类名的首字母小写作为文件名

@SqlResource("myUser")
public interface UserMapper extends BaseMapper<User> {
      
     List<User> selectByName(String name);
}

如果未使用@SqlResource则去resources/sql/下找user.md

使用@SqlResource("myUser")后则去resources/sql/下找myUser.md

@SpringData

@SpringData模仿了 Spring Data 中通过方法名解析出 sql 语句的功能,比如 findById,则表示根据 id 属性查询。findByNameAndAgeOrderByIdDesc,则表示根据 name 和 age 属性查询,且输出结果按照 Id 降序排序。

要了解 BeetlSQL3 支持的所有 Spring Data 关键字,可以查看 SpringDataBuilder (opens new window)类,或参考 Spring Data 文档

11、分页查询

分页查询是我们经常要使用的功能,beetlSql 支持多数据,会自动适配当前数据库生成分页语句

方式一:使用LambdaQuery.limit()分页查询

public interface UserMapper extends BaseMapper<User> {
​
}

调用:

@Autowired
UserMapper userMapper;

/**
* 查询用户
*/
@RequestMapping("page")
public String page() {
    PageResult<User> result = userMapper.createLambdaQuery()
    .andLike(User::getName,"%t%")
    .andIsNotNull(User::getDeleteTime)
    .desc(User::getId)
    .limit(1, 10);
}

方式二:使用LambdaQuery.page()分页查询

@Autowired
UserMapper userMapper;
​
/**
* 查询用户
*/
@RequestMapping("page")
public String page() {
    PageResult<User> result = userMapper.createLambdaQuery()
    .andLike(User::getName,"%t%")
    .andIsNotNull(User::getDeleteTime)
    .desc(User::getId)
    .page(1, 10);
}

page()中传入起始页和查询条数即可

返回值PageResult<T>包含了查询到的列表数据和总条数

List<User> list = result.getList();
long totalRow = result.getTotalRow();

更常用的是传入一个PageRequest对象,通过PageRequest对象可以构造更多选项

比如

  • totalRequired 是否需要查询总条数

  • orderBy 排序方式

PageResult<User> result = userDao.createLambdaQuery()
    .page(DefaultPageRequest.of(1,10));

page 方法还有很多重载方法,具体使用参见代码

方式三:使用 @Sql 或 @Template 注解

使用page()函数指明分页查询,PageRequest是分页参数

public interface UserMapper extends BaseMapper<User> {
    
    @Template("select #{page()} from sys_user where department_id = #{id}")
    PageResult<User> pageQueryById(Integer id,PageRequest pageRequest);
}

方式四:在 markdown 文件中使用pageTag()

public interface UserMapper extends BaseMapper<User> {
​
    PageResult<User> pageTest(PageRequest query);
}

pageTest
===
```sql
select
-- @{pageTag()
    name, age
-- @}
from user
```

lombook

1、简介

Lombok 是一种 Java™ 实用工具,可用来帮助开发人员消除 Java 的冗长,尤其是对于简单的 Java 对象(POJO)。它通过注解实现这一目的。

要使用这个对象,必须还要写一些getter和setter方法,可能还要写一个构造器、equals方法、或者hash方法.这些方法很冗长而且没有技术含量,我们叫它样板式代码.

2、常用注解

@Data : 加在类上,相当于同时使用了@ToString、@EqualsAndHashCode、@Getter、@Setter和@RequiredArgsConstrutor这些注解;

@AllArgsConstructor : 加在类上,可以生成含实体类全参数的构造方法;

@NoArgsConstructor : 加在类上,可以生成无参构造方法

@RequiredArgsConstructor:加在类上,配合@NonNull注解使用,生成指定参数的构造方法。比如在age属性前面加@NonNull注解,则User生成需要age参数的构造方法;

@Getter:加在类上,可以生成实体类所有属性的getter方法;

@Setter:加在类上,可以生成实体类所有属性的setter方法;

@ToString:加在类上,调用toString()方法,可以输出实体类中所有属性的值。

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值