Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the reason for the failure of springboot+atomikos+druid database connection

2025-01-23 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

Today Xiaobian to share with you the springboot+atomikos+druid database connection failure is what the relevant knowledge points, detailed content, clear logic, I believe most people are still too familiar with this knowledge, so share this article for your reference, I hope you have read this article after harvest, let's learn about it together.

I. Causes

The last package successfully received from the server was 40802382 milliseconds ago.

Since our system is used during the day, basically no users use it at night, plus the above error messages appear in the morning, combined with the preliminary analysis of the error log, it should be the database connection timeout automatically disconnected. Baidu after a while, know Mysql default connection time is 8 hours, more than 8 hours after no operation will automatically disconnect, but has used the druid database connection pool, supposedly has done protection and inspection of the database connection, should not appear such a problem. To fully understand this problem, you can only study the druid database connection pool framework.

Druid database connection pool

The basic configuration information of the database connection pool for the project is as follows

According to the above configuration analysis, a database connection will be forcibly recovered after 21600s, i.e. 6 hours, after lending from the connection pool, which will not exceed Mysql's default 8 hours, and there is no transaction with such a long time. Therefore, it is unlikely that the above error is caused by database connection lending timeout. So, the connection applied from the database connection pool has timed out? It also seems unlikely because there is a checking mechanism that checks every 30 seconds for connections in the connection pool to time out, and the maximum time allowed for idle connections in the connection pool is 540 seconds. This is strange, what is the reason for the above error? Notice com.atomikos.datasource.pool.ConnectionPool.findOrWaitForAnavailableConnection in the error stack above Whether the problem is due to the use of Atomikos, with such doubts to read Druid and Atomikos related source code.

Since Atomikos connection pools are based on Druid connection pools, Atomikos creates and destroys database connections by lending and returning database connections from Druid connection pools rather than interacting directly with databases, so let's see how Druid maintains database connections.

public DruidPooledConnection getConnection(long maxWaitMillis) throws SQLException { //Initialize check configuration and background threads init(); if (filters.size() > 0) { FilterChainImpl filterChain = new FilterChainImpl(this); return filterChain.dataSource_connect(this, maxWaitMillis); } else { return getConnectionDirect(maxWaitMillis); } }

To get a database connection from the Druid connection pool, call the init() method to initialize it, and then call getConnectionDirect() to get the connection.

decrementPoolingCount();DruidConnectionHolder last = connections[poolingCount];connections[poolingCount] = null;DruidPooledConnection poolalbeConnection = new DruidPooledConnection(holder);public DruidPooledConnection(DruidConnectionHolder holder){ super(holder.getConnection()); this.conn = holder.getConnection(); this.holder = holder; this.lock = holder.lock; dupCloseLogEnable = holder.getDataSource().isDupCloseLogEnable(); ownerThread = Thread.currentThread(); connectedTimeMillis = System.currentTimeMillis();}

The above is the key code to obtain the connection in the connection pool, that is, to obtain the last element in the connections array. After obtaining the Holder, it needs to be encapsulated as DruidPooledConnection. In this case, the connectedTimeMillis of the connection will be assigned to the current time, which will be very important in the subsequent analysis.

Because testWhileIdle is configured to be true, the following validity check is required to obtain the last active time of the connection to obtain the idle time. If it exceeds 30s, the validity check is performed.

long idleMillis = currentTimeMillis - lastActiveTimeMillis;long timeBetweenEvictionRunsMillis = this.timeBetweenEvictionRunsMillis;if (timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis || idleMillis

< 0 // unexcepted branch ) { boolean validate = testConnectionInternal(poolableConnection.holder, poolableConnection.conn); if (!validate) { if (LOG.isDebugEnabled()) { LOG.debug("skip not validate connection."); } discardConnection(poolableConnection.holder); continue; }}long timeMillis = (currrentNanos - pooledConnection.getConnectedTimeNano()) / (1000 * 1000);if (timeMillis >

= removeAbandonedTimeoutMillis) { iter.remove(); pooledConnection.setTraceEnable(false); abandonedList.add(pooledConnection);}

同时,由于配置了removeAbandoned为true,所以需要检查活跃连接是否超时,如果超时就断开物理连接。下面看一下连接池的回收方法recycle的关键代码

if (phyTimeoutMillis > 0) { long phyConnectTimeMillis = currentTimeMillis - holder.connectTimeMillis; if (phyConnectTimeMillis > phyTimeoutMillis) { discardConnection(holder); return; }}lock.lock();try { if (holder.active) { activeCount--; holder.active = false; } closeCount++; result = putLast(holder, currentTimeMillis); recycleCount++;} finally { lock.unlock();}

在对数据库连接进行回收时,如果连接时间超过了数据库的物理连接时间(默认8小时)则需要断开物理连接,否则就调用putLast方法将该连接回收到连接池。

boolean putLast(DruidConnectionHolder e, long lastActiveTimeMillis) { if (poolingCount >= maxActive || e.discard) { return false; } e.lastActiveTimeMillis = lastActiveTimeMillis; connections[poolingCount] = e; incrementPoolingCount(); if (poolingCount > poolingPeak) { poolingPeak = poolingCount; poolingPeakTime = lastActiveTimeMillis; } notEmpty.signal(); notEmptySignalCount++; return true;}

注意上述标红的地方,回收的这个连接的lastActiveTimeMillis被刷新为当前时间,这个时间也是非常重要的,在后续分析中会用到。

三、Atomikos框架

项目关于Atomikos的配置信息,如下所示

从上面的配置可以看出,atomikos连接池的最大连接数是25个,最小连接数是10个,连接最大的存活时间是500s,下面来看一下atomikos的源码。

private void init() throws ConnectionPoolException{ if ( LOGGER.isTraceEnabled() ) LOGGER.logTrace ( this + ": initializing..." ); //如果连接池最小连接数没有达到就新增数据库连接 addConnectionsIfMinPoolSizeNotReached(); //开启维持连接池平衡的线程 launchMaintenanceTimer();}

以上是Atomikos初始化的部分,先补充数据库连接池达到最小连接数,然后开启后台线程维持连接池的平衡。

private void launchMaintenanceTimer() { int maintenanceInterval = properties.getMaintenanceInterval(); if ( maintenanceInterval

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report