简单的 jdbc 包装器

Posted

技术标签:

【中文标题】简单的 jdbc 包装器【英文标题】:simple jdbc wrapper 【发布时间】:2010-09-22 21:52:33 【问题描述】:

为了在我们的应用程序中实现数据访问代码,我们需要一些框架来包装 jdbc(ORM 不是我们的选择,因为可扩展性)。

我曾经使用过的最酷的框架是Spring-Jdbc。但是我公司的策略是避免外部依赖,尤其是spring、J2EE等。 所以我们正在考虑编写自己的方便的jdbc框架,功能类似于Spring-jdbc:行映射,错误处理,支持java5的特性,但不支持事务。

有没有人写过这样的 jdbc 包装器框架? 如果有人有使用其他 jdbc 包装框架的经验,请分享您的经验。

提前致谢。

【问题讨论】:

"我公司的政策是避免外部依赖,尤其是spring、J2EE等。"哇,这听起来像是一场噩梦。听起来像是一个无限循环的重新发明*** J2EE 是“外部依赖”?? 如果您正在寻找简单的 SQL 执行到对象映射,mybatis 是一个选项。我不会称它为 ORM,因为它不像 hibernate 那样做对象图。它只是允许您执行 sql,并从输入中提取参数,或将列映射到输出对象。 如果有人来这里有类似的问题:你也可以考虑这个包装器:sourceforge.net/p/dyndblayer/wiki/Home(我是开发人员)。 【参考方案1】:

Spring-JDBC 非常棒。考虑到像 Spring 这样的开源项目,外部依赖的负面影响最小化。您可以采用满足您的 JDBC 抽象要求的最稳定的 Spring 版本,并且您知道,如果遇到问题,您将始终能够自己修改源代码——而不依赖于外部方。您还可以通过外部方编写的代码检查您的组织可能存在的任何安全问题的实施。

【讨论】:

【参考方案2】:

我们编写了自己的包装器。这个主题值得写一篇论文,但我怀疑我是否有时间写它,所以这里有一些要点:

我们接受了 sql 并且没有试图隐藏它。唯一的调整是添加对命名参数的支持。参数很重要,因为我们不鼓励使用 on-the-fly sql(出于安全原因),我们始终使用 PreparedStatements。

对于连接管理,我们使用了 Apache DBCP。这在当时很方便,但目前还不清楚现代 JDBC 实现需要多少这样的东西(缺少关于这些东西的文档)。 DBCP 还汇集 PreparedStatements。

我们不关心行映射。相反(对于查询),我们使用了类似于 Apache dbutil 的 ResultSetHandler 的东西,它允许您将结果集“输入”到一个方法中,然后该方法可以将信息转储到您想要的任何地方。这更灵活,实际上为行映射实现 ResultSetHandler 并不难。对于插入/更新,我们创建了一个通用记录类(基本上是一个带有一些额外花里胡哨的哈希图)。行映射(对我们而言)最大的问题是,一旦您执行“有趣”的查询,您就会陷入困境,因为您可能有映射到不同类的字段;因为你可能有一个分层的类结构但是一个扁平的结果集;或者因为映射很复杂并且依赖于数据。

我们内置了错误日志记录。对于异常处理:在查询中我们捕获并记录,但对于更新我们捕获、记录并重新抛出未经检查的异常。

我们使用包装器方法提供事务支持。调用者提供执行事务的代码,我们确保事务得到妥善管理,不会忘记完成事务并内置回滚和错误处理。

稍后,我们添加了一个非常简单的关系方案,允许单个更新/插入应用到记录及其所有依赖项。为简单起见,我们没有在查询中使用它,我们特别决定不支持删除,因为使用级联删除更可靠。

迄今为止,此包装器已成功用于两个项目。它当然是轻量级的,但现在每个人都说他们的代码是轻量级的。更重要的是,它提高了程序员的工作效率,减少了错误的数量(并使问题更容易追踪),并且如果需要的话,它也相对容易追踪,因为我们不相信为了提供漂亮的架构而添加很多层。

【讨论】:

【参考方案3】:

从jcabi-jdbc 尝试JdbcSession。就像 JDBC 一样简单,例如:

String name = new JdbcSession(source)
  .sql("SELECT name FROM foo WHERE id = ?")
  .set(123)
  .select(new SingleOutcome<String>(String.class));

就是这样。

【讨论】:

【参考方案4】:

这听起来像是一个非常短视的决定。考虑开发/维护这样一个框架的成本,特别是当你可以得到它时,它是免费的源代码。不仅不用自己开发,还可以根据需要随意修改。

话虽如此,您真正需要复制的是 JdbcTemplate 的概念及其回调(PreparedStatementCreator、PreparedStatementCallback)以及 RowMapper/RowCallbackHandler。编写这样的东西不应该过于复杂(特别是考虑到您不必进行事务管理)。

但是,正如我所说,既然可以免费获得它并根据需要修改源代码,为什么还要编写它?

【讨论】:

【参考方案5】:

我更喜欢的一个:Dalesbred。它是 MIT 许可的。

获取自定义类(部门)所有行的简单示例。

List<Department> departments = db.findAll(Department.class,
    "select id, name from department");

当自定义类定义为:

public final class Department 
    private final int id;
    private final String name;

    public Department(int id, String name) 
        this.id = id;
        this.name = name;
    

免责声明:这是由我工作的公司提供的。

【讨论】:

【参考方案6】:

mJDBC:https://mjdbc.github.io/

我使用它多年,发现它非常有用(我是这个库的作者)。

它的灵感来自 JDBI 库,但没有依赖项,增加了事务支持,提供性能计数器,并允许在您真正需要时轻松切换到 Java 中可能的最低 SQL 级别(旧的普通 JDBC API)。

【讨论】:

你可能应该提到你是作者。【参考方案7】:

Jedoo

有一个名为Jedoo 的包装类,它使用数据库连接池和单例模式将其作为共享变量进行访问。它有很多功能可以快速运行查询。

用法

要使用它,您应该将它添加到您的项目中并在 java 类中加载它的单例:

import static com.pwwiur.util.database.Jedoo.database;

而且使用起来也很简单:

if(database.count("users") < 100) 
    long id = database.insert("users", new Object[][]
        "name", "Amir",
        "username", "amirfo"
    );
    
    database.setString("users", "name", "Amir Forsati", id);

    try(ResultSetHandler rsh = database.all("users")) 
         while(rsh.next()) 
             System.out.println("User ID:" + rsh.getLong("id"));
             System.out.println("User Name:" + rsh.getString("name"));
         
    

您还可以在上面链接的文档中找到一些有用的功能。

【讨论】:

【参考方案8】:

尝试使用我的库作为替代:

<dependency>
  <groupId>com.github.buckelieg</groupId>
  <artifactId>jdbc-fn</artifactId>
  <version>0.2</version>
</dependency>

更多信息here

【讨论】:

以上是关于简单的 jdbc 包装器的主要内容,如果未能解决你的问题,请参考以下文章

了解Java的自动装箱与拆箱

Java中包装器类的行为[重复]

自动生成函数的类型安全包装,然后仅使用 `__typename` 作为参数动态调用。打字稿

一台机linux器装nginx一台装PHP,怎么能够用nginx访问php页面?

在linux中为脚本创建批处理文件包装器

小记----JDBC学习了解