我在尝试资源方面有问题,我只是想确认一下。如果我需要对异常做出反应,并且我仍然需要catch块中的资源,我可以使用它吗?示例如下:
try (java.sql.Connection con = createConnection())
{
con.setAutoCommit(false);
Statement stm = con.createStatement();
stm.execute(someQuery); // causes SQLException
}
catch(SQLException ex)
{
con.rollback();
// do other stuff
}
我担心在这种情况下,我仍然注定要使用旧的try-catch-最终,即使根据甲骨文留档-“在try-with-资源语句中,任何一抓或最终块都是在声明的资源被关闭后运行的。”
//try with resources
try(Connection conn = this.connectionProvider.getConnection()){//auto close BEFORE reach this , catch block, so we need a inner try block for statement
boolean oldAutoCommit=conn.getAutoCommit();
conn.setAutoCommit(false);//auto commit to false
try(
Statement stm = con.createStatement()
){
stm.execute(someQuery); // causes SQLException
conn.commit();//commit
}
catch (SQLException ex){
conn.rollback();//error, rollback
throw ex;//If you need to throw the exception to the caller
}
finally {
conn.setAutoCommit(oldAutoCommit);//reset auto commit
}
}
在代码中,您正在捕获“SQLException”以执行自动提交重置。任何类型的运行时异常(如空指针异常)都会从代码中冒泡出来,而不会重置自动提交。
try-with-resource语法使编译器生成一些精彩的代码来覆盖所有执行路径,并通过关闭来跟上所有被抑制的异常。通过几个助手类,您可以将提交/回滚和重置自动提交插入到代码生成过程中:
import java.sql.SQLException;
import java.sql.Connection;
public class AutoRollback implements AutoCloseable {
private Connection conn;
private boolean committed;
public AutoRollback(Connection conn) throws SQLException {
this.conn = conn;
}
public void commit() throws SQLException {
conn.commit();
committed = true;
}
@Override
public void close() throws SQLException {
if(!committed) {
conn.rollback();
}
}
}
public class AutoSetAutoCommit implements AutoCloseable {
private Connection conn;
private boolean originalAutoCommit;
public AutoSetAutoCommit(Connection conn, boolean autoCommit) throws SQLException {
this.conn = conn;
originalAutoCommit = conn.getAutoCommit();
conn.setAutoCommit(autoCommit);
}
@Override
public void close() throws SQLException {
conn.setAutoCommit(originalAutoCommit);
}
}
现在您可以使用“尝试使用资源”语法控制回滚和自动提交,如下所示:
try(Connection conn = getConnection(),
AutoSetAutoCommit a = new AutoSetAutoCommit(conn,false),
AutoRollback tm = new AutoRollback(conn))
{
// Do stuff
tm.commit();
}
根据语言规范,连接将在执行catch子句之前关闭(http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.20.3.2).
一种可能的解决方案是嵌套try-with-资源语句:
try (java.sql.Connection con = createConnection())
{
con.setAutoCommit(false);
try (Statement stm = con.createStatement())
{
stm.execute(someQuery); // causes SQLException
}
catch(SQLException ex)
{
con.rollback();
con.setAutoCommit(true);
throw ex;
}
con.commit();
con.setAutoCommit(true);
}
希望这说明了这一点。如果您计划在生产代码中使用它,这应该会得到很大的改进。
例如,如果您使用的是连接池,那么您必须在获得连接时返回连接,因此con.setAutoCommit(true);应该在最终子句中完成。这意味着外部的try-with-资源应该是传统的try-cat-Final。
编辑(2018)
我仍然看到人们对此发表评论,所以我想我会在2018年给它一个回复。我不再使用Java了,主要是在Scala、Clojure和Kotlin中工作,这段代码还没有经过测试,所以请将其视为另一个示例。然而,由于Java有lambdas,我认为下面的方法要好得多。我在其他语言的生产代码中也做过类似的事情。
在这种方法中,有一个inTransaction函数处理所有讨厌的事务。但是用法非常简单。
public class Foo {
interface ConnectionProvider {
Connection get() throws SQLException;
}
public static <A> A doInTransation(ConnectionProvider connectionProvider, Function<Connection, A> f) throws SQLException {
Connection connection = null;
A returnValue;
boolean initialAutocommit = false;
try {
connection = connectionProvider.get();
initialAutocommit = connection.getAutoCommit();
connection.setAutoCommit(false);
returnValue = f.apply(connection);
connection.commit();
return returnValue;
} catch (Throwable throwable) {
// You may not want to handle all throwables, but you should with most, e.g.
// Scala has examples: https://github.com/scala/scala/blob/v2.9.3/src/library/scala/util/control/NonFatal.scala#L1
if (connection != null) {
connection.rollback();
}
throw throwable;
} finally {
if (connection != null) {
try {
if(initialAutocommit){
connection.setAutoCommit(true);
}
connection.close();
} catch (Throwable e) {
// Use your own logger here. And again, maybe not catch throwable,
// but then again, you should never throw from a finally ;)
StringWriter out = new StringWriter();
e.printStackTrace(new PrintWriter(out));
System.err.println("Could not close connection " + out.toString());
}
}
}
}
public static void main(String[] args) throws SQLException {
DataSource ds = null;
// Usage example:
doInTransation(ds::getConnection, (Connection c) -> {
// Do whatever you want in a transaction
return 1;
});
}
}
我希望有一些经过战斗测试的库为你做这些事情,至少在其他语言中是这样的。
我看到一些关于自动提交和连接池的评论。上述示例应该不知道连接来自何处,也不知道连接是否来自池,也就是说,只有当连接的初始值为true时,才将其设置回true。因此,如果从池中得出的结果是错误的,则不应触摸它。
关于资源尝试的最后一句话。我不认为这是一个很好的抽象,所以我会小心地在更复杂的场景中使用它。
问题内容: 我在尝试资源时遇到问题,我只是想确定一下。如果我需要对异常做出反应并且仍然需要catch块中的资源,可以使用它吗?给出的示例是这样的: 我担心即使在oracle文档中,我仍然注定要在这种情况下最终使用旧的try-catch-finally-“在try-with- resources语句中捕获并最终阻止,任何catch或finally块都在资源之后运行宣布已关闭。” 问题答案: 根据语言
下面是一个使用JdbcTemplate的示例。我的问题是,由于runTimeException,doMultipleCalls()在第3步失败,一切是否都会回滚。我只有对多个调用的事务注释,而没有对其他调用的注释。所有人是否共享同一个事务会话?。如果没有,那么如何跨多个服务器传递相同的事务会话?
问题内容: 我正在使用TestNG 6.9.9来构建回归测试环境。但是遇到使用JUnit时从未遇到过的问题。在我看来,当每个测试用例完成时,如果测试方法在与调用方法相同的事务上下文中运行,则默认情况下将自动回滚每个数据的更改。但这似乎不是事实,而且我无法找出我的代码中是否有任何错误。请帮帮我。pom.xml中的属性,指示框架的版本 显然,它们都是最新的。 我的测试课: 创建一个实体实例,然后调用c
问题内容: 有没有一种方法可以不使用ROLLBACK来回滚到事务的先前状态? 信息: ROLLBACK TRANSACTION请求没有相应的BEGIN TRANSACTION。 任何输入都会有很大的帮助。 谢谢 !!! 问题答案: 要在明确将IMPLICIT_TRANSACTIONS设置为ON时扩展gerrytans答案,可以使用ROLLBACK。请参阅与此相关的MSDN doco 。请注意,这不
上下文2。XML 这会导致将抽象类的transactionManager属性设置为服务器启动期间创建的最后一个注释事务方面bean'org.springframework.transaction.interceptor.TransactionAspectSupport。 因此,如果实例化的最后一个bean是dataSource1,则在dataSource1上创建事务,否则在DataSource2上
我发现实际上是Spring,我能够设置一些工作。现在,我想使用Hibernate/JPA将导入的数据保存到数据库中,但我总是出现这样的错误: 我明白问题出在交易上。以下是和的spring java配置: 这是导致异常的代码: 有什么解决这个问题的想法吗? [编辑]我也放入了作业定义和步骤定义。我所有的Spring配置都是用Java编写的。 任何人都可以给出更多的见解,如何在spring Batch