Mybatis进阶提升-(一)Mybatis入门

news2024/11/15 8:24:13
前言

Mybatis是Java 项目开发使用率非常高的一款持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

同时Mybatis也是面试过程中被高频问到的一门技术,今天我就对Mybatis的重要原理及其源码进行一个分析。

Mybatis的入门案例

先写一个简单的入门案例,根据入门来分析Mybatis的执行原理

第一步:我们需要导入Mybatis的基础依赖

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>3.4.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>5.1.47</version>
</dependency>

第二步:然后准备一个mybatis的xml配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <properties resource="db.properties"></properties>
    <!--导入参数来源-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <!--用于生成可视的sql命令-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    <typeAliases>
            <!--如果下面这种,则自动扫描包pojo下的注解类的别名-->
        <package name="cn.whale.domian"></package>
    </typeAliases>
    <environments default="development">
        <environment id="development"><!--环境-->
            <transactionManager type="JDBC"/><!--事务管理器-->
            <dataSource type="POOLED"><!--数据源-->
                <property name="driver" value="${mysql.driver}"/>
                <property name="url" value="${mysql.url}"/>
                <property name="username" value="${mysql.username}"/>
                <property name="password" value="${mysql.password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mapper/StudentMapper.xml"/>
    </mappers>
</configuration>

数据库配置文件如下:

mysql.driver=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/test?useSSL=false
mysql.username=root
mysql.password=admin

第三步:然后编写SQL映射文件StudnetMapper.xml , 先来个简单的查询:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.whale.mapper.StudentMapper">

    <resultMap id="resultMap" type="cn.whale.domian.Student">
        <id column="id" property="id"/>
        <result column="username" property="username" />
    </resultMap>

    <select id="selectAll" resultType="cn.whale.domian.Student">
        select * from student
    </select>

     <select id="selectById" resultMap="resultMap">
        select id,username from student where id = #{id}
    </select>
</mapper>

第四步:编写实体类,和mapper映射器接口:

public interface StudentMapper {
    List<Student> selectAll();
    Student selectById(Long id);
}

第五步:编写测试类

public class StudentTest {

    @Test
    public void test() throws IOException {
        //加载配置
        InputStream inputStream= Resources.getResourceAsStream("mybatis-config.xml");
        //创建一个sqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //创建SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        
        Student student = sqlSession.selectOne("cn.whale.mapper.StudentMapper.selectById",1L);
        System.out.println(student);

        //使用最原始方式: namespace.statementid 执行
        List<Student>  objects = sqlSession.selectList("cn.whale.mapper.StudentMapper.selectAll");
        objects.stream().forEach( System.out::println);
        
  		//使用mapper映射器接口方式执行
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> students = mapper.selectAll();
        students.stream().forEach( System.out::println);
    }

}

入门案例开发完毕

Mybatis执行流程

下面是Mybatis的组成结构图,可能你看起来会有点懵逼,但是没关系,每个组件我们都会在后面说道,这里先混个眼熟就行了:

这里说几个比较重要的组件:

  • SqlSessionFactoryBuilder : 用到了建造者模式,用来解析配置文件和创建SqlSessionFactory
  • SqlSessionFactory : 用来创建SqlSession的工厂类,全局唯一。
  • SqlSession : 这个是MyBatis链接数据库的一次会话对象,如果Mybatis和数据库的链接中断,会话也就结束。所以SqlSession不应该是单利的。
  • Configuration :配置对象,主要包括mybatis-config.xml中的配置项目
  • Executor : 执行器,SqlSesion底层执行的时候用到

然后我们先来分析一下Mybatis的执行流程,根据上面的测试案例我们可以分为两部分。创建SqlSession和执行SqlSession。首先第一行代码 :InputStream inputStream= Resources.getResourceAsStream("mybatis-config.xml")
的作用是加载Mybatis配置文件,然后通过SqlSessionFactoryBuilder().build解析配置文件,以及mapper.xml 映射文件,并创建一个 SqlSessionFactory

然后是通过 sqlSessionFactory.openSession() 创建SqlSession,SqlSession是和数据库的一次会话对象。然后是通过sqlSession.selectList来执行语句,可以通过“namespace”加上“statementid”来找到要执行的SQL,也可以通过获取Mapper映射器接口的方式来执行,第二种方式最终会采用第一种方式去执行SQL。

执行完SQL会有结果集,然后会调用结果映射器处理结果集并返回,下面这个图是宏观层面的,Mybatis执行流程:

Mybatis执行流程如下 :
  1. 初始化阶段,加载配置文件
  2. 根据配置文件,创建SqlSessionFactoryBuider,执行build方法来创建SqlSessionFactory,build方法会解析配置文件,然后封装到一个Configuration对象中。Configuration会保存在创建的SqlSessionFactory
  3. 通过SqlSessionFactory来创建SqlSesion,底层会创建一个Executor执行器保存在SqlSession中
  4. 然后就是SqlSesson的执行了,SqlSession会调用 executor 执行器去执行
  5. 执行器中会创建一个StatementHandler,调用StatementHandler去执行Statement语句,当然执行Statement语句前涉及到参数的处理
  6. 执行完成之后使用ResultSetHandler映射结果为实体对象并返回

 源码解析-SqlSessionFactory的创建

代码入手肯定是new SqlSessionFactoryBuilder().build(inputStream),直接看源码见:org.apache.ibatis.session.SqlSessionFactoryBuilder#build(j…)

 public SqlSessionFactory build(InputStream inputStream) {
   return build(inputStream, null, null);
 }
 
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
    	//1. 创建一个XML配置的Builder,inputStream是通过Resources.getResourceAsStream加载的xml配置
    	//environment 和 properties都是null
    	//这一步会创建一个 Configuration对象
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      //2. parser.parse()解析一个configuration对象,然后创建SqlSessionFactory 
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        inputStream.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }

Mybatis的源码相比Spring来说要简单太多了,首先是通过Resources.getResourceAsStream加载的xml配置(inputStream)交给 XMLConfigBuilder ,创建一个XML解析器在new XMLConfigBuilder(…)代码中会创建Configuration对象。然后调用parser.parse() 解析配置,解析之后得到一个 Configuration 对象,交给builder方法去创建一个默认的DefaultSqlSessionFactory,同时把Configuraton对象保存给SqlSessionFactory。

XMLConfigBuilder是BaseBuilder的实现类,用作配置文件解析,针对于不同的构建目标还有不同的子类。

我们先来看parser.parse()方法的源码,然后再看build方法的源码,见org.apache.ibatis.builder.xml.XMLConfigBuilder#parse

  public Configuration parse() {
  	//parsed是用来判断是否已经解析过了
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    //解析配置,使用的是XPathParser解析器来解析一个configuration根节点。
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }

使用xPathParser解析器来解析配置文件,/configuration 就是mybatis-config.xml配置中的根节点,继续看parseConfiguration方法的源码:

 //解析配置项目
  private void parseConfiguration(XNode root) {
    try {
      //issue #117 read properties first
      //1.拿到properties元素,也就是  <properties resource="db.properties"></properties>
      propertiesElement(root.evalNode("properties"));
      //2.处理 <settings> 元素,并设置到Properties 对象中
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      loadCustomVfs(settings);
      //3.处理  <typeAliases> 用户配置的别名
      typeAliasesElement(root.evalNode("typeAliases"));
      //4.处理 <plugins> 插件
      pluginElement(root.evalNode("plugins"));
      //5.处理  <objectFactory type=""></objectFactory> 对象工厂
      objectFactoryElement(root.evalNode("objectFactory"));
      //用来装饰object的工厂
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      //6.处理反射工厂<reflectorFactory type=""/>
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      //把 settings  设置到COnfiguration对象中
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      //7.处理 <environments default="development"> , 数据源就在这个元素里面
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      //8.处理     <typeHandlers></typeHandlers> 类型处理器
      typeHandlerElement(root.evalNode("typeHandlers"));
      //9 处理mappers 映射文件
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }

这里我们看到,parseConfiguration方法对于mybatis配置文件中的所有项目都做了解析。我大致说一下每个步骤做了啥,具体的细节大家自己去断点看:

  1. propertiesElement(root.evalNode(“properties”)) : 解析 ,加载db.properties中的配置项目,然后会把properties设置到Configuration的variables存储起来

  2. Properties settings = settingsAsProperties(root.evalNode(“settings”)); 处理元素,转换为Properties ,然后通过 settingsElement(settings); 方法把settings中的配置保存到Configfiguration。见org.apache.ibatis.builder.xml.XMLConfigBuilder#settingsElement

  3. typeAliasesElement(root.evalNode(“typeAliases”)); :处理别名配置,如果是通过<package>方式配置别名,会把配置的实体类的class添加到Configuration对象的TypeAliasRegistry别名注册器中,TypeAliasRegistry内部维护了一个new HashMap<String, Class<?>>() ,就是以类的简单名字小写为key,以实体类的class为值来映射别名到HashMap。见org.apache.ibatis.type.TypeAliasRegistry
    如果是通过<typeAlias type="" 方式直接配置别名,那么就会注册到 BaseBuilderTypeAliasRegistry中。
    Configuration对象的构造器中默认映射了很多的内置类型的别名

  4. pluginElement(root.evalNode(“plugins”)); 处理插件配置,该方法会解析拦截器配置比如<plugin interceptor="cn.whale.interceptor.MyInterceptor" ></plugin>,然后使用反射创建实例,保存到Configuration的InterceptorChain interceptorChain 拦截器执行链中,这里使用到了责任链模式。拦截器我们后面单独写一篇文章来说。

  5. objectFactoryElement(root.evalNode(“objectFactory”)); 对象工厂处理解析,默认情况Mybaits在映射结果的时候会使用 DefaultObjectFactory 工厂利用反射来实例化实体类,你可以通过 <objectFactory type=""></objectFactory> 配置来创建自定义的实例化工厂。指定自己的实例化方式。该工厂类也是保存到configuration对象的ObjectFactory objectFactory 字段上。

  6. environmentsElement(root.evalNode(“environments”)); 环境处理<environments default="development">中主要包括事务 <transactionManager type="JDBC"/> 和 <dataSource type="POOLED">数据源的配置。environmentsElement方法中会根据type=JDBC 从TypeAliasRegistry中找到一个JdbcTransactionFactory事务工厂,使用反射创建实例,根据type="POOLED"找到一个PooledDataSource,使用反射创建实例,最后创建一个 Environment 环境对象,把 JdbcTransactionFactory 事务工厂 和PooledDataSource连接池保存到Environment中

  7. typeHandlerElement(root.evalNode(“typeHandlers”)); 处理类型处理器<typeHandlers></typeHandlers>,typeHandler是用来处理数据库的类型到Java的类型转换的,在 TypeHandlerRegistry的构造器中初始化了内置的很多的类型处理器,比如:VARCHAR类型转换为String就需要用到内置的 StringTypeHandler 处理器。当然我们也可以定义我们自己的类型处理器。

  8. mapperElement(root.evalNode(“mappers”)); 处理mapper映射文件,比如:<mapper resource="mapper/StudentMapper.xml"/>,方法内部会构建 XMLMapperBuilder 去解析xml文件,见org.apache.ibatis.builder.xml.XMLMapperBuilder#parse

  public void parse() {
      //解析 cache , cache,parameterMap,resultMap,sql,select|insert|update|delete
      //把SQL元素解析后封装成一个MappedStatement,存储到Configuration中的Map<String, MappedStatement>中
      if (!configuration.isResourceLoaded(resource)) {
        configurationElement(parser.evalNode("/mapper"));
        configuration.addLoadedResource(resource);
        //绑定Mapper接口
        bindMapperForNamespace();
      }
  
      parsePendingResultMaps();
      parsePendingCacheRefs();
      parsePendingStatements();
}

configurationElement方法底层会解析到mapper.xml文件,包括: cache,parameterMap,resultMap,sql,select | insert | update | delete等元素的解析。然后把SQL语句封装成MappedStatement,以 namespace.id 为 key把MappedStatement映射到Configuration中的Map<String, MappedStatement>中。
bindMapperForNamespace();方法中,会根据namespace找到mapper映射器接口,然后添加到 MapperRegistry中。

 private void bindMapperForNamespace() {
  String namespace = builderAssistant.getCurrentNamespace();
  if (namespace != null) {
    Class<?> boundType = null;
    try {
      boundType = Resources.classForName(namespace);
    } catch (ClassNotFoundException e) {
      //ignore, bound type is not required
    }
    if (boundType != null) {
      if (!configuration.hasMapper(boundType)) {
        // Spring may not know the real resource name so we set a flag
        // to prevent loading again this resource from the mapper interface
        // look at MapperAnnotationBuilder#loadXmlResource
        configuration.addLoadedResource("namespace:" + namespace);
        configuration.addMapper(boundType);
      }
    }
  }
}



MapperRegistry中维护了一个HashMap<Class<?>, MapperProxyFactory<?>>() ,key是mapper接口的class 类型,Value是一个MapperProxyFactory工厂,工厂中维护了mapper接口和接口中的方法如下:

public class MapperProxyFactory<T> {
  //mapper接口
private final Class<T> mapperInterface;
//接口中的方法
private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();

源码解析-SqlSession的创建

接下来我们分析 sqlSessionFactory.openSession(); ,该方法是通过SqlSessionFactory创建SqlSession见:org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSession()

@Override
  public SqlSession openSession() {
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  }

这里重configuration中获取默认的executor类型默认是simple,事务的提交方式指定为手动提交,然后交给 openSessionFromDataSource 去处理

// execType :执行器的类型  ; autoCommit :事务提交方式为手动提交
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      //1.从Configuration拿到配置对象,配置对象中包括 JdbcTranscationFactory 和 PooledDataSource
      final Environment environment = configuration.getEnvironment();
      //从environment总获取事务工厂
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      //2.通过事务工厂transactionFactory创建Transaction事务对象,默认实现是JdbcTransaction
      //JdbcTransaction中包括了Connection连接对象;DataSource 数据源;autoCommmit提交方式为false
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      //3.根据execType创建执行器,默认是SimpleExecutor,
      //SimpleExecutor继承了BaseExecutor,其中中维护了Transcation对象和PerpetualCache一级缓存一级configuration
      //SimpleExecutor被包装到 CachingExecutor 总,这里使用了装饰者模式
      //然后会把Executor添加到Configuration的interceptorChain拦截器链中
      final Executor executor = configuration.newExecutor(tx, execType);
      //4.创建SqlSession ,默认实现是DefaultSqlSession
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      //5.发生异常,关闭事务
      closeTransaction(tx); // may have fetched a connection so lets call close()
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

总结一下上面的方法的核心业务:

  1. Configuration拿到Environment对象,该对象中包括 JdbcTranscationFactory事务工厂 和 PooledDataSource 连接池

  2. 从Environment中获取事务工厂TransactionFactory ,通过事务工厂transactionFactory创建Transaction事务对象,默认实现是JdbcTransaction;JdbcTransaction中包括了Connection连接对象、DataSource 数据源、autoCommmit提交方式为false。JdbcTransaction中提供了事务的提交,回滚,关闭等方法。

  3. 然后根据execType创建执行器,默认是SimpleExecutor,SimpleExecutor继承了BaseExecutor,BaseExecutor维护了Transcation对象和PerpetualCache一级缓存、以及Configuration。
    如果配置了 cacheEnabled=ture,会用装饰器模式对 executor 进行包装,SimpleExecutor被包装到 CachingExecutor 中,这里使用了装饰者模式然后会把Executor添加到Configuration的interceptorChain拦截器链中

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
      executorType = executorType == null ? defaultExecutorType : executorType;
      executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
      Executor executor;
      //1.根据类型创建Executor
      if (ExecutorType.BATCH == executorType) {
        executor = new BatchExecutor(this, transaction);
      } else if (ExecutorType.REUSE == executorType) {
        executor = new ReuseExecutor(this, transaction);
      } else {
        executor = new SimpleExecutor(this, transaction);
      }
     
      if (cacheEnabled) {
       //2.如果开启了一级缓存,默认是true,把SimpleExecutor交给Cachin gExecutor ,装饰者模式
        executor = new CachingExecutor(executor);
      }
      //3.把executor加入Configuration的interceptorChain拦截器链中
      executor = (Executor) interceptorChain.pluginAll(executor);
      return executor;
}

Executor的继承体系如下:

4.创建SqlSession ,默认实现是DefaultSqlSession,其中维护了Configuration对象,Executor,autoCommit为false

5.在catch中关闭事务closeTransaction , 底层会调用connection.close关闭事务

这里要单独说一下三个Executor的区别:

  • SimpleExecutor:每执行一次 SQL就创建一个 Statement 对象,用 完立刻关闭 Statement 对象。
  • ReuseExecutor:它能够实现Statement的复用,执行 SQL,会先把SQL 作为 key 查找 Statement 对象, 存在就使用,不存在就创建,用完后把Statement放置于 Map 内不关闭, 供下一次使用。
  • BatchExecutor:执行 Update SQL(没有 select,不支持 select),将所 有 SQL都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存 了多个 Statement 对象,每个 Statement 对象都是 addBatch()完毕后,等待逐一执行 executeBatch()批处理。与 JDBC 批处理相同。

总结

总结一下Mybatis的初始化流程:

  1. SqlSessionFactoryBuilder 加载 mybatis-config.xml配置文件,通过XMLConfigBuilder将配置解析为Configuration,并创建一个SqlSessionFactory。
  • 对于<properties> 会解析为Properties并存储到Configuration的variables
  • 对于<settings> 会解析为Properties并设置到Configuration,比如:延迟加载配置,二级缓存配置等
  • 对于<typeAliases> 会解析解析类的class注册到Configuration的TypeAliasRegistry中,其中维护了一个new HashMap<String, Class<?>>(),TypeAliasRegistry默认以为了内置的别名。
  • 对于<plugins> 插件会注册到Configuration中的InterceptorChain拦截器链中,其中维护了List<Interceptor>
  • 对于 <objectFactory> 对象工厂则会覆盖Configuration中默认的DefaultObjectFactory,它是用来处理结果时,实例化实体类的工厂。
  • 对于<environments> 会解析出 transactionManager 和 dataSource ,事务使用的是JdbcTranscationFactoy。dataSource使用的是PooledDataSource。然后把JdbcTranscationFactory和PooledDataSource保存到Environment对象中,设置给Congifuration。
  • 对于<typeHandlers> 会解析配置的typeHandler的class注册到TypeHandlerRegistry,其中维护了一个ConcurrentHashMap来存储typeHandler。
  • 对于<mapper > mapper.xml映射文件会解析其中的 cache,parameterMap,resultMap,sql,select | insert | update | delete等元素的解析。然后把SQL语句封装成MappedStatement,以 namespace.id 为 key把MappedStatement映射到Configuration中的Map<String, MappedStatement>中。
  • 然后会根据namespace找到mapper映射器接口,然后添加到 MapperRegistry中。MapperRegistry中维护了一个HashMap<Class<?>, MapperProxyFactory<?>>() ,key是mapper接口的class 类型,Value是一个MapperProxyFactory工厂。

2.根据SqlSessionFactory创建SqlSession,默认实现是DefaultSqlSession,其中会创建好 Transaction (默认JdbcTransaction)事务对象,和 Executor (默认SimpleExecutor)执行器。

接下来就是sqlSession.selectList 执行SQL语句的代码分析了,这个我就留到下一章来吧。

文章结束啦,如果对你有帮助,请一定给个好评哦~~~

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

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

相关文章

python+selenium+unittest自动化测试框架

前言 关于自动化测试的介绍&#xff0c;网上已有很多资料&#xff0c;这里不再赘述&#xff0c;UI自动化测试是自动化测试的一种&#xff0c;也是测试金字塔最上面的一层&#xff0c;selenium是应用于web的自动化测试工具&#xff0c;支持多平台、多浏览器、多语言来实现自动化…

【实战】SpringBoot整合ffmpeg实现动态拉流转推

SpringBoot整合ffmpeg实现动态拉流转推 在最近的开发中&#xff0c;遇到一个 rtsp 协议的视频流&#xff0c;前端vue并不能直接播放&#xff0c;因此需要对流进行处理。在网上查阅后&#xff0c;ffmpeg和webrtc是最多的解决方案&#xff0c;但是使用webrtc的时候没成功&#x…

交通 | 不确定条件下旅行者路径选择的K阶均值偏差模型

摘要 现实世界中的交通网络通常具有随机特性&#xff0c;旅行时间可靠性自然成为影响旅行者路线选择的关键因素。在这种情况下&#xff0c;仅凭平均路径旅行时间可能无法充分代表路径对旅行者的吸引力&#xff0c;本研究引入了 k k k 阶均值偏差模型&#xff0c;用于优化大型…

紫辉创投开启Destiny of Gods首轮投资,伯乐与千里马的故事仍在继续

近日&#xff0c;上海紫辉创业投资有限公司&#xff08;以下简称“紫辉创投”&#xff09;宣布开启GameFi链游聚合平台Destiny of Gods首轮投资500,000美金&#xff0c;并与其达成全面战略及业务层合作&#xff0c;双方将协同布局链上生态&#xff0c;共同推动链游行业健康发展…

研究人员可以采用什么策略来批判性地评估和综合其领域的不同文献

VersaBot Literature Review 一键生成文献综述 研究人员可以采用各种策略来批判性地评估和综合其领域内的不同文献&#xff1b; 评估策略 审查方法论&#xff1a; 分析每个来源中使用的研究设计、样本选择、数据收集和分析方法。考虑每种方法的潜在偏见、局限性和优势。评估…

宝通科技携手昇腾技术首席陈仲铭,共探工业大模型与生态发展

在人工智能技术的浪潮中&#xff0c;宝通科技始终致力于探索和应用前沿技术&#xff0c;推动工业智能化的发展。7月26日&#xff0c;宝通科技特邀昇腾生态技术首席陈仲铭博士&#xff0c;为宝通员工带来了一场主题为《工业大模型与业界发展生态》的技术分享会。本次分享会不仅为…

从CNN到Transformer:基于PyTorch的遥感影像、无人机影像的地物分类、目标检测、语义分割和点云分类教程

原文链接&#xff1a;从CNN到Transformer&#xff1a;基于PyTorch的遥感影像、无人机影像的地物分类、目标检测、语义分割和点云分类教程https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247610610&idx5&snf973c3e430c89d6123ca8f4892086c55&chksmfa8271…

nameparser,一个强大的 Python 库!

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 大家好&#xff0c;今天为大家分享一个强大的 Python 库 - nameparser。 Github地址&#xff1a;https://github.com/derek73/python-nameparser 在处理用户数据时&#xff0c;尤其是涉及到用户姓名的场景下&am…

最佳需求管理工具:2024年10大主流工具

本文将分享2024年排名靠前的10款需求管理工具&#xff1a;PingCode、Worktile、Teambition、TAPD、禅道、明道云、CODING、Jama Connect、Jira、Codebeamer。 在选择需求管理工具时&#xff0c;你是否感到不知从何下手&#xff1f;面对市场上数不清的选项&#xff0c;确定哪一款…

远程办公访问优化指南:如何打造高效企业组网

当今数字化时代&#xff0c;远程办公已成为许多企业不可或缺的工作模式。面对地理位置分散、网络环境复杂等挑战&#xff0c;如何打造高效、稳定、安全的企业组网&#xff0c;成为企业IT部门亟需解决的问题。本文将为您提供一份远程办公访问优化指南&#xff0c;帮助您构建高效…

坐牢二十天 20240731(IO)

一.作业 1> 使用父子进程完成两个文件的拷贝 父进程拷贝前一半内容&#xff0c;子进程拷贝后一半内容 子进程结束后退出&#xff0c;父进程回收子进程的资源 #include <myhead.h> //定义求源文件长度的函数 int lenmain(const char *src,const char *dst) {int fd…

各类基于虚拟主机的应用及上线商城系统

一、基于域名访问 查看没有空行&#xff0c;没有注释的文件内容 [rootweb ~]# grep -Ev "#|^$" /usr/local/nginx/conf/nginx.conf [rootweb ~]# cp /usr/local/nginx/conf/nginx.conf /usr/local/nginx/conf/nginx.conf.bak [rootweb ~]# grep -Ev "#|^$"…

temu插件丨temu插件下载免费体验-特喵数据

在当今这个日新月异的电商时代&#xff0c;每一个细微的洞察都可能是商家决胜千里的关键。随着跨境电商平台的蓬勃兴起&#xff0c;Temu作为一股不可忽视的新兴力量&#xff0c;正以其独特的模式和强大的数据分析能力&#xff0c;引领着行业的新风尚。接下来看看让您的Temu店铺…

解决TensorFlow非法指令 (核心已转储)问题

背景 测试环境使用TensorFlow 1.14.0运行实体抽取和事项要素项目正常&#xff0c;打包项目和miniconda3环境进行部署&#xff0c;进行predict时报错。然后使用dockerfile生成环境镜像进行部署&#xff0c;发现仍报错。最后查资料解决该问题。 Using TensorFlow backend. 非法指…

《CSS创意项目实战指南》:点亮网页,从实战中掌握CSS的无限创意

CSS创意项目实战指南 在数字时代&#xff0c;网页不仅是信息的载体&#xff0c;更是艺术与技术的融合体。通过CSS&#xff0c;你可以将平凡的网页转变为引人入胜的视觉盛宴&#xff0c;让用户体验跃升至全新高度。《CSS创意项目实战指南》正是这样一本引领你探索CSS无限可能的…

【全志H616开发】SQLite打开/创建数据库的C接口

文章目录 打开/创建数据库的C接口函数介绍sqlite3_open函数sqlite3_close函数sqlite3_errmsg函数 代码示例 打开/创建数据库的C接口函数介绍 sqlite3_open函数 sqlite3_open 是 SQLite 数据库库中的一个函数&#xff0c;用于打开一个新的数据库连接。如果指定的数据库文件不存…

大厂linux面试题攻略一之网络基础

一、网络基础类面试题 1.简述ISO/OSI七层模型&#xff08;理论模型&#xff09;的分层与作用 ISO&#xff1a;国际标准化组织 OSI&#xff1a;开放系统互联 第7层应用层&#xff1a;为用户提供服务&#xff0c;给用户一个操作界面 第6层表示层&#xff1a;数据提供表示、加密…

从零入门 AI for Science(AI+药物) #Datawhale AI 夏令营 Task2

书接上回: 从零入门 AI for Science&#xff08;AI药物) #Datawhale AI 夏令营 Task2 前面了解了赛题&#xff0c;这个主要讲baseline代码&#xff0c;入门RNN和特征工程 解读官方baseline set_random_seed 统一设置随机种子 def set_random_seed(seed):"""设…

一万亿token!34亿张图像,扩大10倍!史上最大开源多模态数据集MINT-1T发布!

众所周知&#xff0c;现在训练AI最需要的是什么&#xff1f; 数据&#xff0c;数据&#xff0c;还是数据。——毕竟只有让AI学好了&#xff0c;AI才能好好地回答你的问题&#xff0c;否则就会答非所问。 但是喂给AI的数据&#xff0c;现在和GPU一样&#xff0c;成了紧缺资源。…

Java:类集(List,Vector,Set,HashMap)

类集:就是一个动态的对象数组,是对一些实现好的数据结构的包装,这样在使用时会非常方便,而且最重要的是类集框架本身不受对象数组长度的限制。 类集的特性:(1)这种框架是高性能的,对基本类集(动态数组、链接表、树和散列表)的实现是高效率的。所以一般很少需要人工对…