2012-10-23 69 views
0

我的數據庫中有這些表。一個是employee,第二個是employee_Project,第三個是employee_Reporting。每個表格都有一個共同的employee_Number作爲主鍵,並且它們之間存在一對多的關係,因此員工有許多項目和報告日期。jdbc性能

我在這有方法fillResultSet(Result set)List<T> getData()三個數據持有者類運行select * from employeeselect * from employee_projectselect * from employee_reporting。這是基於SqlDbEngine類和runQuery(PreparedStatement,DataHolder)方法,並且實現已完成。

現在我必須設計一個getAllEmployee()方法以及使用JDBC在java中優化代碼的項目和報告細節。我已經使用了一個迭代器,但這個解決方案是不可接受的;現在我必須使用foreach循環。

這是我做了什麼:

public List<Employee> getAllEmployees() { 
    EmployeeDataHolderImpl empdataholder = new EmployeeDataHolderImpl(); 
    List<Employee> list_Employee_Add = null; 

    try { 
     Connection connection = mySqlDbConnection.getConnection(); 
     PreparedStatement preparedStatement = connection 
       .prepareStatement(GET_ALL_EMPLOYEE_DETAILS); 
     mySqlDBEngineImpl.runQuery(preparedStatement, empdataholder); 
    } catch (SQLException e) { 

     e.printStackTrace(); 
    } 
    for (Employee employee : empdataholder.getData()) { 
     new EmployeeDAOImpl().getProject(employee); 
        new EmployeeDAOImpl.getReport(employee); 
    } 
    list_Employee_Add = empdataholder.getData(); 
    return list_Employee_Add; 

} 

,使另一種方法

public void getProject(Employee emp) { 
    EmployeeProjectDataHolderImpl employeeProjectHolder = new EmployeeProjectDataHolderImpl(); 
    try { 
     Connection connection = mySqlDbConnection.getConnection(); 
     PreparedStatement preparedStatement = connection 
       .prepareStatement(GET_ALL_PROJECT_DETAILS); 
     mySqlDBEngineImpl 
       .runQuery(preparedStatement, employeeProjectHolder); 
    } catch (SQLException e) { 
     e.printStackTrace(); 
    } 
    for (EmployeeProject employee_Project : employeeProjectHolder.getData()) { 
     if (employee_Project.getEmployeeNumber() == emp.getEmpNumber()) { 
      emp.getProjects().add(employee_Project); 
     } 
    } 
} 

    public void getReport(Employee emp) { 
    EmployeeReportDataHolderImpl employeeReportHolder = new EmployeeReportDataHolderImpl(); 
    try { 
     Connection connection = mySqlDbConnection.getConnection(); 
     PreparedStatement preparedStatement = connection 
       .prepareStatement(GET_ALL_REPORT_DETAILS); 
     mySqlDBEngineImpl 
       .runQuery(preparedStatement, employeeReportHolder); 
    } catch (SQLException e) { 
     e.printStackTrace(); 
    } 
    for (EmployeeReport employee_Report : employeeReportHolder.getData()) { 
     if (employee_Report.getEmployeeNumber() == emp.getEmpNumber()) { 
      emp.getProjects().add(employee_Project); 
     } 
    } 
} 
} 
爲員工報告

和相同的,但這樣做,這樣的表現是要decrease.no關於關閉連接體憂我會去做

請告訴我怎樣才能改善我的解決方案..

+0

我很困惑你的問題。你說你已經完成了'select * from employee'的實現。這不是基本上會成爲你的'getAllEmployees()'方法嗎?另外,你提到你的基於迭代器的解決方案是不可接受的,所以你需要使用foreach循環。Foreach **是一個迭代器 - 它只是語法糖!什麼是真正的*爲什麼你需要使用foreach? –

回答

0

如果你用你的實際代碼,你將不得不在你的代碼3個影響:

  • 你打開來獲得員工的數據連接。
  • 對於每位員工,您都會打開(並關閉)一個新連接以獲得他的項目。
  • 對於每位員工,您打開(並關閉)一個新的連接以獲取他的報告。

請注意,打開新連接會對應用程序性能造成影響。無論您使用增強型for循環還是迭代器都無關緊要,會有很多點擊會降低您的應用程序。

兩種方式來解決這個問題:

  1. 打開您運行的所有SELECT語句的單一連接。這比打開/關閉很多連接要好。

  2. 創建單個SQL語句來檢索每個員工所需的員工和數據。由於不同的原因,它會有更好的性能:

    • 單個連接到數據庫。
    • 單個查詢而不是大量查詢到數據庫(單個I/O操作)。
    • 如果您的rdbms允許,查詢將針對未來的請求(單個查詢而不是多個查詢)進行優化。

我寧願去與第二個選項。爲此,我傾向於使用執行任何SQL select語句並返回ResultSet的方法。我會發佈一個基本的例子(注意,所提供的代碼可以根據您的需求來改善),這種方法可能是你SqlDbEngine類:

public ResultSet executeSQL(Connection con, String sql, List<Object> arguments) { 
    PreparedStatement pstmt = null; 
    ResultSet rs = null; 
    try { 
     pstmt = con.prepareStatement(sql); 
     if (arguments != null) { 
      int i = 1; 
      for(Object o : arguments) { 
       pstmt.setObject(i++, o); 
      } 
     } 
     //method to execute insert, update, delete statements... 
     rs = pstmt.execute(); 
    } catch(SQLException e) { 
     //handle the error... 
    } 
    return rs; 
} 

這另一種方法來處理所有的查詢操作

public List<Employee> getAllEmployee() { 
    Connection con = null; 
    ResultSet rs = null; 
    List<Employee> lstEmployee = new ArrayList<Employee>(); 
    try { 
     con = mySqlDbConnection.getConnection(); 
     //write the sql to retrieve all the data 
     //I'm assuming these can be your columns, it's up to you 
     //this can be written using JOINs... 
     String sql = "SELECT E.EMPLOYEE_ID, E.EMPLOYEE_NAME, P.PROJECT_NAME, R.REPORT_NAME FROM EMPLOYEE E, PROJECT P, REPORT R WHERE E.EMPLOYEE_ID = P.EMPLOYEE_ID AND E.EMPLOYEE_ID = R.EMPLOYEE_ID"; 
     //I guess you don't need parameters for this... 
     rs = SqlDbEngine.executeSQL(con, sql, null); 
     if (rs != null) { 
      Employee e; 
      int employeeId = -1, lastEmployeeId = -1; 
      while (rs.next()) { 
       //you need to make sure to create a new employee only when 
       //reading a new employee id 
       employeeId = rs.getInt("EMPLOYEE_ID"); 
       if (lastEmployeeId != employeeId) { 
        e = new Employee(); 
        lastEmployeeId = employeeId; 
        lstEmployee.add(e); 
       } 
       Project p = new Project(); 
       Report r = new Report(); 
       //fill values of p... 
       //fill values of r... 
       //you can fill the values taking advantage of the column name in the resultset 
       //at last, link the project and report to the employee 
       e.getProjects().add(p); 
       e.getReports().add(r); 
      } 
     } 
    } catch (Exception e) { 
     //handle the error... 
    } finally { 
     try { 
      if (rs != null) { 
       Statement stmt = rs.getStatement(); 
       rs.close(); 
       stmt.close(); 
      } 
      if (con != null) { 
       con.close(); 
      } 
     } catch (SQLException e) { 
      //handle the error... 
     } 
    } 
    return lstEmployee; 
} 

請注意,第二種方法可能更難代碼,但它會給你最好的性能。它是由你來提高所提供的方法,提出了一些建議:

  • 創建接收一個結果,並建立使用ResultSet(用於ReportEmployee類似)的列名Project實例類。
  • 創建一個處理ResultSet及其Statement關閉的方法。
  • 作爲最佳做法,從不使用select * from mytable,最好編寫所需的列。
1

您的代碼存在一些問題。

1.您每次都初始化EmployeeDAOImpl,而您可以保留一個實例並調用其上的操作。

new EmployeeDAOImpl()。getProject(employee);新 EmployeeDAOImpl.getReport(employee);

2.在執行SQL操作後,我沒有看到關閉連接的位置。

+0

即便如此,在打開連接來檢索所有項目並獲取他/她需要綁定到員工的項目(以及類似的報告)時,性能會受到很大影響。通過使用單個連接可以大大提高代碼的質量,該連接可以檢索所有按照OP所需/需要加入和排序的值。 –

+0

@Arham所有的連接都關閉在sqldbEngine類我不必擔心我只是設計方法getAllEmployee()我已經比較每個員工對象屬性employee_Number EmployeeReporting和EmployeeProject類的每個對象假設爲一個員工有4項目和數據庫中存在數十萬個數據庫,我的邏輯將爲每個對象爆發原因比較每個對象屬性Employee_no項目和報告類迭代使用每個循環,也不必使用連接 –

+0

@ ankurjadiya通過這樣做,你正在恢復像100個元素,當你只需要4.而且你會爲每個員工**做同樣的**。如果你想提高你的表現,你應該學習和應用最佳實踐。 –

0

如果我理解正確,您的代碼首先加載所有EmployeeReport行,然後根據getEmployeeNumber()過濾它們。你可以讓你的數據庫通過修改你的SQL查詢來做到這一點。

既然你沒有顯示你的SQL查詢(我假設他們在GET_ALL_REPORT_DETAILS),我就做一個猜測...嘗試執行SQL這樣的:

select * 
from employee_reporting 
where employeeNumber = ? 

如果你把這個一個PreparedStatement,然後設置參數值,你的數據庫將只返回你需要的數據。例如:

PreparedStatement pstmt = con.prepareStatement(GET_ALL_REPORT_DETAILS); 
pstmt.setInt(1, employee.getEmployeeNumber()); 

這應該只返回EmployeeReport記錄具有所需employeeNumber。在情況下的性能仍然是一個問題,你可以考慮增加一個索引你的EmployeeReport表,但是這是一個不同的故事......

+0

不,先生,我只是宣佈像這樣String GET_ALL_REPORT_DETAILS =「select * from Employee」實際上我已經使用了所有列名稱來代替*對於所有常量而言,這已完成 –

+0

這應該不會有很大的區別。 '*'只是「FROM'子句中列出的所有表中的所有列的快捷方式」。 – mthmulders

1

你應該有

try { 

--code statements 

} 
catch(SQLException e){ 
e.printStackTrace(); 
} 
finally{ 
-- close your connection and preparedStatement 
} 

關閉數據庫連接是非常重要的。