Solon 3.0 新特性:SqlUtils

Solon 3.0 引入了新的 SqlUtils 用于数据库基础操作,SqlUtils 是对 JDBC 较为原始的封装,采用了 Utils API 的风格,极为反普归真。 特性有:

  • 支持事务管理
  • 支持多数据源
  • 支持流式输出
  • 支持批量执行
  • 支持存储过程

一、概述

SqlUtils 是一个轻量的数据库操作框架,采用 Utils API 风格,简单灵活,易于阅读和维护,支持编写复杂的SQL。对于不适合使用复杂的 ORM 框架,或者需要编写复杂的 SQL 的场景,可以使用 SqlUtils 来操作数据库。

二、引入 SqlUtils

  • gradle 依赖

    implementation 'org.noear:solon-data-sqlutils'

  • maven 依赖

    org.noear solon-data-sqlutils

三、配置数据源

配置数据源(具体参考:《数据源的配置与构建》

yml 复制代码
solon.dataSources:
  rock!:
    class: "com.zaxxer.hikari.HikariDataSource"
    jdbcUrl: jdbc:mysql://localhost:3306/rock?useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedStatements=true
    driverClassName: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456

之后就可以按数据源名注入 SqlUtils 了(带 ! 结尾的数据源名,为默认)

java 复制代码
@Component
public class DemoService {
    @Inject //默认数据源名
    SqlUtils sqlUtils;
}

四、查询操作

查数量:

java 复制代码
public Long findCount() throws SQLException {
    return sqlUtils.selectValue("select count(*) from appx where app_id = ?", id);
}

按照主键查数据:

java 复制代码
public Appx findDataById(Integer id) throws SQLException {
    return sqlUtils.selectRow("select * from appx where app_id = ?", id)
                   .toBean(Appx.class);
}

按照自定义查询条件查数据:

java 复制代码
public List<Appx> findDataByGroup(Integer group_id) throws SQLException {
    return sqlUtils.selectRowList("select * from appx where group_id = ?", group_id)
                   .toBeanList(Appx.class);
}

以上几种查询方式,查询条件中的变量使用的是占位符(SqlUtils 只支持占位符),也比较简单。复杂的查询怎么办?比如管理后台的条件统计,可以先使用构建器:

java 复制代码
public List<Appx> findDataStat(int group_id, String channel, int scale) throws SQLException {
    SqlBuilder builder = new SqlBuilder();
    builder.append("select group_id, sum(amount) amount from appx ")
           .append("where group_id = ? group by group_id", group_id);

    builder.appendIf(channel != null, " and title channel ?", channel + "%");

    if(scale > 10){
        builder.append(" and scale = ?", scale);
    }

    return sqlUtils.selectRowList(builder.getSql(), builder.getArgs())
                   .toBeanList(Appx.class);
}

管理后台常见的分页查询:

java 复制代码
public void findDataPage(int group_id, String channel) throws SQLException {
    SqlBuilder builder = new SqlBuilder()
      .append(" from appx  where group_id = ?", group_id)
      .appendIf(channel != null, " and title channel ?", channel + "%");
    
    //备份
    builder.backup();
    builder.insert("select *");
    builder.append(" limit ?,?", 10,10); //分页获取列表
    
    //查询列表
    List<Appx> list = sqlUtils.selectRowList(builder.getSql(), builder.getArgs())
                              .toBeanList(Appx.class);
    
    //回滚(可以复用备份前的代码构建)
    builder.restore();
    builder.insert("select count(*)");
    
    //查询总数
    Long total = sqlUtils.selectValue(builder.getSql(), builder.getArgs());
}

五、流式查询操作

支持 fetchSize 参数

java 复制代码
public void findDataAll(Integer group_id) throws SQLException {
    try (RowIterator iterator = sqlUtils.selectRowIterator("select * from appx where group_id = ?", 100, group_id)) {
        while (iterator.hasNext()){
            Appx app = iterator.next().toBean(Appx.class);
            //....
        }
    }
}

六、插入操作

单条插入:

java 复制代码
public void addData(int id) throws SQLException {
    return sqlUtils.insert("insert appx(app_id) values(?)", id); 
}

单条插入并返回Key:

java 复制代码
public void addData(int id) throws SQLException {
    return sqlUtils.insertReturnKey("insert appx(app_id) values(?)", id); 
}

批量插入:

java 复制代码
public void addDataBatch() throws SQLException {
    List<Object[]> argsList = new ArrayList<>();
    argsList.add(new Object[]{1});
    argsList.add(new Object[]{2});
    argsList.add(new Object[]{3});
    argsList.add(new Object[]{4});
    argsList.add(new Object[]{5});
    
    sqlUtils.executeBatch("insert appx(app_id) values(?)", argsList);
}

六、执行操作(更新或删除)

支持事务控制

java 复制代码
@Tran
public void delData(int id) throws SQLException {
    sqlUtils.execute("delete from appx where app_id=?", id); 
}

@Tran
public void updateData(int id) throws SQLException {
    sqlUtils.execute("update appx set group_id=?  where app_id=?", 2, id); 
}

七、存储过程操作

查询操作

java 复制代码
public Appx findDataById(int id) throws SQLException {
    return sqlUtils.selectRow("{call findDataById(?)}", id).toBean(Appx.class);
}

删除操作

java 复制代码
public int findDataById(int id) throws SQLException {
    return sqlUtils.execute("{call delDataById(?)}", id);
}

八、总结

通过上述的示例,可以看到基本的数据库操作都可以用 SqlUtils 实现,避免了复杂的ORM框架的使用,切操作要比ORM框架简单灵活的多。Utils API 的风格也更容易编写和阅读。

相关推荐
better_liang6 小时前
每日Java面试场景题知识点之-消息队列MQ核心场景与实战
java·面试·kafka·消息队列·rabbitmq·rocketmq·mq
小江的记录本6 小时前
【JVM虚拟机】垃圾回收GC:四种引用类型:强引用、软引用、弱引用、虚引用(附《思维导图》+《面试高频考点清单》)
java·jvm·spring boot·后端·python·spring·面试
小马爱打代码7 小时前
Spring源码 第四篇:Spring 5 源码深度拆解:AOP 全流程核心原理
java·后端·spring
better_liang7 小时前
每日Java面试场景题知识点之-SpringBoot启动流程
java·面试·springboot·源码解析·启动流程
RyFit7 小时前
Java + AI 实战:Spring AI 从入门到企业级落地
java·人工智能·spring
ZhengEnCi8 小时前
01-如何监听接口调用情况?
java·spring boot·后端
JAVA面经实录9179 小时前
MyBatis学习体系
java·mybatis
java1234_小锋9 小时前
在 Spring AI 中如何实现函数调用(Function Calling)?请说明其基本原理和应用场景。
java·人工智能·spring
小马爱打代码10 小时前
Spring源码 第九篇:Spring 5 源码深度拆解 - Spring 事件驱动模型
java·后端·spring
ForgeAI码匠10 小时前
ForgeAdmin|Spring Boot 3 后台框架的自动配置设计:少写配置,多做组合
java·spring boot·后端