【问题标题】:java data access: is this good style of java data access code, or is it too much try finally?java数据访问:这是java数据访问代码的好风格,还是最后尝试的太多了?
【发布时间】:2023-03-22 14:44:01
【问题描述】:

这是java数据访问代码的好风格,还是最后尝试的太多了?

public List<Item> getItems() throws ItemException {
    ArrayList<Item> items = new ArrayList<Item>();
    try {
        Connection con = ds.getConnection();
        try {
            PreparedStatement pStmt = con.prepareStatement("SELECT ....");
            try {
                ResultSet rs = pStmt.executeQuery();
                try {
                    while (rs.next()) {
                        Item item = new Item();
                        item.setItemNo(rs.getString("item_id"));
                        // ...
                        items.add(item);
                    }
                } finally {
                    rs.close();
                }
            } finally {
                pStmt.close();
            }
        } finally {
            con.close();
        }
    } catch (SQLException e) {
        throw new ItemException(e);
    }
    return items;
}

【问题讨论】:

  • 我建议你去冬眠。它有很多功能。 Aarons 代码看起来不错,但如果您每次都使用 JDBC。您最终将创建大量与数据库的连接,这可能会影响应用程序的性能。
  • ArrayList&lt;Item&gt; items = new ArrayList&lt;Item&gt;(); 应该是List&lt;Item&gt; items = new ArrayList&lt;Item&gt;();

标签: java data-access-layer


【解决方案1】:

根据 API 文档,StatementsResultSets 通过 Connection 隐式关闭,所以是的 - 其中 2 个 try/finally 块是不必要的(而且非常难看)。当您为大量查询保留单个连接以减少内存使用时,显式关闭语句可能很有用。

【讨论】:

  • 除了最简单的代码外,你应该手动关闭它们,否则它们会挂掉。
  • 没有。如果您确保 Connection 已关闭,那么可能会出现的只是对象本身,手动关闭它们也不会阻止。
【解决方案2】:

将其与我的代码进行比较:

Connection con = null;
PreparedStatement pStmt = null;
ResultSet rs = null;
try
{
    con = ds.getConnection();
    pStmt = con.prepareStatement("SELECT ....");
    rs = pStmt.executeQuery();
    while (rs.next()) {
        Item item = new Item();

        item.setItemNo(rs.getString("item_id"));
        ...

        items.add(item);
    }
}
finally {
    rs = DBUtil.close (rs);
    pStmt = DBUtil.close (rs);
    con = DBUtil.close (rs);
}

这是close() 的样子:

public static ResultSet close (ResultSet rs) {
    try {
        if (rs != null)
            rs.close ();
    } catch (SQLException e) {
        e.printStackTrace (); 
        // Or use your favorite logging framework.
        // DO NOT THROW THIS EXCEPTION OR IT WILL
        // HIDE EXCEPTIONS IN THE CALLING METHOD!!
    }
    return null; // Make sure no one uses this anymore
}

[编辑] 您需要为其他类型复制此代码。

我还将所有这些都移到了一个名为 DBOp 的辅助类中,因此我只需覆盖 processRow(ResultSet row) 即可进行实际处理,并且可以省略所有样板代码。在 Java 5 中,DBOp 的构造函数为:

public DBOp (Logger log, DataSource ds, String sql, Object... param)

我正在传入记录器,以便显示哪个实例实际上正在轮询数据。

【讨论】:

  • 我想你忘了在第二次调用时将参数更改为 close()。
  • 是的,您需要为每种 JDBC 类型复制一份此代码:(我希望 Sun 能够让它们实现 Closeable
  • 如果 getConnection() 从池中获取连接,则不应关闭它。另外,我认为关闭语句也会自动关闭 ResultSet。
  • @Adrinn:这取决于池的实现。当我关闭它时,我使用的那些将返回到池的连接。这样,无论我是否使用池化,我的代码都是一样的。
【解决方案3】:

...并且您不应该在 getItems() 方法中关闭连接。看起来,您将 Connection 对象存储在该 ds 对象中。所以你应该把它留给ds 来关闭它。否则,存在 ds 使用 getConnection() 方法返回已经关闭的连接的风险,我认为这是一种不希望的和意外的行为;)

【讨论】:

  • ... 当然,除非 ds 对象恰好是 DataSource。然后,您必须在完成后关闭连接。 java.sun.com/javase/6/docs/api/javax/sql/DataSource.html
  • @Dirk,很好,而且(太)短的变量名暗示你是对的。我想到了传统的 DriverManager,您可以在其中通过静态方法获得连接。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-23
相关资源
最近更新 更多