偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Spring Boot 內(nèi)置八種控制數(shù)據(jù)庫連接方式

開發(fā) 前端
DataSourceTransactionManager 類是針對單個(gè) JDBC DataSource 的 PlatformTransactionManager 實(shí)現(xiàn)。它將從指定的 DataSource 中獲取的 JDBC 連接綁定到當(dāng)前正在執(zhí)行的線程,從而可能為每個(gè) DataSource 提供一個(gè)線程綁定的連接。

環(huán)境:SpringBoot3.4.2

1. 簡介

Spring框架管理數(shù)據(jù)庫連接的核心目標(biāo)是確保高效、安全且與事務(wù)緊密集成地使用這一關(guān)鍵資源。它抽象了底層連接獲取和釋放的復(fù)雜性。

關(guān)鍵在于連接的生命周期管理:Spring提倡在需要時(shí)獲取連接,使用后及時(shí)釋放回池(或關(guān)閉),避免資源泄漏。更重要的是,它實(shí)現(xiàn)了連接與當(dāng)前執(zhí)行線程的綁定,尤其是在事務(wù)上下文中。這確保了同一事務(wù)內(nèi)的多個(gè)數(shù)據(jù)庫操作共享同一個(gè)物理連接,從而保證了操作的原子性和一致性(ACID)。

Spring通過其事務(wù)管理基礎(chǔ)設(shè)施自動(dòng)協(xié)調(diào)連接的獲取、綁定、提交/回滾和釋放。開發(fā)者通常無需手動(dòng)處理連接細(xì)節(jié),只需關(guān)注業(yè)務(wù)邏輯和聲明式事務(wù)(如@Transactional),框架會(huì)透明地處理連接的查找、復(fù)用和清理,顯著簡化了開發(fā)并提高了可靠性和性能。

接下來,我們將介紹Spring內(nèi)置的8種數(shù)據(jù)庫連接的控制方式。

2.實(shí)戰(zhàn)案例

2.1 使用DataSource

Spring 通過 DataSource 獲取與數(shù)據(jù)庫的連接。DataSource 是 JDBC 規(guī)范的一部分,是一個(gè)通用的連接工廠。它允許容器或框架將連接池和事務(wù)管理問題從應(yīng)用程序代碼中隱藏起來。

我們可以使用第三方提供的連接池實(shí)現(xiàn)來配置自己的數(shù)據(jù)源。傳統(tǒng)的選擇包括 Apache Commons DBCP 和 C3P0;而對于現(xiàn)代的 JDBC 連接池,可以考慮使用 HikariCP 及其基于構(gòu)建器的 API。

DriverManagerDataSource 和 SimpleDriverDataSource 類(包含在 Spring 發(fā)行版中)應(yīng)僅用于測試目的!這些變體不提供連接池功能,在多個(gè)連接請求發(fā)生時(shí)性能較差。

如下是使用HikariCP數(shù)據(jù)源的配置:

@Configuration
public class DataSourceConfig {
  @Bean
  @ConfigurationProperties(prefix = "spring.datasource.hikari")
  HikariDataSource dataSource(DataSourceProperties properties) {
    return (HikariDataSource) DataSourceBuilder.create()
        .type(HikariDataSource.class)
        .driverClassName(properties.getDriverClassName())
        .url(properties.getUrl())
        .username(properties.getUsername())
        .password(properties.getPassword())
        .build() ;
  }
}

2.2 使用DataSourceUtils

DataSourceUtils 類是一個(gè)便捷且功能強(qiáng)大的輔助類,它提供了一些靜態(tài)方法,用于從 JNDI 獲取連接,并在必要時(shí)關(guān)閉連接。它支持與 DataSourceTransactionManager 綁定線程的 JDBC 連接,同時(shí)也支持與 JtaTransactionManager 和 JpaTransactionManager 的綁定。

需要注意的是,JdbcTemplate 在其內(nèi)部實(shí)現(xiàn)中隱含地使用了 DataSourceUtils 來訪問連接。在每一次 JDBC 操作背后,JdbcTemplate 都會(huì)利用 DataSourceUtils,從而隱式地參與到正在進(jìn)行的事務(wù)中。

如下使用示例:

public class UserRepository {
  private final DataSource dataSource;
  public UserRepository(DataSource dataSource) {
    this.dataSource = dataSource;
  }
  public void updateUserName(Long userId, String newName) {
    Connection conn = null;
    try {
      // 如果當(dāng)前本身就在一個(gè)事務(wù)上下文中,那么這里獲取的連接將是當(dāng)前已經(jīng)綁定到上下文中的Connection對象
      conn = DataSourceUtils.getConnection(dataSource);
      try (PreparedStatement ps = conn.prepareStatement("UPDATE users SET name = ? WHERE id = ?")) {
        ps.setString(1, newName);
        ps.setLong(2, userId);
        ps.executeUpdate();
      }
    } catch (SQLException e) {
      throw new RuntimeException("Update failed", e);
    } finally {
      // 關(guān)鍵點(diǎn):通過 DataSourceUtils 釋放連接(事務(wù)內(nèi)不會(huì)真正關(guān)閉)
      DataSourceUtils.releaseConnection(conn, dataSource);
    }
  }
}

2.3 實(shí)現(xiàn)SmartDataSource接口

如果你有一個(gè)類,它的任務(wù)是給應(yīng)用程序提供與數(shù)據(jù)庫的連接(就像是一個(gè)“數(shù)據(jù)庫連接供應(yīng)商”),那么這個(gè)類可以考慮實(shí)現(xiàn) SmartDataSource 接口。

SmartDataSource 接口是 DataSource 接口的一個(gè)“升級版”。DataSource 接口已經(jīng)提供了獲取數(shù)據(jù)庫連接的基本功能,但 SmartDataSource 接口更進(jìn)一步,它允許使用這個(gè)接口的類去詢問:“嘿,數(shù)據(jù)庫連接供應(yīng)商,在我用完這個(gè)連接之后,你是否希望我把它還給你(也就是關(guān)閉它)?”

為什么這個(gè)功能有用呢?想象一下,你正在進(jìn)行一系列的數(shù)據(jù)庫操作,這些操作都需要用到同一個(gè)數(shù)據(jù)庫連接。如果你每次操作完都關(guān)閉連接,然后再重新獲取一個(gè)新的連接,那就會(huì)很浪費(fèi)時(shí)間,也很低效。但是,如果你知道接下來還要用這個(gè)連接,你就可以告訴連接供應(yīng)商:“我現(xiàn)在不用關(guān)閉它,我接下來還要用。”

所以,SmartDataSource 接口就是給數(shù)據(jù)庫連接供應(yīng)商提供了一個(gè)“智能”的選擇,讓它們可以根據(jù)情況決定是否要關(guān)閉連接。當(dāng)你知道你需要重用連接時(shí),這個(gè)功能就特別有用,因?yàn)樗軒湍愎?jié)省時(shí)間和資源。

接口簽名如下:

public interface SmartDataSource extends DataSource {
  // 詢問是否要關(guān)閉連接
  boolean shouldClose(Connection con);
}

上面介紹的DataSourceUtils工具類,其在關(guān)閉連接時(shí)會(huì)判斷是否是SmartDataSource,代碼如下:

public abstract class DataSourceUtils {
  public static void doCloseConnection(Connection con, @Nullable DataSource dataSource) throws SQLException {
    if (!(dataSource instanceof SmartDataSource smartDataSource) 
      || smartDataSource.shouldClose(con)) {
      con.close();
    }
  }
}

2.4 繼承AbstractDataSource

AbstractDataSource 是 Spring 中 DataSource 實(shí)現(xiàn)的一個(gè)抽象基類。它實(shí)現(xiàn)了所有 DataSource 實(shí)現(xiàn)中通用的代碼。如果你打算編寫自己的 DataSource 實(shí)現(xiàn),那么你應(yīng)該擴(kuò)展 AbstractDataSource 類。

如下代碼實(shí)現(xiàn):

public class Pack extends AbstractDataSource {
  @Override
  public Connection getConnection() throws SQLException {
    return null;
  }
  @Override
  public Connection getConnection(String username, String password) throws SQLException {
    return null;
  }
}

我們只需要實(shí)現(xiàn)獲取Connection連接對象的核心方法即可。

通常我們可以在需要實(shí)現(xiàn)自己的數(shù)據(jù)源或是代理第三方數(shù)據(jù)源時(shí)使用。

2.5 使用SingleConnectionDataSource

SingleConnectionDataSource 類是 SmartDataSource 接口的一個(gè)實(shí)現(xiàn),它封裝了一個(gè)單一的數(shù)據(jù)庫連接,并且這個(gè)連接在每次使用后不會(huì)被關(guān)閉。需要注意的是,它并不支持多線程。

如果有任何客戶端代碼在假設(shè)存在連接池的情況下調(diào)用了 close 方法(例如在使用持久化工具時(shí)),你應(yīng)該將 suppressClose 屬性設(shè)置為 true。這個(gè)設(shè)置會(huì)返回一個(gè)關(guān)閉抑制代理(close-suppressing proxy),它會(huì)封裝實(shí)際的物理連接。

SingleConnectionDataSource 主要是一個(gè)用于測試的類。它通常與簡單的 JNDI 環(huán)境結(jié)合使用,以便在應(yīng)用程序服務(wù)器之外輕松測試代碼。與 DriverManagerDataSource 相比,SingleConnectionDataSource 會(huì)一直重用同一個(gè)連接,從而避免了過多物理連接的創(chuàng)建。

如果你用過UReport一款web在線報(bào)表設(shè)計(jì)工具,那你可能知道SingleConnectionDataSource,該報(bào)表工具內(nèi)部就是使用的該數(shù)據(jù)源。

2.6 使用DriverManagerDataSource

DriverManagerDataSource 類是標(biāo)準(zhǔn) DataSource 接口的一個(gè)實(shí)現(xiàn),它通過 bean 屬性來配置一個(gè)普通的 JDBC 驅(qū)動(dòng),并且每次都會(huì)返回一個(gè)新的連接。

這個(gè)實(shí)現(xiàn)對于在 Jakarta EE 容器之外的測試環(huán)境和獨(dú)立環(huán)境非常有用,既可以作為 Spring IoC 容器中的一個(gè) DataSource bean,也可以與簡單的 JNDI 環(huán)境結(jié)合使用。假設(shè)存在連接池的 Connection.close() 調(diào)用會(huì)關(guān)閉連接,因此任何了解 DataSource 的持久化代碼都應(yīng)該能夠正常工作。然而,即使在測試環(huán)境中,使用基于 JavaBean 風(fēng)格的連接池(例如 commons-dbcp)也非常簡單,幾乎總是比使用 DriverManagerDataSource 更可取。

如下配置示例:

@Bean
DriverManagerDataSource dataSource() {
  DriverManagerDataSource dataSource = new DriverManagerDataSource() ;
  dataSource.setDriverClassName("org.hsqldb.jdbcDriver") ;
  dataSource.setUrl("jdbc:hsqldb:hsql://localhost:") ;
  dataSource.setUsername("sa") ;
  dataSource.setPassword("") ;
  return dataSource ;
}

提醒:注意使用環(huán)境。

2.7 使用TransactionAwareDataSourceProxy

TransactionAwareDataSourceProxy 是一個(gè)目標(biāo) DataSource 的代理類。這個(gè)代理類會(huì)包裝目標(biāo) DataSource,為其添加對 Spring 管理的事務(wù)的感知能力。

通常,除了在必須調(diào)用現(xiàn)有代碼并傳遞一個(gè)標(biāo)準(zhǔn) JDBC DataSource 接口實(shí)現(xiàn)的情況下,很少需要使用這個(gè)類。

TransactionAwareDataSourceProxy 是 Spring 提供的數(shù)據(jù)源代理類,主要用于將非 Spring 管理的 JDBC 數(shù)據(jù)源包裝為支持 Spring 事務(wù)的代理對象。

如下使用示例:

@Configuration
public class LegacyIntegrationConfig {
  @Bean
  public DataSource realDataSource() {
    // 創(chuàng)建原始數(shù)據(jù)源(如 DBCP、HikariCP)
    return new HikariDataSource(...);
  }
  @Bean
  public TransactionAwareDataSourceProxy transactionAwareDataSource() {
    // 包裝原始數(shù)據(jù)源
    return new TransactionAwareDataSourceProxy(realDataSource());
  }
  @Bean
  public PlatformTransactionManager txManager() {
    // 事務(wù)管理器使用原始數(shù)據(jù)源
    return new DataSourceTransactionManager(realDataSource());
  }
  @Bean
  public LegacyDao legacyDao() {
    // 遺留代碼注入代理數(shù)據(jù)源
    return new LegacyDao(transactionAwareDataSource());
  }
}
// 遺留代碼(無法修改)
public class LegacyDao {
  private final DataSource dataSource;
  public LegacyDao(DataSource dataSource) {
    this.dataSource = dataSource;
  }
  public void updateData() throws SQLException {
    // 如果我們沒有使用代理,這里拿到的Connection一定不是由Spring事務(wù)管理的連接
    try (Connection conn = dataSource.getConnection()) {
      conn.prepareStatement("UPDATE t_product x SET x.name = 'xxxooo' WHERE x.id = 2").execute();
    }
  }
}
@Service
public class Service {
  private final LegacyDao legacyDao;
  // 此時(shí)我們就將遺留的代碼加入到了Spring管理的事務(wù)中
  // 這樣我們在updateData方法中獲取的Connection才受Spring事務(wù)管理
  @Transactional
  public void update() {
    this.legacyDao.updateData() ;
  }
}

2.8 使用DataSourceTransactionManager

DataSourceTransactionManager 類是針對單個(gè) JDBC DataSource 的 PlatformTransactionManager 實(shí)現(xiàn)。它將從指定的 DataSource 中獲取的 JDBC 連接綁定到當(dāng)前正在執(zhí)行的線程,從而可能為每個(gè) DataSource 提供一個(gè)線程綁定的連接。 

應(yīng)用程序代碼需要通過 DataSourceUtils.getConnection(DataSource) 來獲取 JDBC 連接,而不是使用 Jarkarta EE 的標(biāo)準(zhǔn) DataSource.getConnection 方法。

DataSourceTransactionManager 類支持保存點(diǎn)(PROPAGATION_NESTED)、自定義隔離級別以及適當(dāng)應(yīng)用為 JDBC 語句查詢超時(shí)的超時(shí)設(shè)置。為了支持后者,應(yīng)用程序代碼必須使用 JdbcTemplate,或者為每個(gè)創(chuàng)建的語句調(diào)用 DataSourceUtils.applyTransactionTimeout(..) 方法。

如下代碼使用示例:

@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
  DataSourceTransactionManager txManager = new DataSourceTransactionManager();
  txManager.setDataSource(dataSource);
  txManager.setDefaultTimeout(10); // 默認(rèn)超時(shí)30秒
  // 在這里我們可以做更多的配置了
  return txManager;
}

這在Spring Boot環(huán)境下將會(huì)覆蓋系統(tǒng)的默認(rèn)事務(wù)管理器。

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

2025-06-06 07:38:49

2010-04-07 18:26:43

Oracle數(shù)據(jù)庫

2010-04-06 10:52:06

Oracle數(shù)據(jù)庫

2010-10-26 14:06:43

oracle連接遠(yuǎn)程數(shù)

2010-04-28 16:23:18

Oracle數(shù)據(jù)庫

2011-03-21 12:51:16

Oracle數(shù)據(jù)庫表連接

2011-04-13 14:38:17

2022-02-17 11:03:33

數(shù)據(jù)庫基礎(chǔ)語法用法

2011-09-21 11:21:00

NoSQL

2024-01-10 08:17:50

HikariCP數(shù)據(jù)庫Spring

2011-06-08 11:15:21

web.configASP.NET

2018-09-27 15:58:06

MySQL數(shù)據(jù)庫性能優(yōu)化

2021-06-29 17:19:44

Spring Boot集成Flyway

2011-03-25 09:05:02

Oracle數(shù)據(jù)庫共享連接專用連接

2010-04-06 11:02:30

Oracle 數(shù)據(jù)庫

2010-10-26 16:07:45

連接oracle數(shù)據(jù)庫

2010-07-27 14:33:24

DB2數(shù)據(jù)庫

2011-03-14 13:33:32

Oracle數(shù)據(jù)庫啟動(dòng)

2020-09-02 13:22:28

IP訪問Oracle數(shù)據(jù)庫

2010-11-29 09:56:00

sybase數(shù)據(jù)庫備份
點(diǎn)贊
收藏

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