2010-05-17 27 views
7

我想在java中開發通用DAO。我已經嘗試了以下。這是 是實現泛型DAO的好方法嗎?我不想使用休眠。我試圖使其儘可能通用,以便我不必一遍又一遍地重複相同的代碼。java中的通用DAO

public abstract class AbstractDAO<T> { 

    protected ResultSet findbyId(String tablename, Integer id){ 
     ResultSet rs= null; 
     try { 
      // the following lines are not working 
      pStmt = cn.prepareStatement("SELECT * FROM "+ tablename+ "WHERE id = ?"); 
      pStmt.setInt(1, id); 
      rs = pStmt.executeQuery(); 


     } catch (SQLException ex) { 
      System.out.println("ERROR in findbyid " +ex.getMessage() +ex.getCause()); 
      ex.printStackTrace(); 
     }finally{ 
      return rs; 
     } 

    } 

} 

現在我有:

public class UserDAO extends AbstractDAO<User>{ 

    public List<User> findbyid(int id){ 
    Resultset rs =findbyid("USERS",id) // "USERS" is table name in DB 
    List<Users> users = convertToList(rs); 
    return users; 
} 


private List<User> convertToList(ResultSet rs) { 
     List<User> userList= new ArrayList(); 
     User user= new User();; 
     try { 
      while (rs.next()) { 
       user.setId(rs.getInt("id")); 
       user.setUsername(rs.getString("username")); 
       user.setFname(rs.getString("fname")); 
       user.setLname(rs.getString("lname")); 
       user.setUsertype(rs.getInt("usertype")); 
       user.setPasswd(rs.getString("passwd")); 
       userList.add(user); 
      } 
     } catch (SQLException ex) { 
      Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex); 
     } 

     return userList; 

    } 
} 
+0

有什麼問題? – Bozho 2010-05-17 11:59:43

+0

plz看到行說// //下面的行不行; – akshay 2010-05-17 12:08:30

+0

爲什麼你不想使用Hibernate(或其他ORM)? – 2010-05-17 12:14:22

回答

0

不要重新發明輪子,你已經可以找到好的項目,這樣一來,例如generic-dao項目上谷歌。

編輯:回答得太快可能,谷歌的項目是基於JPA但仍然可以使用一些裏面的概念。

+0

我想知道爲什麼我的代碼行中提到的代碼行不通 – akshay 2010-05-17 11:56:24

1

它是好的,但改變方法

private List<User> convertToList(ResultSet rs) { 
     List<User> userList= new ArrayList(); 
     User user= new User();; 
     try { 
      while (rs.next()) { 
       user.setId(rs.getInt("id")); 
       user.setUsername(rs.getString("username")); 
       user.setFname(rs.getString("fname")); 
       user.setLname(rs.getString("lname")); 
       user.setUsertype(rs.getInt("usertype")); 
       user.setPasswd(rs.getString("passwd")); 
       userList.add(user); 
      } 
     } catch (SQLException ex) { 
      Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex); 
     } 

     return userList; 

    } 

private List<User> convertToList(ResultSet rs) { 
     List<User> userList= new ArrayList<User>(); 
     try { 
      while (rs.next()) { 
       User user= new User(); 
       user.setId(rs.getInt("id")); 
       user.setUsername(rs.getString("username")); 
       user.setFname(rs.getString("fname")); 
       user.setLname(rs.getString("lname")); 
       user.setUsertype(rs.getInt("usertype")); 
       user.setPasswd(rs.getString("passwd")); 
       userList.add(user); 
      } 
     } catch (SQLException ex) { 
      Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex); 
     } 

     return userList; 

    } 

用戶對象應while循環中被創建。

+0

plz看到行//下面的行不行; – akshay 2010-05-17 12:08:52

+0

如果拋出SQLException,此代碼將泄漏資源。您需要確保結果集,語句和連接已關閉。最簡單的方法是使用Spring JDBC之類的框架而不是原始JDBC。 – Adamski 2010-05-17 12:18:03

+0

你得到的錯誤是什麼? – 2010-05-17 12:18:19

5

我的建議是:

  • 不要寫一個通用的DAO;當你意識到在特定情況下他們沒有完全滿足你需要的東西時,泛型類會回來咬你,而且通常會越來越複雜,以覆蓋越來越多的用例。更好地編寫特定於應用程序的DAO,然後試圖在以後生成任何常見行爲。
  • 考慮使用Spring JDBC來編寫特定於應用程序的DAO,但採用比JDBC更緊湊和更不容易出錯的方式。另外,與Hibernate不同的是,Spring JDBC僅對原始JDBC執行簡潔的包裝,爲您提供更精細的控制和更高的可視性。

// Create or inject underlying DataSource. 
DataSource ds = ... 
// Initialise Spring template, which we'll use for querying. 
SimpleJdbcTemplate tmpl = new SimpleJdbcTemplate(ds);  

// Create collection of "Role"s: The business object we're interested in. 
Set<Role> roles = new HashSet<Role>(); 

// Query database for roles, use row mapper to extract and create 
// business objects and add to collection. If an error occurs Spring 
// will translate the checked SQLException into an unchecked Spring 
// DataAccessException and also close any open resources (ResultSet, Connection). 
roles.addAll(tmpl.query("select * from Role", new ParameterizedRowMapper<Role>() { 
    public Role mapRow(ResultSet resultSet, int i) throws SQLException { 
    return new Role(resultSet.getString("RoleName")); 
    } 
})); 
+0

Spring JDBC的另一投票。它處理很多樣板連接的東西(以避免資源泄漏)。另外,它提供了一種將列映射到對象的更好方法。 另一個評論,我不會硬編碼的主鍵列名稱。只要你這樣做,就會有人來創建一個名爲別的列的表,或者使用多列主鍵。 – David 2010-05-17 15:05:55

6

如果你可以使用Spring活着,我會建議如下改進:

  • 讓春天做異常處理。
  • 使用JdbcTemplate而不是自己創建預準備語句。

獨立使用Spring的,我會建議如下:

  • 作爲參數不要發送表名。這應該在初始化階段完成。
  • 在id參數上使用一個字符串,因爲它更通用。
  • 考慮返回一個通用對象而不是集合,因爲集合應該總是隻包含一個對象。

一種改進AbstractDao的同春:

import java.util.Collection; 

import org.springframework.jdbc.core.JdbcTemplate; 
import org.springframework.jdbc.core.RowMapper; 

public abstract class AbstractDao<T> { 

    protected final RowMapper<T> rowMapper; 

    protected final String findByIdSql; 

    protected final JdbcTemplate jdbcTemplate; 

    protected AbstractDao(RowMapper<T> rowMapper, String tableName, 
      JdbcTemplate jdbcTemplate) { 
     this.rowMapper = rowMapper; 
     this.findByIdSql = "SELECT * FROM " + tableName + "WHERE id = ?"; 
     this.jdbcTemplate = jdbcTemplate; 
    } 

    public Collection<T> findById(final String id) { 
     Object[] params = {id}; 
     return jdbcTemplate.query(findByIdSql, params, rowMapper); 
    } 
} 

正如你看到的,沒有任何異常處理或與原始SQL類黑客攻擊。這個模板爲你關閉了ResultSet,我在你的代碼中看不到。

而且userDAO的:

import java.sql.ResultSet; 
import java.sql.SQLException; 

import org.springframework.jdbc.core.JdbcTemplate; 
import org.springframework.jdbc.core.RowMapper; 

public class UserDao extends AbstractDao<User> { 

    private final static String TABLE_NAME = "USERS"; 

    public UserDao(JdbcTemplate jdbcTemplate) { 
     super(new UserRowMapper(), TABLE_NAME, jdbcTemplate); 
    } 

    private static class UserRowMapper implements RowMapper<User> { 
     public User mapRow(ResultSet rs, int rowNum) throws SQLException { 
      User user = new User(); 
      user.setUserName(rs.getString("username")); 
      user.setFirstName(rs.getString("fname")); 
      user.setLastName(rs.getString("lname")); 

      return user; 
     } 
    } 
} 

更新時間:

當你知道ID和ID對應一個排在數據庫中,你應該考慮返回的通用對象,而不是採集。

public T findUniqueObjectById(final String id) { 
    Object[] params = {id}; 
    return jdbcTemplate.queryForObject(findByIdSql, params, rowMapper); 
} 

這使得您的服務代碼的可讀性,因爲你不需要從列表中檢索用戶,但僅限於:

User user = userDao.findUniqueObjectById("22"); 
+0

我正在嘗試實現你的方法,除了決定在哪裏以及如何初始化userDao對象之外,一切似乎都很好。在實現您的方法之前,我在userService類中使用userDao和autowired註釋。但是現在在你的例子中沒有任何空的構造函數,並且不能使用dao作爲自動裝配的對象。我認爲可以有空的類構造函數調用其他構造函數與自動裝配的jdbctemplate。這有用嗎? – 2013-08-08 10:19:10

0

您需要您的「WHERE」來添加一個空格第 見下圖:

pStmt = cn.prepareStatement("SELECT * FROM "+ tablename+ "WHERE id = ?"); 

pStmt = cn.prepareStatement("SELECT * FROM "+ tablename+ " WHERE id = ?"); 
-1

雖然每個人都在這裏建議使用Spring及其API,但它使用元數據,而且這是代碼的糟糕組合。所以不要使用通用的DAO或Spring。

通用代碼很重,並且會增加您的負擔。

+0

聽起來好像你對泛型代碼有不好的體驗。如果正確完成元數據並不差 - 從代碼移入元數據的信息越多,剩餘的代碼應該越好(如果正確完成)。通用代碼在許多情況下都是唯一的選擇(DRY勝過大多數其他指導方針/氣味,並且是最好的代碼和編碼實踐的根源)。 – 2011-09-20 20:13:38

0

如果我正確地理解了問題陳述,您試圖在您的服務和通過JDBC接口公開的普通數據庫之間實現一種隔離層。隔離層將用作POJO域對象到SQL數據集的數據映射器。這正是iBATIS library的任務,我建議您思考一下,而不是實現自制GenericDAO類。