MySQL数据库连接池泄露导致MySQL Server超时关闭连接

news2025/2/26 8:08:06

前言

最近做项目,发现老项目出现xxx,这个错误其实很简单,出现在MySQL数据库Server端对长时间没有使用的client连接执行清楚处理,因为是druid数据库,且在github也出现这样的issue:The last packet successfully received from the server was 6,011 milliseconds ago. The last packet sent successfully to the server was 6,011 milliseconds ago.,所以怀疑是不是druid配置的问题,毕竟连接池会定时的检查连接,但是实际排查发现不是那么回事,是连接池泄露了,只不过并发不大,表现为{conn-10002} discard错误而已。

准备

按照笔者上次的文章mybatis plus相同Id与xml配置错误时,mybatis plus解决逻辑_mybatis plus xml文件查询id名字相同-CSDN博客

准备数据库,且通过开启root权限 

demo

demo简单写一下,实际项目肯定复杂很多

   <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.7.17</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.22</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
            <version>2.7.17</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.3.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
        </dependency>
    </dependencies>

写一个main controller dao

@SpringBootApplication
@MapperScan("org.example.druid.demo.dao")
public class DruidMain {
    public static void main(String[] args) {
        SpringApplication.run(DruidMain.class, args);
    }
}

@RestController
public class DemoController {

    @Autowired
    private UserDao userDao;

    @RequestMapping(value = "/demo", method = RequestMethod.GET)
    public String demo(){
        int num = userDao.updateUser();
        return "{\"update\" : " + num + "}";
    }
}

@Mapper
public interface UserDao {

    @Update("update User set age = 30 where id = 1")
    int updateUser();
}

配置文件

spring.datasource.druid.url= jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.druid.username= root
spring.datasource.druid.password= 123456i
spring.datasource.druid.driver-class-name= com.mysql.cj.jdbc.Driver
spring.datasource.druid.initialSize=2
spring.datasource.druid.minIdle=2
spring.datasource.druid.maxActive=2
spring.datasource.druid.maxWait=20000
spring.datasource.druid.timeBetweenEvictionRunsMillis=1000
spring.datasource.druid.minEvictableIdleTimeMillis=30000
spring.datasource.druid.validationQuery=SELECT 1
spring.datasource.druid.validationQueryTimeout=1
spring.datasource.druid.testOnBorrow=false
spring.datasource.druid.testOnReturn=false
spring.datasource.druid.testWhileIdle=true
spring.datasource.druid.keepAlive=true
spring.datasource.druid.socketTimeout=6000
spring.datasource.druid.poolPreparedStatements=true

访问 http://localhost:8080/demo

这一步实际上没什么问题,但是如果涉及编程式事务,那么可能出现代码逻辑漏洞

@Configuration
public class DemoConfiguration {

    @Bean
    public PlatformTransactionManager initPlatformTransactionManager(DruidDataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

@RestController
public class DemoController {

    @Autowired
    private UserDao userDao;

    @Autowired
    private PlatformTransactionManager transactionManager;

    @RequestMapping(value = "/demo", method = RequestMethod.GET)
    public String demo(){
        TransactionStatus transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());
        int num = 0;
        try {
            num = userDao.updateUser();
            transactionManager.commit(transactionStatus);
        } catch (TransactionException e) {
            transactionManager.rollback(transactionStatus);
        }
        return "{\"update\" : " + num + "}";
    }
}

这样写也没问题,但是,如果我们在事务拿到后,因为一些逻辑return呢

 设置MySQL的超时时间

通过临时设置或者永久设置,--来自bing AI搜索

比如我们临时设置1分钟试试,问题复现

表现为{conn-10002} discard

2025-02-25 21:52:26.692 DEBUG 2129 --- [nio-8080-exec-1] c.a.druid.pool.PreparedStatementPool     : {conn-10002, pstmt-20000} exit cache
2025-02-25 21:52:26.695 DEBUG 2129 --- [nio-8080-exec-1] com.alibaba.druid.util.JdbcUtils         : close connection error

排查过程

The last packet successfully received from the server was 6,006 milliseconds ago. The last packet sent successfully to the server was 6,006 milliseconds ago.

2025-02-25 21:52:26.690 ERROR 2129 --- [nio-8080-exec-1] druid.sql.Statement                      : {conn-10002, pstmt-20002} execute error. select * from User

com.mysql.cj.jdbc.exceptions.CommunicationsException: The last packet successfully received from the server was 183,457 milliseconds ago. The last packet sent successfully to the server was 183,458 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.
	at com.mysql.cj.jdbc.exceptions.SQLError.createCommunicationsException(SQLError.java:175) ~[mysql-connector-j-8.0.33.jar:8.0.33]
	at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:64) ~[mysql-connector-j-8.0.33.jar:8.0.33]
	at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:916) ~[mysql-connector-j-8.0.33.jar:8.0.33]
	at com.mysql.cj.jdbc.ClientPreparedStatement.execute(ClientPreparedStatement.java:354) ~[mysql-connector-j-8.0.33.jar:8.0.33]
	at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_execute(FilterChainImpl.java:3462) [druid-1.2.22.jar:na]
	at com.alibaba.druid.filter.FilterEventAdapter.preparedStatement_execute(FilterEventAdapter.java:434) [druid-1.2.22.jar:na]
	at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_execute(FilterChainImpl.java:3460) [druid-1.2.22.jar:na]
	at com.alibaba.druid.wall.WallFilter.preparedStatement_execute(WallFilter.java:686) [druid-1.2.22.jar:na]
	at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_execute(FilterChainImpl.java:3460) [druid-1.2.22.jar:na]
	at com.alibaba.druid.filter.FilterEventAdapter.preparedStatement_execute(FilterEventAdapter.java:434) [druid-1.2.22.jar:na]
	at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_execute(FilterChainImpl.java:3460) [druid-1.2.22.jar:na]
	at com.alibaba.druid.proxy.jdbc.PreparedStatementProxyImpl.execute(PreparedStatementProxyImpl.java:158) [druid-1.2.22.jar:na]
	at com.alibaba.druid.pool.DruidPooledPreparedStatement.execute(DruidPooledPreparedStatement.java:483) [druid-1.2.22.jar:na]
	at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65) [mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:80) [mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:65) [mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:336) [mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:158) [mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:110) [mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:90) [mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:154) [mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:147) [mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:142) [mybatis-3.5.14.jar:3.5.14]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_431]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_431]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_431]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_431]
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:425) [mybatis-spring-2.1.2.jar:2.1.2]
	at com.sun.proxy.$Proxy57.selectList(Unknown Source) [na:na]
	at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224) [mybatis-spring-2.1.2.jar:2.1.2]
	at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:147) [mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:80) [mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.binding.MapperProxy$PlainMethodInvoker.invoke(MapperProxy.java:141) [mybatis-3.5.14.jar:3.5.14]
	at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:86) [mybatis-3.5.14.jar:3.5.14]
	at com.sun.proxy.$Proxy61.selectUsers(Unknown Source) [na:na]
	at org.example.druid.demo.controller.DemoController.getUsers(DemoController.java:51) [classes/:na]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_431]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_431]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_431]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_431]
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) [spring-web-5.3.30.jar:5.3.30]
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) [spring-web-5.3.30.jar:5.3.30]
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) [spring-webmvc-5.3.30.jar:5.3.30]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) [spring-webmvc-5.3.30.jar:5.3.30]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) [spring-webmvc-5.3.30.jar:5.3.30]
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) [spring-webmvc-5.3.30.jar:5.3.30]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1072) [spring-webmvc-5.3.30.jar:5.3.30]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:965) [spring-webmvc-5.3.30.jar:5.3.30]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) [spring-webmvc-5.3.30.jar:5.3.30]
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) [spring-webmvc-5.3.30.jar:5.3.30]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:529) [tomcat-embed-core-9.0.82.jar:4.0.FR]
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) [spring-webmvc-5.3.30.jar:5.3.30]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:623) [tomcat-embed-core-9.0.82.jar:4.0.FR]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:209) [tomcat-embed-core-9.0.82.jar:9.0.82]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) [tomcat-embed-core-9.0.82.jar:9.0.82]
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) [tomcat-embed-websocket-9.0.82.jar:9.0.82]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) [tomcat-embed-core-9.0.82.jar:9.0.82]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) [tomcat-embed-core-9.0.82.jar:9.0.82]
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) [spring-web-5.3.30.jar:5.3.30]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) [spring-web-5.3.30.jar:5.3.30]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) [tomcat-embed-core-9.0.82.jar:9.0.82]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) [tomcat-embed-core-9.0.82.jar:9.0.82]
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) [spring-web-5.3.30.jar:5.3.30]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) [spring-web-5.3.30.jar:5.3.30]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) [tomcat-embed-core-9.0.82.jar:9.0.82]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) [tomcat-embed-core-9.0.82.jar:9.0.82]
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) [spring-web-5.3.30.jar:5.3.30]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) [spring-web-5.3.30.jar:5.3.30]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) [tomcat-embed-core-9.0.82.jar:9.0.82]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) [tomcat-embed-core-9.0.82.jar:9.0.82]
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:168) [tomcat-embed-core-9.0.82.jar:9.0.82]
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) [tomcat-embed-core-9.0.82.jar:9.0.82]
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:481) [tomcat-embed-core-9.0.82.jar:9.0.82]
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:130) [tomcat-embed-core-9.0.82.jar:9.0.82]
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) [tomcat-embed-core-9.0.82.jar:9.0.82]
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.82.jar:9.0.82]
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-9.0.82.jar:9.0.82]
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390) [tomcat-embed-core-9.0.82.jar:9.0.82]
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) [tomcat-embed-core-9.0.82.jar:9.0.82]
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:928) [tomcat-embed-core-9.0.82.jar:9.0.82]
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1794) [tomcat-embed-core-9.0.82.jar:9.0.82]
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) [tomcat-embed-core-9.0.82.jar:9.0.82]
	at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) [tomcat-embed-core-9.0.82.jar:9.0.82]
	at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) [tomcat-embed-core-9.0.82.jar:9.0.82]
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.82.jar:9.0.82]
	at java.lang.Thread.run(Thread.java:750) [na:1.8.0_431]
Caused by: com.mysql.cj.exceptions.CJCommunicationsException: The last packet successfully received from the server was 183,457 milliseconds ago. The last packet sent successfully to the server was 183,458 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_431]
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_431]
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_431]
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_431]
	at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:62) ~[mysql-connector-j-8.0.33.jar:8.0.33]
	at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:105) ~[mysql-connector-j-8.0.33.jar:8.0.33]
	at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:150) ~[mysql-connector-j-8.0.33.jar:8.0.33]
	at com.mysql.cj.exceptions.ExceptionFactory.createCommunicationsException(ExceptionFactory.java:166) ~[mysql-connector-j-8.0.33.jar:8.0.33]
	at com.mysql.cj.protocol.a.NativeProtocol.readMessage(NativeProtocol.java:582) ~[mysql-connector-j-8.0.33.jar:8.0.33]
	at com.mysql.cj.protocol.a.NativeProtocol.checkErrorMessage(NativeProtocol.java:762) ~[mysql-connector-j-8.0.33.jar:8.0.33]
	at com.mysql.cj.protocol.a.NativeProtocol.sendCommand(NativeProtocol.java:701) ~[mysql-connector-j-8.0.33.jar:8.0.33]
	at com.mysql.cj.protocol.a.NativeProtocol.sendQueryPacket(NativeProtocol.java:1052) ~[mysql-connector-j-8.0.33.jar:8.0.33]
	at com.mysql.cj.NativeSession.execSQL(NativeSession.java:657) ~[mysql-connector-j-8.0.33.jar:8.0.33]
	at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:893) ~[mysql-connector-j-8.0.33.jar:8.0.33]
	... 83 common frames omitted
Caused by: java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.
	at com.mysql.cj.protocol.FullReadInputStream.readFully(FullReadInputStream.java:67) ~[mysql-connector-j-8.0.33.jar:8.0.33]
	at com.mysql.cj.protocol.a.SimplePacketReader.readHeaderLocal(SimplePacketReader.java:81) ~[mysql-connector-j-8.0.33.jar:8.0.33]
	at com.mysql.cj.protocol.a.SimplePacketReader.readHeader(SimplePacketReader.java:63) ~[mysql-connector-j-8.0.33.jar:8.0.33]
	at com.mysql.cj.protocol.a.SimplePacketReader.readHeader(SimplePacketReader.java:45) ~[mysql-connector-j-8.0.33.jar:8.0.33]
	at com.mysql.cj.protocol.a.TimeTrackingPacketReader.readHeader(TimeTrackingPacketReader.java:52) ~[mysql-connector-j-8.0.33.jar:8.0.33]
	at com.mysql.cj.protocol.a.TimeTrackingPacketReader.readHeader(TimeTrackingPacketReader.java:41) ~[mysql-connector-j-8.0.33.jar:8.0.33]
	at com.mysql.cj.protocol.a.MultiPacketReader.readHeader(MultiPacketReader.java:54) ~[mysql-connector-j-8.0.33.jar:8.0.33]
	at com.mysql.cj.protocol.a.MultiPacketReader.readHeader(MultiPacketReader.java:44) ~[mysql-connector-j-8.0.33.jar:8.0.33]
	at com.mysql.cj.protocol.a.NativeProtocol.readMessage(NativeProtocol.java:576) ~[mysql-connector-j-8.0.33.jar:8.0.33]
	... 88 common frames omitted

这个问题在github也有类似的情况,但是不一定是笔者遇到的问题:https://github.com/alibaba/druid/issues/5963

 对于连接泄露可以配置泄露连接强制回收,但是这个仅在排查问题使用

removeAbandoned: true
removeAbandonedTimeoutMillis: 30000 #(以毫秒数为单位)
logAbandoned: true

貌似有用,但是实际情况是占用数据库连接的线程并不一定是问题的代码逻辑,我这里仅仅写了一个controller,刚好对应上

所以排查还需要另外的思路,下面演示解决A的锅B来背的案例。

解决方法

开启连接池连接的状态日志,这里以druid为例

com.alibaba.druid.filter.logging.LogFilter

既然查看连接情况,那么这个最关键 

spring.datasource.druid.filters=stat,wall,slf4j
logging.level.com.alibaba.druid=TRACE
#最关键的日志
logging.level.druid.sql.Connection=TRACE

当然笔者使用的MySQL版本8.0,这里是客户端缓存,MySQL8.0已经删除了查询缓存,而且这里是更新操作,毕竟查询缓存命中效率比较低,还是吞吐量比较重要,还增加了查询重写插件

以另一个不是事务的请求为例,用于验证问题

update的连接调用

等待1分钟,并发多次请求查询连接后就会报错

错误日志分析

错误的id为10002,从日志往上追溯

这里就是查询业务背了开始更新业务的锅,毕竟查询没有事务。事务代码BUG导致连接没被连接池回收 ,但被查询业务使用了连接,而且有时候可能和mysql Server的一些超时断掉连接的特性结合,那么问题就复杂了。

找到问题就好处理有问题的代码了,毕竟解决问题很简单,找到问题很难。

总结

我们在写代码时,尽量还是使用框架封装的逻辑,比如连接池,比如Spring声明式事务,可以避免编程式事务在写代码时的逻辑漏洞,因为在没触发的时候很难出现,测试很多时候不充分。实际上一起写jdbc的时候还很少出现这个问题,因为那个时候会非常注意连接的回收,事务的提交逻辑,但是Spring自动管理后,这个就很少注意了,因为注解声明式事务太方便了,只有特殊时候才会自己管理事务。

另外这个问题具备隐蔽性,因为报错是MySQL驱动连接MySQL Server报超时未使用关闭连接,但是此处示例的根源却是编程式事务导致连接池泄露,单个问题实际上可以头痛医头,但是当一些mysqlServer的特性加持下,就变成了头痛医脚的感觉了,解决问题很容易,发现问题很难。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2306246.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

力扣 下一个排列

交换位置&#xff0c;双指针&#xff0c;排序。 题目 下一个排列即在组成的排列中的下一个大的数&#xff0c;然后当这个排列为降序时即这个排列最大&#xff0c;因为大的数在前面&#xff0c;降序排列的下一个数即升序。所以&#xff0c;要是想找到当前排列的下一个排列&…

事务管理-03.事务进阶-propagation属性

一.工具 在介绍事务的propagation属性前&#xff0c;我们首先介绍一个工具&#xff1a;Grep Console&#xff0c;该工具用来实现将idea输出出的日志信息进行选择性的高亮展示。 当要选择日志中的某一部分高亮展示时&#xff0c;只需要右键点击Add Highlight即可。此时日志中所…

Pretraining Language Models with Text-Attributed Heterogeneous Graphs

Pretraining Language Models with Text-Attributed Heterogeneous Graphs EMNLP 推荐指数&#xff1a;#paper/⭐⭐#​ 贡献&#xff1a; 我们研究了在更复杂的数据结构上预训练LM的问题&#xff0c;即&#xff0c;TAHG。与大多数只能从每个节点的文本描述中学习的PLM不同&…

模型疑问图像、嵌入、推理类型与说明

在进行模型使用的时候,有时候会碰到模型存在模型类型需要选择的情况,如下面deepseek模型选择模型类型图像、嵌入、推理。 以下是针对此问题的了解与说明: DeepSeek 模型是一个多模态人工智能模型,能够同时处理图像和文本数据,并在多种任务中实现高效的嵌入表示和推理。以下…

WiFi IEEE 802.11协议精读:IEEE 802.11-2007,6,MAC service definition MAC服务定义

继续精读IEEE 802.11-2007 6&#xff0c;MAC service definition MAC服务定义 6.1 MAC服务概述 6.1.1 数据服务 此服务为对等逻辑链路控制&#xff08;LLC&#xff09;实体提供交换MAC服务数据单元&#xff08;MSDU&#xff09;的能力。为支持此服务&#xff0c;本地媒体访…

Visual Studio Code 跨平台安装与配置指南(附官方下载链接)

一、软件定位与核心功能 Visual Studio Code&#xff08;简称VS Code&#xff09;是微软开发的开源跨平台代码编辑器&#xff0c;支持超过50种编程语言的智能补全、调试和版本控制功能。2025版本新增AI辅助编程模块&#xff0c;可自动生成单元测试代码和API文档注释。 二、下载…

deepseek自动化代码生成

使用流程 效果第一步&#xff1a;注册生成各种大模型的API第二步&#xff1a;注册成功后生成API第三步&#xff1a;下载vscode在vscode中下载agent&#xff0c;这里推荐使用cline 第四步&#xff1a;安装完成后&#xff0c;设置模型信息第一步选择API provider&#xff1a; Ope…

OceanBase + DeepSeek:5分钟免费搭建企业知识库

过去一个月&#xff0c;DeepSeek 在全球范围内引发了热烈讨论。其突破性的 AI 能力使其日流量显著超越 Claude 和 Perplexity&#xff0c;吸引了众多企业和技术专家的高度关注。随着 AI 技术的不断进步&#xff0c;企业正面临一场深刻的智能化变革——如何通过 AI 重构业务&…

水利工程安全包括哪几个方面

水利工程安全培训的内容主要包括以下几个方面&#xff1a; 基础知识和技能培训 &#xff1a; 法律法规 &#xff1a;学习水利工程相关的安全生产法律法规&#xff0c;了解安全生产标准及规范。 事故案例 &#xff1a;通过分析事故案例&#xff0c;了解事故原因和教训&#x…

基于 sklearn 的均值偏移聚类算法的应用

基于 sklearn 的均值偏移聚类算法的应用 在机器学习和数据挖掘中&#xff0c;聚类算法是一类非常重要的无监督学习方法。它的目的是将数据集中的数据点划分为若干个类&#xff0c;使得同一类的样本点彼此相似&#xff0c;而不同类的样本点相互之间差异较大。均值偏移聚类&…

国产OS上完整编译Qt5.15、搭建基本开发环境需要的库

近期有师弟问我国产OS安装Qt5.15编译老是不完整&#xff0c;不是没声音&#xff0c;就是没视频&#xff0c;或者没有xcb。通过QEMU模拟Arm64&#xff0c;闲来20几天摸索&#xff0c;完整编译了Qt5.15&#xff0c;并编译成功了我的SDR玩具taskBus。 1.主要结论&#xff1a; 该O…

MyBatis简明教程

MyBatis 是一个用于简化数据库操作的持久层框架&#xff0c;它的核心思想是 将 SQL 与 Java 代码解耦&#xff0c;让开发者专注于 SQL 的编写&#xff0c;同时自动处理重复的数据库操作步骤。 一、核心思想&#xff1a;SQL 与 Java 解耦 传统 JDBC 需要开发者手动管理数据库连…

有什么区别?Elastic 和 Splunk 数据层

作者&#xff1a;来自 Elastic Ugo Sangiorgi, Matt Wehle 了解 Elastic 和 Splunk 数据管理方法之间的主要区别&#xff0c;以便做出明智的决策&#xff0c;实现高效的数据处理 在数据管理领域&#xff0c;在讨论如何根据不同的性能要求提供和/或保留数据时&#xff0c;经常会…

BGP状态和机制

BGP邻居优化 为了增加稳定性,通常建议实验回环口来建立邻居。更新源:建立邻居和邻居所学习到的路由的下一跳。多跳:EBGP邻居建立默认选哟直连,因为TTL=1,如果非直连,必须修改TTL。命令备注peer 2.2.2.2 connect-interface lo1配置更新源peer 2.2.2.2 ebgp-max-hop 2配置T…

【电机控制器】PY32F00BF15U6TR-从KEIL5中计算资源消耗资源

【电机控制器】PY32F00BF15U6TR-从KEIL5中计算资源消耗资源 文章目录 [TOC](文章目录) 前言一、MCU芯片手册二、实验三、实验结论四、参考资料总结 前言 使用工具&#xff1a; 1.KEIL5编译器 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、MCU芯片…

python实战项目58:采集蜻蜓FM热门音频top排行榜

python实战项目58:采集蜻蜓FM热门音频top排行榜 一、采集流程介绍二、数据接口采集三、使用xpath提取页面数据1、抓包,找到数据接口2、发送请求,获取数据3、提取数据4、保存数据一、采集流程介绍 蜻蜓FM热门音频top排行榜的链接为: https://m.qingting.fm/rank/,首页如下图…

STM32【3】芯片的底层组成概论

关于单片机的组成 单片机的意思是&#xff0c;小小计算电脑&#xff0c;麻雀虽小&#xff0c;五脏俱全&#xff0c;里面包含了CPU&#xff0c;ROM&#xff0c;RAM&#xff0c;各种外设。 CPU地位最高&#xff0c;可以访问ROM和RAM&#xff0c;Flash&#xff0c;GPIO等外设&…

基于django图书信息管理系统的搭建(增删改查)

✍django项目搭建教程 ☞ ----------------- 教程 本文主要讲解django如何连接数据库MySQL并且可视化展示&#xff0c;实现增删改查功能 目录 一. 创建django应用 二. 数据库配置 三. 查看数据库 四. 编写代码 4.1视图函数 4.2 配置URL 4.3创建模板文件 4.…

Kotlin 知识点二 延迟初始化和密封类

对变量延迟初始化 Kotlin 语言的许多特性&#xff0c;包括变量不可变&#xff0c;变量不可为空&#xff0c;等等。这些特性 都是为了尽可能地保证程序安全而设计的&#xff0c;但是有些时候这些特性也会在编码时给我们带来不 少的麻烦。 比如&#xff0c;如果你的类中存在很多…

基于SpringBoot的“古城景区管理系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“古城景区管理系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统整体功能图 系统首页界面 系统注册界面 景…