将 ResultSet 分配给类中的变量

Posted

技术标签:

【中文标题】将 ResultSet 分配给类中的变量【英文标题】:Assign ResultSet to variables in class 【发布时间】:2012-05-07 23:24:12 【问题描述】:

我有以下功能:

public Map<Integer, Product> fetchAllProducts() 

  Map<Integer, Product> pArr = new HashMap();
  try 
     Statement st = conn.createStatement();
     ResultSet rs = st.executeQuery("SELECT id, intro, content, price FROM Product");
     while (rs.next()) 
       pArr.put(rs.getInt("id"), new Product(rs));
     
     st.close();
   catch (SQLException ex) 
   //...
  
  return pArr;

它从 mysqlProduct 中获取所有行,并为每一行创建一个新的 Product 类。产品构造函数:

 public Product(ResultSet rs) 
    try 
       price = rs.getInt("price");
       content = rs.getString("content");
       intro = rs.getString("intro");
     catch (SQLException ex) 
       //...
    
   

我的问题是:有没有更好的方法将结果列分配给Product 中的变量?代码price = rs.getInt("price"); 等等似乎是多余的,不是吗?完美的是,如果我将查询语句更改为SELECT intro, content, tax, delivery FROM ...,构造函数会自动将其分配给构造函数中的适当变量(即介绍、内容、税收、交付)。这可以用 Java 完成还是我只是在做梦?

【问题讨论】:

如果我理解正确,您希望在 SQL 查询中使用 Java 变量,以便自动分配它们。好吧,从 SQL 不能有 Java 变量的意义上说,这是不可能的。如果你真的想要这样的东西,为什么不试一试制作这样的东西!顺便说一句,试试 Ruby on Rails。它可能会让你更接近你的梦想。 【参考方案1】:

首先:你真的不应该将ResultSet 传递给Product 的构造函数!您应该清楚地将数据库访问代码与业务逻辑分开。

所以通常我希望在您的代码中看到这一点:

private static final String TABLE_NAME = "product";
private static final String ID_COLUMN = "id";
private static final String INTRO_COLUMN = "intro";
private static final String CONTENT_COLUMN = "content";
private static final String PRICE_COLUMN = "price";

private static final String FETCHALLPRODUCTS_QUERY = String.format("SELECT %s, %s, %s, %s FROM %s", ID_COLUMN, INTRO_COLUMN, CONTENT_COLUMN, PRICE_COLUMN, TABLE_NAME);

public Map<Integer, Product> fetchAllProducts() 

  Map<Integer, Product> pArr = new HashMap();
  try 
     Statement st = conn.createStatement();
     ResultSet rs = st.executeQuery(FETCHALLPRODUCTS_QUERY);
     while (rs.next()) 
        Integer price = rs.getInt(PRICE_COLUMN);
        String content = rs.getString(CONTENT_COLUMN);
        String intro = rs.getString(INTRO_COLUMN);

        Product product = new Product(price, content, intro);
        Integer id = rs.getInt(ID_COLUMN);
        pArr.put(id, product);
     
     st.close();
   catch (SQLException ex) 
   //...
  
  return pArr;

但要回答您的问题:在处理普通 JDBC 时,这样做是一种非常常见的做法。您正在寻找的是一个 ORM 框架,例如 Hibernate。

使用 JDBC 连接时我正在做的一件事是为列名和表名声明常量。在我看来,这样它会更干净一些。

【讨论】:

好的,我不会将整个 ResultSet 传递给构造函数(我意识到这确实很愚蠢)。 问题是,即使我有列名和表名的常量,我仍然会在 Product 类中拥有名为“hardcodely”的变量,这意味着我必须(嗯,我应该)重命名这些变量同样,在重命名列的情况下。但正如你所说,它更干净一些。你能因此显示带有常量的代码吗?它只是带有静态变量的最终公共类吗?顺便说一句,“在处理普通 JDBC 时这样做是一种非常常见的做法”,您是否修改了您修改的代码或使用 ORM 框架?谢谢你的疲惫回答! @aGr:我的意思是我的答案中的代码是处理普通 JDBC 时的好习惯。一般来说,在我看来,使用 ORM 是一种更好的做法。如果项目有一定的规模,我更喜欢使用 Hibernate。请在上面找到更改后的代码。 谢谢,这个项目很小,所以也许我会坚持一段时间。【参考方案2】:

您可以在反射的帮助下实现这一点,ResultSetMapper 也是如此。

一个tutorial。

Apache BeanUtils 有类似的东西,但它会返回DynaBean。

如果您可以迁移到更复杂和完整的系统,您应该考虑使用 ORM,如 hibernate、JPA。

对于普通的 JDBC,您可以使用自己的反射工具,也可以使用 ResultMapper。

【讨论】:

【参考方案3】:

我猜想使用一些或映射库(如 Hibernate)会使代码更愉快。正如我听说的那样,它使您想要的东西变得普遍。但是,使用它涉及替换项目中的所有数据库交互代码。我觉得你的代码没有那么难看,可能这样做会更愉快一点:

 while (rs.next()) 
   pArr.put(rs.getInt("id"), new Product(rs));
   Integer id = rs.getInt("id");
   Integer price = rs.getInt("price");
   Integer content = rs.getString("content");
   Integer intro = rs.getString("intro");
   Product product = new Product(price, content, intro);
   pArr.put(id, product);
 

嗯,当我输入答案时,似乎出现了三个相同的答案。对不起各位:)

【讨论】:

【参考方案4】:

Commons DbUtils,它是 JDBC 之上的一个薄层(不像 Hibernate 那样复杂)可以set bean properties from a ResultSet。

【讨论】:

【参考方案5】:

我认为如果您使用例如休眠,这是可能的。 但就像我的前身写的那样:不要在 Product 的构造函数中设置 ResultSet,因为您将处理 ResultSet 的另一个副本(ResultSet 很重),并且如果您有很多数据,那会降低性能。

那就这样吧:

...

pArr.put(rs.getInt("id"), new Product(rs.getint("Price") ....));

...

public Product(int price ....) 

【讨论】:

以上是关于将 ResultSet 分配给类中的变量的主要内容,如果未能解决你的问题,请参考以下文章

Kivy 将变量传递给类中的函数

将标准输入中的字符串分配给类成员变量

python 类中的变量传递给类中的函数

将类变量作为默认值分配给类方法参数

Spring给类中静态变量赋值

Spring给类中静态变量赋值