2013-06-30 74 views
2

我正在學習Java,現在我正在學習JDBC。我想我已經掌握瞭如何使用resultset對象,但是我想確保我做對了。從結果集中創建對象。我做對了嗎?

請參閱下面的代碼。它在名爲「餐館」的數據庫中查詢名爲「菜單」的表。該表有四列:

  • id_menu整數,該表的主鍵。
  • 字符串,菜單項的名稱(如「雙層吉士漢堡」)
  • DESCR字符串,菜單項的說明(如「在全麥饃兩個全牛肉餅「)。
  • 價格雙,項目(如價格。5.95)(注意:我知道我可以使用的錢的類型,但我試圖保持簡單)

這裏是在Java一個menuItem對象的代碼。表格中的每一行都應該用來創建一個menuItem對象:

public class menuItem { 

    public int id = 0; 
    public String descr = ""; 
    public Double price = 0.0; 
    public String name = ""; 
    public menuItem(int newid, String newdescr, Double newprice, String newname){ 
     id = newid; 
     descr = newdescr; 
     price = newprice; 
     name = newname; 
     } 
    } 

爲了簡化這個練習,一切都是公開的。

下面就來填充數據庫的代碼。目前,這個代碼是主類中的一個方法。

public static ArrayList<menuItem> reQuery() throws ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException{  

    ArrayList<menuItem> mi = new ArrayList<menuItem>(); 

    //Step 1. User Class.forname("").newInstance() to load the database driver. 
    Class.forName("com.mysql.jdbc.Driver").newInstance(); 

    //Step 2. Create a connection object with DriverManager.getConnection("") 
    //Syntax is jdbc:mysql://server/database? + user=username&password=password 
    Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/miguelel_deliveries?" + "user=root&password="); 

    //Step 3. Create a statement object with connection.createStatement(); 
    Statement stmt = conn.createStatement(); 

    //Step 4. Create variables and issue commands with the Statement object. 
    ResultSet rs = stmt.executeQuery("Select * from menu"); 

    //Step 5. Iterate through the ResultSet. Add a new menuItem object to mi for each item. 
    while(rs.next()){ 
    menuItem item = new menuItem(rs.getInt("id_menu"),rs.getString("descr"),rs.getDouble("price"),rs.getString("name")); 
    mi.add(item); 
    } 
    return mi; 
} 

此代碼有效。我最終得到了一個menuItem的ArrayList,以便每個元素對應於表中的一行。但這是最好的方式嗎?我可以將它推廣到一種處理ResultSets的方式嗎?

  1. 對於數據庫中的每個表或視圖,創建一個具有與表格列相同屬性的Java類。

  2. 將表內容加載到ResultSet對象中。

  3. 使用而(ResultSet.next())通過ResultSet迭代,在用於在ResultSet每個項目步驟1創建(從類)的新對象。

  4. 隨着每個新對象的創建,將其添加到類的ArrayList中。

  5. 根據需要操縱的ArrayList。

這是一種有效的方法嗎?有沒有更好的方法來做到這一點?

+1

這屬於上[codereview.se] –

+0

感謝。我不知道Code Review甚至在那裏。我準備了另外三個問題,「這個代碼有效,但它是最好的方式」,就像這個。我將在Code Review上發佈它們,而不是Stack Overflow。隨時關閉此問題,並再次感謝。 – Bagheera

回答

4

的代碼邏輯是好的,但執行有幾個問題:

  • 它不尊重命名約定。類以大寫字母
  • 你不應該使用公共字段。和初始化字段默認值是無用的,如果他們之後重新初始化由構造
  • 你不關閉連接,這意味着每次執行方法時,它會留下一個連接打開,導致內存被消費者無所事事,而且由於達到了最大數量的開放連接,你的程序最終會失敗。應該在finally塊中關閉連接,或者使用自Java 7以來可用的try-with-resources結構。結果集和語句也應該關閉,儘管不關閉它們不像關閉連接那樣有問題。
  • 對於最近足夠的驅動程序和JVM,Class.forName()。newInstance()不應該是必需的。選擇的類型是奇怪的。例如,價格存儲在一個可爲空的Double變量中。但是你使用getDouble(),它永遠不會返回null來獲取它的值。另外,使用雙倍價格是一個不錯的選擇。改爲使用BigDecimal。
  • 使用select *是不好的做法。選擇你想要的列,而不是所有的列。

我不會推廣每個表的類的創建。很多時候,您不會查詢單個表中的所有列,而是查詢多個連接表中的某些列。

我還會考慮使用ORM(JPA)而不是使用JDBC。這將使您的代碼更清潔,更短,更易讀和更安全。

+0

+1不錯的答案。 – Vinay

+0

非常感謝。這些評論非常有幫助。響應:我將menuItem重命名爲MenuItem。我將公共屬性更改爲private並添加getter方法(我想我不需要setter?關閉時,是否需要關閉Connection,Statement和ResultSet?或者將conn.close()關閉Statement並ResultSet?我註釋了Class.forName()。newInstace()行,代碼的行爲是一致的,我想知道爲什麼我的Java教科書(Big Java,從2010年開始,第4版)說它是必需的。 – Bagheera

+0

很久以前,它是必需的,現在有一種機制允許jar定義一個JDBC驅動程序,並在不需要任何代碼的情況下向驅動程序管理器註冊它,關閉連接是非常重要的,儘快關閉其他兩個。在實際的代碼中,你有時在同一個連接上打開幾個語句和結果集,關閉它們釋放內存和其他資源。 –