日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

【转】Spring事务超时时间可能存在的错误认识

發(fā)布時(shí)間:2025/3/19 javascript 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【转】Spring事务超时时间可能存在的错误认识 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>

1、先看代碼

1.1、spring-config.xml

Java代碼??
  • <bean?id="dataSource"?class="org.springframework.jdbc.datasource.DriverManagerDataSource">??
  • ????<property?name="driverClassName"?value="com.mysql.jdbc.Driver"/>??
  • ????<property?name="url"?value="jdbc:mysql://localhost:3306/test?autoReconnect=true&amp;useUnicode=true&amp;characterEncoding=utf-8"/>??
  • ????<property?name="username"?value="root"/>??
  • ????<property?name="password"?value=""/>??
  • </bean>??
  • ??
  • <bean?id="txManager"?class="org.springframework.jdbc.datasource.DataSourceTransactionManager">??
  • ????<property?name="dataSource"?ref="dataSource"/>??
  • </bean>??
  • ?

    1.2、測試用例

    Java代碼??
  • @RunWith(SpringJUnit4ClassRunner.class)??
  • @ContextConfiguration(locations?=?"classpath:spring-config.xml")??
  • @TransactionConfiguration(transactionManager?=?"txManager",?defaultRollback?=?false)??
  • @Transactional(timeout?=?2)??
  • public?class?Timeout1Test?{??
  • ????@Autowired??
  • ????private?DataSource?ds;??
  • ????@Test??
  • ????public?void?testTimeout()?throws?InterruptedException?{??
  • ????????System.out.println(System.currentTimeMillis());??
  • ????????JdbcTemplate?jdbcTemplate?=?new?JdbcTemplate(ds);??
  • ????????jdbcTemplate.execute("?update?test?set?name?=?name?||?'1'");??
  • ????????System.out.println(System.currentTimeMillis());??
  • ????????Thread.sleep(3000L);??
  • ????}??
  • }??
  • ?

    我設(shè)置事務(wù)超時(shí)時(shí)間是2秒;但我事務(wù)肯定執(zhí)行3秒以上;為什么沒有起作用呢???這其實(shí)是對(duì)Spring實(shí)現(xiàn)的事務(wù)超時(shí)的錯(cuò)誤認(rèn)識(shí)。那首先分析下Spring事務(wù)超時(shí)實(shí)現(xiàn)吧。

    ?

    2、分析

    2.1、在此我們分析下DataSourceTransactionManager;首先開啟事物會(huì)調(diào)用其doBegin方法:

    Java代碼??
  • …………??
  • int?timeout?=?determineTimeout(definition);??
  • if?(timeout?!=?TransactionDefinition.TIMEOUT_DEFAULT)?{??
  • ????txObject.getConnectionHolder().setTimeoutInSeconds(timeout);??
  • }??
  • …………??
  • ?其中determineTimeout用來獲取我們?cè)O(shè)置的事務(wù)超時(shí)時(shí)間;然后設(shè)置到ConnectionHolder對(duì)象上(其是ResourceHolder子類),接著看ResourceHolderSupport的setTimeoutInSeconds實(shí)現(xiàn):

    Java代碼??
  • public?void?setTimeoutInSeconds(int?seconds)?{??
  • ????setTimeoutInMillis(seconds?*?1000);??
  • }??
  • ??
  • public?void?setTimeoutInMillis(long?millis)?{??
  • ????this.deadline?=?new?Date(System.currentTimeMillis()?+?millis);??
  • }??
  • 大家可以看到,其會(huì)設(shè)置一個(gè)deadline時(shí)間;用來判斷事務(wù)超時(shí)時(shí)間的;那什么時(shí)候調(diào)用呢?首先檢查該類中的代碼,會(huì)發(fā)現(xiàn):

    Java代碼??
  • public?int?getTimeToLiveInSeconds()?{??
  • ????double?diff?=?((double)?getTimeToLiveInMillis())?/?1000;??
  • ????int?secs?=?(int)?Math.ceil(diff);??
  • ????checkTransactionTimeout(secs?<=?0);??
  • ????return?secs;??
  • }??
  • ??
  • public?long?getTimeToLiveInMillis()?throws?TransactionTimedOutException{??
  • ????if?(this.deadline?==?null)?{??
  • ????????throw?new?IllegalStateException("No?timeout?specified?for?this?resource?holder");??
  • ????}??
  • ????long?timeToLive?=?this.deadline.getTime()?-?System.currentTimeMillis();??
  • ????checkTransactionTimeout(timeToLive?<=?0);??
  • ????return?timeToLive;??
  • }??
  • private?void?checkTransactionTimeout(boolean?deadlineReached)?throws?TransactionTimedOutException?{??
  • ????if?(deadlineReached)?{??
  • ????????setRollbackOnly();??
  • ????????throw?new?TransactionTimedOutException("Transaction?timed?out:?deadline?was?"?+?this.deadline);??
  • ????}??
  • }??
  • 會(huì)發(fā)現(xiàn)在調(diào)用getTimeToLiveInSeconds和getTimeToLiveInMillis,會(huì)檢查是否超時(shí),如果超時(shí)設(shè)置事務(wù)回滾,并拋出TransactionTimedOutException異常。到此我們只要找到調(diào)用它們的位置就好了,那什么地方調(diào)用的它們呢??最簡單的辦法使用如“IntelliJ IDEA”中的“Find Usages”找到get***的使用地方;會(huì)發(fā)現(xiàn):

    DataSourceUtils.applyTransactionTimeout會(huì)調(diào)用DataSourceUtils.applyTimeout,DataSourceUtils.applyTimeout代碼如下:

    Java代碼??
  • public?static?void?applyTimeout(Statement?stmt,?DataSource?dataSource,?int?timeout)?throws?SQLException?{??
  • ????Assert.notNull(stmt,?"No?Statement?specified");??
  • ????Assert.notNull(dataSource,?"No?DataSource?specified");??
  • ????ConnectionHolder?holder?=?(ConnectionHolder)?TransactionSynchronizationManager.getResource(dataSource);??
  • ????if?(holder?!=?null?&&?holder.hasTimeout())?{??
  • ????????//?Remaining?transaction?timeout?overrides?specified?value.??
  • ????????stmt.setQueryTimeout(holder.getTimeToLiveInSeconds());??
  • ????}??
  • ????else?if?(timeout?>?0)?{??
  • ????????//?No?current?transaction?timeout?->?apply?specified?value.??
  • ????????stmt.setQueryTimeout(timeout);??
  • ????}??
  • }??
  • 其中其在stmt.setQueryTimeout(holder.getTimeToLiveInSeconds());中會(huì)調(diào)用getTimeToLiveInSeconds,此時(shí)就會(huì)檢查事務(wù)是否超時(shí);

    ?

    ?

    然后在JdbcTemplate中,執(zhí)行sql之前,會(huì)調(diào)用其applyStatementSettings:其會(huì)調(diào)用DataSourceUtils.applyTimeout(stmt, getDataSource(), getQueryTimeout());設(shè)置超時(shí)時(shí)間;具體可以看其源碼;

    ?

    到此我們知道了在JdbcTemplate拿到Statement之后,執(zhí)行之前會(huì)設(shè)置其queryTimeout,具體意思參考Javadoc:

    ?

    3、結(jié)論

    寫道 Spring事務(wù)超時(shí) = 事務(wù)開始時(shí)到最后一個(gè)Statement創(chuàng)建時(shí)時(shí)間 + 最后一個(gè)Statement的執(zhí)行時(shí)超時(shí)時(shí)間(即其queryTimeout)。

    ?

    4、因此

    假設(shè)事務(wù)超時(shí)時(shí)間設(shè)置為2秒;假設(shè)sql執(zhí)行時(shí)間為1秒;

    如下調(diào)用是事務(wù)不超時(shí)的

    Java代碼??
  • public?void?testTimeout()?throws?InterruptedException?{??
  • ????System.out.println(System.currentTimeMillis());??
  • ????JdbcTemplate?jdbcTemplate?=?new?JdbcTemplate(ds);??
  • ????jdbcTemplate.execute("?update?test?set?hobby?=?hobby?||?'1'");??
  • ????System.out.println(System.currentTimeMillis());??
  • ????Thread.sleep(3000L);??
  • }??
  • 而如下事務(wù)超時(shí)是起作用的;

    Java代碼??
  • public?void?testTimeout()?throws?InterruptedException?{??
  • ????Thread.sleep(3000L);??
  • ????System.out.println(System.currentTimeMillis());??
  • ????JdbcTemplate?jdbcTemplate?=?new?JdbcTemplate(ds);??
  • ????jdbcTemplate.execute("?update?test?set?hobby?=?hobby?||?'1'");??
  • ????System.out.println(System.currentTimeMillis());??
  • }??
  • ??

    ?

    因此,不要忽略應(yīng)用中如遠(yuǎn)程調(diào)用產(chǎn)生的事務(wù)時(shí)間和這個(gè)事務(wù)時(shí)間是否對(duì)您的事務(wù)產(chǎn)生影響。

    ?

    另外:

    1、事務(wù)超時(shí)不起作用,您要首先檢查您的事務(wù)起作用了沒:可以參考使用Aop工具類診斷常見問題

    2、如果您用的JPA,且spring版本低于3.0,可能您的事務(wù)超時(shí)不起作用:https://jira.springsource.org/browse/SPR-5195

    3、如果您用JDBC,但沒有用JdbcTemplate,直接使用DateSourceUtils進(jìn)行事務(wù)控制時(shí),要么自己設(shè)置Statement的queryTimeout超時(shí)時(shí)間,要么使用TransactionAwareDataSourceProxy,其在創(chuàng)建Statement時(shí)會(huì)自動(dòng)設(shè)置其queryTimeout。

    4、關(guān)于JDBC超時(shí)時(shí)間設(shè)置一篇不錯(cuò)的翻譯:深入理解JDBC的超時(shí)設(shè)置?

    http://www.cubrid.org/blog/dev-platform/understanding-jdbc-internals-and-timeout-configuration/

    轉(zhuǎn)載于:https://my.oschina.net/javahongxi/blog/1523722

    總結(jié)

    以上是生活随笔為你收集整理的【转】Spring事务超时时间可能存在的错误认识的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。