我正在Java应用程序中工作,我需要同时执行这两个查询(如java中的字符串)并在有错误的情况下回滚事务。
SELECT dblink_exec('hostaddr=xxx.xx.xxx.xxx port=5432 dbname=bdname user=myuser password=mypass connect_timeout=2',
'INSERT INTO table3(field4)
VALUES (5)') AS result;
SELECT dblink_exec('hostaddr=xxx.xx.xxx.xxx port=5432 dbname=bdname user=myuser password=mypass connect_timeout=2',
'UPDATE table1 SET field2 = field2 + 3.0 WHERE field1 = 16436') AS result;
更新
我创建了一个字符串,其中两个查询用;
分隔,如评论建议
更新
我尝试过JDBC原子事务作为java中的代码。我强制第二个sql失败,但即使我指定.setAutoCommit(false); dblink使用第一个查询影响了另一个数据库。我使用NO dblink事务尝试了相同的代码,并且回滚效果很好。 dblink就是问题所在。
Java更新
public static boolean ejecutarTransaccionDblink(String sql) {
boolean estado = false;
try {
Statement sentencia = conexion.createStatement();
conexion.setAutoCommit(false);
if (sql.length() != 0) {
if (sentencia.execute(sql)) {
conexion.commit();
estado = true;
}
}
} catch (SQLException ex) {
System.out.println(ex.toString());
try {
estado = false;
conexion.rollback();
} catch (SQLException ex1) {
}
} finally {
try {
conexion.setAutoCommit(true);
return estado;
} catch (SQLException ex) {
return estado;
}
}
}
感谢您的帮助。
答案 0 :(得分:1)
为了在事务中运行查询,您只需要在连接上将"data3"
功能设置为false(记住在完成后将其设置为true,尤其是在检索连接时)来自连接池 - 因此重用)。
代码相对简单:
auto-commit
希望有所帮助
更新
正如@a_horse_with_no_name指出的那样,dblink_exec连接到远程数据库,因此上面的内容不完整,因为它只处理第一个数据库中的事务。
我认为答案应该是将命名连接与ResultSet resultado = null;
String statement1 = "SELECT dblink_exec('hostaddr=xxx.xx.xxx.xxx port=5432 dbname=bdname user=myuser password=mypass connect_timeout=2','INSERT INTO table3(field4) VALUES (5)') AS result";
String statement2 = "SELECT dblink_exec('hostaddr=xxx.xx.xxx.xxx port=5432 dbname=bdname user=myuser password=mypass connect_timeout=2','UPDATE table1 SET field2 = field2 + 3.0 WHERE field1 = 16436') AS result";
try {
// set auto-commit to false, to indicate start of transaction
conexion.setAutoCommit(false);
// run whatever queries you want on the connection, in a transaction, e.g. :
Statement sentencia = conexion.createStatement();
resultado = sentencia.executeQuery(sql);
//manually commit the transaction when you're done
conexion.commit();
return resultado;
} catch (SQLException ex) {
System.out.println("Error Consulta:" + ex);
// ensure transaction is rolled-back in case of error. (note: you might want to add an NPE check here
con.rollback();
return null;
} finally {
// close any statements / preparedStatements, etc. Note you MUST do this in the finally block, to ensure your connection won't stay in transaction.
con.setAutoCommit(true);
}
一起使用,其中涉及以下过程:
dblink_exec
dblink_connect
dblink_exec
执行查询1 dblink_exec
执行查询2 因此,代码如下所示:
dblink_exec
问题是,这都是未经测试的,所以@KazMiller可以试试这个吗?
答案 1 :(得分:1)
如果所有其他方法都失败了,请使用一个或多个 CTE 将多个SQL命令链接到一个:
WITH upd AS (
UPDATE table1 SET field2 = field2 + 3.0 WHERE field1 = 16436
)
INSERT INTO table3(field4)
VALUES (5)') AS result;
或INSERT
首先,无关紧要。通常,以这种方式链接两个不相关的命令是没有意义的,但它是该功能的干净应用。你可以用这种方式链接尽可能多的命令。您只能将两个命令写入同一行。您甚至可以获得最终SELECT
返回相关或不相关的值。与CTE中的SELECT
不同,所有数据修改CTE始终执行完成。 The manual:
WITH
中的数据修改语句只执行一次,并且 始终完成,与主查询是否读取无关 所有(或实际上任何)他们的输出。请注意,这是不同的 来自SELECT
中WITH
的规则:如上一节所述, 只有主查询才会执行SELECT
的执行 要求它的输出。
相关:
另一种选择是在目标服务器上创建一个函数(LANGUAGE sql
或LANGUAGE plpgsql
- 但任何语言都应该这样做)以在一个服务器中封装任意数量的命令事务:
CREATE OR REPLACE FUNCTION f_wrapper()
RETURNS void AS
$func$
UPDATE table1 SET field2 = field2 + 3.0 WHERE field1 = 16436;
INSERT INTO table3(field4) VALUES (5);
$func$ LANGUAGE sql;
然后:
SELECT dblink_exec('hostaddr=xxx.xx.xxx.xxx port=5432 dbname=bdname user=myuser password=mypass connect_timeout=2',
'SELECT f_wrapper()') AS result;
您可以动态创建(并删除)一个函数,或者保留一个带有值参数的函数。