偶然读到熊老师的文章《老熊的三分地-JDBC中语句超时与事务》了解到:JAVA代码的最后正常断开数据库连接,在默认情况下,正常断开的数据库连接会自动提交没有提交的事务。
通过文章的测试JAVA程序,可以表明,JDBC中的语句超时,只会使当前的SQL中止运行,但如果是在一个事务中,之前运行的DML语句并没有提交。这造成的后果有两种:
今天正好有国产数据库工程师师给我们培训的时候也提到了这一点,表示:“JDBC连接ORACLE,在断开连接时会把未提交的事务进行提交,在Oracle 23ai版本进行了修复,其它数据库都是回滚事务。”
这着(zhuo)实有点刷新我对Oracle的基础认知。这是一篇对自己认知纠正的测试文章。复现一下熊老师的测试,实践出真知。
SQL*Plus: Release 11.2.0.3.0 Production on Tue Nov 19 21:32:31 2024
[root@db ~]$ mkdir /usr/local/java
[root@db ~]$ cd /usr/local/java
[root@db java]$ mv /root/jdk-11.0.21_linux-x64_bin.tar.gz ./
[root@db java]$ tar -zxvf jdk-11.0.21_linux-x64_bin.tar.gz
[root@db java]$ cd jdk-11.0.21
[root@db jdk-11.0.21]# pwd
/usr/local/java/jdk-11.0.21
[root@db jdk-11.0.21]# vi /etc/profile
...
export JAVA_HOME=/usr/local/java/jdk-11.0.21
export CLASSPATH=$JAVA_HOME/lib
export PATH=$PATH:$JAVA_HOME/bin
...
[root@db ~]# source /etc/profile
[root@db ~]# java -version
java version "11.0.21" 2023-10-17 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.21+9-LTS-193)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.21+9-LTS-193, mixed mode)
[oracle@db ~]$ cat .bash_profile
......
export NLS_LANG=AMERICAN_AMERICA.AL32UTF8
export JAVA_HOME=/usr/local/java/jdk-11.0.21
export CLASSPATH=$JAVA_HOME/lib
export PATH=$PATH:$JAVA_HOME/bin
......
[oracle@db ~]$ source .bash_profile
[oracle@db ~]$ java -version
java version "11.0.21" 2023-10-17 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.21+9-LTS-193)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.21+9-LTS-193, mixed mode)
[oracle@db java_oracle]$ cat TestTimeout.java
import java.sql.*;
public class TestTimeout {
public static Connection getConnection() throws Exception {
String driver = "oracle.jdbc.driver.OracleDriver";
String url = "jdbc:oracle:thin:@10.10.5.64:1521/phytest1";
Class.forName(driver);
return DriverManager.getConnection(url, "two", "two");
}
public static void main(String args[]) {
test1();
}
public static void test1() {
Connection conn = null;
Statement pstmt = null;
try {
conn = getConnection();
conn.setAutoCommit(false);
pstmt = conn.createStatement();
pstmt.setQueryTimeout(60);
System.out.println("连接成功!");
ResultSet rs = pstmt.executeQuery("select userenv('sid') sid from dual");
while (rs.next()) {
System.out.println("SID:" + rs.getString("sid"));
}
rs.close();
pstmt.execute("insert into t1 values (1,userenv('sid'),'xx')");
System.out.println("Insert t1 succeed!");
pstmt.execute("update t2 set name='x' where id=1");
System.out.println("Update t2 succeed!");
conn.commit();
} catch (Exception e) {
e.printStackTrace();
try {
System.out.println("等待......");
Thread.sleep(300000);
} catch (Exception f) {
}
} finally {
try {
System.out.println("关闭连接!");
pstmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
[oracle@db java_oracle]$ ls
ojdbc8.jar TestTimeout.java
[oracle@db java_oracle]$ javac TestTimeout.java
[oracle@db java_oracle]$ ls
ojdbc8.jar TestTimeout.class TestTimeout.java
[oracle@db java_oracle]$ java -cp .:ojdbc8.jar TestTimeout
连接成功!
SID:387
Insert t1 succeed!
Update t2 succeed!
关闭连接!
TWO@phytest1:1489> select * from t1;
ID SID NAME
---------- -------------------- ----------------
1 387 xx
[oracle@db ~]$ cat /u01/oracle/11.2.0.3/product/sqlplus/admin/glogin.sql
SET TERMOUT OFF
DEFINE sqlprompt=none
COLUMN sqlprompt NEW_VALUE sqlprompt
SELECT USER ||'@'|| NVL('&_CONNECT_IDENTIFIER', global_name )||':'|| userenv('sid') sqlprompt FROM global_name;
SET SQLPROMPT '&sqlprompt> '
UNDEFINE sqlprompt
SET TERMOUT ON
col NAME format a50
col VALUE format a50
set lin 250
set pagesize 500
[oracle@db ~]$ sqlplus / as sysdba
SYS@phytest1:387>
TWO@phytest1:1489> create table t1 ( id number primary key,sid varchar2(20),name varchar2(20));
Table created.
TWO@phytest1:1489> create table t2 ( id number primary key,sid varchar2(20),name varchar2(20));
Table created.
TWO@phytest1:1489> insert into t2 values (1,userenv('sid'),'a');
1 row created.
TWO@phytest1:1489> commit;
Commit complete.
TWO@phytest1:1489> select * from t2;
ID SID NAME
---------- -------------------- --------------
1 1489 a
TWO@phytest1:1489> update t2 set name='y' where id=1;
1 row updated.
TWO@phytest1:1489>
[oracle@db java_oracle]$ java -cp .:ojdbc8.jar TestTimeout
连接成功!
SID:659
Insert t1 succeed!
SYS@phytest1:74> set line 800
SYS@phytest1:74> col EVENT for a50
SYS@phytest1:74> select sid,event,sql_id from v$session where sid=659;
SID EVENT SQL_ID
---------- ------------------------------------- ----------
659 enq: TX - row lock contention 3b3b7s22dv13t
col blocker for a10
SELECT (SELECT username
FROM v$session
WHERE SID = a.SID) blocker, a.SID, 'is blocking',
(SELECT username
FROM v$session
WHERE SID = b.SID) blockee, b.SID
FROM v$lock a, v$lock b
WHERE a.BLOCK = 1 AND b.request > 0 AND a.id1 = b.id1 AND a.id2 = b.id2;
BLOCKER SID 'ISBLOCKING BLOCKEE SID
---------- ---------- ----------- ------------------------------ ----------
TWO 659 is blocking TWO 277
select start_time,xidusn,xidslot,xidsqn,status from v$transaction where ses_addr=(select saddr from v$session where sid=387);
select * from v$lock where sid=387;
-- 取TM锁对象id(v$lock.ID1)
select owner,object_name,object_type from dba_objects where object_id in (256012);
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。