Druid介绍

Druid介绍

   Druid首先是一个数据库连接池,并且是目前最好的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池,包括DBCP、C3P0、BoneCP、Proxool、JBoss DataSource。但它不仅仅是一个数据库连接池,它还包含一个ProxyDriver,一系列内置的JDBC组件库,一个SQL Parser。

   Druid支持所有JDBC兼容的数据库,包括Oracle、MySQL、Derby、Postgresql、SQL Server、H2等等,并且Druid针对Oracle和MySql做了特别优化,比如Oracle的PS Cache内存占用优化,MySql的ping检测优化。

   通过Druid提供的监控功能,监控SQL的执行时间、ResultSet持有时间、返回行数、更新行数、错误次数、错误堆栈信息,可以清楚知道连接池和SQL的工作情况,能够详细统计SQL的执行性能,这对于线上分析数据库访问性能有帮助。

Druid配置

<dependency>  
  <groupId>com.alibaba</groupId>  
  <artifactId>druid</artifactId>  
  <version>1.0.20</version>  
</dependency>

   数据源的配置:

 <!-- 引入配置文件 -->    
 <bean id="mybatisPropertyConfigurer"    
 class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">    
 <property name="order" value="1" />    
 <property name="ignoreUnresolvablePlaceholders" value="true" />  
 <property name="locations">  
 <list>   
 <value>classpath:druid.properties</value>  
 </list>  
 </property>    
 </bean>    
      
 <!-- druid连接池配置 -->  
 <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">    
 <property name="url" value="${url}" />    
 <property name="username" value="${username}" />    
 <property name="password" value="${password}" />    
 <property name="filters" value="${filters}" />    
 <property name="maxActive" value="${maxActive}" />     
 <property name="initialSize" value="${initialSize}" />    
 <property name="maxWait" value="${maxWait}" />    
 <property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}" />  
 <property name="minEvictableIdleTimeMillis" value="${minEvictableIdleTimeMillis}" />  
 <property name="validationQuery" value="${validationQuery}" />    
 <property name="testWhileIdle" value="${testWhileIdle}" />    
 <property name="testOnBorrow" value="${testOnBorrow}" />    
 <property name="testOnReturn" value="${testOnReturn}" />    
 <property name="poolPreparedStatements" value="${poolPreparedStatements}" />    
 <property name="maxPoolPreparedStatementPerConnectionSize" value="${maxPoolPreparedStatementPerConnectionSize}" />  
</bean>

 druid.properties的内容:

 url=jdbc:mysql://localhost:3306/era  
 username=root  
 password=123456  
 #初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时   
 initialSize =1  
 #定义最大连接池数量    
 maxActive=20  
 #获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。  
 maxWait=60000  
 #是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。  
 #在mysql5.5以下的版本中没有PSCache功能,建议关闭掉。5.5及以上版本有PSCache,建议开启。   
 poolPreparedStatements=false  
 #要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。  
 #在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100  
 maxPoolPreparedStatementPerConnectionSize=100  
 #用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用。   
 validationQuery=SELECT 'x'  
 #申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。   
 testOnBorrow=false  
 #归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。  
 testOnReturn=false  
 #建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。   
 testWhileIdle=true  
 #属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有:监控统计用的filter:stat;日志用的filter:log4j;防御sql注入的filter:wall   
 filters=stat,wall  
 #有两个含义:1) Destroy线程会检测连接的间隔时间;2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明   
 timeBetweenEvictionRunsMillis=3000  
 #配置一个连接在池中最小生存的时间,单位是毫秒  
 minEvictableIdleTimeMillis=300000

 如果要使用Druid的内置监控功能,需要配置数据源时加上<property name="filters" value="stat" />,上面已经有了。


   还需要在web.xml中加上:

 <!-- 启用Web监控统计功能需要在Web应用的web.xml中加入这个Servlet声明 -->  
 <servlet>  
 <servlet-name>DruidStatView</servlet-name>  
 <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>  
 <init-param>    
 <!-- 是否允许清空统计数据,不写时默认true -->  
 <param-name>resetEnable</param-name>    
 <param-value>true</param-value>    
 </init-param>    
 <init-param>    
 <!-- 用户名,用户名和密码可以不写,不写时不需要输入,直接登录 -->  
 <param-name>loginUsername</param-name>    
 <param-value>druid</param-value>    
 </init-param>    
 <init-param>    
 <!-- 密码 -->  
 <param-name>loginPassword</param-name>    
 <param-value>123456</param-value>    
 </init-param>    
 </servlet>  
 <servlet-mapping>  
 <servlet-name>DruidStatView</servlet-name>  
 <url-pattern>/druid/*</url-pattern>  
 </servlet-mapping>

启动项目后在浏览器输入:

http://ip:port/项目名/druid/或http://ip:port/项目名/druid/index.html即可访问。

问题描述

程序部署在生产环境(数据库是oracle),大概半个小时不用,再次使用的时候就出现查询数据库卡主,停顿大概15分钟左右,15分钟之后程序抛出异常,然后再使用就可以了,多刷新几次,跳过当前有问题的那个数据库连接也能正常使用,最后解决的方法是添加了一个参数,参数名字是:keepAlive
github druid的上对这个参数的说明

https://github.com/alibaba/druid/wiki/KeepAlive_cn

问题解决办法:

      第一步:

druidDataSource.setConnectionProperties("oracle.net.CONNECT_TIMEOUT=2000;oracle.jdbc.ReadTimeout=30000");

//后面的ReadTimeout单位也是毫秒,不要设置的太短,否则有些sql执行时间本来就长,报错会影响正常使用。mysql可以这样写:

druidDataSource.setConnectionProperties("connectTimeout=2000;socketTimeout=30000);

sqlserver或postgresql可以这写:

druidDataSource.setConnectionProperties("loginTimeout=2000;socketTimeout=30000);

         第二步:

druidDataSource.setMinEvictableIdleTimeMillis(180000);

//配置一个连接在池中最小生存的时间,单位是毫秒,这里配置为3分钟180000
druidDataSource.setKeepAlive(true);

//打开druid.keepAlive之后,当连接池空闲时,池中的minIdle数量以内的连接,空闲时间超过minEvictableIdleTimeMillis,则会执行keepAlive操作,即执行druid.validationQuery指定的查询SQL,一般为select 1 from dual,其他数据库一般为select 1,只要minEvictableIdleTimeMillis设置的小于防火墙切断连接时间,就可以保证当连接空闲时自动做保活检测,不会被防火墙切断
 

数据源的初始化

了解下DruidDataSource这个类

这里先来介绍下DruidDataSource这个类:

DruidDataSource的UML图

图中我只列出了几个重要的属性,这几个属性没有理解好,后面的源码很难看得进去。

概括下初始化的过程

DruidDataSource的初始化时机是可选的,当我们设置init=true时,在createDataSource时就会调用DataSource.init()方法进行初始化,否则,只会在getConnection时再进行初始化。数据源初始化主要逻辑在DataSource.init()这个方法,可以概括为以下步骤:

  1. 加锁
  2. 初始化initStackTrace、id、xxIdSeed、dbTyp、driver、dataSourceStat、connections、evictConnections、keepAliveConnections等属性
  3. 初始化过滤器
  4. 校验maxActive、minIdle、initialSize、timeBetweenLogStatsMillis、useGlobalDataSourceStat、maxEvictableIdleTimeMillis、minEvictableIdleTimeMillis、validationQuery等配置是否合法
  5. 初始化ExceptionSorter、ValidConnectionChecker、JdbcDataSourceStat
  6. 创建initialSize数量的连接
  7. 创建logStatsThread、createConnectionThread和destroyConnectionThread
  8. 等待createConnectionThread和destroyConnectionThread线程run后再继续执行
  9. 注册MBean,用于支持JMX
  10. 如果设置了keepAlive,通知createConnectionThread创建连接对象
  11. 解锁

这个方法差不多200行,考虑篇幅,我删减了部分内容。

加锁和解锁

druid数据源初始化采用的是ReentrantLock,如下:

注意,以下步骤均在这个锁的范围内。

初始化属性

这部分内容主要是初始化一些属性,需要注意的一点就是,这里使用了AtomicLongFieldUpdater来进行原子更新,保证写的安全和读的高效,当然,还是cocurrent包的工具。

初始化过滤器

看到下面的代码会发现,我们还可以通过SPI机制来配置过滤器。

使用SPI配置过滤器时需要注意,对应的类需要加上@AutoLoad注解,另外还需要配置load.spifilter.skip=false,SPI相关内容可参考我的另一篇博客:使用SPI解耦你的实现类。

在这个方法里,主要就是初始化过滤器的一些属性而已。过滤器的部分,本文不会涉及到太多。

校验配置

这里只是简单的校验,不涉及太多复杂的逻辑。

初始化ExceptionSorter、ValidConnectionChecker、JdbcDataSourceStat

这里重点关注ExceptionSorter和ValidConnectionChecker这两个类,这里会根据数据库类型进行选择。其中,ValidConnectionChecker用于对连接进行检测。

创建initialSize数量的连接

这里有两种方式创建连接,一种是异步,一种是同步。但是,根据我们的使用例子,createScheduler为null,所以采用的是同步的方式。

注意,后面的所有代码也是基于createScheduler为null来分析的。

创建logStatsThread、createConnectionThread和destroyConnectionThread

这里会启动三个线程。

等待

这里使用了CountDownLatch,保证当createConnectionThread和destroyConnectionThread开始run时再继续执行。

private final CountDownLatch initedLatch = new CountDownLatch(2);
        // 线程进入等待,等待CreatorThread和DestroyThread执行
        initedLatch.await();

我们进入到
DruidDataSource.CreateConnectionThread.run(),可以看到,一执行run方法就会调用countDown。destroyConnectionThread也是一样,这里就不放进来了。

注册MBean

接下来是注册MBean,会去注册
DruidDataSourceStatManager和DruidDataSource,启动我们的程度,通过jconsole就可以看到这两个MBean。JMX相关内容这里就不多扩展了,感兴趣的话可参考我的另一篇博客: 如何使用JMX来管理程序?

// 注册MBean,用于支持JMX
        registerMbean();

通知createConnectionThread创建连接对象

前面已经讲过,当我们调用empty.signal(),会去唤醒处于empty.await()状态的CreateConnectionThread。CreateConnectionThread这个线只有在需要创建连接时才运行,否则会一直等待,后面会讲到。

连接对象的获取

了解下DruidPooledConnection这个类

用户调用
DruidDataSource.getConnection,拿到的对象是DruidPooledConnection,里面封装了DruidConnectionHolder,而这个对象包含了原生的连接对象和我们一开始创建的数据源对象。

DruidPooledConnection的UML图

概括下获取连接的过程

连接对象的获取过程可以概括为以下步骤:

  1. 初始化数据源(如果还没初始化);
  2. 获得连接对象,如果无可用连接,向createConnectionThread发送signal创建新连接,此时会进入等待;
  3. 如果设置了testOnBorrow,进行testOnBorrow检测,否则,如果设置了testWhileIdle,进行testWhileIdle检测;
  4. 如果设置了removeAbandoned,则会将连接对象放入activeConnections;
  5. 设置defaultAutoCommit,并返回;
  6. 执行filterChain。

初始化数据源的前面已经讲过了,这里就直接从第二步开始。

获取连接对象

进入
DruidDataSource.getConnectionInternal方法。除了获取连接对象,其他的大部分是校验和计数的内容。

下面再看下DruidDataSource.takeLast()方法(即没有配置maxWait时调用的方法)。该方法中,当没有空闲连接对象时,会尝试创建连接,此时该线程进入等待(notEmpty.await()),只有连接对象创建完成或池中回收了连接对象(notEmpty.signal()),该线程才会继续执行。

创建连接对象

前面已经讲到,创建连接是采用异步方式,进入到
DruidDataSource.CreateConnectionThread.run()。当不需要创建连接时,该线程进入empty.await()状态,此时需要用户线程调用empty.signal()来唤醒。

testOnBorrow或testWhileIdle

进入
DruidDataSource.getConnectionDirect(long)。该方法会使用到validConnectionChecker来校验连接的有效性。

removeAbandoned

进入
DruidDataSource.getConnectionDirect(long),这里不会进行检测,只是将连接对象放入activeConnections,具体泄露连接的检测工作是在DestroyConnectionThread线程中进行。

DestroyConnectionThread线程会根据我们设置的
timeBetweenEvictionRunsMillis来进行检验,具体的校验会去运行DestroyTask(DruidDataSource的内部类),这里看下DestroyTask的run方法。

进入
DruidDataSource.removeAbandoned(),当连接对象使用时间超过removeAbandonedTimeoutMillis,则会被丢弃掉。

执行filterChain

进入
DruidDataSource.getConnection。

进入到
FilterChainImpl.dataSource_connect。

这里以
StatFilter.dataSource_getConnection为例。

以上,druid的源码基本已经分析完,其他部分内容有空再做补充。

数据源的初始化

了解下DruidDataSource这个类

这里先来介绍下DruidDataSource这个类:

DruidDataSource的UML图

图中我只列出了几个重要的属性,这几个属性没有理解好,后面的源码很难看得进去。

概括下初始化的过程

DruidDataSource的初始化时机是可选的,当我们设置init=true时,在createDataSource时就会调用DataSource.init()方法进行初始化,否则,只会在getConnection时再进行初始化。数据源初始化主要逻辑在DataSource.init()这个方法,可以概括为以下步骤:

  1. 加锁
  2. 初始化initStackTrace、id、xxIdSeed、dbTyp、driver、dataSourceStat、connections、evictConnections、keepAliveConnections等属性
  3. 初始化过滤器
  4. 校验maxActive、minIdle、initialSize、timeBetweenLogStatsMillis、useGlobalDataSourceStat、maxEvictableIdleTimeMillis、minEvictableIdleTimeMillis、validationQuery等配置是否合法
  5. 初始化ExceptionSorter、ValidConnectionChecker、JdbcDataSourceStat
  6. 创建initialSize数量的连接
  7. 创建logStatsThread、createConnectionThread和destroyConnectionThread
  8. 等待createConnectionThread和destroyConnectionThread线程run后再继续执行
  9. 注册MBean,用于支持JMX
  10. 如果设置了keepAlive,通知createConnectionThread创建连接对象
  11. 解锁

这个方法差不多200行,考虑篇幅,我删减了部分内容。

加锁和解锁

druid数据源初始化采用的是ReentrantLock,如下:

注意,以下步骤均在这个锁的范围内。

初始化属性

这部分内容主要是初始化一些属性,需要注意的一点就是,这里使用了AtomicLongFieldUpdater来进行原子更新,保证写的安全和读的高效,当然,还是cocurrent包的工具。

初始化过滤器

看到下面的代码会发现,我们还可以通过SPI机制来配置过滤器。

使用SPI配置过滤器时需要注意,对应的类需要加上@AutoLoad注解,另外还需要配置load.spifilter.skip=false,SPI相关内容可参考我的另一篇博客:使用SPI解耦你的实现类。

在这个方法里,主要就是初始化过滤器的一些属性而已。过滤器的部分,本文不会涉及到太多。

校验配置

这里只是简单的校验,不涉及太多复杂的逻辑。

初始化ExceptionSorter、ValidConnectionChecker、JdbcDataSourceStat

这里重点关注ExceptionSorter和ValidConnectionChecker这两个类,这里会根据数据库类型进行选择。其中,ValidConnectionChecker用于对连接进行检测。

创建initialSize数量的连接

这里有两种方式创建连接,一种是异步,一种是同步。但是,根据我们的使用例子,createScheduler为null,所以采用的是同步的方式。

注意,后面的所有代码也是基于createScheduler为null来分析的。

创建logStatsThread、createConnectionThread和destroyConnectionThread

这里会启动三个线程。

等待

这里使用了CountDownLatch,保证当createConnectionThread和destroyConnectionThread开始run时再继续执行。

private final CountDownLatch initedLatch = new CountDownLatch(2);
        // 线程进入等待,等待CreatorThread和DestroyThread执行
        initedLatch.await();

我们进入到
DruidDataSource.CreateConnectionThread.run(),可以看到,一执行run方法就会调用countDown。destroyConnectionThread也是一样,这里就不放进来了。

注册MBean

接下来是注册MBean,会去注册
DruidDataSourceStatManager和DruidDataSource,启动我们的程度,通过jconsole就可以看到这两个MBean。JMX相关内容这里就不多扩展了,感兴趣的话可参考我的另一篇博客: 如何使用JMX来管理程序?

// 注册MBean,用于支持JMX
        registerMbean();

通知createConnectionThread创建连接对象

前面已经讲过,当我们调用empty.signal(),会去唤醒处于empty.await()状态的CreateConnectionThread。CreateConnectionThread这个线只有在需要创建连接时才运行,否则会一直等待,后面会讲到。

连接对象的获取

了解下DruidPooledConnection这个类

用户调用
DruidDataSource.getConnection,拿到的对象是DruidPooledConnection,里面封装了DruidConnectionHolder,而这个对象包含了原生的连接对象和我们一开始创建的数据源对象。

DruidPooledConnection的UML图

概括下获取连接的过程

连接对象的获取过程可以概括为以下步骤:

  1. 初始化数据源(如果还没初始化);
  2. 获得连接对象,如果无可用连接,向createConnectionThread发送signal创建新连接,此时会进入等待;
  3. 如果设置了testOnBorrow,进行testOnBorrow检测,否则,如果设置了testWhileIdle,进行testWhileIdle检测;
  4. 如果设置了removeAbandoned,则会将连接对象放入activeConnections;
  5. 设置defaultAutoCommit,并返回;
  6. 执行filterChain。

初始化数据源的前面已经讲过了,这里就直接从第二步开始。

获取连接对象

进入
DruidDataSource.getConnectionInternal方法。除了获取连接对象,其他的大部分是校验和计数的内容。

下面再看下DruidDataSource.takeLast()方法(即没有配置maxWait时调用的方法)。该方法中,当没有空闲连接对象时,会尝试创建连接,此时该线程进入等待(notEmpty.await()),只有连接对象创建完成或池中回收了连接对象(notEmpty.signal()),该线程才会继续执行。

创建连接对象

前面已经讲到,创建连接是采用异步方式,进入到
DruidDataSource.CreateConnectionThread.run()。当不需要创建连接时,该线程进入empty.await()状态,此时需要用户线程调用empty.signal()来唤醒。

testOnBorrow或testWhileIdle

进入
DruidDataSource.getConnectionDirect(long)。该方法会使用到validConnectionChecker来校验连接的有效性。

removeAbandoned

进入
DruidDataSource.getConnectionDirect(long),这里不会进行检测,只是将连接对象放入activeConnections,具体泄露连接的检测工作是在DestroyConnectionThread线程中进行。

DestroyConnectionThread线程会根据我们设置的
timeBetweenEvictionRunsMillis来进行检验,具体的校验会去运行DestroyTask(DruidDataSource的内部类),这里看下DestroyTask的run方法。

进入
DruidDataSource.removeAbandoned(),当连接对象使用时间超过removeAbandonedTimeoutMillis,则会被丢弃掉

执行filterChain

进入
DruidDataSource.getConnection。

进入到
FilterChainImpl.dataSource_connect。

这里以
StatFilter.dataSource_getConnection为例。

以上,druid的源码基本已经分析完,其他部分内容有空再做补充。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用frp搭建内网穿透服务

使用frp搭建内网穿透服务 frp 是一个专注于内网穿透的高性能的反向代理应用&#xff0c;支持 TCP、UDP、HTTP、HTTPS 等多种协议&#xff0c;且支持 P2P 通信。可以将内网服务以安全、便捷的方式通过具有公网 IP 节点的中转暴露到公网。 1.下载frp 下载地址 2.服务端安装 …

工作电压范围,转换速率高,相位补偿等特性的双运算放大器芯片D4510的描述

D4510是一块双运算放大器&#xff0c;具有较宽的工作电压范围&#xff0c;转换速率高&#xff0c;相位补偿等特性。电路能在低电源电压下:工作,电源电压范围:双电源为1V-3.5V和单电源电压为2V~7V。 主要特点&#xff1a; ● 低电压工作 ● 转换速率高 ● 动态输…

深度学习领域中的耦合与解耦

在阅读论文的时候应该会看到两个操作&#xff0c;一个是耦合&#xff0c;一个是解耦&#xff0c;经常搭配着出现的就是两个词语&#xff0c;耦合头&#xff08;Coupled head&#xff09;以及Decoupled head&#xff08;解耦合头&#xff09;&#xff0c;那为什么要耦合&#xf…

冬天起不来床怎么办?羊大师给你好建议

冬天起不来床怎么办&#xff1f;羊大师给你好建议 冬季是让人感到懒散的季节&#xff0c;尤其是早上起床。寒冷的天气和温暖的被窝让人们很难离开床铺。如果你也常常遇到这个问题&#xff0c;不要担心&#xff0c;本文小编羊大师将为你分析起床困难的原因&#xff0c;并提供一…

“我“摸爬滚打5年,干了测试工程师,现在测试怎么样了...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 小刘&#xff1a;…

nginx 代理接口报404 问题排查

今天遇到一个nginx代理后端接口请求报404的问题&#xff0c;问题是这样的&#xff0c;后端由于服务器没有环境&#xff0c;但是需要和前端联调&#xff0c;于是采用cpolar内网穿透的方式&#xff0c;穿出来了。但是前端请求跨域&#xff0c;于是前端用nginx代理了一下后端接口&…

网络工程师网络配置经典例题(五)

1、配置SwitchA的单臂静态BFD特性 [SwitchA] bfd [SwitchA-bfd] quit [SwitchA] bfd 1 bind peer-ip 10.2.2.2 interface vlanif 10 source-ip 10.1.1.1 one-arm-echo [SwitchA-bfd-session-1] discriminator local 1 [SwitchA-bfd-session-1] min-echo-rx-interval 200 …

赠人玫瑰,手有余香,分享5款精致小巧的软件

​ 分享是一种美好的事情&#xff0c;它能让快乐变得更多&#xff0c;它能让悲伤变得更少&#xff0c;我会持续分享一些好用的软件给大家。 1.矢量图形设计——Affinity Designer ​ Affinity Designer是一款屡获殊荣的矢量图形设计软件&#xff0c;适用于 Windows、macOS 和…

微信可以注册小号啦,看看怎么操作

微信支持同一手机号绑定两个账号啦&#xff01; 生活号和工作号可以分开啦&#xff5e;实用又简单&#xff01; 详细步骤如下&#xff1a; ①点击微信-我的-设置 ②点击“切换账号” ③点击“添加账号” ④点击“注册新账号” ⑤点击“通过当前微信的手机号辅助注册” ⑥安…

工业4.0时代,烤漆房控制柜如何远程监控?

烤漆房控制柜远程监控方案 一、现状 烤漆房是汽车、机械、家具等工业领域广泛应用的设备&#xff0c;主要用于产品的表面涂装。传统的烤漆房控制柜采用本地控制方式&#xff0c;操作人员在现场进行参数设置和设备控制。这种控制方式需要操作人员需要具备一定的专业知识&#x…

OpenHarmony Ohpm安装历程(个人踩坑,最后安装成功)

大家好&#xff0c;我是【八戒&#xff0c;你又涨价了哎】 以下是我个人在学习OpenHarmony过程中的分享&#xff0c;请大家多多指教 目录 问题描述&#xff1a; 尝试解决 尝试一、 尝试二、 尝试三、 最终解决方案 问题描述&#xff1a; 当我学习到使用OpenHarmony的三方…

劲松中西医医院谭巍主任在线分析:HPV复阳的三大祸首

提到hpv&#xff0c;大家都不陌生&#xff0c;似乎对这个病毒很畏惧。即便如此&#xff0c;我们仍然要知道hpv病毒它与其他病毒有所不同&#xff0c;这是一种微小的DNA病毒&#xff0c;其感染性更&#xff0c;传播速度更快&#xff0c;感染途径更加广泛&#xff0c;可以说给人们…

Keka v1.3.5(mac压缩解压工具)

Keka是一款功能强大的文件压缩和解压缩软件&#xff0c;为Mac系统用户提供便捷、高效的文件管理工具。以下是Keka的主要特点和功能&#xff1a; 多种压缩格式支持&#xff1a;Keka支持多种常见的压缩格式&#xff0c;包括ZIP、7Z、RAR、TAR、GZIP等。它能够方便地创建和提取这些…

SAP 通过游标来分批从数据库表读取2G数据

原文链接&#xff1a;https://blog.csdn.net/Buffalo_soldier/article/details/109772612 我们在写程序的时候可能会遇到用内表处理超大量数据的情况&#xff0c;比如取MSEG、BSEG表&#xff0c;内表里的数据如果超过2G就会报程序dump了&#xff0c;所以关键是要控制内表的数据…

知云文献翻译——外语论文你get了吗?

今天博主分享一款实用的翻译软件&#xff0c;希望对大家日后的学习有所帮助。这个翻译网站&#xff0c;主要做文档翻译&#xff0c;可以上传PDF、Word、Excel这些格式&#xff0c;翻译语言也比较齐全。操作简单&#xff0c;功能多样的翻译软件;知云文献翻译最新版可以直接对PDF…

Jmeter —— jmeter接口自动化测试操作流程

在企业使用jmeter开展实际的接口自动化测试工具&#xff0c;建议按如下操作流程&#xff0c; 可以使整个接口测试过程更规范&#xff0c;更有效。 接口自动化的流程&#xff1a; 1、获取到接口文档&#xff1a;swagger、word、excel ... 2、熟悉接口文档然后设计测试用例&…

Git 远程仓库(Github)

目录 添加远程库 查看当前的远程库 提取远程仓库 推送到远程仓库 删除远程仓库 Git 并不像 SVN 那样有个中心服务器。 目前我们使用到的 Git 命令都是在本地执行&#xff0c;如果你想通过 Git 分享你的代码或者与其他开发人员合作。 你就需要将数据放到一台其他开发人员…

5.什么是Spring的依赖注入(DI)?IOC和DI的区别是什么

很多人把IOC和DI说成一个东西&#xff0c;笼统来说的话是没有问题的&#xff0c;但是本质上还是有所区别的,希望大家能够严谨一点&#xff0c; IOC和DI是从不同的角度描述的同一件事&#xff0c;IOC是从容器的角度描述&#xff0c;而DI是从应用程序的角度来描述&#xff0c;也…

走进低代码:不懂编程也能5分钟开发一个应用

目录 一、低代码开发者 1&#xff09;低代码赋能IT技术人员--低代码 2&#xff09;低代码赋能业务人员--零代码 二、低代码基础功能及搭建 1.代码生成器 2.工作流程 3.门户设计 4.大屏设计 5.报表设计 6.第三方登录 7.多租户实现 三、写在最后 低代码就是将代码转变…

前端实现移动端Tab栏(附带源码)

文章目录 先上图,附带源码index.html 主要视图层Main.css 主要样式demo.css主要的JS,在index.html 引入即可先上图,附带源码 提示:一款JS和CSS3炫酷Tabbar导航栏动画特效。该Tabbar导航栏在点击切换时,会有类似波浪运动的动画效果,非常炫酷。 index.html 主要视图层 &l…