Question

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
}
Was it helpful?

Solution

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.

OTHER TIPS

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

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

EDIT

  1. In Eclipse Juno it works very well. I don't think it is a java 7 bug. It is not working when run from Eclipse Indigo.

  2. It also works from Command Line.

Previous Answer

In following cases I run your program and it worked, I am checking your case

case 1 :

public class Test implements AutoCloseable {

    public int execute() {
        return 1;
    }

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



public class Test1 {

    public static void main(String[] args) throws Exception {

        try (Test test = new Test()) {
            System.out.println(test.execute() > 0);
        }

    }

}

Output :

true
CLOSED

case 2 :

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()) {
            throw new ArrayIndexOutOfBoundsException("exc"); // just for testing
            //return test.execute() > 0;
        }

    }

    private int execute() {
        return 1;
    }

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

Output :

CLOSED
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: exc
    at com.aquent.rambo.auth.Test.doTest(Test.java:11)
    at com.aquent.rambo.auth.Test.main(Test.java:6)

case 3 : Here this is wierd, and it works

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()) {
            boolean result = test.execute() > 0; // Change : result variable declared
            return result;
        }

    }

    private int execute() {
        return 1;
    }

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

Output :

CLOSED
true

Have you tried to close the statements and/or the connections after you're done.

Also make sure to do this in a finally block:

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top