代码之家  ›  专栏  ›  技术社区  ›  binaryLV

最佳实践:在Java中使用DB

  •  4
  • binaryLV  · 技术社区  · 14 年前

    首先,我是Java新手。

    我想找出用Java来处理DB的好方法。我正在使用c3p0连接池。这次Hibernate或其他ORM不是一个选项,我们决定暂时使用“纯SQL”。

    当前基本的数据检索如下:

    private int getUserID(int sessionID, String userIP) {
     int result = 0;
     Connection conn = null;
     PreparedStatement st = null;
     ResultSet rs = null;
     try {
      // Application.cpds is an instance of c3p0's ComboPooledDataSource
      conn = Application.cpds.getConnection();
      st = conn.prepareStatement("SELECT user_id, user_ip, is_timed_out FROM g_user.user_session WHERE id = ?");
      st.setInt(1, sessionID);
      rs = st.executeQuery();
      if ( rs.next() ) {
       if ( !rs.getBoolean("is_timed_out") && userIP.equals(rs.getString("user_ip")) ) {
        result = rs.getInt("user_id");
       }
      }
     }
     catch (SQLException e) {
      e.printStackTrace();
     }
     finally {
      if ( rs != null ) {
       try { rs.close(); } catch (SQLException e) { e.printStackTrace(); }
      }
      if ( st != null ) {
       try { st.close(); } catch (SQLException e) { e.printStackTrace(); }
      }
      if ( conn != null ) {
       try { conn.close(); } catch (SQLException e) { e.printStackTrace(); }
      }
     }
     return result;
    }
    

    对于这样的基本操作,代码看起来很长。另一个问题是,大多数代码必须在许多地方重复(声明连接、PreparedStatement、ResultSet、关闭它们、捕获异常)。不过,这是我在谷歌搜索时看到的大多数例子。

    在PHP中,我将创建一个包装类,该类将具有方法select(),该方法接受2个参数(字符串)sqlquery和(数组)参数,并返回简单的数据数组。包装器类也有一些更具体的方法,比如:

    • selectValue()用于单个值(例如, select count(*) from user )
    • 对于单行(例如, select name, surname from user where id = :user_id )
    • 选择单列(例如, select distinct remote_address from user )

    在Java中是否有这样的做法?或者有更好的/更方便的吗?或者我应该使用和 getUserID() 上面的例子?如我所说,这次ORM不是一个选项。

    事先谢谢:)


    编辑: 目前 DBConnection 类被写入。它从构造函数中的c3p0连接池获取连接。它很少有公共方法来使用DB: select() 对于表格数据, selectValue() 对于单个值, selectRow() selectColumn() 对于单行或列,以及 insert() , update() , delete() ddl() . 方法接受 String query, Object[] params 论点,用 params 是可选的。 插入() , UpDead() 删除() 返回 Integer 这是由于 PreparedStatement.executeUpdate() . select 方法返回不同的结果:

    • ArrayCollection<HashMap<String, Object>> select()
    • Object selectValue()
    • HashMap<String, Object> selectRow()
    • ArrayCollection<Object> selectColumn()

    最后一个问题是编译器警告- "warning: [unchecked] unchecked cast" . 这是因为所有方法都调用返回 Object 并将其结果强制转换为上述类型。由于我是Java新手,我也不确定是否选择了合适的类型来进行选择。除此之外,一切似乎都按预期工作。

    4 回复  |  直到 10 年前
        1
  •  5
  •   Tim Büthe    10 年前

    如果一个ORM没有选项,您仍然可以使用Spring的JDBC助手类: http://docs.spring.io/spring-framework/docs/4.1.0.RELEASE/spring-framework-reference/html/jdbc.html

    或者您可以自己编写一些助手方法。也许是 DBUtil.close(conn, st, rs); 会很好。

    顺便说一下,您确实应该使用日志框架,而不是“ e.printStackTrace()

    编辑: 还有一件事:当您已经用纯JDBC编写了所有SQL时,我认为事后添加ORM有点困难。你不能重构那些东西,你必须把它扔掉再做一次。

    编辑: 如果仍要关闭语句,则不必关闭结果集。这个 Java ResultSet API 阅读:

    结果集对象自动 当语句对象 生成,关闭,重新执行, 或用于检索下一个结果 从一系列多个结果中。

    除此之外,c3p0还进行资源管理,并在返回连接时关闭语句。你也可以查一下。

        2
  •  2
  •   zcourts    14 年前

    为了避免代码的重复,也许可以使事情变得简单。 您可以做的是创建一个数据库类。

    在类中,您可以创建用于访问数据库的通用方法。 例如

    如果该类称为dbmanager.java,则在 创建方法

    private connect()
    public boolean update()
    public ResultSet query()
    

    Connect方法的原因很明显,您可以使用它来获取连接。因为它是私有的,所以您可以在dbmanager的构造函数中调用它。

    然后,使用update()方法可以执行SQL插入、更新、删除等操作,基本上,除了更新方法的成功状态之外,任何不返回任何数据的SQL操作都可以完成。

    当要执行选择查询时,将使用查询方法。您可以返回结果集,然后在调用方法/类中迭代结果。

    如何处理异常取决于您自己。用这种方式处理dbmanager类中的异常可能会更好,因为在进行查询的各种类中,您不必处理这些异常。

    因此,而不是

    public ResultSet query() Throws SQLException{
    

    您将在查询方法中使用一个try-catch,就像在上面的示例中那样。 在dbmanager类中处理它的明显优点是,在使用SQL连接的所有其他类中,您不必担心它。

    希望这有帮助

    回应您的评论:

    这取决于你返回什么,返回结果集只是一个主意,但也许最好返回某种类型的集合而不是数组,也许?取决于你需要什么。结果集不需要关闭。

    public ResultSet query(String strSql) {
    
            try {
                Statement tmpStatement = connection.createStatement();
                ResultSet resultSet = tmpStatement.executeQuery(strSql);
                return resultSet;
            } catch (java.sql.SQLException ex) {
               //handle exception here
                return null;
            }
        }
    

    然后你的更新会是这样的

    public boolean updateSql(String strSQL) {
             try {
                Statement tmpStatement = connection.createStatement();
                tmpStatement.executeUpdate(strSQL);
               return true;
            } catch (java.sql.SQLException ex) {
                //handle exception
                return false;
            }
    }
    

    erm,然后您可以像这样使用查询方法

     ResultSet r = query(sql);
    
            try {
    
                while (r.next()) {
                    someVar[i] = r.getString("columnName");           
                }
            } catch (SomeException ex) {
               //handle exception etc
            }
    

    但是,正如您所说,您可以更改查询方法,将结果复制到数组或集合中,然后返回集合并用

    tmpStatement.close();
    

    但当一个语句对象关闭时,它的当前resultset对象(如果存在)也会关闭。(来自api文档)

    最好的做法是在将结果复制到集合对象后立即释放数据库资源,然后关闭语句。这又取决于你。

        3
  •  0
  •   Greg    14 年前

    这次不能选择Hibernate或其他ORM,我们决定暂时使用“纯SQL”。 出于好奇,坚持使用普通SQL的原因是什么?查看您提到的示例和问题,第一个明显的答案是使用ORM,不用担心——在大多数情况下,标准的ORM特性列表就足够了。

    很明显,有很多理由不使用ORM,所以我对你们感兴趣?

        4
  •  0
  •   4NDR01D3    14 年前

    我认为O级粒度始终是开发人员的决定。我的意思是,拥有如此多的异常和验证的好处在于,您可以捕获特定的错误并根据它进行操作,但是,如果您所需要的不需要那么高的健壮性,正如您所展示的那样,它只是打印出堆栈跟踪,我认为包装方法在您的情况下是有用的。