SpringBoot druid配置datasource啟動初始化資料庫連線
1、問題場景:
1.1、服務在啟動之後的第一筆或者幾筆請求,處理時間較長,對於呼叫方來說超時,引發技術保底。
1.2、資料庫連線資訊配置錯誤,專案啟動過程中卻不產生任何異常,等到實際功能用到資料庫了才丟擲異常。
2、問題分析:
2.1、呼叫發系統通過http請求呼叫服務,設定超時時間為1s,超時時間過短,調整為3s;
2.2、應用啟動之後的初始幾筆請求處理時間過長,超過1s,跟蹤日誌發現在init-datasource中等待時間佔用過多;
2.3、經過本地測試發現,在應用啟動之後,在jvisualvm中檢視mbeans中的druid.pool中的讀寫datasource的屬性,啟動之後的creatCount為0。在有請求進入之後才初始化了配置檔案中的init連線數,導致了線上的問題;
3、解決方案:在資料庫配置檔案中配置讀寫datasource的bean中增加init-method=init的配置即可。druid官方文件中介紹,如果想要在專案啟動的時候初始化配置的資料庫連線數,需要顯示配置或者呼叫init-method。
具體實現,如下圖:
你可以在bean中增加init-method=init的配置,
也可以建立 dataSource 後,顯示的呼叫 init 方法。
附 init 方法原始碼:
public void init() throws SQLException {
if (inited) {
return;
}
final ReentrantLock lock = this.lock;
try {
lock.lockInterruptibly();
} catch (InterruptedException e) {
throw new SQLException("interrupt", e);
}
boolean init = false;
try {
if (inited) {
return;
}
initStackTrace = Utils.toString(Thread.currentThread().getStackTrace());
this.id = DruidDriver.createDataSourceId();
if (this.id > 1) {
long delta = (this.id - 1) * 100000;
this.connectionIdSeed.addAndGet(delta);
this.statementIdSeed.addAndGet(delta);
this.resultSetIdSeed.addAndGet(delta);
this.transactionIdSeed.addAndGet(delta);
}
if (this.jdbcUrl != null) {
this.jdbcUrl = this.jdbcUrl.trim();
initFromWrapDriverUrl();
}
for (Filter filter : filters) {
filter.init(this);
}
if (this.dbType == null || this.dbType.length() == 0) {
this.dbType = JdbcUtils.getDbType(jdbcUrl, null);
}
if (JdbcConstants.MYSQL.equals(this.dbType) || //
JdbcConstants.MARIADB.equals(this.dbType)) {
boolean cacheServerConfigurationSet = false;
if (this.connectProperties.containsKey("cacheServerConfiguration")) {
cacheServerConfigurationSet = true;
} else if (this.jdbcUrl.indexOf("cacheServerConfiguration") != -1) {
cacheServerConfigurationSet = true;
}
if (cacheServerConfigurationSet) {
this.connectProperties.put("cacheServerConfiguration", "true");
}
}
if (maxActive <= 0) {
throw new IllegalArgumentException("illegal maxActive " + maxActive);
}
if (maxActive < minIdle) {
throw new IllegalArgumentException("illegal maxActive " + maxActive);
}
if (getInitialSize() > maxActive) {
throw new IllegalArgumentException("illegal initialSize " + this.initialSize + ", maxActieve " + maxActive);
}
if (timeBetweenLogStatsMillis > 0 && useGlobalDataSourceStat) {
throw new IllegalArgumentException("timeBetweenLogStatsMillis not support useGlobalDataSourceStat=true");
}
if (maxEvictableIdleTimeMillis < minEvictableIdleTimeMillis) {
throw new SQLException("maxEvictableIdleTimeMillis must be grater than minEvictableIdleTimeMillis");
}
if (this.driverClass != null) {
this.driverClass = driverClass.trim();
}
initFromSPIServiceLoader();
if (this.driver == null) {
if (this.driverClass == null || this.driverClass.isEmpty()) {
this.driverClass = JdbcUtils.getDriverClassName(this.jdbcUrl);
}
if (MockDriver.class.getName().equals(driverClass)) {
driver = MockDriver.instance;
} else {
driver = JdbcUtils.createDriver(driverClassLoader, driverClass);
}
} else {
if (this.driverClass == null) {
this.driverClass = driver.getClass().getName();
}
}
initCheck();
initExceptionSorter();
initValidConnectionChecker();
validationQueryCheck();
if (isUseGlobalDataSourceStat()) {
dataSourceStat = JdbcDataSourceStat.getGlobal();
if (dataSourceStat == null) {
dataSourceStat = new JdbcDataSourceStat("Global", "Global", this.dbType);
JdbcDataSourceStat.setGlobal(dataSourceStat);
}
if (dataSourceStat.getDbType() == null) {
dataSourceStat.setDbType(this.getDbType());
}
} else {
dataSourceStat = new JdbcDataSourceStat(this.name, this.jdbcUrl, this.dbType, this.connectProperties);
}
dataSourceStat.setResetStatEnable(this.resetStatEnable);
connections = new DruidConnectionHolder[maxActive];
SQLException connectError = null;
try {
// init connections
for (int i = 0, size = getInitialSize(); i < size; ++i) {
PhysicalConnectionInfo pyConnectInfo = createPhysicalConnection();
DruidConnectionHolder holder = new DruidConnectionHolder(this, pyConnectInfo);
connections[poolingCount] = holder;
incrementPoolingCount();
}
if (poolingCount > 0) {
poolingPeak = poolingCount;
poolingPeakTime = System.currentTimeMillis();
}
} catch (SQLException ex) {
LOG.error("init datasource error, url: " + this.getUrl(), ex);
connectError = ex;
}
createAndLogThread();
createAndStartCreatorThread();
createAndStartDestroyThread();
initedLatch.await();
init = true;
initedTime = new Date();
registerMbean();
if (connectError != null && poolingCount == 0) {
throw connectError;
}
} catch (SQLException e) {
LOG.error("{dataSource-" + this.getID() + "} init error", e);
throw e;
} catch (InterruptedException e) {
throw new SQLException(e.getMessage(), e);
} finally {
inited = true;
lock.unlock();
if (init && LOG.isInfoEnabled()) {
LOG.info("{dataSource-" + this.getID() + "} inited");
}
}
}
在 init 裡呼叫 createPhysicalConnection() 建立物理連線
public PhysicalConnectionInfo createPhysicalConnection() throws SQLException {
String url = this.getUrl();
Properties connectProperties = getConnectProperties();
String user;
if (getUserCallback() != null) {
user = getUserCallback().getName();
} else {
user = getUsername();
}
String password = getPassword();
PasswordCallback passwordCallback = getPasswordCallback();
if (passwordCallback != null) {
if (passwordCallback instanceof DruidPasswordCallback) {
DruidPasswordCallback druidPasswordCallback = (DruidPasswordCallback) passwordCallback;
druidPasswordCallback.setUrl(url);
druidPasswordCallback.setProperties(connectProperties);
}
char[] chars = passwordCallback.getPassword();
if (chars != null) {
password = new String(chars);
}
}
Properties physicalConnectProperties = new Properties();
if (connectProperties != null) {
physicalConnectProperties.putAll(connectProperties);
}
if (user != null && user.length() != 0) {
physicalConnectProperties.put("user", user);
}
if (password != null && password.length() != 0) {
physicalConnectProperties.put("password", password);
}
Connection conn;
long connectStartNanos = System.nanoTime();
long connectedNanos, initedNanos, validatedNanos;
try {
conn = createPhysicalConnection(url, physicalConnectProperties);
connectedNanos = System.nanoTime();
if (conn == null) {
throw new SQLException("connect error, url " + url + ", driverClass " + this.driverClass);
}
initPhysicalConnection(conn);
initedNanos = System.nanoTime();
validateConnection(conn);
validatedNanos = System.nanoTime();
setCreateError(null);
} catch (SQLException ex) {
setCreateError(ex);
throw ex;
} catch (RuntimeException ex) {
setCreateError(ex);
throw ex;
} catch (Error ex) {
createErrorCount.incrementAndGet();
throw ex;
} finally {
long nano = System.nanoTime() - connectStartNanos;
createTimespan += nano;
}
return new PhysicalConnectionInfo(conn, connectStartNanos, connectedNanos, initedNanos, validatedNanos);
}
相關文章
- SpringBoot系列之資料庫初始化-datasource配置方式Spring Boot資料庫
- Springboot 整合阿里資料庫連線池 druidSpring Boot阿里資料庫UI
- springboot+atomikos+druid 資料庫連線失效分析Spring BootUI資料庫
- springboot專案整合druid資料庫連線池Spring BootUI資料庫
- druid資料庫連線池的配置類UI資料庫
- 聊聊資料庫連線池 Druid資料庫UI
- 資料庫連線池-Druid資料庫連線池原始碼解析資料庫UI原始碼
- Java Druid資料庫連線池+SpringJDBCJavaUI資料庫SpringJDBC
- 阿里Druid資料庫連線工具類阿里UI資料庫
- Spring Boot整合Druid資料庫連線池Spring BootUI資料庫
- Druid資料庫連線池使用體驗UI資料庫
- SpringBoot_資料庫連線Spring Boot資料庫
- 資料庫連線池優化配置(druid,dbcp,c3p0)資料庫優化UI
- 資料庫連線池_druid基本使用&工具類資料庫UI
- springboot activiti 整合專案框架原始碼 shiro 安全框架 druid 資料庫連線池Spring Boot框架原始碼UI資料庫
- SpringBoot資料訪問之Druid啟動器的使用Spring BootUI
- springboot 配置DRUID資料來源的方法Spring BootUI
- spring boot 不連線資料庫啟動Spring Boot資料庫
- Druid資料庫連線池就這麼簡單UI資料庫
- Mybatis配置資料庫連線MyBatis資料庫
- 連線oracle資料庫時,報錯:{dataSource-1} init errorOracle資料庫Error
- SpringBoot專案連線MySQL資料庫Spring BootMySql資料庫
- springboot的服務不需要連線資料庫,如何保證正常啟動Spring Boot資料庫
- SpringBoot專案整合阿里Druid連線池Spring Boot阿里UI
- springboot系列文章之啟動時初始化資料Spring Boot
- ORACLE 配置連線遠端資料庫Oracle資料庫
- mysql資料庫連線池配置教程MySql資料庫
- 資料來源(DataSource)是什麼以及SpringBoot中資料來源配置Spring Boot
- SpringBoot——專案啟動時讀取配置及初始化資源Spring Boot
- springboot連線hive無法啟動Spring BootHive
- SpringBoot2 基礎案例(07):整合Druid連線池,配置監控介面Spring BootUI
- springboot 多資料來源 activiti 工作流 整合專案框架原始碼 druid 資料庫連線池ehcache快取Spring Boot框架原始碼UI資料庫快取
- springboot+druid+mybatis plus的多資料來源配置Spring BootUIMyBatis
- 網站連線資料庫配置錯誤網站資料庫
- 網站連線資料庫配置檔案網站資料庫
- 2.6 Laravel配置多個資料庫連線Laravel資料庫
- Docker容器啟動時初始化Mysql資料庫DockerMySql資料庫
- SpringBoot整合Druid資料來源Spring BootUI