如何在 Java 脚本中有效地使用 JDBC

简介: 如何在 Java 脚本中有效地使用 JDBC

使用 Java 脚本

       Java 脚本的优点是文本格式的易于移植,并且无需事先编译即可运行,同时我们在运行时从该语言的标准库中获得了大量资源。为各种原型提供了脚本的使用,其中可以解决更复杂的数据导出或数据转换(连接到数据库后)。无论我们不想(或不能)将实现放入标准 Java 项目中,脚本都很有用。

       但是,脚本的使用有一些限制。例如,代码必须写在单个文件中。我们可以在运行脚本时包含所有必要的库,但这些库可能会有额外的依赖项,简单地在命令行上列出它们可能会令人沮丧。与分发这种脚本相关的复杂性可能不需要强调。由于上述原因,我认为最好避免使用脚本中的外部库。如果我们仍然想走脚本路线,那么选择就落在了纯JDBC上。多行文本文本可以有利地用于编写 SQL 查询,以及自动关闭对象,如 PreparedStatement(实现接口)。那么问题出在哪里呢?AutoCloseable

映射 SQL 参数值

       出于安全原因,建议将 SQL 参数值映射到问号。我认为 JDBC 的主要障碍是使用问号的序列号(以 1 开头)映射参数。参数映射到 SQL 脚本的第一个版本通常效果很好,但随着参数数量和其他 SQL 修改的增加,出错的风险也会增加。我提醒您,通过在第一个位置插入一个新参数,必须对下一行重新编号。

       另一个复杂因素是运算符的使用,因为对于枚举的每个值,必须在 SQL 模板中写入一个问号,该问号必须映射到单独的参数。如果参数列表是动态的,则 SQL 模板中的问号列表也必须是动态的。调试大量更复杂的 SQL 可能会开始花费大量时间。IN

       要使用字符串模板插入 SQL 参数,我们将不得不等待更长的时间。但是,可以通过在 上添加一个简单的包装器来方便插入 SQL 参数,该包装器将(在调用 SQL 语句之前)使用 JPA 样式的命名标记(以冒号开头的字母数字文本)附加参数。如果包装器允许将必要的方法链接到单个语句中,最好使用返回类型,则包装器还可以简化从数据库(使用语句)读取数据的过程。interfacePreparedStatementSELECTStream<ResultSet>

SqlParamBuilder 类

       带有附加参数的 SQL 命令的可视化有时对于调试或记录 SQL 查询很有用。我向您介绍类 SqlParamBuilder。实现的首要任务是用一个具有极简代码的 Java 类来满足所述需求。编程界面的灵感来自JDBI库。这些示例在内存模式下使用 H2 数据库。但是,连接数据库驱动程序是必要的。

爪哇岛

void mainStart(Connection dbConnection) throws Exception {
    try (var builder = new SqlParamBuilder(dbConnection)) {
        System.out.println("# CREATE TABLE");
        builder.sql("""
                        CREATE TABLE employee
                        ( id INTEGER PRIMARY KEY
                        , name VARCHAR(256) DEFAULT 'test'
                        , code VARCHAR(1)
                        , created DATE NOT NULL )
                        """)
                .execute();

        System.out.println("# SINGLE INSERT");
        builder.sql("""
                        INSERT INTO employee
                        ( id, code, created ) VALUES
                        ( :id, :code, :created )
                        """)
                .bind("id", 1)
                .bind("code", "T")
                .bind("created", someDate)
                .execute();

        System.out.println("# MULTI INSERT");
        builder.sql("""
                        INSERT INTO employee
                        (id,code,created) VALUES
                        (:id1,:code,:created),
                        (:id2,:code,:created)
                        """)
                .bind("id1", 2)
                .bind("id2", 3)
                .bind("code", "T")
                .bind("created", someDate.plusDays(7))
                .execute();
        builder.bind("id1", 11)
                .bind("id2", 12)
                .bind("code", "V")
                .execute();

        System.out.println("# SELECT");
        List<Employee> employees = builder.sql("""
                        SELECT t.id, t.name, t.created
                        FROM employee t
                        WHERE t.id < :id
                          AND t.code IN (:code)
                        ORDER BY t.id
                        """)
                .bind("id", 10)
                .bind("code", "T", "V")
                .streamMap(rs -> new Employee(
                        rs.getInt("id"),
                        rs.getString("name"),
                        rs.getObject("created", LocalDate.class)))
                .toList();

        System.out.printf("# PRINT RESULT OF: %s%n", builder.toStringLine());
        employees.stream()
                 .forEach((Employee employee) -> System.out.println(employee));
        assertEquals(3, employees.size());
        assertEquals(1, employees.get(0).id);
        assertEquals("test", employees.get(0).name);
        assertEquals(someDate, employees.get(0).created);
    }
}

record Employee (int id, String name, LocalDate created) {}
static class SqlParamBuilder {…}

使用说明和最终想法

可以为多个 SQL 语句回收该类型的实例。调用命令后,可以更改参数并再次运行该命令。参数将分配给上次使用的对象。SqlParamBuilderPreparedStatement

方法自动关闭内部对象(如果之前打开过一个对象)。sql()PrepradedStatement

如果我们更改参数组(通常用于运算符),我们需要为相同的 .否则,将需要使用该方法。INPreparedStatementagainsql()

在最后一次命令执行后,需要一个对象来显式关闭 .但是,由于我们正在实现一个 接口 ,只需将整个块包含在一个块中即可。关闭不会影响包含的数据库连接。SqlParamBuilderAutoCloseabletry

在 Bash shell 中,可以使用脚本 SqlExecutor.sh 运行该示例,该脚本可以下载必要的 JDBC 驱动程序(此处为 H2 数据库)。

如果我们更喜欢 Kotlin,我们可以尝试 Bash 脚本 SqlExecutorKt.sh,它将准备好的 Kotlin 代码迁移到脚本并运行它。

我们不要因为该类存储在 Maven 类型的项目中这一事实而感到困惑。原因之一是运行 JUnit 测试的便利性。

该类根据 Apache 许可证 2.0 版获得许可。

创建自己的实现的最快方法可能是下载示例脚本,重新设计方法,然后将连接参数修改到自己的数据库。使用您自己的 JDBC 驱动程序运行。mainRun()


目录
相关文章
|
3月前
|
Java 关系型数据库 数据库连接
JDBC:Java与数据库的“黄金搭档”,为何它如此重要?
JDBC:Java与数据库的“黄金搭档”,为何它如此重要?
47 8
|
3月前
|
Java 数据库连接 API
JDBC:Java数据库连接的“黑科技”大揭秘
JDBC:Java数据库连接的“黑科技”大揭秘
38 7
|
3月前
|
SQL Java 数据库连接
为何JDBC是Java开发者的“心头好”?原因竟然这么简单!
为何JDBC是Java开发者的“心头好”?原因竟然这么简单!
40 3
|
1月前
|
运维 Java Linux
【运维基础知识】Linux服务器下手写启停Java程序脚本start.sh stop.sh及详细说明
### 启动Java程序脚本 `start.sh` 此脚本用于启动一个Java程序,设置JVM字符集为GBK,最大堆内存为3000M,并将程序的日志输出到`output.log`文件中,同时在后台运行。 ### 停止Java程序脚本 `stop.sh` 此脚本用于停止指定名称的服务(如`QuoteServer`),通过查找并终止该服务的Java进程,输出操作结果以确认是否成功。
36 1
|
1月前
|
Java Python
如何通过Java程序调用python脚本
如何通过Java程序调用python脚本
28 0
|
3月前
|
SQL Java 关系型数据库
【前端学java】JDBC快速入门
【8月更文挑战第12天】JDBC快速入门
31 2
【前端学java】JDBC快速入门
|
3月前
|
Java 数据库连接 网络安全
JDBC数据库编程(java实训报告)
这篇文章是关于JDBC数据库编程的实训报告,涵盖了实验要求、实验环境、实验内容和总结。文中详细介绍了如何使用Java JDBC技术连接数据库,并进行增删改查等基本操作。实验内容包括建立数据库连接、查询、添加、删除和修改数据,每个部分都提供了相应的Java代码示例和操作测试结果截图。作者在总结中分享了在实验过程中遇到的问题和解决方案,以及对Java与数据库连接操作的掌握情况。
JDBC数据库编程(java实训报告)
|
3月前
|
SQL Java 关系型数据库
探索Java数据库连接的奥秘:JDBC技术全攻略
探索Java数据库连接的奥秘:JDBC技术全攻略
58 8
|
3月前
|
SQL Java 数据库连接
JDBC之旅:从陌生到熟悉的Java数据库连接之路
JDBC之旅:从陌生到熟悉的Java数据库连接之路
29 9
|
3月前
|
SQL Java 数据库连接
Java开发者必知:JDBC连接数据库的“三大法宝”
Java开发者必知:JDBC连接数据库的“三大法宝”
34 7