Почему этот код не закрывает соединения JDBC? (Java 7 Autocloseable неожиданное поведение)
С помощью Java 7u5 с конструкцией try-with-resources появляется следующий код , который протекает через соединения jdbc:
try (Connection connection = ..; PreparedStatement stmt = ..) {
stmt.setString(..);
return stmt.executeUpdate() > 0;
}
Следующий фрагмент кода работает так, как ожидалось и предполагалось:
int ret = 0;
try (Connection connection = ..; PreparedStatement stmt = ..) {
stmt.setString(..);
ret = stmt.executeUpdate();
}
return ret > 0;
Кажется, что в первом случае метод Connection.close()
не вызывается.
Я использую последний соединитель mysql. Это неожиданное поведение, правильно?
Test
Следующий тест НЕ будет печатать 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");
}
}
Странно, если execute()
изменено на return 0;
, тогда будет напечатано CLOSED
WILL.
javap -p -c Выход Test.class
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
}
Ответы
Ответ 1
После обновления до последней версии eclipse (Juno) это странное поведение больше не происходит.
Он также отлично работает с использованием командной строки для компиляции и запуска.
Я подозреваю, что Eclipse Indigo использовал старый javac
для компиляции и не жаловался на нарушение правил.
Ответ 2
Я столкнулся с той же проблемой, используя JDK 1.7.0_17.
После тщательного устранения выяснилось, что мой IntelliJ использовал компилятор AspectJ. Как только я скомпилировал класс явно с JDK javac, он работал, как ожидалось.
Мой коллега подал отчет об ошибке для людей AspectJ. Они запланировали исправление для версии 1.7.3
Ответ 3
Это ошибка java 7u5; go зарегистрировать ошибку.
Работала Java 7u4.
return test.execute() > 0;
дает неправильный код для > 0:
13: invokespecial #40 // Method execute:()I
16: ifle 21
19: iconst_1
20: ireturn
Ответ 4
ИЗМЕНИТЬ
-
В Eclipse Juno
он работает очень хорошо. Я не думаю, что это ошибка java 7. Он не работает при запуске от Eclipse Indigo
.
-
Он также работает от Command Line
.
Предыдущий ответ
В следующих случаях я запускаю вашу программу, и она работает, я проверяю ваше дело
случай 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);
}
}
}
Выход:
true
CLOSED
случай 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");
}
}
Выход:
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)
случай 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");
}
}
Выход:
CLOSED
true
Ответ 5
Вы пытались закрыть инструкции и/или соединения после завершения.
Также обязательно сделайте это в блоке finally: