rabbit-sql 最佳实践

准备工作

开发工具:IDEA Ultimate 版本 2023.1 以上。

Java版本:8 以上。

安装插件

项目初始化

创建maven项目。

使用spring boot starter

java 8+

<dependency>
    <groupId>com.github.chengyuxing</groupId>
    <artifactId>rabbit-sql-spring-boot-starter</artifactId>
    <version>5.3.0</version>
</dependency>

使用 rabbit-sql 提供的 Spring Boot Starter,通过单数据源自动配置可以简化配置,快速集成项目。通过 application.ymlapplication.properties 来配置数据库连接。

示例配置

spring:
  datasource:
    url: jdbc:postgresql://127.0.0.1:5432/postgres
    username: chengyuxing
    password: 

创建 XQL 文件管理配置

  1. .../src/main/resources 目录下创建文件 xql-file-manager.yml ,通过插件快速生成:

  2. 创建xql文件,通过插件来创建xql文件并自动注册到 xql-file-manager.yml,降低手动配置的错误率:

项目结构

目录结构

/src
  ├─ main/
  |    ├─ java/org/example/
  |    └─ resources/xqls/
  |           ├─ user.xql
  |           └─ order.xql

XQL 文件编写最佳实践

SQL 语句命名

/*[findAllUsers]*/
/*#Some description.#*/
SELECT * FROM users;

/*[queryUserById]*/
/*#Some description.#*/
SELECT * FROM users WHERE id = :id;

SQL语句参数使用的是命名参数 :id,将被预编译处理为 ? 号,可有效避免SQL注入的风险。

对象路径表达式

默认情况下通过形如: :users.0 获取 users 的第一个值,但在具有语法检查的 SQL IDE 中认为是语法错误,建议将写法改为标准的数组下标取值规避语法错误。

{"users": [{"name": "cyx"}, {"name": "abc"}, ...]}

SELECT * FROM users WHERE name = :users[0].name;

内联模版

XQL 文件管理器支持定义 SQL 内联模版片段 -- //TEMPLATE-BEGIN:<name> ,如果一条 SQL 的条件必须完全等于另一条 SQL,例如分页查询的条件,此时使用内联模版来创建降低复杂度,同时也能有效避免单独的模版片段引起的 SQL IDE 语法检查到不完整 SQL 的语法错误影响整体格式化:

/*[queryUserList]*/
select * from users where
-- //TEMPLATE-BEGIN:cnd
id = :id
-- //TEMPLATE-END
;

/*[queryUserCount]*/
select count(*) from users where ${cnd};

PLSQL 语句块

XQL 文件管理器中,每个 SQL 对象根据结尾的 ; 号来进行解析结构化,但有些DDL语句和 PLSQL 会包含多段 SQL,每个 SQL有 ; 号结尾,为了保证解析的正确性,通过在 ; 后面加上行注释 -- 来进行规避,这是一种合理合法的规避方式:

/*[myProc]*/
begin;
  select 1; -- 也可以加点描述
  select 2; -- 
end;

动态 SQL

示例

select * from users where
-- #if :id >= 100
  id = 99
-- #else
  id = :id
-- #fi

For 循环指令

在构建类似 in 子句的情况下,通过上下文 first 属性来判断 , 拼接的时机规避 SQL 语法错误,虽然最终并不影响解析后的正确性,但在解析之前,在具有 SQL 语法检查的 IDE 中会提醒语法错误,影响格式化和美观,所以,强烈建议使用如下写法:

select * from users where id in (
-- #for item of :list; last as isLast
   -- #if !:isLast
   :item,
   -- #else
   :item
   -- #fi
-- #done
)

通过这样的写法在解析前就具有合法的 in (:item, :item) ,从而达到规避语法错误的展现形式。

SQL语句与接口方法映射

当 SQL 编写好以后,使用插件来快速生成接口文件方法注释文档,减少重复操作,提高效率:

Return Types: 选择需要返回的类型,有些 SQL 在一些情况是存在复用需要返回不同类型的需求。

T: 默认情况下,返回类型泛型内置了 DataRowMap,如果需要返回 java bean,则需要写完全限定类名,如上图 org.example.entity.User

可重复点击 Generate Code...,每次都会记录上一次的配置。

映射接口

左侧导航图标表明sql和方法映射成功。

同一条 SQL 不同返回类型的复用,插件生成的接口格式为 SQL名+返回类型

每次重新点击 Generate Code... ,接口文件 //CODE-BEGIN ... //CODE-END 区域之间的内容不会被覆盖,例如:

// Rabbit-SQL plugin - Your methods  //CODE-BEGIN:methods
@Function("{:res = call func_get_user(:id)}")
DataRow funcGetUser(@Arg("id")Param id);
// Rabbit-SQL plugin - End of your methods  //CODE-END:methods

接口映射的更多使用方法和注意事项可具体参考文档接口映射

接口使用指南

动态代理接口

在springboot启动类上添加注解 @XQLMapperScan ,所有被标记了 @XQLMapper 的接口都会被扫描到spring上下文中,即可通过依赖注入注入接口。

@SpringBootApplication
@XQLMapperScan
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

ExampleService.java

@Autowired
private ExampleMapper exampleMapper;

Baki 核心接口

除了接口映射之外,默认还提供了可选择的核心接口Baki

SQL名示例

@Autowired
private Baki baki;

public Stream<DataRow> getUsersByName() {
    return baki.query("&example.queryAllUsers").args().stream();
}

事务处理

示例

// 通过 Spring 注解管理事务
@Transactional
public void a() {
    
}
// 通过手动管理事务
// com.github.chengyuxing.sql.spring.autoconfigure.Tx
@Autowired;
Tx tx;

public void b(){
   tx.using(()->{

   });
}

性能优化

惰性查询

如果对查询结果需要进行二次处理转换等操作,推荐返回类型为 Stream,减少循环的次数,提升性能。

批量操作

对于批量插入、更新等操作,推荐使用批量提交,减少数据库的网络交互次数,提升性能。

baki.insert("&<sql名>", <Collection>);
baki.execute("&<sql名>", <Collection>);

insert, update, delete 通过传入集合来执行批量操作。

缓存重复查询

针对频繁执行的相同查询,推荐使用应用层缓存或数据库查询缓存,减少重复 SQL 请求,提升系统响应速度。

实现接口:com.github.chengyuxing.sql.plugins.QueryCacheManager 来实现自定义的缓存层,并注册到 BakiDao#setQueryCacheManager 来启用缓存。

SQL 优化

错误处理与调试

错误日志
常见错误处理

插件使用指南

插件功能几乎都可以直接通过 IDEA 工具栏 XQL File Manager 面板来进行操作。

测试动态 SQL

有效利用插件进行动态SQL测试,确保在项目启动前最大化降低错误率,尤其是针对复杂动态SQL的计算,提前明白每个参数对动态SQL计算结果的影响。

安全性最佳实践

防止 SQL 注入

数据库连接池配置

版本控制与部署

结语

rabbit-sql 是一个强大而灵活的持久层框架,通过遵循以上最佳实践,可以确保您的项目具有高效、可维护、性能优越的数据库交互逻辑。随时保持对最新功能和优化的关注,并根据项目需求灵活应用这些实践。