如何正确关闭数据源连接?

时间:2017-02-22 17:45:31

标签: java mysql datasource

我有这个类,但我不确定如何正确关闭连接,因为我仍然有这个错误,即使我只有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;  
    }
}

SpringConfiguration.xml

    <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>

1 个答案:

答案 0 :(得分:1)

请注意,您多次致电.getConnection()。虽然文档在这方面可以更清楚DataSource.getConnection()实际上打开一个新连接(而不是返回现有连接),因此您需要关闭从该方法返回的每个实例。

由于.getConnection()每次调用时都会创建一个新实例,因此该行是连接泄漏,因为它没有关闭返回的连接:

pstmt = dataSource.getConnection().prepareStatement(query);

这条线浪费地打开一个新的连接只是为了立即关闭它:

dataSource.getConnection().close();

看起来你正试图为isValidUser()的每次调用打开和关闭一个单独的连接(因为你在该方法调用结束时关闭了连接)。即使您修复了上述泄漏,也不是如何使用连接。相反,您应该在应用程序中共享一个连接(或少数连接)。因此,当您的程序启动时,您打开这样的连接,并且一旦整个程序不再需要连接(通常在终止之前不久),您将其关闭。

这种行为通常由dependency injection实现,您可以在其中构建连接和其他资源,然后将它们传递到需要它们的任何对象中 - 这将资源管理与使用这些资源的代码分离。作为一个简单的例子:

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