广告
返回顶部
首页 > 资讯 > 精选 >springboot+atomikos+druid数据库连接失效的原因是什么
  • 692
分享到

springboot+atomikos+druid数据库连接失效的原因是什么

2023-06-29 02:06:32 692人浏览 薄情痞子
摘要

今天小编给大家分享一下SpringBoot+atomikos+druid数据库连接失效的原因是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我

今天小编给大家分享一下SpringBoot+atomikos+druid数据库连接失效的原因是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

一、起因

  最近查看系统的后台日志,经常发现这样的报错信息:The last package successfully received from the server was 40802382 milliseconds aGo,截图如下所示。

springboot+atomikos+druid数据库连接失效的原因是什么

springboot+atomikos+druid数据库连接失效的原因是什么

  由于我们的系统都是在白天使用,夜里基本上没有用户使用,再加上以上的报错信息都是出现在早晨,结合错误日志初步分析,应该是数据库连接超时自动断开了。百度一番后,得知Mysql的默认连接时间是8小时,超过8小时没有操作后就会自动断开连接,但是已经使用了druid数据库连接池,按理说已经对数据库连接做了保护和检查,不应该出现这样的问题。要想彻底弄明白这个问题,就只能去研究druid数据库连接池框架了。

二、Druid数据库连接池

  项目的数据库连接池基本配置信息如下所示

springboot+atomikos+druid数据库连接失效的原因是什么

  通过以上的配置分析得知,一个数据库连接从连接池中借出后经过21600s即6小时后会被强制回收,不会超过Mysql的默认8小时,而且也不存在这么长时间的事务,所以不太可能是因为数据库连接借出超时导致上面的错误,那么就是从数据库连接池中申请的连接已经超时了?似乎也不太可能,因为有检查机制,即每隔30s就会检查一次连接池中的连接是否超时,并且连接池中允许存在的空闲连接最大时间为540s。这就奇怪了,到底是什么原因导致上面的错误呢?这时注意到上述错误堆栈中的com.atomikos.datasource.pool.ConnectionPool.findOrWaitForAnAvailableConnection。是否问题的原因在于使用了Atomikos呢,带着这样的疑惑去阅读了Druid和Atomikos相关的源码

  由于Atomikos连接池是基于Druid连接池之上的,所以Atomikos新建和销毁数据库连接都是从Druid连接池中借出和归还数据库连接,而不是直接与数据库交互,那么我们就来看看Druid是如何维持数据库连接的。

public DruidPooledConnection getConnection(long maxWaitMillis) throws sqlException {     //初始化检查配置和后台线程        init();        if (filters.size() > 0) {            FilterChainImpl filterChain = new FilterChainImpl(this);            return filterChain.dataSource_connect(this, maxWaitMillis);        } else {            return getConnectionDirect(maxWaitMillis);        }    }

从Druid连接池中获取数据库连接,先调用init()方法进行初始化工作,然后调用getConnectionDirect()获取连接。

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();}

上述是获取连接池中连接的关键代码,即获取connections数组中的最后一个元素,获取到Holder后还需要将其封装为DruidPooledConnection,这时该连接的connectedTimeMillis会被赋值为当前时间,这个时间在后续的分析中会非常重要。

  因为配置了testWhileIdle为true,所以需要进行下面的有效性检查,获取该连接的上次活跃时间,得到空闲时间,如果超过30s则做有效性检查。

long idleMillis  = currentTimeMillis - lastActiveTimeMillis;long timeBetweenEvictionRunsMillis = this.timeBetweenEvictionRunsMillis;if (timeBetweenEvictionRunsMillis <= 0) {      timeBetweenEvictionRunsMillis = DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;}if (idleMillis >= 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的配置信息,如下所示

springboot+atomikos+druid数据库连接失效的原因是什么

从上面的配置可以看出,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 <= 0 ) {            if ( LOGGER.isTraceEnabled() ) LOGGER.logTrace ( this + ": using default maintenance interval..." );            maintenanceInterval = DEFAULT_MAINTENANCE_INTERVAL;        }        maintenanceTimer = new PooledAlarmTimer ( maintenanceInterval * 1000 );        maintenanceTimer.addAlarmTimerListener(new AlarmTimerListener() {            public void alarm(AlarmTimer timer) {                reapPool();          //如果达到了最大的存活时间就移除该连接                removeConnectionsThatExceededMaxLifetime();          //如果没有满足最小连接数就新增连接                addConnectionsIfMinPoolSizeNotReached();           //移除超过最小连接数以外的连接                removeIdleConnectionsIfMinPoolSizeExceeded();            }        });        TaskManager.SINGLETON.executeTask ( maintenanceTimer );    }

在配置中,maintenanceInterval的值为30,即每个30秒执行一次上述的四个方法,主要看一下removeConnectionsThatExceededMaxLifetime()这个方法。

private synchronized void removeConnectionsThatExceededMaxLifetime()    {        long maxLifetime = properties.getMaxLifetime();        if ( connections == null || maxLifetime <= 0 ) return;        if ( LOGGER.isTraceEnabled() ) LOGGER.logTrace ( this + ": closing connections that exceeded maxLifetime" );        Iterator<XPooledConnection> it = connections.iterator();        while ( it.hasNext() ) {            XPooledConnection xpc = it.next();            long creationTime = xpc.getCreationTime();            long now = System.currentTimeMillis();            if ( xpc.isAvailable() &&  ( (now - creationTime) >= (maxLifetime * 1000L) ) ) {                if ( LOGGER.isTraceEnabled() ) LOGGER.logTrace ( this + ": connection in use for more than " + maxLifetime + "s, destroying it: " + xpc );          //如果超过最大的存活时间就销毁该连接                destroyPooledConnection(xpc);                it.remove();            }        }        logCurrentPoolSize();    }

上述方法遍历数据库连接池中的所有连接,如果存活时间超过maxLifetime即500s就销毁该连接,这时由于连接池中的连接数就小于minPoolSize,所以会立即补充新的连接到连接池中。那么,系统在夜间没有用户使用时,Atomikos连接池的运行状态为:维持最小的连接数10个数据库连接,当这10个连接超过500s时就会销毁,再重新创建10个新的数据库连接,不断重复这样的操作。

四、分析与总结

  下面我们开始分析产生错误日志的原因,当没有用户使用系统时,Druid连接池应该有10个空闲的连接,Atomikos连接池也有10个空闲的连接,这时Atomikos的10个连接达到了最大的生存时间500s,就需要销毁这些连接,对于Druid来说就是回收连接,调用recycle方法。由于这10个连接应该是500s之前从Druid连接池借出的,所以它们的connectTimeMillis也是500s之前的时间,即物理连接时间肯定小于8小时,可以成功回收到Druid连接池中,同时lastActiveTimeMillis也更新为当前时间,放在connections数组的末尾。

  与此同时,Atomikos还需要重新生成10个新的连接,即从Druid连接池获取10个连接,调用getConnection方法,这时会进行有效性的检查,又因为lastActiveTimeMillis基本上为当前时间,所以idleMillis肯定比30s小,不需要进行select 1的连接数据库操作,这样即使该连接已经失效了还是会借出给Atomikos。每隔500s不断循环上述操作,并且期间没有用户的操作,一旦超过8个小时的mysql连接时间,Atomikos在使用数据库连接时就会产生上述日志中的错误了。

springboot+atomikos+druid数据库连接失效的原因是什么

以上就是“springboot+atomikos+druid数据库连接失效的原因是什么”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网精选频道。

--结束END--

本文标题: springboot+atomikos+druid数据库连接失效的原因是什么

本文链接: https://www.lsjlt.com/news/322034.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • springboot+atomikos+druid数据库连接失效的原因是什么
    今天小编给大家分享一下springboot+atomikos+druid数据库连接失效的原因是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我...
    99+
    2023-06-29
  • 详解springboot+atomikos+druid 数据库连接失效分析
    目录一、起因二、Druid数据库连接池三、Atomikos框架四、分析与总结一、起因   最近查看系统的后台日志,经常发现这样的报错信息:The last package succe...
    99+
    2022-11-13
  • springboot druid数据库连接池连接失败后一直重连怎么解决
    这篇文章主要介绍了springboot druid数据库连接池连接失败后一直重连怎么解决的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇springboot druid数据库连接池连接失败后一...
    99+
    2023-06-30
  • 数据库连接失败的原因有哪些
    这篇文章将为大家详细讲解有关数据库连接失败的原因有哪些,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。数据库连接失败的原因及解决方法:1、登录账号、密码、服务器名称、数据库名称登录错误,应输入正确;2、没能...
    99+
    2023-06-13
  • powerdesigner连接数据库报错是什么原因
    本篇内容主要讲解“powerdesigner连接数据库报错是什么原因”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“powerdesigner连接数据库报错是什么...
    99+
    2022-10-18
  • oracle数据库连接失败的原因有哪些
    1. 数据库服务未启动或未正确配置。需要确保数据库服务已经启动,并且监听程序正确配置。2. 数据库连接参数错误。需要确保连接字符串中...
    99+
    2023-08-23
    oracle数据库
  • 连接服务器失败的原因是什么
    连接服务器失败是与服务器建立连接时不成功导致的。解决办法有:1、检查网络连接,确保计算机与服务器连接正常;2、检查服务器状态,确保处于开机状态并网络服务正常运行;3、检查防火墙和配置设置问题,尝试暂时禁用防火墙来测试是否可以成功连接服务器;...
    99+
    2023-08-08
  • mongodb远程连接失败的原因是什么
    mongodb远程连接失败的原因有:原因一、27017端口未开启,使用netstat命令开启27017端口;原因二、mongodb未开启远程连接权限,修改mongodb.conf配置文件;具体方法如下:原因一:服务器27017端口未开启,导...
    99+
    2022-10-17
  • 电脑丢失网络连接的原因是什么
    这篇文章主要介绍“电脑丢失网络连接的原因是什么”,在日常操作中,相信很多人在电脑丢失网络连接的原因是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”电脑丢失网络连接的原因是...
    99+
    2023-03-13
    电脑
  • php连接mysql失败的主要原因是什么
    本篇内容主要讲解“php连接mysql失败的主要原因是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“php连接mysql失败的主要原因是什么”吧!MySQL服务器无法访问首先,我们需要检查M...
    99+
    2023-07-05
  • linux中链接库失败的原因是什么
    这篇文章将为大家详细讲解有关linux中链接库失败的原因是什么,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。我遇到过几种情况:路径添加失败。在makefile中,我添加了库的路径,不管是绝对路径还是相对路...
    99+
    2023-06-12
  • SQL Server数据库复制失败的原因是什么
    SQL Server数据库复制失败的原因是什么,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。原因:在复制数据库时,必须先停止mssqlse...
    99+
    2022-10-18
  • SQL数据库连接不上的原因及解决方法是什么
    SQL数据库连接不上的原因及解决方法可能有以下几种:1. 数据库服务未启动或停止:查看数据库服务是否已启动,如果未启动,需要启动数据...
    99+
    2023-09-22
    SQL数据库
  • 连接云服务器失败是什么原因导致的
    如果您的云服务器连接到云平台时发生了失败,通常会出现以下几种原因: 网络连接问题:云平台会通过各种网络接口和连接方式连接用户的云服务器,当连接问题导致云服务器无法正确识别您的云平台时,就会出现连接失败的情况。 配置错误:在云平台上启用了...
    99+
    2023-10-27
    服务器
  • 连接云服务器失败是什么原因造成的
    如果您的云服务器连接到云平台时发生了失败,通常会出现以下几种原因: 网络连接问题:云平台通常采用多跳连接模式,连接服务器的计算机需要连接到另一个云平台上才能完成计算任务。这个问题可能是由于网络连接问题导致的。 数据库连接问题:如果您的应...
    99+
    2023-10-27
    服务器
  • php连接数据库注册和登录失败的原因有哪些
    今天小编给大家分享一下php连接数据库注册和登录失败的原因有哪些的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。PHP连接数据...
    99+
    2023-07-05
  • php总是连接数据库不成功的原因是什么及怎么解决
    这篇文章主要介绍“php总是连接数据库不成功的原因是什么及怎么解决”,在日常操作中,相信很多人在php总是连接数据库不成功的原因是什么及怎么解决问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”php总是连接数据...
    99+
    2023-07-05
  • 连接云服务器失败是什么原因造成的呢
    网络连接问题:当你尝试连接云服务器时,网络连接可能会出现问题,例如网络延迟、丢包、网络堵塞等。此外,如果你使用的是HTTP/HTTPS协议,那么连接失败可能会导致服务器无法正确解析你的请求。 服务器配置问题:云服务器的配置可能会影响连接成...
    99+
    2023-10-27
    服务器
  • php连接mysql失败的原因是什么及如何解决
    这篇“php连接mysql失败的原因是什么及如何解决”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“php连接mysql失败的...
    99+
    2023-07-05
  • idea连接mysql失败的原因及解决方法是什么
    连接MySQL失败的原因及解决方法有很多种,以下是一些常见的原因和解决方法:1. 错误的主机名或IP地址:检查主机名或IP地址是否正...
    99+
    2023-08-19
    idea mysql
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作