简体   繁体   English

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

[英]How to properly close datasource connection?

I have this class but Im not sure on how to properly close connection because Im still having this error even though I only have 3 users logged in but with multiple sql queries.我有这个课程,但我不确定如何正确关闭连接,因为即使我只有 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>

Notice that you're calling .getConnection() multiple times.请注意,您多次调用.getConnection() Although the documentation could be clearer on this front DataSource.getConnection() actually opens a new connection (as opposed to returning an existing one) thus you need to close each instance returned from that method.尽管文档在这方面可能更清楚,但DataSource.getConnection()实际上打开了一个新连接(而不是返回现有连接),因此您需要关闭从该方法返回的每个实例。

As .getConnection() creates a new instance every time it's called this line is a connection leak, since it's not closing the connection being returned:由于.getConnection()每次被调用时都会创建一个新实例,此行是连接泄漏,因为它没有关闭返回的连接:

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

And this line wastefully opens a new connection only to immediately close it:这条线浪费地打开一个新连接,只是为了立即关闭它:

dataSource.getConnection().close();

It looks like you're trying to open and close a separate connection for each invocation of isValidUser() (since you're closing the connection at the end of that method call).看起来您正在尝试为isValidUser()每次调用打开和关闭单独的连接(因为您在该方法调用结束时关闭连接)。 Even if you fix the leak described above, that's not how connections are intended to be used.即使您修复了上述泄漏,也不是打算使用连接的方式。 Instead you should share one connection (or a small number of them) across your application.相反,您应该在您的应用程序中共享一个连接(或少数连接)。 So when your program starts up you open such a connection, and once the whole program no longer needs the connection (often shortly before terminating) you close it.因此,当您的程序启动时,您打开这样一个连接,一旦整个程序不再需要该连接(通常在终止前不久),您就关闭它。

This sort of behavior is commonly implemented by dependency injection , where you construct your connections and other resources and then pass them into whatever objects need them - this decouples resource management from the code that uses those resources.这种行为通常通过依赖注入来实现,您可以在其中构建连接和其他资源,然后将它们传递给需要它们的任何对象 - 这将资源管理与使用这些资源的代码分离。 As a simplistic example:作为一个简单的例子:

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) {
  // ...
}

As a rule of thumb, objects should only be responsible for closing objects they construct, and should avoid closing objects they are passed.根据经验,对象应该只负责关闭它们构造的对象,并且应该避免关闭传递给它们的对象。 In your current code UserDaoImpl is opening the connection, so it should be responsible for closing it, but I'm suggesting passing in the Connection instead.在您当前的代码中UserDaoImpl正在打开连接,因此它应该负责关闭它,但我建议改为传入Connection

dataSource.getConnection() will always return you a new connection, therefore you are not closing the connection that you think. dataSource.getConnection()将始终为您返回一个新连接,因此您不会关闭您认为的连接。 You must use DataSourceUtils.getConnection() to get the active connection of the current thread or else store the reference returned like conn = dataSource.getConnection() and the call conn.close()您必须使用DataSourceUtils.getConnection()来获取当前线程的活动连接,否则存储返回的引用,如 conn = dataSource.getConnection() 和调用conn.close()

try this instead.试试这个。

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

and later when you don't need connection to database anymore just close using稍后当您不再需要连接到数据库时,只需关闭使用

conn.close();

Update:更新:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM