[英]Execute multiple queries as one dblink transaction
我在 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 通過第一個查詢影響了另一個數據庫。 我在沒有 dblink 事務的情況下嘗試了相同的代碼,並且回滾效果很好。 dblink 是問題所在。
更新
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;
}
}
}
謝謝你的幫助。
為了在事務中運行查詢,您只需要在連接上將auto-commit
功能設置為 false(記住在完成后將其設置回 true,尤其是從連接池中檢索連接時 -因此被重用)。
代碼比較簡單:
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);
}
希望有幫助
更新
正如@a_horse_with_no_name 指出的那樣,dblink_exec 連接到遠程數據庫,因此上述內容並不完整,因為它僅處理第一個數據庫中的事務。
我相信答案應該在於使用帶有dblink_exec
命名連接,其中該過程涉及:
dblink_connect
打開一個新連接dblink_exec
在新命名連接中啟動事務dblink_exec
執行查詢 1dblink_exec
執行查詢 2因此,代碼如下所示:
SELECT dblink_connect('myconn','hostaddr=xxx.xx.xxx.xxx port=5432 dbname=bdname user=myuser password=mypass connect_timeout=2');
SELECT dblink_exec('myconn','BEGIN');
SELECT dblink_exec('myconn', 'INSERT INTO table3(field4) VALUES (5)');
SELECT dblink_exec('myconn', 'UPDATE table1 SET field2 = field2 + 3.0 WHERE field1 = 16436');
SELECT dblink_exec('myconn','COMMIT');
問題是,這一切都未經測試,所以@KazMiller 你能試試嗎?
如果所有其他方法都失敗了,請使用一個或多個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 總是執行完成。 手冊:
WITH
中的數據修改語句只執行一次,並且總是完成,與主查詢是否讀取所有(或實際上任何)輸出無關。 請注意,這WITH
SELECT
規則不同:如上一節所述,僅在主查詢需要其輸出時才會執行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;
您可以即時創建(和刪除)一個函數,也可以保留一個接受值參數的函數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.