2011-09-29 104 views
22

我想確定我是否實際使用JDBC連接池。在做了一些研究之後,實現幾乎看起來太簡單了。實際上比常規連接更容易,所以我想驗證一下。我是否使用JDBC連接池?

這裏是我的連接類:

public class DatabaseConnection { 

Connection conn = null; 

public Connection getConnection() { 

    BasicDataSource bds = new BasicDataSource(); 
    bds.setDriverClassName("com.mysql.jdbc.Driver"); 
    bds.setUrl("jdbc:mysql://localhost:3306/data"); 
    bds.setUsername("USERNAME"); 
    bds.setPassword("PASSWORD"); 

    try{ 
     System.out.println("Attempting Database Connection"); 
     conn = bds.getConnection(); 
     System.out.println("Connected Successfully"); 
    }catch(SQLException e){ 
     System.out.println("Caught SQL Exception: " + e); 
    } 
    return conn; 
} 

public void closeConnection() throws SQLException { 
    conn.close(); 
} 

}

這是真的連接池?我正在使用另一個類的連接,因此:

 //Check data against database. 
    DatabaseConnection dbConn = new DatabaseConnection(); 
    Connection conn; 
    ResultSet rs; 
    PreparedStatement prepStmt; 

    //Query database and check username/pass against table. 
    try{ 
     conn = dbConn.getConnection(); 
     String sql = "SELECT * FROM users WHERE username=? AND password=?"; 
     prepStmt = conn.prepareStatement(sql); 
     prepStmt.setString(1, user.getUsername()); 
     prepStmt.setString(2, user.getPassword()); 
     rs = prepStmt.executeQuery(); 

     if(rs.next()){ //Found Match. 
      do{ 
       out.println("UserName = " + rs.getObject("username") + " Password = " + rs.getObject("password")); 
       out.println("<br>"); 
      } while(rs.next()); 
     } else { 
      out.println("Sorry, you are not in my database."); //No Match. 
     } 

     dbConn.closeConnection(); //Close db connection. 

    }catch(SQLException e){ 
     System.out.println("Caught SQL Exception: " + e); 
    } 

回答

45

假設它的BasicDataSourceDBCP,那麼,您使用的是連接池。但是,您正在每個連接獲取上重新創建另一個連接池。你不是真的從同一個池中彙集連接。您只需在應用程序啓動時創建連接池一次,並從中獲取每個連接。你也不應該把連接作爲一個實例變量。您還應該關閉連接,語句和結果集,以確保資源已正確關閉,並且在出現異常情況時也是如此。 Java 7的try-with-resources statement在這方面很有幫助,它會在try塊完成時自動關閉資源。

這裏的一個次要重寫:

public final class Database { 

    private static final BasicDataSource dataSource = new BasicDataSource(); 

    static { 
     dataSource.setDriverClassName("com.mysql.jdbc.Driver"); 
     dataSource.setUrl("jdbc:mysql://localhost:3306/data"); 
     dataSource.setUsername("USERNAME"); 
     dataSource.setPassword("PASSWORD"); 
    } 

    private Database() { 
     // 
    } 

    public static Connection getConnection() throws SQLException { 
     return dataSource.getConnection(); 
    } 

} 

(這可以根據需要進行重構,作爲一個抽象工廠改善可插拔)

private static final String SQL_EXIST = "SELECT * FROM users WHERE username=? AND password=?"; 

public boolean exist(User user) throws SQLException { 
    boolean exist = false; 

    try (
     Connection connection = Database.getConnection(); 
     PreparedStatement statement = connection.prepareStatement(SQL_EXIST); 
    ) { 
     statement.setString(1, user.getUsername()); 
     statement.setString(2, user.getPassword()); 

     try (ResultSet resultSet = preparedStatement.executeQuery()) { 
      exist = resultSet.next(); 
     } 
    }  

    return exist; 
} 

其是被用來如下:

try { 
    if (!userDAO.exist(username, password)) { 
     request.setAttribute("message", "Unknown login. Try again."); 
     request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response); 
    } else { 
     request.getSession().setAttribute("user", username); 
     response.sendRedirect("userhome"); 
    } 
} catch (SQLException e) { 
    throw new ServletException("DB error", e); 
} 

在真正的Java EE environement你應該然而委託DataSource的創立到容器/應用服務器和從JNDI獲得它。在Tomcat的情況下,也見例如這個文件:http://tomcat.apache.org/tomcat-6.0-doc/jndi-resources-howto.html

+0

哇,謝謝你的重寫。爲像我這樣的新人提供完美的幫助。 – ryandlf

+0

此解決方案是線程安全嗎?我需要調用connection.close(); – swapyonubuntu

+0

@swapyonubuntu:密切與新的Java7'嘗試與 - resources'自動完成語句https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html – BalusC

3

似乎並不像它的彙集。您應該將數據源存儲在DatabaseConnection中,而不是使用每個getConnection()調用創建一個新數據源。 getConnection()應該返回datasource.getConnection()。

2

看起來像一個DBCP使用。如果是這樣,那麼是的。它已經合併。這裏是DBCP的默認池屬性值。

/** 
* The default cap on the number of "sleeping" instances in the pool. 
* @see #getMaxIdle 
* @see #setMaxIdle 
*/ 
public static final int DEFAULT_MAX_IDLE = 8; 
/** 
* The default minimum number of "sleeping" instances in the pool 
* before before the evictor thread (if active) spawns new objects. 
* @see #getMinIdle 
* @see #setMinIdle 
*/ 
public static final int DEFAULT_MIN_IDLE = 0; 
/** 
* The default cap on the total number of active instances from the pool. 
* @see #getMaxActive 
*/ 
public static final int DEFAULT_MAX_ACTIVE = 8; 
1

作爲後續行動,以BalusC的解決方案,下面是我需要一個以上的連接,或者在公共庫,不會事先知道連接屬性的應用程序中使用的實現.. 。

import org.apache.commons.dbcp.BasicDataSource; 

import java.sql.Connection; 
import java.sql.SQLException; 
import java.util.concurrent.ConcurrentHashMap; 

public final class Database { 

    private static final ConcurrentHashMap<String, BasicDataSource> dataSources = new ConcurrentHashMap(); 

    private Database() { 
     // 
    } 

    public static Connection getConnection(String connectionString, String username, String password) throws SQLException { 

     BasicDataSource dataSource; 

     if (dataSources.containsKey(connectionString)) { 
      dataSource = dataSources.get(connectionString); 
     } else { 
      dataSource = new BasicDataSource(); 
      dataSource.setDriverClassName("com.mysql.jdbc.Driver"); 
      dataSource.setUrl(connectionString); 
      dataSource.setUsername(username); 
      dataSource.setPassword(password); 
      dataSources.put(connectionString, dataSource); 
     } 

     return dataSource.getConnection(); 

    } 

} 
+0

此解決方案不能始終工作。儘管使用了ConcurrentHashMap,它仍然受到競爭條件的限制。 –