[英]How to properly close datasource connection?
我有這個課程,但我不確定如何正確關閉連接,因為即使我只有 3 個用戶登錄但有多個 sql 查詢,我仍然有這個錯誤。
> com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: > Data source rejected establishment of connection, message from > server: "Too many connections"
import java.io.File;
import java.io.IOException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.sql.DataSource;
public class UserDaoImpl implements UserDao
{
DataSource dataSource;
public DataSource getDataSource()
{
return this.dataSource;
}
public void setDataSource(DataSource dataSource)
{
this.dataSource = dataSource;
}
public boolean isValidUser(String username, String password) throws SQLException
{
PreparedStatement pstmt = null;
ResultSet resultSet = null;
boolean rt = false;
try{
PasswordEncryptor pws = new PasswordEncryptor();
String encryptedPass = pws.encrypt(password);
String query = "Select count(1) from userdetails where username = ? and password = ?";
pstmt = dataSource.getConnection().prepareStatement(query);
pstmt.setString(1, username);
pstmt.setString(2, encryptedPass);
resultSet = pstmt.executeQuery();
if (resultSet.next()){
rt = (resultSet.getInt(1) > 0);
}
else{
rt = false;
}
}
catch(Exception e){
e.printStackTrace();
}
finally{
resultSet.close();
pstmt.close();
dataSource.getConnection().close();
}
return rt;
}
}
配置文件
<bean name="userDao" class="com.spring.acadconnect.services.UserDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/acadconnect" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
請注意,您多次調用.getConnection()
。 盡管文檔在這方面可能更清楚,但DataSource.getConnection()
實際上打開了一個新連接(而不是返回現有連接),因此您需要關閉從該方法返回的每個實例。
由於.getConnection()
每次被調用時都會創建一個新實例,此行是連接泄漏,因為它沒有關閉返回的連接:
pstmt = dataSource.getConnection().prepareStatement(query);
這條線浪費地打開一個新連接,只是為了立即關閉它:
dataSource.getConnection().close();
看起來您正在嘗試為isValidUser()
每次調用打開和關閉單獨的連接(因為您在該方法調用結束時關閉連接)。 即使您修復了上述泄漏,也不是打算使用連接的方式。 相反,您應該在您的應用程序中共享一個連接(或少數連接)。 因此,當您的程序啟動時,您打開這樣一個連接,一旦整個程序不再需要該連接(通常在終止前不久),您就關閉它。
這種行為通常通過依賴注入來實現,您可以在其中構建連接和其他資源,然后將它們傳遞給需要它們的任何對象 - 這將資源管理與使用這些資源的代碼分離。 作為一個簡單的例子:
public static void main(String[] args) {
DataSource dataSource = createDataSource();
try (Connection connection = dataSource.getConnection()) {
runProgram(connection);
}
}
/**
* this method doesn't need to worry about closing the Connection,
* it trusts that its caller will be responsible for that.
*/
private static void runProgram(Connection connection) {
// ...
}
根據經驗,對象應該只負責關閉它們構造的對象,並且應該避免關閉傳遞給它們的對象。 在您當前的代碼中UserDaoImpl
正在打開連接,因此它應該負責關閉它,但我建議改為傳入Connection
。
dataSource.getConnection()
將始終為您返回一個新連接,因此您不會關閉您認為的連接。 您必須使用DataSourceUtils.getConnection()
來獲取當前線程的活動連接,否則存儲返回的引用,如 conn = dataSource.getConnection() 和調用conn.close()
試試這個。
conn = dataSource.getConnection();
pstmt = conn.prepareStatement(query);
稍后當您不再需要連接到數據庫時,只需關閉使用
conn.close();
更新:
Connection conn = dataSource.getConnection();
PreparedStatement ps = pstmt = conn.prepareStatement(query);
try {
// ur code
}
catch (SQLException ex)
{
// Exception handling
}
finally
{
if (rs != null)
{
if (ps != null) {
try {
ps.close();
} catch (SQLException e) { out.print(e)} // This will print exception to help better
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) { out.print(e)}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.