最佳实践:在Java中使用DB

时间:2010-08-02 10:20:41

标签: java database

首先,我是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;
}

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

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

  • selectValue()表示单个值(例如select count(*) from user
  • selectRow()表示单行(例如select name, surname from user where id = :user_id
  • selectColumn for single column(例如select distinct remote_address from user

用Java练习这样的东西吗?还是有什么更好/更方便的?或者我应该使用与上面getUserID()示例中相同的样式?正如我所说,这次ORM不是一个选择。

提前致谢:)


编辑:目前正在撰写DBConnection课程。它从构造函数中的c3p0连接池获取连接。使用数据库的公共方法很少:表格数据为select(),单值为selectValue(),单行或列为selectRow()selectColumn(),以及{{ 1}},insert()update()delete()。方法接受ddl()个参数,String query, Object[] params是可选的。 paramsinsert()update()返回delete(),这是Integer的结果。 PreparedStatement.executeUpdate()方法会返回不同的结果:

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

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

4 个答案:

答案 0 :(得分:5)

如果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()

修改 还有一件事:我认为之后添加ORM很困难,因为所有的SQL都是用纯JDBC编写的。你不能重构那些东西,你必须扔掉它再做一次。

修改 如果要关闭语句,则不必关闭resultSet。 Java ResultSet API读取:

  

自动生成ResultSet对象   当Statement对象关闭时关闭   生成它关闭,重新执行,   或用于检索下一个结果   来自多个结果的序列。

除此之外,C3P0也进行资源管理,并在返回连接时关闭语句。你也可以这样看。

答案 1 :(得分:2)

避免重复代码并使事情变得更简单。 你可以做的是创建一个Database类。

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

如果该类被调用DBManager.java然后在里面 创建方法

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

连接方法的原因很明显,你用它来获取你的连接。由于它是私有的,你可以在DBManager的构造函数中调用它。

然后使用update()方法允许您执行SQL插入,更新,删除等,基本上任何不返回任何数据的SQL操作除了可能的更新完成状态方法

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

中遍历结果

您如何处理异常取决于您。您可以更好地处理DBManager类中的异常,这样您就不必在进行查询的各个类中处理它们。

所以而不是

public ResultSet query() Throws SQLException{

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

希望有用

回应你的评论:

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

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;
        }
}
嗯,你可以使用你的查询方法

 ResultSet r = query(sql);

        try {

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

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

关闭语句,而不是返回结果集。
tmpStatement.close();

但是当一个Statement对象关闭时,它的当前ResultSet对象(如果存在)也会被关闭。(来自api docs)

一旦将结果复制到集合对象然后关闭语句,最好是释放数据库资源。再取决于你。

答案 2 :(得分:0)

“这次Hibernate或其他ORM不是一个选项,我们现在决定坚持使用”普通SQL“。” 出于好奇,坚持使用纯SQL的原因是什么?看一下您提到的示例和问题,首先明显的答案是使用ORM并且不要打扰 - 在大多数情况下,标准的ORM功能列表就足够了。

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

答案 3 :(得分:0)

我认为粒度级别始终是开发人员的决定。我的意思是,拥有如此多的异常和验证的好处是你可以捕获特定的错误并根据它采取行动,但是如果你需要的不需要那种稳健性并且你正在展示它只是为了打印在堆栈跟踪中,我认为包装器方法在您的情况下非常有用。