聊聊jdbc socketTimeout的設(shè)置

本文主要介紹下jdbc的socket timeout的設(shè)置

jdbc timeout類別

主要有如下幾個(gè)類別


  • transaction timeout

設(shè)置的是一個(gè)事務(wù)的執(zhí)行時(shí)間涮母,里頭可能包含多個(gè)statement

  • statement timeout(也相當(dāng)于result set fetch timeout)

設(shè)置的是一個(gè)statement的執(zhí)行超時(shí)時(shí)間沛贪,即driver等待statement執(zhí)行完成,接收到數(shù)據(jù)的超時(shí)時(shí)間(注意statement的timeout不是整個(gè)查詢的timeout,只是statement執(zhí)行完成并拉取fetchSize數(shù)據(jù)返回的超時(shí)豺总,之后resultSet的next在必要的時(shí)候還會(huì)觸發(fā)fetch數(shù)據(jù),每次fetch的超時(shí)時(shí)間是單獨(dú)算的信认,默認(rèn)也是以statement設(shè)置的timeout為準(zhǔn))

  • jdbc socket timeout

設(shè)置的是jdbc I/O socket read and write operations的超時(shí)時(shí)間惧磺,防止因網(wǎng)絡(luò)問題或數(shù)據(jù)庫問題,導(dǎo)致driver一直阻塞等待赏寇。(建議比statement timeout的時(shí)間長)

  • os socket timeout

這個(gè)是操作系統(tǒng)級(jí)別的socket設(shè)置(如果jdbc socket timeout沒有設(shè)置吉嫩,而os級(jí)別的socket timeout有設(shè)置,則使用系統(tǒng)的socket timeout值)嗅定。

上面的不同級(jí)別的timeout越往下優(yōu)先級(jí)越高自娩,也就是說如果下面的配置比上面的配置值小的話,則會(huì)優(yōu)先觸發(fā)timeout渠退,那么相當(dāng)于上面的配置值就"失效"了忙迁。

jdbc socket timeout

這個(gè)不同數(shù)據(jù)的jdbc driver實(shí)現(xiàn)不一樣

mysql

jdbc:mysql://localhost:3306/ag_admin?useUnicode=true&characterEncoding=UTF8&connectTimeout=60000&socketTimeout=60000

通過url參數(shù)傳遞即可

pg

jdbc:postgresql://localhost/test?user=fred&password=secret&&connectTimeout=60&socketTimeout=60

pg也是通過url傳遞,不過它的單位與mysql不同碎乃,mysql是毫秒姊扔,而pg是秒

oracle

oracle需要通過oracle.jdbc.ReadTimeout參數(shù)來設(shè)置,連接超時(shí)參數(shù)是oracle.net.CONNECT_TIMEOUT

  • 通過properties設(shè)置
            Class.forName("oracle.jdbc.driver.OracleDriver");
            Properties props = new Properties() ;
            props.put( "user" , "test_schema") ;
            props.put( "password" , "pwd") ;
            props.put( "oracle.net.CONNECT_TIMEOUT" , "10000000") ;
            props.put( "oracle.jdbc.ReadTimeout" , "2000" ) ;
            Connection conn = DriverManager.getConnection( "jdbc:oracle:thin:@10.0.1.9:1521:orcl" , props ) ;
  • 通過環(huán)境變量設(shè)置
String readTimeout = "10000"; // ms
System.setProperty("oracle.jdbc.ReadTimeout", readTimeout);
Class.forName("oracle.jdbc.OracleDriver");
Connection conn = DriverManager.getConnection(jdbcUrl, user, pwd);

注意需要在connection連接之前設(shè)置環(huán)境變量

  • tomcat jdbc pool

一般我們不直接使用jdbc connection荠锭,而是使用連接池旱眯。由于tomcat jdbc pool是springboot默認(rèn)使用的數(shù)據(jù)庫連接池,這里就講述一下如何在tomcat jdbc pool下設(shè)置证九。

spring.datasource.tomcat.connectionProperties=oracle.net.CONNECT_TIMEOUT=10000;oracle.jdbc.ReadTimeout=60000

注意删豺,這里是分號(hào)分隔,單位是毫秒愧怜,這里可以根據(jù)各自的情況配置前綴(tomcat jdbc連接池的話呀页,默認(rèn)是spring.datasource.tomcat),可以自定義拥坛,比如

    @Bean
    @Qualifier("writeDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.write")
    public DataSource writeDataSource() {
        return DataSourceBuilder.create().build();
    }

假設(shè)你這里是自定義了prefix為spring.datasource.write蓬蝶,那么上述配置就變?yōu)?/p>

spring.datasource.write.connectionProperties=oracle.net.CONNECT_TIMEOUT=10000;oracle.jdbc.ReadTimeout=60000

oracle.jdbc.ReadTimeout如果沒有設(shè)置的話尘分,driver里頭默認(rèn)是0

oracle.jdbc.ReadTimeout

driver內(nèi)部將該值設(shè)置到oracle.net.READ_TIMEOUT變量上

  • oracle.net.nt.TcpNTAdapter
    @Override
    public void setReadTimeoutIfRequired(final Properties properties) throws IOException, NetException {
        String s = ((Hashtable<K, String>)properties).get("oracle.net.READ_TIMEOUT");
        if (s == null) {
            s = "0";
        }
        this.setOption(3, s);
    }
    
    public void setOption(int var1, Object var2) throws IOException, NetException {
        String var3;
        switch(var1) {
        case 0:
            var3 = (String)var2;
            this.socket.setTcpNoDelay(var3.equals("YES"));
            break;
        case 1:
            var3 = (String)var2;
            if(var3.equals("YES")) {
                this.socket.setKeepAlive(true);
            }
        case 2:
        default:
            break;
        case 3:
            this.sockTimeout = Integer.parseInt((String)var2);
            this.socket.setSoTimeout(this.sockTimeout);
        }

    }

可用看到最后設(shè)置的是socket的soTimeout

實(shí)例

    @Test
    public void testReadTimeout() throws SQLException {
        Connection connection = dataSource.getConnection();
        String sql = "select * from demo_table";
        PreparedStatement pstmt;
        try {
            pstmt = (PreparedStatement)connection.prepareStatement(sql);
            ResultSet rs = pstmt.executeQuery();
            int col = rs.getMetaData().getColumnCount();
            System.out.println("============================");
            while (rs.next()) {
                for (int i = 1; i <= col; i++) {
                    System.out.print(rs.getObject(i));
                }
                System.out.println("");
            }
            System.out.println("============================");
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //close resources
        }
    }

超時(shí)錯(cuò)誤輸出

//部分?jǐn)?shù)據(jù)輸出......
java.sql.SQLRecoverableException: IO 錯(cuò)誤: Socket read timed out
    at oracle.jdbc.driver.T4CPreparedStatement.fetch(T4CPreparedStatement.java:1128)
    at oracle.jdbc.driver.OracleResultSetImpl.close_or_fetch_from_next(OracleResultSetImpl.java:373)
    at oracle.jdbc.driver.OracleResultSetImpl.next(OracleResultSetImpl.java:277)
    at com.example.demo.DemoApplicationTests.testReadTimeout(DemoApplicationTests.java:68)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: oracle.net.ns.NetException: Socket read timed out
    at oracle.net.ns.Packet.receive(Packet.java:339)
    at oracle.net.ns.DataPacket.receive(DataPacket.java:106)
    at oracle.net.ns.NetInputStream.getNextPacket(NetInputStream.java:315)
    at oracle.net.ns.NetInputStream.read(NetInputStream.java:260)
    at oracle.net.ns.NetInputStream.read(NetInputStream.java:185)
    at oracle.net.ns.NetInputStream.read(NetInputStream.java:102)
    at oracle.jdbc.driver.T4CSocketInputStreamWrapper.readNextPacket(T4CSocketInputStreamWrapper.java:124)
    at oracle.jdbc.driver.T4CSocketInputStreamWrapper.read(T4CSocketInputStreamWrapper.java:80)
    at oracle.jdbc.driver.T4CMAREngine.unmarshalUB1(T4CMAREngine.java:1137)
    at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:290)
    at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:192)
    at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:531)
    at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:207)
    at oracle.jdbc.driver.T4CPreparedStatement.fetch(T4CPreparedStatement.java:1119)
    ... 35 more

剛開始會(huì)有數(shù)據(jù)輸出,但是到了某個(gè)resultSet的next的時(shí)候丸氛,報(bào)了超時(shí)(close_or_fetch_from_next)培愁,這個(gè)超時(shí)指定的是當(dāng)result.next方法觸發(fā)新的一批數(shù)據(jù)的拉取(當(dāng)一個(gè)fetchSize的數(shù)據(jù)消費(fèi)完之后,接下來的next會(huì)觸發(fā)新一批數(shù)據(jù)的fetch)之后在timeout時(shí)間返回內(nèi)沒有收到數(shù)據(jù)庫返回的數(shù)據(jù)缓窜。

oracle的jdbc默認(rèn)的fetchSize為10定续,也就是每個(gè)fetch,如果超過指定時(shí)間沒接收到數(shù)據(jù)禾锤,則拋出timeout異常私股。

小結(jié)

jdbc的socketTimeout值的設(shè)置要非常小心,不同數(shù)據(jù)庫的jdbc driver設(shè)置不一樣恩掷,特別是使用不同連接池的話倡鲸,設(shè)置也可能不盡相同。對于嚴(yán)重依賴數(shù)據(jù)庫操作的服務(wù)來說黄娘,非常有必要設(shè)置這個(gè)值峭状,否則萬一網(wǎng)絡(luò)或數(shù)據(jù)庫異常,會(huì)導(dǎo)致服務(wù)線程一直阻塞在java.net.SocketInputStream.socketRead0逼争。

  • 如果查詢數(shù)據(jù)多宁炫,則會(huì)導(dǎo)致該線程持有的data list不能釋放,相當(dāng)于內(nèi)存泄露氮凝,最后導(dǎo)致OOM
  • 如果請求數(shù)據(jù)庫操作很多且阻塞住了,會(huì)導(dǎo)致服務(wù)器可用的woker線程變少望忆,嚴(yán)重則會(huì)導(dǎo)致服務(wù)不可用罩阵,nginx報(bào)504 Gateway Timeout

doc

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市启摄,隨后出現(xiàn)的幾起案子稿壁,更是在濱河造成了極大的恐慌,老刑警劉巖歉备,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件傅是,死亡現(xiàn)場離奇詭異,居然都是意外死亡蕾羊,警方通過查閱死者的電腦和手機(jī)喧笔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來龟再,“玉大人书闸,你說我怎么就攤上這事±眨” “怎么了浆劲?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵嫌术,是天一觀的道長。 經(jīng)常有香客問我牌借,道長度气,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任膨报,我火速辦了婚禮磷籍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘丙躏。我一直安慰自己择示,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布晒旅。 她就那樣靜靜地躺著栅盲,像睡著了一般。 火紅的嫁衣襯著肌膚如雪废恋。 梳的紋絲不亂的頭發(fā)上谈秫,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天,我揣著相機(jī)與錄音鱼鼓,去河邊找鬼拟烫。 笑死,一個(gè)胖子當(dāng)著我的面吹牛迄本,可吹牛的內(nèi)容都是我干的硕淑。 我是一名探鬼主播,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼嘉赎,長吁一口氣:“原來是場噩夢啊……” “哼置媳!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起公条,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤拇囊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后靶橱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體寥袭,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年关霸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了传黄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,992評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡谒拴,死狀恐怖尝江,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情英上,我是刑警寧澤炭序,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布啤覆,位于F島的核電站,受9級(jí)特大地震影響惭聂,放射性物質(zhì)發(fā)生泄漏窗声。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一辜纲、第九天 我趴在偏房一處隱蔽的房頂上張望笨觅。 院中可真熱鬧,春花似錦耕腾、人聲如沸见剩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽苍苞。三九已至,卻和暖如春狼纬,著一層夾襖步出監(jiān)牢的瞬間羹呵,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工疗琉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留冈欢,地道東北人审磁。 一個(gè)月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓潮饱,卻偏偏與公主長得像,于是被迫代替她去往敵國和親攒钳。 傳聞我的和親對象是個(gè)殘疾皇子柠贤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評論 2 355