Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't this code close JDBC connections? (Java 7 Autocloseable unexpected behavior)

Using Java 7u5, with the try-with-resources construct, the following code appears to leak jdbc connections:

try (Connection connection = ..; PreparedStatement stmt = ..) {
    stmt.setString(..);
    return stmt.executeUpdate() > 0;
}

The next piece of code works as expected and intended:

int ret = 0;

try (Connection connection = ..; PreparedStatement stmt = ..) {
    stmt.setString(..);
    ret = stmt.executeUpdate();
}

return ret > 0;

It seems that in the first case, the Connection.close() method is not being invoked.

I am using the latest mysql connector. This is unexpected behavior, correct?

Test

The following test will NOT print CLOSED:

public class Test implements AutoCloseable {

public static void main(String[] args) throws Exception {
    System.out.println(doTest());
}

private static boolean doTest() throws Exception {
    try (Test test = new Test()) {
        return test.execute() > 0;
    }

}

private int execute() {
    return 1;
}

@Override
public void close() throws Exception {
    System.out.println("CLOSED");
}
}

Strangely, if execute() is modified to return 0; then CLOSED WILL be printed.

javap -p -c Test.class output

    Compiled from "Test.java"
public class Test implements java.lang.AutoCloseable {
  public Test();
    Code:
       0: aload_0
       1: invokespecial #10                 // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]) throws java.lang.Exception;
    Code:
       0: getstatic     #21                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: invokestatic  #27                 // Method doTest:()Z
       6: invokevirtual #31                 // Method java/io/PrintStream.println:(Z)V
       9: return

  private static boolean doTest() throws java.lang.Exception;
    Code:
       0: aconst_null
       1: astore_0
       2: aconst_null
       3: astore_1
       4: new           #1                  // class Test
       7: dup
       8: invokespecial #39                 // Method "<init>":()V
      11: astore_2
      12: aload_2
      13: invokespecial #40                 // Method execute:()I
      16: ifle          21
      19: iconst_1
      20: ireturn
      21: iconst_0
      22: aload_2
      23: ifnull        30
      26: aload_2
      27: invokevirtual #44                 // Method close:()V
      30: ireturn
      31: astore_0
      32: aload_2
      33: ifnull        40
      36: aload_2
      37: invokevirtual #44                 // Method close:()V
      40: aload_0
      41: athrow
      42: astore_1
      43: aload_0
      44: ifnonnull     52
      47: aload_1
      48: astore_0
      49: goto          62
      52: aload_0
      53: aload_1
      54: if_acmpeq     62
      57: aload_0
      58: aload_1
      59: invokevirtual #47                 // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V
      62: aload_0
      63: athrow
    Exception table:
       from    to  target type
          12    22    31   any
          30    31    31   any
           4    42    42   any

  private int execute();
    Code:
       0: iconst_1
       1: ireturn

  public void close() throws java.lang.Exception;
    Code:
       0: getstatic     #21                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #55                 // String CLOSED
       5: invokevirtual #57                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return
}
like image 875
beefyhalo Avatar asked Jul 16 '12 01:07

beefyhalo


3 Answers

After upgrading to the latest version of eclipse (Juno), this strange behavior is no longer occurring.

It also works fine using the command line to compile and run.

I suspect Eclipse Indigo was using an old javac to compile, and not complaining about any compliance violation.

like image 116
beefyhalo Avatar answered Nov 16 '22 14:11

beefyhalo


I've encountered the very same issue using JDK 1.7.0_17. After careful elimination, it turned out it my IntelliJ was using an AspectJ compiler. Once I compiled the class explicitly with the JDK's javac it worked as expected.

My colleague has filed a bug report to the AspectJ people. They have scheduled a fix for version 1.7.3

like image 2
bowmore Avatar answered Nov 16 '22 15:11

bowmore


It is a java 7u5 bug; go register a bug. Java 7u4 worked.

return test.execute() > 0;

gives wrong code for > 0:

  13: invokespecial #40                 // Method execute:()I
  16: ifle          21
  19: iconst_1
  20: ireturn
like image 1
Joop Eggen Avatar answered Nov 16 '22 14:11

Joop Eggen