Druid连接池经常性断链问题

news2024/11/24 16:27:35

前段时间有应用使用Druid连接池经常的提示断链报错,整个问题排查分析过程很有意思。这里将Druid连接池、数据库层以及负载均衡层的配置分析下,记录整个问题的分析过程,同时梳理下Druid连接池的配置和连接保活及回收机制。

1、问题背景

应用通过数据库连接池申请连接,再通过负载均衡连接到数据库代理然后访问数据库,这是一个典型的架构,如下图所示:

但是系统上线后应用总是出现偶发性的断链报错,经常性的出现以下错误信息:

discard connection
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
The last packet successfully received from the server was 72,557 milliseconds ago. The last packet sent successfully to the server was 0 milliseconds ago.

根据错误日志初步判断肯定是与 DB之间的链接已经断开,尝试使用了一个已经断开的链接才会引起这个错误发生,但是根据Druid的连接检查功能,不应出现这样的问题。接下去了解下Druid连接池的基本配置以及连接保活和回收机制。

2、Druid连接池

2.1 Druid连接概览

Druid是开源的数据库连接池,它结合了C3P0、DBCP、Proxool等DB池的优点,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况。

  1. 在druidDataSource中有一个重入锁和衍生的两个condition:一个监控连接池是否为空,一个监控连接池不为空。
  2. 在druidDataSource中有两个线程,一个生成连接CreateConnectionThread,一个回收连接DestoryConnectionThread。在创建、获取、回收的时候都会使用这些锁和condition。
  3. 每次获取Connection都会调用init,内部使用inited标识DataSource是否已经初始化OK。
  4. 每次获取Connection都会需要进行加锁保证线程安全,所有操作都在加锁后执行。
  5. 如果连接池内没有连接了,则调用empty.signal(),通知CreateThread创建连接,并且等待指定的时间,被唤醒之后再去查看是否有可用连接。

2.2 Druid参数配置说明


1)基本属性
  • name:配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。如果没有配置,将会生成一个名字,格式是:“DataSource-” + System.identityHashCode(this).
  • url:连接数据库的url,不同数据库不一样。例如:mysql : jdbc:mysql://10.20.153.104:3306/druid2、oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto
  • username:连接数据库的用户名
  • password:连接数据库的密码
  • driverClassName:这一项可配可不配,如果不配置druid会根据url自动识别dbType,然后选择相应的driverClassName

2)连接池大小
  • initialSize:初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时。缺省值为0
  • maxActive:最大连接池数量。缺省值为8
  • minIdle:最小连接池数量。缺省值为0
  • maxWait:获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。缺省值为-1
3)连接检测
  • testOnBorrow:申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。缺省值为true
  • testOnReturn:归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。缺省值为false
  • testWhileIdle:建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。缺省值为false
  • timeBetweenEvictionRunsMillis:有两个含义:1) Destroy线程会检测连接的间隔时间,如果连接空闲时间大于等于minEvictableIdleTimeMillis则关闭物理连接。2) testWhileIdle的判断依据。缺省值为60s
  • maxEvictableIdleTimeMillis:连接空闲时间大于该值,不管minidle是多少都关闭这个连接。缺省值为7小时
  • minEvictableIdleTimeMillis:连接空闲时间大于该值并且池中空闲连接数大于minidle则关闭这个连接。缺省值为30分钟
  • maxPoolPreparedStatementPerConnectionSize:要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100。缺省值为-1
  • PhyTimeoutMillis:物理连接打开的时间超过这个超时时间,并且不再使用时会关闭这个物理连接,一般不建议打开
  • validationQuery:用来检测连接是否有效的sql,要求是一个查询语句,常用select ‘x’。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。缺省值为null
  • validationQueryTimeout:单位:秒,检测连接是否有效的超时时间。底层调用jdbc Statement对象的void setQueryTimeout(int seconds)方法。缺省值为-1
  • keepAlive:连接池中的minIdle数量以内的连接,并且连接的空闲时间大于keepAliveBetweenTimeMillis但小于minEvictableIdleTimeMillis,则会执行validationQuery来保持连接的有效性。缺省值为false
  • keepAliveBetweenTimeMillis:打开KeepAlive时,当连接的空闲时间超过该值,会使用validationQuery执行一次查询,检查连接是否可用。缺省值为120s
4)缓存语句
  • poolPreparedStatements:是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。缺省值为false
  • sharePrepareStatements
  • maxPoolPreparedStatementPerConnectionSize:要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100。缺省值为-1

2.3 Druid连接池使用

使用druid连接池,主要是使用DruidDataSourceFactory创建出DataSource数据源对象,然后调用其getConnection方法获取数据库连接对象,拿到连接对象之后,和其它数据库连接不同的是当调用连接的close方法时,底层不再是关闭销毁连接对象,而是将连接对象放入到连接池中,以便后续新的请求到来时,直接拿去使用。

import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;
public class druidtest {
public static void main(String[] args) throws Exception {
//加载配置文件
        InputStream is = druidtest.class.getClassLoader().getResourceAsStream("druid.properties");
        Properties prop = new Properties();
        prop.load(is);
//根据配置文件内容,创建出数据源对象
        DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//通过数据源对象获取数据库连接
        //如果连接池中的连接已经被用完,则会等待一定的时间(所配置的时间)
        //如果等待超时,就会抛出异常
        Connection con = dataSource.getConnection();
//执行 sql 语句,获取并打印结果集
        String sql = "select e_id,e_name,e_age from employee";
        PreparedStatement pst = con.prepareStatement(sql);
        ResultSet rs = pst.executeQuery();
        while(rs.next()) {
            System.out.println(
                    rs.getInt("e_id") + "\t" +
                    rs.getString("e_name") + "\t" +
                    rs.getInt("e_age"));
        }
//释放资源
        rs.close();
        pst.close();
//这里的关闭连接,并没有关闭和销毁连接而是把连接对象,放入到连接池中,供后续访问时直接拿去使用
        con.close();
}
}

注意其中的con.close(),这里的关闭连接,并没有关闭和销毁连接而是把连接对象,放入到连接池中,供后续访问时直接拿去使用。

2.4 连接保活和回收机制

2.4.1 连接保活

为了防止一个数据库连接太久没有使用,而被其它下层的服务关闭,druid中定义了KeepAlive选项,机制上与TCP中的类似。保活机制能够保证连接池中的连接是真实有效的连接,假如遇到特殊情况导致连接不可用时,keepAlive机制将无效连接进行驱逐。保活机制是由守护线程DestroyConnectionThread发起的,启动后守护线程会进入无线循环,根据心跳间隔时间timeBetweenEvictionRunsMillis循环调用DestoryTask线程,默认时间为60s。

1)开启KeepAlive

// 一个连接在连接池中最小生存的时间
dataSurce.setMinEvictableIdleTimeMillis(60 * 1000);单位毫秒
// 开启keepAlive
dataSource.setKeepAlive(true);

2)DruidDataSource中的两个成员变量

// 存放检查需要抛弃的连接
private DruidConnectionHolder[] evictConnections;
// 用来存放需要连接检查的存活连接
private DruidConnectionHolder[] keepAliveConnections;

如果KeepAlive打开,当一个连接的空闲时间超过keepAliveBetweenTimeMillis时,则会将此连接放入此连接放入keepAliveConnections数组,然后使用validationQuery执行一次查询。

if (keepAlive && idleMillis >= keepAliveBetweenTimeMillis) {
                        keepAliveConnections[keepAliveCount++] = connection;
}
…
if (keepAliveCount > 0) {
     // keep order
     for (int i = keepAliveCount - 1; i >= 0; --i) {
                DruidConnectionHolder holer = keepAliveConnections[i];
                Connection connection = holer.getConnection();
                holer.incrementKeepAliveCheckCount();

                boolean validate = false;
                try {
                    this.validateConnection(connection);
                    validate = true;
                } catch (Throwable error) {
                    if (LOG.isDebugEnabled()) {
                        LOG.debug("keepAliveErr", error);
                    }
                    // skip
                }

如果本次validationQuery执行失败,则关闭该链接,并丢弃。

2.4.2 数据源收缩

在Druid数据源初始化的时候,会创建一个定时运行的DestroyTask,该任务的主要目的是将已空闲时间满足关闭条件的连接关闭。

1)当前连接存活时长 > 配置的物理连接时间时长,则放入evictConnections

if (phyConnectTimeMillis > phyTimeoutMillis) {
    evictConnections[evictCount++] = connection;
    continue;
}

2)空闲时间 > 最小驱逐时间

                    if (idleMillis >= minEvictableIdleTimeMillis) {
                        if (checkTime && i < checkCount) {
                            evictConnections[evictCount++] = connection;
                            continue;
                        } else if (idleMillis > maxEvictableIdleTimeMillis) {
                            evictConnections[evictCount++] = connection;
                            continue;
                        }
                    }
…
        if (evictCount > 0) {
            for (int i = 0; i < evictCount; ++i) {
                DruidConnectionHolder item = evictConnections[i];
                Connection connection = item.getConnection();
                JdbcUtils.close(connection);
                destroyCountUpdater.incrementAndGet(this);
            }
            Arrays.fill(evictConnections, null);
        }

           
从代码逻辑中可以看到,对于要关闭的空闲连接选择逻辑如下:

  • 对于空闲时间> minEvictableIdleTimeMillis的连接,仅会关闭poolingCount-minIdle个,后面的连接不受影响;
  • 处于> maxEvictableIdleTimeMillis的空闲连接则会直接关闭;
  • timeBetweenEvictionRunsMillis即为该定时任务运行的间隔;
  • minEvictableIdleTimeMillis为可关闭连接的最小空闲时间

2.5 Druid连接生命周期

Druid连接的生命周期从两个维度去看:一个是应用使用方,包括连接的申请、使用和关闭;一个是Druid自己管理的连接池,包括连接的创建和回收、保活机制等。具体如下所示:

1)客户端连接管理
  • 客户端发起连接请求从Druid连接池申请连接,如果连接池内连接不够会调用CreateThread创建连接;
  • 客户端拿到连接后,访问数据库进行操作;
  • 连接操作完成后,释放数据库资源并close连接,这一步通常是由应用主动去做的,连接关闭后会回收,归还给Druid连接池。
2)Druid连接池管理
  • Druid连接池设置最小连接数minIdle和最大连接数maxActive,最小连接数支持预热功能,应用每次申请连接的时候不需要重新初始化,高并发下可以提升性能;
  • 连接池会定时进行连接保活,KeepAlive的周期由timeBetweenEvictionRunsMillis控制(默认值60s),当发现连接的空闲时长超过keepAliveBetweenTimeMillis(默认值120s)时,会主动发起链路保活,一般是向数据库发起SQL查询,这个SQL语句可以自定义,通常为“select 1 from dual”
  • 为了防止连接泄露,会定时回收空闲的连接,对于连接空闲时间大于minEvictableIdleTimeMillis(默认为30分钟)并且连接池中空闲连接数大于minIdle则关闭这个连接;如果连接空闲时间大于maxEvictableIdleTimeMillis(默认值为7小时)则直接关闭连接
  • 从上可以看出,如果没有连接保活,当设置minIdle后会有一部分在最小连接内的连接因为空闲连接超时被关闭;当然如果设置了KeepAlive并且当保活的检测频率和keepAliveBetweenTimeMillis小于minEvictableIdleTimeMillis时,就不会出现空闲连接被关闭的情况。

3、问题分析

回到应用断链的问题,基于Druid连接池的设置和应用访问数据库整个链路的超时设置,以MySQL数据库为例,可以得到下面配置:

3.1 应用JDBC的url连接配置

JDBC的url连接配置中connectTimeout和socketTimeout都属于TCP层面的超时

  • connectTimeout:表示的是数据库驱动与数据库服务器建立TCP连接的超时时间。超时以后可能会出现以下异常信息
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    ...
Caused by: java.net.SocketTimeoutException: connect timed out
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
    ...
  • socketTimeout:通过TCP连接发送数据后,等待响应的超时时间。通常是在sql的执行时间超过了socket timeout设置的情况下出现。超时以后会出现类似的报错信息:
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
The last packet successfully received from the server was 3,080 milliseconds ago.  The last packet sent successfully to the server was 3,005 milliseconds ago.
    ...
Caused by: java.net.SocketTimeoutException: Read timed out
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)

3.2 数据库层超时设置

以MySQL为例,在数据库层设置空闲连接的超时参数wait_timeout,默认为7小时,超过后会自动断开空闲连接。在实际过程中,应用通过负载均衡或者Druid连接到数据库,如果负载均衡没有开启会话保持或者Druid没有连接保活机制,客户端的连接空闲时间超过7小时后,会在数据库层主动杀掉。但是既然已经使用了Druid连接池,那么应用端的数据库连接就可以由Druid进行很好的管理。

3.3 Druid连接配置

从应用断链报错信息来看,不是超过7小时断开,而是300s左右,所以排除了数据库层主动断链的问题。再来分析下Druid端的配置,和连接有关的参数如下:

datasource.druid.validationQuery=SELECT 1 from dual
datasource.druid.validationQueryTimeout=2000
datasource.druid.testWhileIdle=true
datasource.druid.minIdle=50
datasource.druid.maxActive=100
datasource.druid.minEvictableIdleTimeMillis=300000
datasource.druid.timeBetweenEvictionRunsMillis=600000
datasource.druid.keepAlive=true
datasource.druid.keepAliveBetweenTimeMillis=300s
  1. Druid的KeepAlive开关是打开的,连接保活的机制是生效的。默认情况下druid采用的是mysql.ping协议进行检查,使用检查语句“SELECT 1 from dual”同样更新session的闲置时间,这里不存在问题
  2. Druid的链路保活检测周期是timeBetweenEvictionRunsMillis为600s,默认值为60s,应用考虑到性能调整了检测周期。如果空闲连接超过600s,满足检测周期是可以重新进行保活的,但是如果连接空闲时间小于600s而被close掉,那就不是Druid这边导致的,也就是该问题中300s左右链路断开了。

3.4 负载均衡的会话保持配置

有一点很容易忽略的就是负载均衡的会话保持,会话保持是指在负载均衡器上有一种机制,在作负载均衡的同时,还保证同一用户相关连的访问请求会被分配到同一台服务器上。会话保持是有时间限制的,以F5为例默认为5分钟,也就是检测到连接空闲超过5分钟,会主动将它断开。这里似乎找到了问题点了,Druid连接池的保活是10分钟而负载均衡这边的空闲连接检测是5分钟,当有连接的空闲时间超过5分钟但是小于10分钟后,会被负载均衡这边杀掉,应用在使用这个连接的时候当然会报断链的错误了。最后是调整了负载均衡的会话保持的检测时间,以规避类似的问题。

4、总结

应用在使用Druid连接池访问数据库的时候,需要根据业务TPS和并发调整合适的配置,以利用Druid连接池的实现对连接的创建、保活和释放管理。当遇到类似断链的问题的时候,要从端到端的每个点进行排查分析,以定位到最终的原因,比如这次的负载均衡的配置是很难想到的。应用从Druid申请了连接后,这个连接已经超出Druid的管理范围,需要由应用自己去做处理,及时的close归还到连接池里,否则的话数据库端的连接会越来越多,而且空闲连接超过一定时间后也会被数据库层或者负载均衡层断掉进而出现断链的错误,这个就需要应用做额外的处理了。

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

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

相关文章

【图文详解】Maven Helper插件解决Maven冲突

文章目录 插件问题解决过程 在面试中解决问题的能力和思路是考察的重点&#xff0c;面试官问会问我们有没有解决过maven冲突。以下造了一个maven冲突&#xff0c;手把手教学如何解决Maven冲突。 插件 插件在idea插件中搜索Maven Helper 问题 解决过程 根据上面日志知道是log…

基于SWOT的智能手机企业财务战略研究1.62

摘 要 近些年&#xff0c;网络技术日新月异&#xff0c;智能手机深受消费者喜爱&#xff0c;人们通过网络&#xff0c;手机应用&#xff0c;可以极大地方便人们学习&#xff0c;工作等等。由于国家对电信行业的大力支持&#xff0c;中国消费者群体逐步成为最具潜力的手机购买者…

【Emgu CV教程】9.3、形态学常用操作之开运算

文章目录 一、相关概念1.什么叫开运算3.开运算的函数 二、演示1.原始素材2.代码3.运行结果 一、相关概念 1.什么叫开运算 腐蚀、膨胀已经讲完&#xff0c;这两个是最基础的形态学操作。这次讲的是开运算&#xff0c;它是一个先腐蚀、后膨胀的过程。原始图像先被腐蚀&#xff…

对GIS与游戏引擎(UE4 或 U3D)结合的看法

GIS与游戏引擎结合&#xff0c;这在6年前就已经很多公司在进行探索了&#xff0c;经过这几年的发展&#xff0c;结合当前的政策&#xff0c;从以下几方面说一下我的看法&#xff1a; 1.GIS客户都是特殊单位及领域。2018年后&#xff0c;国内已经对国产化有明确要求了&#xff0…

Spring中使用自带@Autowired注解实现策略模式

场景 SpringBoot中策略模式工厂模式业务实例(接口传参-枚举类查询策略映射关系-执行不同策略)规避大量if-else&#xff1a; SpringBoot中策略模式工厂模式业务实例(接口传参-枚举类查询策略映射关系-执行不同策略)规避大量if-else_springboot编写策略工厂-CSDN博客 设计模式…

BUUCTF-----[SWPU2019]Web1

打开页面&#xff0c;原本以为是二次注入,结果不是&#xff0c;先注册一个账户 在申请发布广告中&#xff0c;发现反射性xss(然而没有什么用) 在广告申请名字中发现注入点 开始注入 通过一系列的测试&#xff0c;发现系统过滤了#&#xff0c;or&#xff0c;空格 orde…

【C++庖丁解牛】vector容器的简易模拟实现(C++实现)(最后附源码)

&#x1f341;你好&#xff0c;我是 RO-BERRY &#x1f4d7; 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f384;感谢你的陪伴与支持 &#xff0c;故事既有了开头&#xff0c;就要画上一个完美的句号&#xff0c;让我们一起加油 目录 前言vector容器代码实现内…

xss.haozi.me靶场“0x0B-0x12”通关教程

君衍. 一、0x0B 实体编码绕过二、0x0C script绕过三、0x0D 注释绕过四、0X0E ſ符号绕过五、0x0F 编码解码六、0x10 直接执行七、0x11 闭合绕过八、0x12 闭合绕过 一、0x0B 实体编码绕过 我们首先构造payload进行测试&#xff1a; 这里我们可以看到全部转为了大写&#xff0c…

低压线性恒流LED恒流驱动芯片SM15633EH:用于洗墙灯和线条灯

洗墙灯和线条灯是两种常见的LED照明产品&#xff0c;它们都需要使用LED恒流驱动芯片来确保稳定、可靠的电流供应&#xff0c;从而保证LED的使用寿命和亮度。 对于洗墙灯而言&#xff0c;由于其发出的光线需要覆盖较大的区域&#xff0c;因此需要使用较大功率的LED芯片&#xf…

rust入门(1)创建项目

安装 vscode 安装插件 rust-analyzerNative Debug vscode 配置自动格式化代码 settings.json{"editor.defaultFoldingRangeProvider": null,"[rust]": {"editor.defaultFormatter": "rust-lang.rust-analyzer", // Makes the magi…

mysql5.6---windows和linux安装教程和忘记密码怎么办

一、windows安装 1.完成解压 解压完成之后将其放到你喜欢的地址当中去&#xff0c;这里我默认放在了D盘&#xff0c;这是我的根目录 2.配置环境变量 我的电脑->属性->高级->环境变量->系统变量 选择PATH,在其后面添加: (注意自己的安装地址) D:\mysql-5.6.49…

在域控批量导出用户及其所在路径的信息

在Windows Server的Active Directory环境中&#xff0c;要批量导出用户及其所在OU&#xff08;组织单位&#xff09;的信息&#xff0c;可以使用PowerShell命令来实现。以下是一个简单的示例&#xff1a; Get-ADUser -Filter * -Properties CanonicalName | Select-Object Nam…

CCCorelib 点云球形特征(CloudCompare内置算法库)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 这里基于每个点的邻域协方差来获取点云中具有的球形几何特征的点,计算方式如下图所示: 二、实现代码 // CloudCompare #include <CCCoreLib/PointCloudTpl.h> #include <CCCoreLib/

数据库基础理论知识

1.基本概念 数据(Data)&#xff1a;数据库存储的基本对象。数字、字符串、图形、图像、音频、视频等数据库(DB)&#xff1a;在计算机内&#xff0c;永久存储、有组织、可共享的数据集合数据库管理系统(DBMS)&#xff1a;管理数据库的系统软件数据库系统(DBS):DBDBMSDBADBAP 数…

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《考虑碳捕集机组与氢储能系统协调运行的源荷储低碳经济调度》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

机器人ChatGPT来了,80亿参数、前OpenAI人员经数年打造

严格地说&#xff0c;是“拾取与放置任务”版本的ChatGPT来了。除了自然语言交流&#xff0c;还能像Sora一样生成视频。 有了机器人基础模型RFM-1&#xff0c;使用简单英语就能指导机器人完成拣选工作。 机器人 AI 公司 Covariant CEO Peter Chen ‍坐在一个聊天机器人面前&…

图像分割损失函数

为什么要乘以2&#xff0c;是为了让DICE的值域在0和1之间 优化&#xff1a;两种LOSS相加 Focus loss:

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的田间杂草检测系统(深度学习模型+UI界面+Python代码+训练数据集)

摘要&#xff1a;开发用于田间杂草识别的系统对提高农业运营效率和提升作物产出至关重要。本篇文章详尽阐述了如何应用深度学习技术开发一个用于田间杂草识别的系统&#xff0c;并附上了完备的代码实现。该系统基于先进的YOLOv8算法&#xff0c;并对比了YOLOv7、YOLOv6、YOLOv5…

提前爆料:绝地求生七周年预告片餐厅改版,七周年主题战术手套

七周年预告片刚刚在官博上线&#xff0c;让我们一起逐帧分析一下都有哪些皮肤吧。 开局就是一个七周年喷漆 然后出生岛手里会拿着七周年的蛋糕&#xff0c;互相丢。 艾伦格的餐厅们进行改版&#xff0c;成为七周年主题 餐厅内有一个七周年的饮料机&#xff0c;不知道是不是和米…

浅淡 C++ 与 C++ 入门

我们知道&#xff0c;C语言是结构化和模块化的语言&#xff0c;适用于较小规模的程序。而当解决复杂问题&#xff0c;需要高度抽象和建模时&#xff0c;C语言则不合适&#xff0c;而C正是在C的基础之上&#xff0c;容纳进去了面向对象编程思想&#xff0c;并增加了许多有用的库…