請注意,在 PHP 5.3 或更高版本中,您可以使用 oci_close() 關閉以 oci_pconnect() 開啟的持續連線。
如此處所述
https://php.dev.org.tw/manual/en/oci8.configuration.php#ini.oci8.persistent-timeout
(PHP 5, PHP 7, PHP 8, PECL OCI8 >= 1.1.0)
oci_close — 關閉 Oracle 連線
取消設定 connection
。如果底層資料庫連線沒有其他資源正在使用,而且它是使用 oci_connect() 或 oci_new_connect() 建立的,則該連線將會被關閉。
建議關閉不再需要的連線,因為這可以將資料庫資源釋放給其他使用者。
當 oci8.old_oci_close_semantics 啟用時,傳回 null
,否則傳回 true
。
範例 #1 關閉連線
應該關閉與連線關聯的資源,以確保底層資料庫連線正確終止並釋放資料庫資源。
<?php
$conn = oci_connect('hr', 'welcome', 'localhost/XE');
if (!$conn) {
$e = oci_error();
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR);
}
$stid = oci_parse($conn, 'SELECT * FROM departments');
$r = oci_execute($stid);
oci_fetch_all($stid, $res);
var_dump($res);
// 關閉連線時釋放敘述識別碼
oci_free_statement($stid);
oci_close($conn);
?>
範例 #2 資料庫連線在所有參考關閉之前不會關閉
連線識別碼的內部參考計數必須為零,底層資料庫連線才會關閉。
<?php
$conn = oci_connect('hr', 'welcome', 'localhost/XE');
if (!$conn) {
$e = oci_error();
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR);
}
$stid = oci_parse($conn, 'SELECT * FROM departments'); // 這會增加 $conn 的引用計數
oci_execute($stid);
oci_fetch_all($stid, $res);
var_dump($res);
oci_close($conn);
// $conn 在腳本中已無法使用,但底層的資料庫
// 連線仍保持開啟狀態,直到 $stid 被釋放。
var_dump($conn); // 顯示 NULL
// 當 PHP 休眠時,在終端機視窗中查詢 Oracle V$SESSION 視圖
// 將會顯示資料庫使用者仍然處於連線狀態。
sleep(10);
// 當 $stid 被釋放時,資料庫連線才會實際關閉
oci_free_statement($stid);
// 當 PHP 休眠時,在終端機視窗中查詢 Oracle V$SESSION 視圖
// 將會顯示資料庫使用者已斷開連線。
sleep(10);
?>
範例 #3 關閉已開啟多次的連線
當資料庫憑證被重複使用時,兩個連線都必須關閉,底層的資料庫連線才會關閉。
<?php
$conn1 = oci_connect('hr', 'welcome', 'localhost/XE');
// 使用相同的憑證會重複使用相同的底層資料庫連線
// 在 $conn1 上執行的任何未提交的變更在 $conn2 中都可看見
$conn2 = oci_connect('hr', 'welcome', 'localhost/XE');
// 當 PHP 休眠時,在終端視窗中查詢 Oracle V$SESSION 視圖將只顯示一個資料庫使用者已連線。
sleep(10);
oci_close($conn1); // 不會關閉底層資料庫連線
var_dump($conn1); // 顯示 NULL,因為變數 $conn1 不再可用
var_dump($conn2); // 顯示 $conn2 仍然是一個有效的連線資源
?>
範例 #4 連線在變數超出範圍時關閉
當所有參考連線的變數超出範圍並被 PHP 釋放時,將會進行回滾(如果需要),並且底層與資料庫的連線將被關閉。
<?php
function myfunc() {
$conn = oci_connect('hr', 'hrpwd', 'localhost/XE');
if (!$conn) {
$e = oci_error();
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR);
}
$stid = oci_parse($conn, 'UPDATE mytab SET id = 100');
oci_execute($stid, OCI_NO_AUTO_COMMIT);
return "Finished";
}
$r = myfunc();
// 此時發生了回滾,並且底層資料庫連線已被釋放。
print $r; // 顯示函式回傳值 "Finished"
?>
注意:
依賴於連線識別碼的變數,例如 oci_parse() 返回的陳述式識別碼,也必須在底層資料庫連線關閉之前釋放。
注意:
oci_close() 函式不會關閉使用 oci_pconnect() 建立的底層資料庫連線。
請注意,在 PHP 5.3 或更高版本中,您可以使用 oci_close() 關閉以 oci_pconnect() 開啟的持續連線。
如此處所述
https://php.dev.org.tw/manual/en/oci8.configuration.php#ini.oci8.persistent-timeout
為了使用持續連線 && 並使其能夠休眠,我使用
function close_db_locks_on_abort( ) {
global $conn;
if( connection_aborted() ) {
$fp = fopen( "/tmp/shutdown-func.txt", "a" );
fwrite( $fp, sprintf( "連線於 %s 中斷\n", date( "d-m-Y H:i:s" ) ) );
if( $conn ) {
OCIRollBack( $conn );
fwrite( $fp, sprintf( "-- 連線期間!ip=%s, 使用者=%s, 頁面=%s\n", $_SERVER["REMOTE_ADDR"], $_SERVER["PHP_AUTH_USER"], $_SERVER["SCRIPT_FILENAME"] ) );
}
fclose( $fp );
}
}
register_shutdown_function ( "close_db_locks_on_abort" );
這確保了當使用者按下「停止」時,連線會執行回滾,因此資料表列上不會有任何鎖定。