2024年 Java 面试八股文——Mybatis篇

目录

1. 什么是Mybatis?

2. 说说Mybatis的优缺点

3. Xml映射文件中,都有哪些标签

4. #{}和&{}有什么区别

5. Mybatis是如何进行分页的,分页插件的原理是什么

6. Mybatis是如何将sql执行结果封装为目标对象并返回的?

7. Mybatis是怎么将mapper与xml联系起来的

8. 如何执行批量插入(SqlSessionFactory)

9. Mybatis通过jdk动态代理的原理

10. Mybatis的工作原理(重要)

11. Mybatis实现一对一、一对多有几种方式

12. Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?

13. 说说Mybatis的缓存机制


MyBatis 是一个优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通的 Java 对象)为数据库中的记录。 

1. 什么是Mybatis?

Mybatis是持久层框架,半自动ORM框架,对JDBC操作数据库的过程进行了封装,使得开发者只需要关注sql本身。

JDBC操作数据库:加载JDBC驱动程序、提供JDBC连接的URL 、创建数据库的连接connection、创建一个Statement、执行SQL语句、处理结果、关闭JDBC对象

2. 说说Mybatis的优缺点

MyBatis 作为一个优秀的持久层框架,具有许多优点,但同时也存在一些潜在的缺点。以下是 MyBatis 的主要优缺点概述:

优点

  1. 灵活性:MyBatis 提供了非常灵活的方式来映射 SQL 语句到 Java 对象。通过 XML 配置文件或注解,你可以精确地控制 SQL 语句的生成,这使得在复杂或特定需求的场景中能够编写出精确的 SQL 语句。

  2. 避免 JDBC 编码:MyBatis 封装了 JDBC 的底层实现,开发者无需再编写大量的 JDBC 代码,如设置参数、处理结果集等,这大大减少了代码量,提高了开发效率。

  3. 动态 SQL:MyBatis 提供了强大的动态 SQL 功能,允许你根据参数的不同动态地生成 SQL 语句。这使得在构建复杂查询时更加灵活和方便。

  4. 解耦:MyBatis 将 SQL 语句从 Java 代码中分离出来,放在 XML 配置文件中,这使得代码更加清晰、易于维护。同时,这也使得数据库层的修改可以独立于应用层进行。

  5. 插件机制:MyBatis 提供了插件机制,允许你编写自定义的插件来拦截和修改 SQL 语句的执行过程。这为扩展 MyBatis 的功能提供了很大的便利。

  6. 良好的性能:MyBatis 在处理大量数据时仍然能够保持较高的性能。它提供了缓存机制来缓存查询结果,避免重复执行相同的 SQL 语句。

缺点

  1. SQL 语句编写:虽然 MyBatis 提供了灵活的方式来映射 SQL 语句,但这也要求开发者具备一定的 SQL 编写能力。如果 SQL 语句编写不当,可能会影响性能或引发错误。

  2. XML 配置文件:MyBatis 的配置主要基于 XML 文件,这增加了配置文件的复杂性和维护成本。对于不熟悉 XML 的开发者来说,可能会感到有些困难。

  3. 错误处理:MyBatis 没有提供完整的错误处理机制。当 SQL 语句执行出错时,通常需要开发者自行处理错误并给出相应的提示。

  4. 学习曲线:对于初学者来说,MyBatis 的学习曲线可能比较陡峭。需要了解 MyBatis 的核心概念、配置方式、映射规则等。

  5. 与 ORM 框架的对比:与一些 ORM(对象关系映射)框架相比,MyBatis 需要手动编写 SQL 语句,这可能会增加一些工作量。ORM 框架通常能够自动处理数据库表与 Java 对象之间的映射关系,但在某些复杂场景下可能不够灵活。

  6. 依赖数据库:MyBatis 的 SQL 语句是针对特定数据库的,如果更换数据库,可能需要修改大量的 SQL 语句和映射配置。这增加了迁移数据库的难度。

3. Xml映射文件中,都有哪些标签

  1. <mapper>:这是 XML 映射文件的根元素。它通常包含一个 namespace 属性,该属性指向映射文件对应的接口全限定路径。

  2. <select>:用于映射查询操作,包含 SELECT SQL 语句。

  3. <insert>:映射插入操作,包含 INSERT SQL 语句。

  4. <update>:映射更新操作,包含 UPDATE SQL 语句。

  5. <delete>:映射删除操作,包含 DELETE SQL 语句。

  6. <resultMap>:定义结果集映射规则,将数据库查询结果与 Java 对象属性进行映射。它通常包含 <id><result><association><collection> 等子标签。

  7. <sql>:定义可重用的 SQL 片段,可以被其他语句引用。然后通过 <include> 标签引入这个 SQL 片段。

  8. <include>:用于引用已定义的 SQL 片段。

  9. <selectKey>:用于在插入操作后获取生成的主键值,通常用于不支持自增主键的数据库。

  10. 动态 SQL 标签:这些标签用于构建动态 SQL 语句,可以根据条件参数动态生成不同的 SQL。包括 <if><choose><when><otherwise><where><set><foreach> 等。

    • <if>:根据条件包含或排除 SQL 片段。
    • <choose><when><otherwise>:类似于 Java 中的 switch-case 结构,根据条件选择执行不同的 SQL 片段。
    • <where>:用于简化 WHERE 子句的构建,自动去除多余的“AND”或“OR”关键字。
    • <set>:用于更新语句中动态包含需要更新的字段,同样可以自动去除多余的逗号。
    • <foreach>:用于遍历集合或数组,并构建 SQL 语句的 IN 条件等。
  11. <cache>:用于配置二级缓存。

4. #{}和&{}有什么区别

  1. #{}是预编译处理,${}是字符串替换
  2. 处理#{}时,会将sql中的#{}替换为?号,调用预编译PreparedStatement 的set方法来赋值
  3. 处理时${}时,就是把{}替换成变量的值
  4. #{}可以防止 SQL 注入,安全

5. Mybatis是如何进行分页的,分页插件的原理是什么

MyBatis 提供了两种主要的分页方式:逻辑分页和物理分页。但通常我们讨论的是物理分页,因为它更加高效。

MyBatis 的物理分页

物理分页是通过在 SQL 语句中添加 LIMIT 和 OFFSET 子句来实现的。MyBatis 并没有直接提供物理分页的内置支持,但我们可以使用 MyBatis 的插件机制来扩展其功能,实现物理分页。

分页插件的原理

分页插件(如 PageHelper)的原理主要基于 MyBatis 的拦截器(Interceptor)机制。以下是分页插件的基本工作原理:

  1. 配置插件:在 MyBatis 的配置文件(如 mybatis-config.xml)中配置分页插件,并设置相关参数,如数据库方言、分页参数等。
  2. 拦截 SQL 语句:当 MyBatis 执行查询操作时,分页插件会拦截 SQL 语句。这通常是通过实现 MyBatis 的 Interceptor 接口,并在 intercept 方法中完成拦截的。
  3. 修改 SQL 语句:分页插件会分析拦截到的 SQL 语句,并根据分页参数(如当前页码、每页显示数量)来修改 SQL 语句。具体来说,插件会在 SQL 语句的末尾添加 LIMIT 和 OFFSET 子句,以实现分页功能。
  4. 执行修改后的 SQL 语句:分页插件将修改后的 SQL 语句返回给 MyBatis,然后由 MyBatis 执行该 SQL 语句,并返回结果。
  5. 处理结果:MyBatis 将查询结果封装成 List 或其他形式,并返回给调用者。分页插件可能还需要对返回的结果进行处理,如计算总页数等。

注意事项

  • 性能考虑:在使用物理分页时,应尽量减少每页显示的记录数,以减少数据库查询的压力。
  • 插件选择:除了 PageHelper 之外,还有其他一些分页插件可供选择,如 MyBatis-Plus 的内置分页功能等。在选择插件时,应根据项目需求和团队习惯进行选择。
  • 配置参数:在使用分页插件时,应仔细配置相关参数,以确保插件能够正常工作。例如,需要正确设置数据库方言、分页参数等。
  • 兼容性:不同的分页插件可能具有不同的兼容性和限制。在使用插件之前,应仔细阅读文档并了解插件的兼容性和限制情况。

分页插件步骤:

项目中引入 PageHelper 的依赖。如果你使用 Maven,可以在 pom.xml 文件中添加以下依赖:

<dependency>  <groupId>com.github.pagehelper</groupId>  <artifactId>pagehelper-spring-boot-starter</artifactId>  <version>你的PageHelper版本号</version>  
</dependency>请注意将 你的PageHelper版本号 替换为当前可用的最新版本号。

 MyBatis 配置文件(如 mybatis-config.xml)或者 Spring Boot 项目的配置文件中(如 application.properties 或 application.yml)不需要特别的配置(如果使用了 Spring Boot starter 的话)。

使用 PageHelper 进行分页的 Java 代码示例:

import com.github.pagehelper.Page;  
import com.github.pagehelper.PageHelper;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.stereotype.Service;  import java.util.List;  @Service  
public class YourService {  @Autowired  private YourMapper yourMapper; // 假设这是你的 MyBatis Mapper 接口  public Page<YourEntity> findYourEntitiesByPage(int pageNum, int pageSize) {  // 设置分页信息,注意这里 pageNum 和 pageSize 的值是从 1 开始的,不是从 0 开始  PageHelper.startPage(pageNum, pageSize);  // 接下来执行的查询会进行分页,注意这里的查询语句会被 PageHelper 拦截并处理  List<YourEntity> list = yourMapper.selectYourEntities();  // 使用 Page 对象包装查询结果,Page 对象包含了当前页数据、总页数、总记录数等信息  Page<YourEntity> page = (Page<YourEntity>) list;  // 返回分页数据  return page;  }  
}

 

6. Mybatis是如何将sql执行结果封装为目标对象并返回的?

1.  使用resultMap标签

使用resultMap标签,做java对象名和数据库列名映射

2. 数据库别名

使用数据库别名

7. Mybatis是怎么将mapper与xml联系起来的

MyBatis 将 Mapper 接口与 XML 映射文件联系起来的原理主要依赖于 JDK 动态代理技术和 MyBatis 的内部实现机制。以下是具体的过程:

  1. Mapper 接口定义:首先,你需要定义一个 Mapper 接口,这个接口中包含了与数据库操作相关的方法。
  2. XML 映射文件:然后,你需要编写一个与 Mapper 接口对应的 XML 映射文件(通常以 .xml 为后缀)。这个文件包含了具体的 SQL 语句、参数类型、结果映射等信息。在 XML 文件中,<mapper> 标签的 namespace 属性通常设置为 Mapper 接口的全限定名,这样 MyBatis 就能知道这个 XML 文件是为哪个 Mapper 接口服务的。
  3. Mapper 代理类的生成:当 MyBatis 启动或 Mapper 接口被加载时,MyBatis 会使用 JDK 动态代理技术为这个 Mapper 接口生成一个代理类(通常是 MapperProxy)。这个代理类实现了 Mapper 接口,并拦截了接口中所有方法的调用。
  4. 方法调用与 SQL 执行:当应用程序调用 Mapper 接口中的方法时,实际上是在调用 Mapper 代理类的方法。Mapper 代理类会拦截这个方法的调用,并根据方法的名称和参数信息,在 XML 映射文件中找到对应的 SQL 语句。然后,MyBatis 会创建一个 SqlSession 对象,并将方法名和参数传递给 SqlSession 对象。SqlSession 对象会根据 XML 映射文件中的配置,解析 SQL 语句,设置参数,并执行 SQL 语句。
  5. 结果处理:执行完 SQL 语句后,SqlSession 对象会将查询结果返回给 Mapper 代理类。Mapper 代理类会根据 XML 映射文件中的结果映射规则(如 <resultMap> 标签),将查询结果转换成 Java 对象,并返回给应用程序。

8. 如何执行批量插入(SqlSessionFactory)

在 MyBatis 中执行批量插入通常涉及到 SqlSession 的使用,而不是直接使用 SqlSessionFactorySqlSessionFactory 是用于创建 SqlSession 的工厂类,而 SqlSession 是执行 SQL 语句的接口。

以下是如何使用 MyBatis 执行批量插入的步骤:

  1. 配置 MyBatis:确保你的 MyBatis 配置文件(如 mybatis-config.xml)和 Mapper XML 文件已经正确配置。
  2. 获取 SqlSessionFactory:从 MyBatis 配置文件中获取 SqlSessionFactory
  3. 打开 SqlSession:使用 SqlSessionFactory 打开一个新的 SqlSession
  4. 执行批量插入
    • 使用 Mapper 接口中的方法执行多次插入(如果 Mapper 方法支持批量插入)。
    • 或者,手动构建批量插入的 SQL 语句,并使用 SqlSession 的 insert() 方法执行。
  5. 提交事务:确保在批量插入后提交事务。
  6. 关闭 SqlSession:在完成所有操作后关闭 SqlSession

示例代码:

使用 MyBatis 执行批量插入的示例:

UserMapper.java
public interface UserMapper {  // 通常 Mapper 接口中不会有直接的批量插入方法,但你可以定义一个方法来执行自定义的 SQL  int batchInsertUsers(List<User> users);  
}

UserMapper.xml 

<mapper namespace="com.example.mapper.UserMapper">  <!-- 假设你有一个批量插入的 SQL 语句 -->  <insert id="batchInsertUsers" parameterType="list">  INSERT INTO users (column1, column2, ...)  VALUES   <foreach collection="list" item="user" separator=",">  (#{user.property1}, #{user.property2}, ...)  </foreach>  </insert>  
</mapper>

执行批量插入

try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) {  UserMapper userMapper = sqlSession.getMapper(UserMapper.class);  List<User> users = ... // 填充用户列表  // 假设 batchInsertUsers 是你的批量插入方法  userMapper.batchInsertUsers(users);  // 提交事务  sqlSession.commit();  
}

 

9. Mybatis通过jdk动态代理的原理

MyBatis 通过 JDK 动态代理实现 Mapper 接口与 SQL 语句之间的关联,其原理步骤:

  1. Mapper 接口定义
    • 开发者定义 Mapper 接口,该接口中包含了与数据库操作相关的方法。
  2. XML 映射文件
    • 开发者为每个 Mapper 接口编写对应的 XML 映射文件,文件中定义了 SQL 语句、参数类型、结果映射等信息。
    • XML 映射文件的 <mapper> 标签的 namespace 属性设置为 Mapper 接口的全限定名,这样 MyBatis 就知道这个 XML 文件是为哪个 Mapper 接口服务的。
  3. SqlSessionFactory 与 SqlSession
    • MyBatis 通过 SqlSessionFactoryBuilder 加载配置文件(如 mybatis-config.xml),然后创建 SqlSessionFactory。
    • SqlSessionFactory 负责创建 SqlSession,SqlSession 是执行 SQL 语句的接口。
  4. JDK 动态代理
    • 当应用程序通过 SqlSession 调用 Mapper 接口中的方法时,MyBatis 不会直接执行这些方法。
    • 相反,MyBatis 使用 JDK 动态代理为 Mapper 接口生成一个代理对象(MapperProxy)。
    • 这个代理对象实现了 Mapper 接口,并拦截了接口中所有方法的调用。
  5. 方法调用与 SQL 执行
    • 当应用程序调用 Mapper 接口中的方法时,实际上是调用了 Mapper 代理对象(MapperProxy)的方法。
    • Mapper 代理对象会根据方法的名称和参数信息,在 XML 映射文件中找到对应的 SQL 语句。
    • 然后,Mapper 代理对象会创建一个 SqlCommand 对象(包含 SQL 语句、参数等信息),并将其传递给 SqlSession 执行。
  6. 结果处理
    • SqlSession 执行 SQL 语句后,会将查询结果返回给 Mapper 代理对象。
    • Mapper 代理对象会根据 XML 映射文件中的结果映射规则(如 <resultMap>),将查询结果转换成 Java 对象,并返回给应用程序。
  7. 事务管理
    • MyBatis 支持事务管理,可以在 SqlSession 级别控制事务的提交和回滚。
    • 开发者可以通过 SqlSession 的 commit() 和 rollback() 方法来管理事务。

演示如何通过 JDK 动态代理实现 Mapper 接口与 SQL 语句之间的关联:

1. Mapper 接口定义

package com.example.mapper;  import com.example.model.User;  public interface UserMapper {  User selectUserById(int id);  void insertUser(User user);  // ... 其他方法 ...  
}

2. 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="com.example.mapper.UserMapper">  <select id="selectUserById" resultType="com.example.model.User">  SELECT * FROM users WHERE id = #{id}  </select>  <insert id="insertUser" parameterType="com.example.model.User">  INSERT INTO users (name, age) VALUES (#{name}, #{age})  </insert>  <!-- ... 其他 SQL 语句 ... -->  
</mapper>

3. MyBatis 配置文件 

<?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>  <environments default="development">  <environment id="development">  <transactionManager type="JDBC"/>  <dataSource type="POOLED">  <!-- 数据库连接信息 -->  <property name="driver" value="com.mysql.jdbc.Driver"/>  <property name="url" value="jdbc:mysql://localhost:3306/mydatabase"/>  <property name="username" value="root"/>  <property name="password" value="password"/>  </dataSource>  </environment>  </environments>  <mappers>  <mapper resource="com/example/mapper/UserMapper.xml"/>  <!-- ... 其他映射文件 ... -->  </mappers>  
</configuration>

4. SqlSessionFactory 与 SqlSession

import org.apache.ibatis.io.Resources;  
import org.apache.ibatis.session.SqlSession;  
import org.apache.ibatis.session.SqlSessionFactory;  
import org.apache.ibatis.session.SqlSessionFactoryBuilder;  import java.io.IOException;  
import java.io.Reader;  public class MyBatisDemo {  public static void main(String[] args) {  String resource = "mybatis-config.xml";  try (Reader reader = Resources.getResourceAsReader(resource)) {  SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);  try (SqlSession sqlSession = sqlSessionFactory.openSession()) {  // ... 使用 sqlSession 调用 Mapper 接口的方法 ...  }  } catch (IOException e) {  e.printStackTrace();  }  }  
}

5. JDK 动态代理

在 MyBatis 的内部实现中,当通过 sqlSession.getMapper(UserMapper.class) 获取 Mapper 接口的实例时,MyBatis 会使用 JDK 动态代理为 UserMapper 接口生成一个代理对象。但是,这部分代码是 MyBatis 框架内部实现的,我们不需要直接编写。

6. 方法调用与 SQL 执行

通过 sqlSession.getMapper(UserMapper.class) 获得的代理对象,我们可以像调用普通 Java 方法一样调用 Mapper 接口中的方法,MyBatis 会根据 XML 映射文件中的配置执行相应的 SQL 语句:

try (SqlSession sqlSession = sqlSessionFactory.openSession()) {  UserMapper userMapper = sqlSession.getMapper(UserMapper.class);  User user = userMapper.selectUserById(1); // 执行 SQL 查询

10. Mybatis的工作原理(重要)

 

MyBatis 的工作原理可以概括为以下几个重要步骤:

  1. mybatis应用程序通过SqlSessionFactoryBuilder从mybatis-config.xml配置文件(或者Java文件配置)来构建SqlSessionFactory(SqlSessionFactory是线程安全的)
  2. SqlSessionFactory实例通过openSession方法开启一个SqlSession
  3. 通过SqlSession实例的getMapper方法获得指定的Mapper对象并运行Mapper映射的SQL语句,完成对数据库的CRUD和事务提交,之后关闭SqlSession

11. Mybatis实现一对一、一对多有几种方式

  1. 一对一
    1.  联合查询:联合查询是几个表联合查询,只查询一次,通过在 resultMap 里面配置 association 节点配置一对一的类就可以完成
    2.  嵌套查询:先查一个表,根据这个表里面的结果的外键id,去再另外一个表里面查询数据,也是
    3.  通过 association 配置,但另外一个表的查询通过 select 属性配置
  2. 一对多
    1.  联合查询:联合查询是几个表联合查询,只查询一次,通过在 resultMap 里面配置 collection 节点配置一对一的类就可以完成
    2.  嵌套查询:先查一个表,根据这个表里面的结果的外键id,去再另外一个表里面查询数据,也是
    3.  通过 collection 配置,但另外一个表的查询通过 select 属性配置

12. Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?

MyBatis支持延迟加载

延迟加载(Lazy Loading)是一种加载数据的策略,它只在真正需要数据时才进行加载,从而有助于提高系统性能和减少资源消耗。在MyBatis中,延迟加载的实现原理如下:

  1. 配置延迟加载:在MyBatis的配置文件或映射文件中,需要设置lazyLoadingEnabled=true来开启延迟加载功能。
  2. 生成代理对象:当主对象(如一个实体对象)被查询时,MyBatis会生成一个代理对象。这个代理对象包含了对关联对象的引用,但并不会立即加载关联对象的数据。
  3. 触发时机:当应用程序需要访问代理对象中的关联属性时,延迟加载机制会被触发。此时,MyBatis会创建一个新的SQL语句来查询关联对象的数据。
  4. 填充数据:查询完成后,MyBatis会将查询到的数据填充到代理对象中,使得关联属性变得可用。

MyBatis的延迟加载主要有两种类型:

  • 全局延迟加载(全局懒加载):在MyBatis的配置文件中配置开启全局延迟加载。这样,对于所有的关联关系,都会按照配置进行延迟加载。
  • 按需延迟加载(按需懒加载):在映射文件中使用fetchType属性设置按需延迟加载。这样,只有在需要的时候才会进行延迟加载。

通过配置全局延迟加载或按需延迟加载,可以根据实际业务需求灵活地使用延迟加载功能,从而提高系统性能。

13. 说说Mybatis的缓存机制

Mybatis 有两级缓存,一级缓存是 SqlSession 级别的,默认开启,无法关闭;二级缓
存是 Mapper 级别的,二级缓存默认是没有开启的,但是手动开启

1. 一级缓存:基础 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,Session 中的所有 Cache 就将清空

2. 二级缓存其存储作用域为 Mapper(Namespace),使用二级缓存属性类需要实现Serializable 序列化接口

3. 对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存 Namespaces)的进行了 C(增加)/U(更新)/D(删除)操作后,默认该作用域下所有 select 中的缓存将被 clear.需要在 setting 全局参数中配置开启二级缓存,如下 conf.xml 配置:

  

当我们的配置文件配置了 cacheEnabled=true 时,就会开启二级缓存,二级缓存是
mapper 级别的,如果你配置了二级缓存,那么查询数据的顺序应该为:二级缓存→一级缓
存→数据库。

 

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

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

相关文章

vscode远程免密ssh原理与实操方法

什么是SSH SSH是一种加密协议&#xff0c;全称为Secure Shell&#xff0c;用于安全地远程登录到服务器或其他远程设备上执行命令或传输文件。它提供了一种安全的加密通信机制&#xff0c;使得远程登录和文件传输等操作不会被恶意攻击者窃取或篡改&#xff0c;确保了数据的保密…

5.3 进程间通信管道和共享内存

每次打开一个网页都是一个进程 进行管道之间通信的方式&#xff1a;以前学到的有可以在磁盘上开辟空间进行交互&#xff0c;也可以在内存中开辟缓冲区进行交互。 一定注意可读性 管道就是属于在内存中的一片缓冲区&#xff0c;管道可以在命令行中创建管道mkfifo也可以在vim中…

(优作)基于STM32蓝牙控制小车系统设计(硬件+源代码+论文)竞赛作品

基于STM32蓝牙控制小车系统设计&#xff08;硬件源代码论文&#xff09;竞赛作品 基于意法半导体与ARM公司生产的STM32F4 DISCOVERY开发板的集电机驱动模块、电源管理模块、stm32f4主控模块、蓝牙串口通信模块、android控制端模块。电机驱动模块使用了两个L298N芯片来驱动4路电…

基于SSM SpringBoot vue教务排课系统

基于SSM SpringBoot vue教务排课系统 系统功能 登录 个人中心 学生信息管理 教师信息管理 课室信息管理 班级信息管理 系别信息管理 专业信息管理 课程信息管理 选课信息管理 课表信息管理 开发环境和技术 开发语言&#xff1a;Java 使用框架: SSM(Spring SpringMVC Myba…

【Qt基础教程】QGridLayout与QFormLayout

文章目录 前言一、QGridLayout二、QFormLayout总结 前言 在Qt应用程序开发中&#xff0c;布局管理器是一种关键的技术&#xff0c;用于管理和安排窗口小部件的位置和大小。QGridLayout和QFormLayout是两个常用的布局管理器&#xff0c;它们分别适用于网格状和表单状的界面布局…

创新指南 | 围绕“获客、转化、增长”三要素,构建 PLG线上运营 体系

构建一个高效的 PLG线上运营 体系&#xff0c;对于任何希望利用产品本身优势推动业务增长的公司来说都是至关重要的。PLG模式通过产品本身的力量来驱动用户增长、促进转化并提升用户体验&#xff0c;从而实现自然而持续的增长。 一、PLG线上运营的整体框架和思路 PLG线上运营 …

百度网盘里的文件怎么打印?

在日常生活和工作中&#xff0c;我们经常需要打印各种文件&#xff0c;包括学习资料、工作报告、合同文件等。有时候&#xff0c;这些文件保存在百度网盘等云存储服务中&#xff0c;我们该如何方便地打印出来呢&#xff1f;今天&#xff0c;就为大家介绍一种便捷的方法——通过…

InfiniFlow 創始人兼CEO張穎峰確認出席“邊緣智能2024 - AI開發者峰會”

隨著AI技術的迅猛發展&#xff0c;全球正逐步進入邊緣計算智能化與分布式AI深度融合的新時代&#xff0c;共同書寫著分布式智能創新應用的壯麗篇章。邊緣智能&#xff0c;作為融合邊緣計算和智能技術的新興領域&#xff0c;正逐漸成為推動AI發展的關鍵力量。借助分布式和去中心…

[数据结构]———归并排序

具体代码&#xff1a;在gitee仓库&#xff1a;登录 - Gitee.com 目录 ​编辑 1.基本思想&#xff1a; 2. 代码解析 1.分析 2.逻辑图 3.运行结果 1.基本思想&#xff1a; 归并排序&#xff08;MERGE-SORT&#xff09;是建立在归并操作上的一种有效的排序算法,该算法是采用分…

7个策略,让你的可视化大屏打动人心!

要打动人心的可视化大屏&#xff0c;可以采取以下策略&#xff1a; 引人入目的设计&#xff1a; 选择鲜明而吸引人的颜色和视觉效果&#xff0c;使用引人注目的动画和过渡效果&#xff0c;以及吸引眼球的图形和图案设计。通过精心设计的布局和排版&#xff0c;确保信息清晰可…

leetcode_43.字符串相乘

43. 字符串相乘 题目描述&#xff1a;给定两个以字符串形式表示的非负整数 num1 和 num2&#xff0c;返回 num1 和 num2 的乘积&#xff0c;它们的乘积也表示为字符串形式。 注意&#xff1a;不能使用任何内置的 BigInteger 库或直接将输入转换为整数。 示例 1: 输入: num1 &q…

Static内存分析

title: Static内存分析 tags: Java基础知识 abbrlink: 49066 date: 2021-04-25 19:06:41 Static内存分析 一.基础须知 1.静态变量 1&#xff09;定义&#xff1a; 在一个Java类中&#xff0c;可以使用static关键字来修饰全员变量&#xff0c;该变量被称作静态变量 2&…

【linux】重定向

重定向 什么是重定向如何实现一个简单的重定向关于重定向的系统调用接口 注意&#xff1a;在看这篇博客之前&#xff0c;最好是要对文件在系统中是如何被打开的以及操作系统是如何管理文件有一个初步了解&#xff0c;如果不了解的话&#xff0c;可以看看这篇博客《初步认识文件…

苹果CEO对未来一代人工智能投资持乐观态度

尽管在动荡的第二季度&#xff0c;苹果的收入和iPhone销量有所下降&#xff0c;但其新兴的人工智能技术可能会带来急需的提振。 在5月2日的电话财报会议上&#xff0c;苹果公布季度收入为908亿美元&#xff0c;比去年下降4%。iPhone的收入也下降了10%&#xff0c;至460亿美元。…

无言:破局之道:顿悟+坚持——早读(逆天打工人爬取热门微信文章解读)

致无言 引言Python 代码第一篇 洞见 7年跟踪调查北京28个精英家庭&#xff1a;为什么顶尖大学孩子大多来自有钱家庭&#xff1f;第二篇 人民日报 来了&#xff01;新闻早班车要闻社会政策 结尾 控制你的情绪 否则它将控制你 在紧张的游戏中 控制情绪 避免冲动行为 是每个玩家的…

Linux中动态库的用法及优缺点?怎样制作动态库和静态库?

一、什么是gcc gcc的全称是GNU Compiler Collection&#xff0c;它是一个能够编译多种语言的编译器。最开始gcc是作为C语言的编译器&#xff08;GNU C Compiler&#xff09;&#xff0c;现在除了c语言&#xff0c;还支持C、java、Pascal等语言。gcc支持多种硬件平台. 在 Linux…

地震学角度说明横波纵波哪个才是垂直于传播方向振动

上面两幅图片&#xff0c;第一个是横波&#xff0c;第二个是纵波。死记硬背过一段时间总会忘记哪个是哪个。现通过地震学对横波纵波的定义来说明&#xff0c;如何从图形一眼判断横波和纵波。 横波&#xff1a; 因为地震的发生是由于地球内部的板块运动造成的&#xff0c;所以…

数据分析必备:一步步教你如何用numpy改变数据处理(2)

1、NumPy 简单入门教程 NumPy是Python中的一个运算速度非常快的一个数学库&#xff0c;它非常重视数组。它允许你在Python中进行向量和矩阵计算&#xff0c;并且由于许多底层函数实际上是用C编写的&#xff0c;因此你可以体验在原生Python中永远无法体验到的速度。 NumPy绝对是…

【软件开发规范篇】JAVA后端开发异常处理规范

作者介绍&#xff1a;本人笔名姑苏老陈&#xff0c;从事JAVA开发工作十多年了&#xff0c;带过大学刚毕业的实习生&#xff0c;也带过技术团队。最近有个朋友的表弟&#xff0c;马上要大学毕业了&#xff0c;想从事JAVA开发工作&#xff0c;但不知道从何处入手。于是&#xff0…

01 Activiti 7:步骤

01 Activiti 7&#xff1a;步骤 1. 整合Activiti2. 业务流程建模3. 部署业务流程4. 启动流程实例5. 查询待办任务6. 处理待办任务7. 结束流程 1. 整合Activiti 业务系统使用 Activiti 来对系统的业务流程进行自动化管理。为了方便业务系统访问&#xff08;操作&#xff09;Act…