【MyBatis源码】详解datasource包,DataSourceFactory,数据库连接池

🎮 作者主页:点击
🎁 完整专栏和代码:点击
🏡 博客主页:点击

文章目录

  • java.sql包和javax.sql包
    • java.sql 包核心接口
    • javax.sql 包核心接口
  • 数据源工厂接口DataSourceFactory
    • 自定义HikariCPDataSourceFactory
    • 自定义数据源实现
  • JNDI数据源工厂
  • PooledDataSourceFactory池化数据源
    • PoolState连接池属性对象
    • activeConnections活跃池
      • (1) 连接从空闲池到活跃池
      • (2) 连接归还到空闲池
      • (3) 连接超时处理
      • (4) 监控活跃连接数量
      • (5) 防止连接泄漏
      • (6) 最大活跃连接数
    • activeConnections空闲池
      • (1) 添加到空闲池
      • (2) 从空闲池中获取连接

java.sql包和javax.sql包

Java提供的与数据库操作相关的包主要有两个,它们是 java.sql包和 javax.sql包。
java.sql通常被称为 JDBC核心 API包,它为 Java提供了访问数据源中数据的基础功能。基于该包能实现将 SQL语句传递给数据库、从数据库中以表格的形式读写数据等功能。
javax.sql通常被称为 JDBC扩展 API包,它扩展了 JDBC核心 API包的功能,提供了对服务器端的支持,是 Java企业版的重要部分。

在这里插入图片描述

java.sql 包核心接口

DriverManager:管理数据库驱动,建立与数据库的连接。
Connection:表示与数据库的连接。
Statement:用于执行静态 SQL 语句。
ResultSet:表示 SQL 查询的结果集。
ResultSetMetaData:提供结果集的元数据。
DatabaseMetaData:获取数据库的元信息(如支持的功能、表结构等)。
Blob 和 Clob:分别用于处理二进制大对象和字符大对象。

javax.sql 包核心接口

DataSource:提供一种获取数据库连接的标准方式,比 DriverManager 更灵活,支持连接池。
ConnectionPoolDataSource:专为连接池提供的接口。
PooledConnection:表示从连接池中获取的连接。
XADataSource:支持分布式事务的高级数据源。
XAConnection:表示参与分布式事务的数据库连接。
RowSet:支持对结果集的更灵活操作,能在脱离连接的情况下处理数据。
RowSetListener:监听 RowSet 操作的变化。

数据源工厂接口DataSourceFactory

datasource 包采用了典型的工厂方法模式。DataSourceFactory 作为所有工厂的接口,javax.sql包中的 DataSource作为所有工厂产品的接口。

/**
 * @author Clinton Begin
 */
public interface DataSourceFactory {

  // 通过传入的配置属性初始化数据源
  void setProperties(Properties props);

  // 返回一个具体的 DataSource 对象
  DataSource getDataSource();

}

在这里插入图片描述
org.apache.ibatis.builder.xml.XMLConfigBuilder#dataSourceElement

  private DataSourceFactory dataSourceElement(XNode context) throws Exception {
    if (context != null) {
      String type = context.getStringAttribute("type");
      // 获取<dataSource>子节点的配置
      Properties props = context.getChildrenAsProperties();
      // 根据getStringAttribute("type");获取对应的实现DataSourceFactory
      DataSourceFactory factory = (DataSourceFactory) resolveClass(type).getDeclaredConstructor().newInstance();
      // 映射转换数据源配置 driver;url;username;password
      factory.setProperties(props);
      return factory;
    }
    throw new BuilderException("Environment declaration requires a DataSourceFactory.");
  }

自定义HikariCPDataSourceFactory

以下是一个自定义数据源实现的示例,使用了流行的 HikariCP 连接池作为数据源,并通过实现 MyBatis 的 DataSourceFactory 接口集成到 MyBatis 中。
HikariCPDataSourceFactory 实现类

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

import org.apache.ibatis.datasource.DataSourceFactory;

import javax.sql.DataSource;
import java.util.Properties;

public class HikariCPDataSourceFactory implements DataSourceFactory {
    private HikariDataSource dataSource;

    @Override
    public void setProperties(Properties properties) {
        HikariConfig config = new HikariConfig();

        // 从配置中加载数据源参数
        config.setJdbcUrl(properties.getProperty("url"));
        config.setUsername(properties.getProperty("username"));
        config.setPassword(properties.getProperty("password"));

        // 可选的高级配置
        config.setDriverClassName(properties.getProperty("driver"));
        config.setMaximumPoolSize(Integer.parseInt(properties.getProperty("maxPoolSize", "10")));
        config.setMinimumIdle(Integer.parseInt(properties.getProperty("minIdle", "5")));
        config.setIdleTimeout(Long.parseLong(properties.getProperty("idleTimeout", "60000")));

        this.dataSource = new HikariDataSource(config);
    }

    @Override
    public DataSource getDataSource() {
        return this.dataSource;
    }
}

在 mybatis-config.xml 中,配置自定义的数据源工厂:

<configuration>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="com.zy.datasource.HikariCPDataSourceFactory">
        <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/test"/>
        <property name="username" value="root"/>
        <property name="password" value="password"/>
        <property name="maxPoolSize" value="20"/>
        <property name="minIdle" value="5"/>
        <property name="idleTimeout" value="30000"/>
      </dataSource>
    </environment>
  </environments>
</configuration>

使用 MyBatis 加载配置并执行 SQL

  @Test
  public void  testHikariCPDataSourceFactory() throws IOException {
    InputStream resource = Resources.getResourceAsStream(MybatisTest.class.getClassLoader(), "mybatis-config.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resource);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserBean userBean = new UserBean();
    userBean.setId(1);
    Object objects1 = sqlSession.selectOne("user.selectById", userBean);
    System.out.println(objects1);
  }

自定义数据源实现

创建一个简单的数据源类,通过管理 java.sql.Connection 对象提供基本的数据源功能。
自定义 SimpleDataSource

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

public class SimpleDataSource implements DataSource {
  private String url;
  private String username;
  private String password;

  public SimpleDataSource(Properties properties) {
    this.url = properties.getProperty("url");
    this.username = properties.getProperty("username");
    this.password = properties.getProperty("password");
    try {
      String driver = properties.getProperty("driver");
      if (driver != null) {
        Class.forName(driver); // 加载驱动类
      }
    } catch (ClassNotFoundException e) {
      throw new RuntimeException("Failed to load database driver", e);
    }
  }

  @Override
  public Connection getConnection() throws SQLException {
    return DriverManager.getConnection(url, username, password);
  }

  @Override
  public Connection getConnection(String username, String password) throws SQLException {
    return DriverManager.getConnection(url, username, password);
  }

  // 以下方法为 `DataSource` 接口的默认实现,仅作占位符
  @Override
  public <T> T unwrap(Class<T> iface) throws SQLException {
    throw new UnsupportedOperationException("Not implemented");
  }

  @Override
  public boolean isWrapperFor(Class<?> iface) throws SQLException {
    return false;
  }

  @Override
  public java.io.PrintWriter getLogWriter() throws SQLException {
    return null;
  }

  @Override
  public void setLogWriter(java.io.PrintWriter out) throws SQLException {}

  @Override
  public void setLoginTimeout(int seconds) throws SQLException {}

  @Override
  public int getLoginTimeout() throws SQLException {
    return 0;
  }

  @Override
  public java.util.logging.Logger getParentLogger() {
    return java.util.logging.Logger.getLogger("SimpleDataSource");
  }
}

为了将自定义数据源集成到 MyBatis 中,实现 DataSourceFactory 接口:

public class SimpleDataSourceFactory implements DataSourceFactory {
  private SimpleDataSource dataSource;

  @Override
  public void setProperties(Properties properties) {
    this.dataSource = new SimpleDataSource(properties);
  }

  @Override
  public DataSource getDataSource() {
    return this.dataSource;
  }
}

配置文件 mybatis-config.xml

      <dataSource type="com.zy.client.datasource.SimpleDataSourceFactory">
        <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/test"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
      </dataSource>

在这里插入图片描述

JNDI数据源工厂

JNDI(Java Naming and Directory Interface)是 Java命名和目录接口,它能够为Java应用程序提供命名和目录访问的接口,我们可以将其理解为一个命名规范。在使用该规范为资源命名并将资源放入环境(Context)中后,可以通过名称从环境中查找(lookup)对应的资源。
MyBatis 提供的 JndiDataSourceFactory 类封装了这一过程,它通过 JNDI 查找到对应的 DataSource 并将其注入 MyBatis 的环境配置中。
在 Java EE 容器(如 Tomcat、Jetty、WebLogic、WildFly)或其他支持 JNDI 的环境中,通常会由管理员预先配置好数据源,并绑定到一个 JNDI 名称上(例如 java:/comp/env/jdbc/MyDB)。
应用程序通过 JNDI 名称直接获取这个数据源,而无需自行创建和管理。

MyBatis 配置文件使用 JNDI 数据源
在 mybatis-config.xml 中:

<configuration>
  <environments default="production">
    <environment id="production">
      <transactionManager type="JDBC"/>
      <dataSource type="JNDI">
        <property name="jndiName" value="java:/comp/env/jdbc/MyDB"/>
      </dataSource>
    </environment>
  </environments>
</configuration>

• type=“JNDI”:MyBatis 会加载 JndiDataSourceFactory。
• jndiName:指向在容器中配置的 JNDI 数据源。

容器中配置 JNDI 数据源示例
以 Tomcat 为例,配置 JNDI 数据源:

  1. 在 conf/context.xml 或项目的 META-INF/context.xml 中:
<Context>
  <Resource name="jdbc/MyDB"
            auth="Container"
            type="javax.sql.DataSource"
            maxTotal="20"
            maxIdle="10"
            minIdle="5"
            driverClassName="com.mysql.cj.jdbc.Driver"
            url="jdbc:mysql://localhost:3306/test"
            username="root"
            password="password"/>
</Context>

在 web.xml 中声明(可选,推荐在 Spring 或其他框架中直接管理):

<resource-ref>
  <description>My Database</description>
  <res-ref-name>jdbc/MyDB</res-ref-name>
  <res-type>javax.sql.DataSource</res-type>
  <res-auth>Container</res-auth>
</resource-ref>

PooledDataSourceFactory池化数据源

PooledDataSourceFactory 是 MyBatis 提供的内置数据源工厂之一,旨在支持数据库连接池功能。通过连接池,应用程序可以复用已有的数据库连接,从而显著提高性能并降低资源消耗。

在 MyBatis 的配置文件中使用字符串“POOLED”来代表池化数据源,在池化数据源的配置中,除了非池化数据源中的相关属性外,还增加了一些与连接池相关的属性。

PoolState连接池属性对象

在 PooledDataSource 中,定义了一些用于管理和统计数据库连接池状态的字段。这些字段帮助 MyBatis 连接池监控其连接池的使用情况,包括空闲连接、活跃连接的数量、连接请求的统计数据、超时连接、等待的线程数等。

  /**
   * 连接池的核心数据源,负责管理数据库连接的获取、使用和释放
   */
  protected PooledDataSource dataSource;

  /**
   * 空闲连接对象池
   */
  protected final List<PooledConnection> idleConnections = new ArrayList<>();
  /**
   * 活跃连接对象池
   */
  protected final List<PooledConnection> activeConnections = new ArrayList<>();
  /**
   * 记录连接池的连接请求总数。每当应用程序请求连接时,这个值就会增加。它是一个重要的统计数据,帮助监控系统的整体负载。
   */
  protected long requestCount = 0;
  /**
   * 记录所有连接请求的累计时间。通过该字段可以统计每次连接请求从发起到获得连接的总时间,帮助评估连接池的响应效率和数据库性能。
   */
  protected long accumulatedRequestTime = 0;
  /**
   * 记录所有活跃连接的累计使用时间(即被借出的时间)。该值越大,说明连接池中的连接被长时间占用,可能需要优化连接池配置或者数据库查询性能。
   */
  protected long accumulatedCheckoutTime = 0;
  /**
   * 记录那些被借用并超过最大允许借用时间(poolMaximumCheckoutTime)的连接数。
   * 当连接超时未归还时,这个值会增加。这个字段帮助监控数据库连接是否被合理使用,并防止连接泄漏。
   */
  protected long claimedOverdueConnectionCount = 0;
  /**
   * 记录所有超时连接的累计占用时间。这可以帮助了解超时连接对系统性能的影响。
   * 如果该值过大,意味着连接池中存在不合理使用的连接,可能需要优化连接超时设置。
   */
  protected long accumulatedCheckoutTimeOfOverdueConnections = 0;
  /**
   * 记录等待连接的累计时间。它表示连接池中等待获取连接的线程总共等待了多少时间。
   * 这个字段对于评估连接池的响应能力和识别潜在的性能瓶颈非常重要。
   */
  protected long accumulatedWaitTime = 0;
  /**
   * 记录等待连接的次数。如果连接池已满,且没有空闲连接可用,新的连接请求会被挂起,直到有连接可用。
   * 该字段用于统计发生等待的连接请求次数。这个值过高表明连接池的容量可能不足,需要增加连接数或优化查询性能。
   */
  protected long hadToWaitCount = 0;
  /**
   * 记录发生错误的连接数(例如无法建立连接或连接池中的连接出现故障)。
   * 这个字段有助于监控连接池的健康状态,并可以帮助快速定位和修复连接相关的问题。
   */
  protected long badConnectionCount = 0;

activeConnections活跃池

在数据库连接池中,activeConnections(活跃池)是用来存储当前正在被应用程序使用的数据库连接的容器。在 MyBatis 的 PooledDataSource 中,activeConnections 是一个关键的成员变量,它通过管理活跃连接来优化数据库连接的使用效率,并且帮助处理连接的获取、释放及生命周期管理。

管理活跃连接:当连接池中的连接被借用时,它会从空闲池(idleConnections)转移到活跃池(activeConnections)。这些连接是被应用程序使用并未归还的。
跟踪连接使用情况:通过 activeConnections 可以知道当前有多少连接正在被使用,以及每个连接的状态。
连接超时管理:通过 activeConnections,可以监控连接是否超时,并强制回收已超时的连接。

(1) 连接从空闲池到活跃池

当应用程序请求一个连接时,首先会从空闲池(idleConnections)中取出一个连接,并将其放入活跃池中。这个连接就被认为是“活跃的”,直到它被归还。

synchronized (state) {
    if (!state.idleConnections.isEmpty()) {
        // 从空闲池取出连接
        PooledConnection conn = state.idleConnections.remove(0);
        // 将连接加入活跃池
        state.activeConnections.add(conn);
        return conn;
    }
}

在上面的代码中,state.idleConnections 是空闲连接池,state.activeConnections 是活跃连接池。连接从空闲池取出后被放入活跃池。

(2) 连接归还到空闲池

当应用程序完成数据库操作后,连接需要被归还到连接池中。在这个过程中,连接会从活跃池移除,并被放回空闲池。

synchronized (state) {
    // 从活跃池移除连接
    state.activeConnections.remove(conn);
    // 将连接放回空闲池
    if (state.idleConnections.size() < poolMaximumIdleConnections) {
        state.idleConnections.add(conn);
    } else {
        conn.invalidate(); // 如果空闲池已满,销毁连接
    }
}

在这段代码中,conn 会被从 activeConnections 中移除,并且重新加入 idleConnections 中,或者在池已满的情况下销毁。

(3) 连接超时处理

为了避免连接长时间被占用导致资源浪费,MyBatis 连接池会在活跃连接中检查是否有超时的连接。如果某个连接超过了最大借出时间(poolMaximumCheckoutTime),它会被回收。
下面的代码是在获取连接,并且判断连接池已满的情况下关闭超时的

// 获取活跃池第一个连接
PooledConnection oldestActiveConnection = state.activeConnections.get(0);
// 借出时间,即连接使用的时间戳和当前时间时间对比
long longestCheckoutTime = oldestActiveConnection.getCheckoutTime();
if (longestCheckoutTime > poolMaximumCheckoutTime) {
    state.activeConnections.remove(oldestActiveConnection); // 移除超时连接
    state.idleConnections.add(oldestActiveConnection); // 放回空闲池
}

(4) 监控活跃连接数量

可以通过监控 activeConnections 的大小来判断当前有多少连接正在被应用程序使用。

System.out.println("当前活跃连接数: " + state.activeConnections.size());

(5) 防止连接泄漏

连接池要防止连接泄漏,即连接被借出后没有及时归还。为此,activeConnections 可以配合其他机制,如超时检测和连接关闭回收,确保每个借出的连接最终都被归还。
在 MyBatis 中,PooledDataSource 会通过最大借用时间(poolMaximumCheckoutTime)来防止连接被长时间占用。当连接超时未归还时,系统会回收连接并标记其为失效。

(6) 最大活跃连接数

MyBatis 连接池的配置项之一是 poolMaximumActiveConnections,它限制了同时存在的最大活跃连接数。如果池中已达到最大活跃连接数,则新的请求会被阻塞,直到有连接归还或超时。

activeConnections空闲池

idleConnections负责存储空闲连接的列表。与 activeConnections 配合,它实现了对数据库连接的状态管理。用于存储一组 PooledConnection 对象,表示当前未被借出的数据库连接(即空闲连接)。
存储空闲连接:当数据库连接未被应用程序使用时,这些连接会存储在 idleConnections 列表中,以便快速复用。
连接复用:如果应用程序需要连接,PooledDataSource 优先从 idleConnections 中取出一个可用连接,而不是重新创建新的连接。这大大减少了连接创建和销毁的开销。
池管理:在连接池达到最大活跃连接数时,空闲连接可被借出以支持更多的数据库操作。若空闲连接超过配置的 poolMaximumIdleConnections,多余的连接会被销毁以释放资源。

(1) 添加到空闲池

当应用程序归还数据库连接时,该连接会从 activeConnections 移至 idleConnections。

// org.apache.ibatis.datasource.pooled.PooledDataSource#pushConnection
synchronized (state) {
    state.activeConnections.remove(conn); // 从活跃池移除
    if (state.idleConnections.size() < poolMaximumIdleConnections) {
        // 若空闲池未满,添加连接
        state.idleConnections.add(conn);
    } else {
        // 若空闲池已满,销毁连接
        conn.invalidate();
    }
}

(2) 从空闲池中获取连接

当应用程序需要连接时,优先从 idleConnections 中取出连接。

synchronized (state) {
    if (!state.idleConnections.isEmpty()) {
        // 从空闲池中移除一个连接
        PooledConnection conn = state.idleConnections.remove(0);
        state.activeConnections.add(conn); // 添加到活跃池
        return conn;
    }
}

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

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

相关文章

基于组件软件可信度量

基于组件软件可信度量 课程&#xff1a;软件质量分析 作业 可编写下面的java程序&#xff1a; package org.example;import java.util.Arrays;public class ComponentBasedMeasurementModel {public static void main(String[] args) {double[][] keyComponentJudgmentMatrix …

Windows.old 文件夹是什么?它可以手动删除吗?

当我们在 Windows 系统中进行重大更新&#xff0c;如从 Windows 7 升级到 Windows 10&#xff0c;或者在 Windows 10 中执行某些系统重置操作后&#xff0c;会在系统盘&#xff08;通常是 C 盘&#xff09;中发现一个名为 “Windows.old” 的文件夹。那么&#xff0c;这个文件夹…

Android13 允许桌面自动旋转

一&#xff09;需求-场景 Android13 实现允许桌面自动旋转 Android13 版本开始后&#xff0c;支持屏幕自动旋转&#xff0c;优化体验和兼容性&#xff0c;适配不同屏幕 主界面可自动旋转 二&#xff09;参考资料 android framework13-launcher3【06手机旋转问题】 Launcher默…

Goland2024.3 发布,有点东西

好多人夸我嘴甜&#xff0c;你要不要尝尝~ 上周&#xff0c;Goland2024 年最后的一个大版本正式发布了。 虽然这次的更新并不是很丰富&#xff0c;但是仍然有几个值得我们关注的几个亮点。 第一个&#xff0c;支持循环导入的检查 循环导入的出现往往是不经意的&#xff0c;但是…

数据结构之算法复杂度(超详解)

文章目录 1. 算法复杂度1.1 数据结构1.2 算法1.3 二者的重要性 2. 算法效率开胃小菜&#xff1a;复杂度概念 3. 时间复杂度3.1 大O表示法3.2 时间复杂度示例练习例1例2例3例4例5例6例7 4. 空间复杂度4.1 空间复杂度示例练习例1例2 5. 开胃小菜扩展5.1 思路2&#xff1a;采用空间…

【C++笔记】map和set的使用

【C笔记】map和set的深度剖析 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;C笔记 文章目录 【C笔记】map和set的深度剖析前言一.set1.1 序列式容器和关联式容器1.2 set系列的使用1.3 set类的介绍1.4 set的构造和迭代器1.5 set的增删查1.6…

最新AI自动无人智享直播系统 —— 视频自动播软件热门之选

在当今数字化浪潮汹涌澎湃的时代&#xff0c;直播行业正经历着前所未有的变革与创新。而最新的 AI 自动无人智享直播系统&#xff0c;无疑成为了视频自动播软件中的热门之选&#xff0c;正引领着直播领域迈向新的高度。 这款 AI 自动无人智享直播系统&#xff0c;其核心优势在于…

气膜球幕:科技与艺术的完美融合,沉浸式体验引领未来—轻空间

在现代化展览和活动中&#xff0c;如何突破传统展示方式&#xff0c;吸引观众的目光&#xff0c;带来前所未有的沉浸式体验&#xff1f;气膜球幕作为一种创新的科技展示平台&#xff0c;凭借其独特的球形结构和多功能应用&#xff0c;正在成为各大展览、活动和娱乐项目的首选。…

计算机视觉硬件知识点整理六:工业相机选型

文章目录 前言一、工业数字相机的分类二、相机的主要参数三、工业数字摄像机主要接口类型四、选择工业相机的考量因素六、实例分析 前言 随着科技的不断进步&#xff0c;工业自动化领域正经历着前所未有的变革。作为工业自动化的重要组成部分&#xff0c;工业相机在工业检测、…

Mysql读写分离分库分表

读写分离 什么是读写分离 读写分离主要是为了将对数据库的读写操作分散到不同的数据库节点上。 这样的话&#xff0c;就能够小幅提升写性能&#xff0c;大幅提升读性能。一般情况下&#xff0c;我们都会选择一主多从&#xff0c;也就是一台主数据库负责写&#xff0c;其他的从…

【C语言】结构体(四)

本篇重点是typedef关键字 一&#xff0c;是什么&#xff1f; typedef用来定义新的数据类型&#xff0c;通常typedef与结构体的定义配合使用。 简单来说就是取别名 ▶ struct 是用来定义新的数据类型——结构体 ▶ typedef是给数据类型取别名。 二&#xff0c;为什么&#xf…

普中51单片机——LED流水灯模块

1、GPIO概念 GPIO&#xff08;general purpose intput output&#xff09;是通用输入输出端口的简称&#xff0c;可以通过软件来控制其输入和输出。51 单片机芯片的 GPIO 引脚与外部设备连接起来&#xff0c;从而实现与外部通讯、 控制以及数据采集的功能。 1.1、GPIO分类 &a…

Linux入门系列--压缩与解压

一、前言 为了使传输的文件大小尽可能地小&#xff0c;我们采用压缩的方式生成压缩文件&#xff0c;然后将压缩包传输过去就可以了。衡量压缩方法地好坏主要有两点综合考量&#xff1a;一是压缩速度&#xff0c;二是压缩程度。很好理解&#xff0c;压缩一个文件&#xff0c;我…

云服务器重装系统后 一些报错与解决[ vscode / ssh / 子用户]

碰见的三个问题&#xff1a; 1.vscode连接失败 2.登录信息配置 3.新建子用户的一些设置 思考&#xff1a;遇见问题&#xff0c;第一反应 应该如何解决 目录 1. 错误 解决方法 原因 步骤 1&#xff1a;找到known_hosts文件并编辑 步骤 2&#xff1a;通过VSCode终端输入…

【包教包会】CocosCreator3.x——重写Sprite,圆角、3D翻转、纹理循环、可合批调色板、不影响子节点的位移旋转缩放透明度

一、效果演示 重写Sprite组件&#xff0c;做了以下优化&#xff1a; 1、新增自变换&#xff0c;在不影响子节点的前提下位移、旋转、缩放、改变透明度 新增可合批调色板&#xff0c;支持色相、明暗调节 新增圆角矩形、3D透视旋转、纹理循环 所有功能均支持合批、原生平台&…

南昌榉之乡托养机构解读:自闭症与看电视并无必然联系

在探讨自闭症的成因时&#xff0c;有人会问&#xff1a;自闭症是多看电视引起的吗&#xff1f;今天&#xff0c;就让我们来看看南昌榉之乡托养机构对此有何见解。 榉之乡大龄自闭症托养机构在江苏、广东、江西等地都有分校&#xff0c;一直致力于为大龄自闭症患者提供专业的支持…

卷积神经网络(CNN)的层次结构

卷积神经网络&#xff08;CNN&#xff09;是一种以其处理图像和视频数据的能力而闻名的深度学习模型&#xff0c;其基本结构通常包括以下几个层次&#xff0c;每个层次都有其特定的功能和作用&#xff1a; 1. 输入层&#xff08;Input Layer&#xff09;&#xff1a; 卷积神经网…

Milvus×OPPO:如何构建更懂你的大模型助手

01. 背景 AI业务快速增长下传统关系型数据库无法满足需求。 2024年恰逢OPPO品牌20周年&#xff0c;OPPO也宣布正式进入AI手机的时代。超千万用户开始通过例如通话摘要、新小布助手、小布照相馆等搭载在OPPO手机上的应用体验AI能力。 与传统的应用不同的是&#xff0c;在AI驱动的…

数据结构之二叉树详解:从原理到实现

1. 什么是二叉树&#xff1f; 二叉树&#xff08;Binary Tree&#xff09;是一种树形数据结构&#xff0c;其中每个节点最多有两个子节点&#xff0c;分别被称为左子节点和右子节点。二叉树可以用来表示层次关系&#xff0c;如文件目录、组织结构&#xff0c;或用于快速查找、…

CTF-PWN: WEB_and_PWN [第一届“吾杯”网络安全技能大赛 Calculator] 赛后学习(不会)

附件 calculate.html <!DOCTYPE html> <html lang"en"> <head><!-- 设置字符编码为 UTF-8&#xff0c;支持多语言字符集 --><meta charset"UTF-8"><!-- 设置响应式视图&#xff0c;确保页面在不同设备上自适应显示 --&…