自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Spring事務(wù)超時(shí)到底是怎么回事?

開發(fā) 架構(gòu)
Spring事務(wù)超時(shí)是指一個(gè)事務(wù)在執(zhí)行中最長的允許時(shí)間。如果事務(wù)在超時(shí)時(shí)間內(nèi)未能完成,則會(huì)自動(dòng)回滾。超時(shí)時(shí)間可以通過設(shè)置來控制,以確保事務(wù)在規(guī)定的時(shí)間內(nèi)完成或回滾,避免數(shù)據(jù)一致性問題。

環(huán)境:Spring5.3.23

Spring事務(wù)超時(shí)是指一個(gè)事務(wù)在執(zhí)行中最長的允許時(shí)間。如果事務(wù)在超時(shí)時(shí)間內(nèi)未能完成,則會(huì)自動(dòng)回滾。超時(shí)時(shí)間可以通過設(shè)置來控制,以確保事務(wù)在規(guī)定的時(shí)間內(nèi)完成或回滾,避免數(shù)據(jù)一致性問題。

在工作中你有配置事務(wù)的超時(shí)時(shí)間嗎?如何進(jìn)行配置事務(wù)超時(shí)時(shí)間?

1. 配置事務(wù)超時(shí)時(shí)間

注解方式:

// 這里單位是s
@Transactional(timeout = 2)
public void save() {
}

編程方式1:

@Resource
private PlatformTransactionManager tm ;


DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
definition.setTimeout(2) ;

編程方式2:

@Resource
private PlatformTransactionManager tm ;
public void update() {
  TransactionTemplate template = new TransactionTemplate(tm) ;
  template.setTimeout(2) ;
  template.execute(new TransactionCallback<Object>() {
    @Override
    public Object doInTransaction(TransactionStatus status) {
      // ...
      return null ;
    }
  }) ;
}

以上3種方式讀可以進(jìn)行事務(wù)超時(shí)的設(shè)置,什么情況下才能算是事務(wù)超時(shí)呢?

2. 準(zhǔn)備環(huán)境

準(zhǔn)備一張2000w數(shù)據(jù)的表

圖片圖片

表字段信息如下:

圖片圖片

此表除主鍵外沒有任何的索引。

圖片圖片

3. 模擬事務(wù)超時(shí)

  • 測試1

統(tǒng)計(jì)查詢表的數(shù)據(jù)量,將該操作放到一個(gè)事務(wù)中,同時(shí)設(shè)置事務(wù)的超時(shí)時(shí)間。

// 將超時(shí)時(shí)間設(shè)置為20s
@Transactional(timeout = 20)
public void query() {
  long start = System.currentTimeMillis() ;
  jdbcTemplate.execute("select count(*) from p_user") ;
  System.out.println("耗時(shí):" + (System.currentTimeMillis() - start) + "毫秒") ;
}

執(zhí)行結(jié)果:

耗時(shí):3198毫秒

接下來將超時(shí)時(shí)間改成3s

執(zhí)行結(jié)果如下:

13:56:01.425 [main] WARN  c.zaxxer.hikari.pool.ProxyConnection - HikariPool-1 - Connection com.mysql.cj.jdbc.ConnectionImpl@504ecd marked as broken because of SQLSTATE(null), ErrorCode(0)
com.mysql.cj.jdbc.exceptions.MySQLTimeoutException: Statement cancelled due to timeout or client request
  at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:113)
  at com.mysql.cj.jdbc.StatementImpl.checkCancelTimeout(StatementImpl.java:2167)

從異常信息看到拋出了超時(shí)異常。這里的超時(shí)是sql執(zhí)行的超時(shí),是由我們的驅(qū)動(dòng)程序拋出的異常。

  • 測試2

模擬其它非數(shù)據(jù)庫操作耗時(shí),而這個(gè)是在執(zhí)行數(shù)據(jù)庫操作之前

@Transactional(timeout = 2)
public void query() {
  long start = System.currentTimeMillis() ;
  try {
    TimeUnit.SECONDS.sleep(3) ;
  } catch (InterruptedException e) {
    e.printStackTrace();
  }
  // 執(zhí)行非常簡單的操作
  jdbcTemplate.execute("select 1") ;
  System.out.println("耗時(shí):" + (System.currentTimeMillis() - start) + "毫秒") ;
}

執(zhí)行結(jié)果:

14:08:44.000 [main] DEBUG o.s.jdbc.core.JdbcTemplate - Executing SQL statement [select 1]
Exception in thread "main" org.springframework.transaction.TransactionTimedOutException: Transaction timed out: deadline was Wed Oct 11 14:08:42 CST 2023
  at org.springframework.transaction.support.ResourceHolderSupport.checkTransactionTimeout(ResourceHolderSupport.java:155)

拋出了超時(shí)異常,而這個(gè)異常是由Spring框架拋出的。

  • 測試3

模擬其它非數(shù)據(jù)庫操作耗時(shí),而這個(gè)是在執(zhí)行數(shù)據(jù)庫操作之后,適當(dāng)調(diào)整上面的代碼順序

@Transactional(timeout = 2)
public void query() {
  long start = System.currentTimeMillis() ;
  jdbcTemplate.execute("select 1") ;
  try {
    TimeUnit.SECONDS.sleep(3) ;
  } catch (InterruptedException e) {
    e.printStackTrace();
  }
  System.out.println("耗時(shí):" + (System.currentTimeMillis() - start) + "毫秒") ;
}

執(zhí)行結(jié)果:

耗時(shí):3015毫秒

程序正常運(yùn)行

  • 測試4

在測試3的基礎(chǔ)上,最后再次執(zhí)行數(shù)據(jù)庫相關(guān)的操作

@Transactional(timeout = 2)
public void query() {
  long start = System.currentTimeMillis() ;
  jdbcTemplate.execute("select 1") ;
  try {
    TimeUnit.SECONDS.sleep(3) ;
  } catch (InterruptedException e) {
    e.printStackTrace();
  }
  System.out.println("耗時(shí):" + (System.currentTimeMillis() - start) + "毫秒") ;
  // 再次執(zhí)行數(shù)據(jù)庫相關(guān)操作
  jdbcTemplate.execute("select 1") ;
}

執(zhí)行結(jié)果:

耗時(shí):3024毫秒
14:14:38.257 [main] DEBUG o.s.jdbc.core.JdbcTemplate - Executing SQL statement [select 1]
Exception in thread "main" org.springframework.transaction.TransactionTimedOutException: Transaction timed out: deadline was Wed Oct 11 14:14:37 CST 2023
  at org.springframework.transaction.support.ResourceHolderSupport.checkTransactionTimeout(ResourceHolderSupport.java:155)

第一個(gè)數(shù)據(jù)庫操作,沒有拋出異常,直到第二個(gè)執(zhí)行時(shí)拋出了異常。

總結(jié):      事務(wù)方法開始執(zhí)行時(shí)就開始計(jì)時(shí),在執(zhí)行到數(shù)據(jù)庫操作時(shí)判斷當(dāng)前的執(zhí)行時(shí)間點(diǎn)是否已經(jīng)超過了設(shè)置的超時(shí)時(shí)間,如果是則拋出Timeout異常。

4. 事務(wù)超時(shí)原理

在開始一個(gè)事務(wù)時(shí)會(huì)在DataSourceTransactionManager#doBegin方法中設(shè)置超時(shí)時(shí)間

protected void doBegin(Object transaction, TransactionDefinition definition) {
  int timeout = determineTimeout(definition);
  if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
    // 如果注解@Transactional中設(shè)置了timeout,則設(shè)置超時(shí)時(shí)間
    txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
  }
}
protected int determineTimeout(TransactionDefinition definition) {
  if (definition.getTimeout() != TransactionDefinition.TIMEOUT_DEFAULT) {
    return definition.getTimeout();
  }
  return getDefaultTimeout();
}

當(dāng)通過JdbcTemplate操作數(shù)據(jù)庫時(shí),還會(huì)執(zhí)行如下操作

public class JdbcTemplate {
  private <T> T execute(StatementCallback<T> action, boolean closeResources) {
    Statement stmt = null;
    try {
      stmt = con.createStatement();
      // 配置Statement對象,這其中會(huì)設(shè)置超時(shí)時(shí)間
      applyStatementSettings(stmt);
      // ...
      return result;
    }
  }  
  protected void applyStatementSettings(Statement stmt) throws SQLException {
    // ...
    // getQueryTimeout方法返回的是當(dāng)前JdbcTemplate對象中設(shè)置d餓超時(shí)時(shí)間
    DataSourceUtils.applyTimeout(stmt, getDataSource(), getQueryTimeout());
  }
}

DataSourceUtils工具類

public abstract class DataSourceUtils {
  public static void applyTimeout(Statement stmt, @Nullable DataSource dataSource, int timeout) throws SQLException {
    ConnectionHolder holder = null;
    if (dataSource != null) {
      holder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
    }
    // 如果當(dāng)前事務(wù)執(zhí)行配置了超時(shí)時(shí)間
    if (holder != null && holder.hasTimeout()) {
      // 剩余事務(wù)超時(shí)將覆蓋指定的值。
      stmt.setQueryTimeout(holder.getTimeToLiveInSeconds());
    }
    else if (timeout >= 0) {
      // No current transaction timeout -> apply specified value.
      stmt.setQueryTimeout(timeout);
    }
  }  
}

ResourceHolderSupport類

public abstract class ResourceHolderSupport implements ResourceHolder { 
  public int getTimeToLiveInSeconds() {
    double diff = ((double) getTimeToLiveInMillis()) / 1000;
    int secs = (int) Math.ceil(diff);
    // 檢查超時(shí)時(shí)間
    checkTransactionTimeout(secs <= 0);
    return secs;
  }
  private void checkTransactionTimeout(boolean deadlineReached) throws TransactionTimedOutException {
    if (deadlineReached) {
      // 設(shè)置事務(wù)回滾
      setRollbackOnly();
      // 拋出異常
      throw new TransactionTimedOutException("Transaction timed out: deadline was " + this.deadline);
    }
  }
}

完畢!??!

責(zé)任編輯:武曉燕 來源: Spring全家桶實(shí)戰(zhàn)案例源碼
相關(guān)推薦

2022-04-15 08:54:39

PythonAsync代碼

2021-10-15 21:16:00

手機(jī)內(nèi)存漏洞

2023-03-29 08:24:30

2019-07-23 15:34:29

MySQL存儲(chǔ)引擎

2015-05-29 09:34:13

2018-01-28 13:59:23

小程序微信開發(fā)者

2018-03-13 10:32:43

2022-05-26 11:36:12

APK文件小米

2020-02-18 11:19:36

物聯(lián)網(wǎng)病毒物聯(lián)網(wǎng)IOT

2010-04-20 09:55:37

2022-01-25 20:23:21

聯(lián)邦通信委員會(huì)聯(lián)邦航空管理局5G

2020-08-12 09:10:16

AI芯片AI人工智能

2021-06-04 11:10:04

JavaScript開發(fā)代碼

2020-02-04 17:42:17

寬帶運(yùn)營商攜號轉(zhuǎn)網(wǎng)

2021-05-11 11:51:15

飛機(jī)Wi-Fi通信

2013-04-18 09:56:05

2023-03-05 15:41:58

MySQL日志暴漲

2016-11-22 19:54:56

點(diǎn)擊率預(yù)估推薦算法廣告

2024-01-08 08:35:28

閉包陷阱ReactHooks

2023-06-13 18:45:00

研究監(jiān)督
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號