【问题标题】:Will the code have any impact on MySQL available connections?代码会对 MySQL 可用连接产生影响吗?
【发布时间】:2019-06-24 03:58:08
【问题描述】:

我开发了一个 Java Web 应用程序,它使用 JDBC 连接器连接到 MySQL 数据库并建立 2 个连接池。该应用程序部署在 tomcat 服务器上。

我的问题是,如果我多次部署应用程序并且在我关闭 tomcat 时代码没有任何行来关闭可用连接,此代码是否会影响 MySQL 可用连接?重启时tomcat会关闭连接吗?

连接工具:

import javax.sql.DataSource;

import org.apache.commons.dbcp.ConnectionFactory;
import org.apache.commons.dbcp.DriverManagerConnectionFactory;
import org.apache.commons.dbcp.PoolableConnectionFactory;
import org.apache.commons.dbcp.PoolingDataSource;
import org.apache.commons.pool.impl.GenericObjectPool;

public class MySQLConnectionPool {


     public static DataSource setUpPool(){

         GenericObjectPool gPool = null;
         String dbName = "DBName";
         String userName = "Username";
         String password = "Password";
         String hostname = "Host";
         String port = "Port";
         try {
             Class.forName("com.mysql.jdbc.Driver");
            // Creates an Instance of GenericObjectPool That Holds Our Pool of Connections Object!
                gPool = new GenericObjectPool();
                gPool.setMaxActive(2);

                // Creates a ConnectionFactory Object Which Will Be Use by the Pool to Create the Connection Object!
                ConnectionFactory cf = new DriverManagerConnectionFactory("jdbc:mysql://" + hostname + ":" + port + "/" + dbName, userName, password);

                // Creates a PoolableConnectionFactory That Will Wraps the Connection Object Created by the ConnectionFactory to Add Object Pooling Functionality!
                PoolableConnectionFactory pcf = new PoolableConnectionFactory(cf, gPool, null, null, false, true);
         }catch (Exception e) {
            // TODO: handle exception
             System.out.println("Error: "+e.toString());
        }

            return new PoolingDataSource(gPool);
     }

}

道:

@Override
public ArrayList<User> getUserDetails(String environment, String MySQLQuery) {
    // TODO Auto-generated method stub
    ArrayList<User> users = new ArrayList<User>();
    Connection connObj = null;
    Statement stmt = null;
    ResultSet result = null;
    try {   
        DataSource dataSource = MySQLConnectionPool.setUpPool();

        // Performing Database Operation!
        System.out.println("\n=====Making A New Connection Object For Db Transaction=====\n");
        connObj = dataSource.getConnection();

        stmt = connObj.createStatement();
        result = stmt.executeQuery(MySQLQuery);
        while(result.next()) {
            //Some code here
        }

        System.out.println("\n=====Releasing Connection Object To Pool=====\n");            
    } catch(Exception sqlException) {

    } finally {
        try {
            // Closing ResultSet Object
            if(result != null) {
                result.close();
            }
            // Closing Statement Object
            if(stmt != null) {
                stmt.close();
            }
            // Closing Connection Object
            if(connObj != null) {
                connObj.close();
            }
        } catch(Exception sqlException) {

        }
    }
    return users;
}

【问题讨论】:

  • 您应该定义一个且只有一个连接池,您当前的代码是在每次调用MySQLConnectionPool.setUpPool() 时创建一个新池。那是一场等待发生的事故。还可以考虑查看内置于 tomcat 中的数据源/连接池支持,而不是尝试(严重)推出您自己的解决方案。还可以了解 try-with-resources:您当前的资源处理很脆弱且不必要地复杂。
  • @MarkRotteveel:谢谢!!如果我将 maxActive 更改为 1,我的问题会得到解决吗?我是 Java 新手,不知道如何确保这段代码不会影响我的生产数据库。
  • 我的主要观点是,您目前所做的完全是错误的方法,将 maxActive 减少到 1 只是对糟糕解决方案的微不足道的改变。如需更好的方法,请参阅 Tomcat 9 文档:tomcat.apache.org/tomcat-9.0-doc/… 或考虑使用 Spring 或 Spring Boot 之类的东西。

标签: java tomcat jdbc datasource


【解决方案1】:

如果你停止整个tomcat,那么你与数据库的连接将被关闭,因为运行Tomcat的java可执行文件会在停止时释放连接。

即使您不停止服务器,如果 Java 确定您的 Connection 对象不再使用,那么它将被垃圾回收。你只是不知道什么时候。

关于另一个笔记:

  • 您可能应该寻找将DataSource 嵌入服务器并从服务器获取DataSource 的方法:这page 可能会有所帮助。
  • 您应该重写您的代码以使用 try with resources (Java 7++),它会注意正确关闭您的资源(您的代码是错误的)。

使用资源尝试

DataSource dataSource = MySQLConnectionPool.setUpPool();
try (Connection connObj = dataSource.getConnection()) {   
  try (Statement stmt = connObj.createStatement()) {
    try (ResultSet result = stmt.executeQuery(MySQLQuery)) {
      while(result.next()) {
        //Some code here
      }
    }
  } 
} catch (SQLException sqlException) {
  // do something
}

或者:

DataSource dataSource = MySQLConnectionPool.setUpPool();
try (Connection connObj = dataSource.getConnection();
     Statement stmt = connObj.createStatement();
     ResultSet result = stmt.executeQuery(MySQLQuery)
    ) {
  while(result.next()) {
    //Some code here
  }
} catch (SQLException sqlException) {
  // do something
}

正如我上面所说,您的代码是错误的,因为您在关闭ResultSetStatement 时可能会出现异常(至少是SQLException),因此后面的对象将永远不会被您释放代码:

    try {
        // Closing ResultSet Object
        if(result != null) {
            result.close(); // if it fails, stmt and connObj are not closed.
        }
        // Closing Statement Object
        if(stmt != null) {
            stmt.close(); // if it fails, connObj is not closed.
        }
        // Closing Connection Object
        if(connObj != null) {
            connObj.close();
        }
    } catch(Exception sqlException) {

    }

如果你不能使用 try with resources(Java 6 大概几十年后就不再支持了,但谁知道呢),那么你的代码代码应该是这样的:

Connection connObj = null;
Statement stmt = null;
ResultSet result = null;
try {
  // ... do whatever is needed
} finally {
  if(result != null) {
    try {result.close();} catch (Exception ignored) {}
  }
  if(stmt != null) {
    try {stmt.close();} catch (Exception ignored) {}
  }
  if(connObj != null) {
    try {connObj .close();} catch (Exception ignored) {}
  }
}

【讨论】:

  • '那他们会'什么?
  • 它指的是数据库连接。
  • 感谢@NoDataFound!我已经在我的代码中使用资源实现了尝试。另外,我已经浏览了您提供的tomcat链接; tomcat 建议使用将数据库详细信息存储在 tomcat xml 中的 JNDI。但是我正在从一个应用程序连接多个数据库,并且我部署了代码的服务器可供其他人公开访问,并且无法将数据库凭据存储在 xml 中。你有没有其他方法可以让我从我有解密的应用程序内部创建我的连接池来解密密码并在那里使用它?
  • 这只是一个建议。如果您需要创建连接,因为您的客户端/用户作为参数传递了一些登录名/密码来连接到某个数据库,那么您可能甚至不需要数据源(想想看:数据源的优势是重用已经建立的连接,因为连接到一个数据库需要一些时间)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-02-20
  • 1970-01-01
  • 1970-01-01
  • 2012-12-14
  • 2012-03-11
  • 2011-03-23
  • 1970-01-01
相关资源
最近更新 更多