Sonar建议在"finally"代码块中使用try-with-resources或关闭此“Connection”。

5

我希望拥有一个干净的项目。因此,我使用Sonar检测潜在缺陷,...

在下面的方法中,Sonar建议: 使用try-with-resources或在“finally”子句中关闭此“Connection”

private Connection createConnection() throws JMSException {
    MQConnectionFactory mqCF = new MQConnectionFactory();
    ...

    Connection connection = mqCF.createConnection(...);
    connection.start();

    return connection;
}

你能解释一下我做错了什么,以及如何避免Sonar的提示信息吗?谢谢。


一个选择是使用 try-with-resources - Guy
4个回答

6

Connection 实现了 AutoCloseable 接口,Sonar 正在检测此类对象(它并不关心您是否使用连接或其他可自动关闭的对象)。

未关闭此类资源可能会导致资源泄漏,因此 Sonar 建议您执行以下操作:

//try-with-resources - the connection will be closed after this block
try(Connection connection = mqCF.createConnection(...)) {
  //use connection here
}

//traditional try - the connection will be closed after the finally block
Connection connection = mqCF.createConnection(...);
try {
  //use connection here
} finally {
   connection.close();
}

在你的情况下问题是你只是创建了连接并返回它 - 我强烈怀疑你想要保持它处于打开状态 :)
Sonar 不能确定你是否会关闭连接,所以它会抱怨。可能有办法让 Sonar 忽略这样的事情(我不太熟悉这里的选项),但这仍然是一个潜在的风险,你必须想办法予以缓解。

1
谢谢您的评论。是的,我想要保持它开放 :),所以我想在这种情况下没有解决方案。 - Royce
try-with-resources 中使用 return connection; 不能解决这个问题吗? - Royce
1
不,try-with-resources 的目的是在离开该块时关闭自动可关闭资源(返回会这样做)。 - Thomas

4

在Java中,如果您使用像FileInputStream,Connection,ResultSet,Input / OutputStream,BufferedReader,PrintWriter这样的资源,您必须在垃圾收集发生之前关闭它。

因此,每当连接对象不再使用时,您都必须关闭它。

请尝试下面的代码片段:

Connection c = null;
    try {
        c = mqCF.createConnection(...);
        // do something
    } catch(SomeException e) {
        // log exception
    } finally {
      try {
        c.close();
      } catch(IOException e1){
        // log something else
      }
    }

//try-with-resources
try(Connection connection = mqCF.createConnection(...)) {
  //use connection here
}

在“try with resource”情况下,连接将由JVM自动关闭,但Connection接口必须扩展AutoCloseable/Closable接口。

2

您上面的代码可能会导致Connection对象未关闭,这可能会导致重大问题。

有几种方法可以确保在使用完Connection后关闭它:

public Connection createConnection() {
    return connectionFactory.createConnection(...);  // note that this method does not open the connection
}

当你想要使用连接时,可以使用try-catch-finally

try {
    Connection c = createConnection();
    doSomethingWithPossibleException(c);
} catch(PossibleException e) {
    handleException(e);
} finally {
    // now close the connection
    c.close();
}

或者您可以使用try-with-resources(从Java 7开始):

try (Connection c = getConnection()) {
    doSomethingWithPossibleException(c);
} catch (PossibleException e) {
    handle(e);
}

在我看来,使用try-with-resources会更易读一些,尽管这个问题的口味因人而异。请注意,在try-with-resources中创建的对象必须实现AutoCloseable接口。


谢谢。不过我不想关闭它,因为我之后还要用到它。 - Royce
你可能需要了解“连接池”。在整个应用程序的生命周期中仅使用单个数据库连接存在一些问题。连接池可以帮助消除这些问题。在你的代码中,你可以像处理当前连接工厂对象一样处理你的连接池,并在完成后关闭连接。 - cameron1024

0
我找到了一种解决这个问题的方法。 你可以像这样覆盖现有的DBManger:
@Override
    public Connection getConnection() throws SQLException {
        Connection conn = new ProxyConnection(DriverManager.getConnection(...));
        return conn;
    }

    private static class ProxyConnection implements Connection {

        Connection connection;

        private ProxyConnection(Connection connection) {
            this.connection = connection;
        }

        /**
         * Standard method, add logging.
         */
        @Override
        public void close() throws SQLException {
            logger.debug("Connection to database was released");
            connection.close();
        }
    }

如果你使用这个,SonarQube 将不会显示任何违规。 - Krishna Kumar Singh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接