MyBatis3源码深度解析(十二)MyBatis的核心组件(一)Configuration

文章目录

  • 第四章 MyBatis的核心组件
    • 4.1 使用MyBatis操作数据库
    • 4.2 MyBatis核心组件
    • 4.3 Configuration组件
      • 4.3.1 属性
      • 4.3.2 设置
      • 4.3.3 类型别名
      • 4.3.3 类型处理器
      • 4.3.5 对象工厂
      • 4.3.6 插件
      • 4.3.7 配置环境
      • 4.3.8 映射器

第四章 MyBatis的核心组件

4.1 使用MyBatis操作数据库

在研究MyBatis的核心组件之前,有必要了解一下如何使用MyBatis操作数据库。本文使用maven创建一个简单的示例项目来演示。

(1)准备数据库环境:使用MySQL数据库,创建一个新的database:mybatis_demo,新的表user,并插入数据。

CREATE DATABASE mybatis_demo;
USE mybatis_demo;
CREATE TABLE `user` (`id` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,`name` VARCHAR(20) DEFAULT NULL,`age` INT(11) DEFAULT NULL,`phone` VARCHAR(20) DEFAULT NULL,`birthday` DATETIME DEFAULT NULL
)
insert into user (name, age, phone, birthday) values('孙悟空', 1500, '18705464523', '0000-01-01');
insert into user (name, age, phone, birthday) values('猪八戒', 1000, '15235468789', '0500-03-10');

(2)创建maven项目,导入相关依赖。

<dependencies><!--单元测试--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>compile</scope></dependency><!--mybatis--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.15</version></dependency><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency>
</dependencies>

(3)编写MyBatis主配置文件mybatis-config.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><settings><!--支持返回自动生成主键--><setting name="useGeneratedKeys" value="true"/><!--支持实体名驼峰原则--><setting name="mapUnderscoreToCamelCase" value="true"/></settings><!--别名处理--><typeAliases><package name="com.star.mybatis.entity"/></typeAliases><!--环境信息--><environments default="dev"><environment id="dev"><!--事务管理器--><transactionManager type="JDBC"/><!--数据源:用户名和密码需要改成自己定义的--><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mybatis_demo"/><property name="username" value="******"/><property name="password" value="******"/></dataSource></environment></environments><!--Mapper映射文件--><mappers><mapper resource="mapper/UserMapper.xml"/></mappers>
</configuration>

MyBatis主配置文件用于配置MyBatis框架的配置信息,这些参数会改变MyBatis的运行时行为。

(4)编写Java实体User。

public class User {private Integer id;private String name;private Integer age;private String phone;private Date birthday;// constructor getter setter ...
}

(5)编写UserMapper接口。

public interface UserMapper {List<User> selectAll();@Select("select * from user where id = #{id, jdbcType=INTEGER}")User selectById(@Param("id") Integer id);}

为了演示方便,这里使用两种方式配置SQL语句,selectAll()方法用XML的方式,selectById()方法用注解的方式。

(6)编写映射文件UserMapper.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.star.mybatis.mapper.UserMapper"><select id="selectAll" resultType="User">select * from user</select></mapper>

(7)编写单元测试。

@Test
public void testMybatis() throws IOException {// 读取配置文件Reader reader = Resources.getResourceAsReader("mybatis-config.xml");// 创建会话SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);SqlSession sqlSession = sqlSessionFactory.openSession();// 获取Mapper接口UserMapper userMapper = sqlSession.getMapper(UserMapper.class);// 操作数据库List<User> userList = userMapper.selectAll();userList.forEach(System.out::println);System.out.println("---------");User user = userMapper.selectById(1);System.out.println(user.toString());
}

(8)执行单元测试,控制台打印结果。

User{id=1, name='孙悟空', age=1500, phone='18705464523', birthday=Thu Jan 01 00:00:00 CST 1}
User{id=2, name='猪八戒', age=1000, phone='15235468789', birthday=Fri Mar 10 00:00:00 CST 500}
---------
User{id=1, name='孙悟空', age=1500, phone='18705464523', birthday=Thu Jan 01 00:00:00 CST 1}

如示例代码所示,SqlSession是MyBatis提供的与数据库交互的接口,其实例通过工厂模式创建。

为了创建SqlSession对象,首先需要创建SqlSessionFactory对象,而SqlSessionFactory对象的创建又依赖于SqlSessionFactoryBuilder类,该类提供了一系列重载的build()方法,将主配置文件的输入流作为参数传入SqlSessionFactoryBuilder对象的build()方法,则可以返回一个SqlSessionFactory对象。

有了SqlSessionFactory对象后,调用其openSession()方法即可获得一个与数据库建立连接的SqlSession实例。

调用SqlSession对象的getMapper()方法创建一个Mapper接口的动态代理对象,然后调用代理实例的方法即可完成与数据库的交互。

需要注意的是,MyBatis来源于iBatis项目,依然保留了iBatis执行Mapper的方式,例如:

// 兼容iBatis执行Mapper的方式
List<User> userList = sqlSession.selectList("com.star.mybatis.mapper.UserMapper.selectAll");

另外,MyBatis还提供了一个SqlSessionManager类,同样可以用于与数据库的交互,例如可以把单元测试方法修改成如下:

@Test
public void testSqlSessionManager() throws IOException {Reader reader = Resources.getResourceAsReader("mybatis-config.xml");// 创建SqlSessionManager对象SqlSessionManager sqlSessionManager = SqlSessionManager.newInstance(reader);sqlSessionManager.startManagedSession();// 通过SqlSessionManager获取Mapper接口UserMapper userMapper = sqlSessionManager.getMapper(UserMapper.class);List<User> userList = userMapper.selectAll();userList.forEach(System.out::println);System.out.println("---------");User user = userMapper.selectById(1);System.out.println(user.toString());
}

如示例代码所示,SqlSessionManager使用了单例模式,在整个应用程序中只存在一个实例。通过该类的静态方法newInstance()即可获取SqlSessionManager的实例。

SqlSessionManager实现了SqlSessionFactory和SqlSession接口,因此可以替代SqlSession完成与数据库的交互。

4.2 MyBatis核心组件

在上面的示例项目中,有一个比较核心的MyBatis组件——SqlSession,它是面向用户的操作数据库的API。除此之外,MyBatis还有一些其他的核心组件,其执行流程如下图所示:

这些核心组件的作用大致描述如下:

  • Configuration

用于描述MyBatis的主配置信息。其他组件需要获取配置信息时,可以直接通过Configuration对象获取。MyBatis在应用启动时,会读取主配置文件mybatis-config.xml中的配置,并将这些配置注册到Configuration组件中,其他组件需要这些配置时,可以直接通过Configuration对象获取。

  • MappedStatement

用于描述Mapper中的SQL配置信息,是对Mapper XML配置文件中的、、、等标签或者@Select、@Update、@Delete、@Insert等注解的封装。

  • SqlSession

是MyBatis提供的面向用户的API,表示和数据库交互时的会话对象,用于完成数据库的增删改查功能。SqlSession是Executor组件的外观,目的是对外提供易于理解和使用的数据库操作接口。

  • Executor

Executor是MyBatis的SQL执行器,MyBatis中对数据库的所有增删改查操作都是由Executor组件完成的。

  • StatementHandler

StatementHandler封装了对JDBC的Statement对象的操作,比如为Statement对象设置参数、调用Statement接口提供的方法与数据库交互等。

  • ParameterHandler

当MyBatis使用的Statement类型为PreparedStatement和CallableStatement时,ParameterHandler用于为Statement对象的参数占位符设置值。

  • ResultSetHandler

ResultSetHandler封装了对JDBC中的ResultSet对象的操作,当执行SQL类型为SELECT语句时,ResultSetHandler用于将查询结果转换为Java对象。

  • TypeHandler

TypeHandler是MyBatis的类型处理器,用于处理Java类型与JDBC类型之间的映射。它能够根据Java类型调用PreparedStatement或CallableStatement对象的setXXX()方法为Statement对象设置值,而且能够根据Java类型调用ResultSet对象的getXXX()方法获取SQL执行结果。

MyBatis操作数据库的过程大致如下:

  1. SqlSession是用户层面的API,它是Executor组件的外观,目的是为用户提供更友好的数据库操作接口。
  2. 真正执行SQL操作的是Executor组件,它是SQL执行器,会使用StatementHandler组件对JDBC的Statement对象进行操作。
  3. 当Statement类型为PreparedStatement和CallableStatement时,会通过ParameterHandler组件为参数占位符赋值。
  4. ParameterHandler组件会根据Java类型找到对应的TypeHandler对象,TypeHandler中会通过Statement对象提供的setXXX()方法为Statement对象中的参数占位符设置值。
  5. StatementHandler组件使用JDBC中的Statement对象与数据库完成交互后,当SQL语句类型为SELECT时,通过ResultSetHandler组件从Statement对象中获取ResultSet对象,然后将ResultSet对象转换为Java对象。

4.3 Configuration组件

MyBatis框架的配置信息有两种,一种是配置MyBatis框架属性的主配置文件,另一种是配置执行SQL语句的Mapper配置文件。

Configuration组件的作用是描述MyBatis主配置文件的信息,即mybatis-config.xml文件。

4.3.1 属性

在mybatis-config.xml文件中,属性使用标签进行配置,其特点是可外部配置可动态替换。例如:

<!-- mybatis-config.xml -->
<properties resource="C:\workspace\mybatis_demo2\config\config.properties"><property name="username" value="dev_user"/><property name="password" value="*****"/>
</properties>

可外部配置的意思是,属性既可以在标签下使用标签直接配置,也可以通过resource属性引用外部的一个properties文件。如果两种方式都配置了属性,则优先加载标签下的属性,再加载resource路径下properties文件中的属性,并覆盖已有的同名属性。

可动态替换的意思是,标签下设置的属性,可以在整个配置文件中用于替换需要动态配置的属性值。例如,在配置文件的其它位置使用<property name="username" value="${username}"/>时,${username}会被替换为dev_user

在Configuration组件中,组合了一个Properties对象,用于保存属性配置。

源码1org.apache.ibatis.session.Configurationprotected Properties variables = new Properties();

借助Debug工具,可以看到属性均被加载到Configuration组件中:

4.3.2 设置

在mybatis-config.xml文件中,属性使用标签进行配置,这些设置属性的值会改变MyBatis运行时的行为,因此非常重要。

相对应的,Configuration组件定义了一系列属性来保存这些设置属性。例如:

<!-- mybatis-config.xml -->
<settings><!--支持返回自动生成主键--><setting name="useGeneratedKeys" value="true"/><!--支持自动驼峰命名规则--><setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

对应到Configuration组件定义的属性是:

源码2org.apache.ibatis.session.Configurationpublic class Configuration {protected boolean mapUnderscoreToCamelCase;protected boolean useGeneratedKeys;// ......
}

除了 源码1 中列出的2个设置属性,还有一系列属性,这些属性的作用、默认值等可以参见 W3Cschool的文档-MyBatis教程-XML配置 中的一张表。

借助Debug工具,可以看到设置属性被加载到Configuration组件中:

在这里插入图片描述

4.3.3 类型别名

类型别名就是为Java类型设置一个短的名字,用来减少类的完全限定名的冗余。例如使用User作为com.star.mybatis.entity.User的别名:

在mybatis-config.xml文件中,类型别名使用标签进行配置。例如:

<!-- mybatis-config.xml -->
<typeAliases><typeAlias alias="User" type="com.star.mybatis.entity.User"/>
</typeAliases>

也可以指定一个包名,MyBatis会在包下面搜索需要的Java对象,例如:

<!-- mybatis-config.xml -->
<typeAliases><package name="com.star.mybatis.entity"/>
</typeAliases>

在没有@Alias注解的情况下,MyBatis会使用Java对象的首字母小写的非限定类名来作为它的别名,例如com.star.mybatis.entity包下的User类的别名为user;若该类有@Alias注解,则别名为其注解值。

@Alias("user")
public class User {...}

MyBatis本身已经为许多常见的Java类型内置了相应的类型别名,如下表:

在这里插入图片描述

对应到Configuration组件,组合了一个类型别名注册器,用于注册所有的类型别名。其源码如下:

源码3org.apache.ibatis.session.Configuration// 用于注册所有的类型别名
protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();

借助Debug工具,可以看到加载到Configuration组件中的别名有81个,其中包括自定义的User类的别名:

4.3.3 类型处理器

类型处理器的作用在于,MyBatis在预处理语句(PreparedStatement)中设置一个参数时,或者从ResulrSet结果集中取出一个值时,都会用类型处理器将获取的值以合适的方式转换成JDBC类型或Java类型。

在mybatis-config.xml文件中,类型别名使用标签进行配置。例如:

<!-- mybatis-config.xml -->
<typeHandlers><typeHandler handler="com.star.mybatis.handler.ExampleTypeHandler"javaType="String"jdbcType="VARCHAR"/>
</typeHandlers>

MyBatis有许多默认的类型处理器实现,基本涵盖Java全部基本数据类型,如下表所示:

另外,类型处理器支持重写,或创建自定义的类型处理器来处理不支持的或非标准的类型

具体做法是:实现 org.apache.ibatis.type.TypeHandler接口, 或继承org.apache.ibatis.type.BaseTypeHandler,然后在主配置文件mybatis-config.xml中使用标签进行配置。例如:

@MappedTypes({String.class})
@MappedJdbcTypes({JdbcType.VARCHAR})
public class ExampleTypeHandler extends BaseTypeHandler {...}

那如何确定这个自定义的类型处理器是处理什么类型的呢?

设置类型处理器处理的Java类型:

  • 在类型处理器的配置元素上增加一个javaType属性,如:<typeHandler javaType="String"/>
  • 在类型处理器的类上增加一个@MappedTypes注解,如:@MappedTypes({String.class})。 如果同时配置javaType属性和@MappedTypes注解,则注解方式将被忽略。

设置类型处理器处理的JDBC类型:

  • 在类型处理器的配置元素上增加一个jdbcType属性,如:<typeHandler jdbcType="VARCHAR"/>
  • 在类型处理器的类上增加一个@MappedJdbcTypes注解,如:@MappedJdbcTypes({JdbcType.VARCHAR})。 如果同时配置jdbcType属性和@MappedJdbcTypes注解,则注解方式将被忽略。

最后,还可以通过设置包名让MyBatis自动查找类型处理器,此时只能通过注解方式来指定类型处理器要处理的Java类型和JDBC类型。例如:

<!-- mybatis-config.xml -->
<typeHandlers><package name="com.star.mybatis.handler"/>
</typeHandlers>

在Configuration组件中,组合了一个类型处理器的注册器,用于注册所有的类型处理器。

源码4org.apache.ibatis.session.Configuration// 用于注册所有的类型处理器
protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry(this);

借助Debug可知,Configuration组件中最终注册的类型处理器一共有41个,包括1个自定义的ExampleTypeHandler:

4.3.5 对象工厂

MyBatis每次创建结果映射对象的新实例时,会使用一个对象工厂(ObjectFactory)实例来完成。 默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认构造方法,要么在参数映射存在的时候通过参数构造方法来实例化。

在mybatis-config.xml文件中,对象工厂使用标签进行配置。例如:

<!-- mybatis-config.xml -->
<objectFactory type="com.star.mybatis.factory.ExampleObjectFactory"><property name="name" value="test"/>
</objectFactory>

通过创建自定义的对象工厂,可以覆盖对象工厂的默认行为。例如:

public class ExampleObjectFactory extends DefaultObjectFactory {// 处理默认构造方法@Overridepublic <T> T create(Class<T> type) {return super.create(type);}// 处理带参数的构造方法@Overridepublic <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {return super.create(type, constructorArgTypes, constructorArgs);}// 配置ObjectFactory属性@Overridepublic void setProperties(Properties properties) {}}

在Configuration组件中,组合了一个ObjectFactory对象,用于保存对象工厂,默认实现类为DefaultObjectFactory。

源码5org.apache.ibatis.session.Configurationprotected ObjectFactory objectFactory = new DefaultObjectFactory();

借助Debug可知,Configuration组件最终会将自定义的对象工厂注册到Configuration组件中:

4.3.6 插件

MyBatis允许在SQL语句执行过程中的某一点使用插件进行拦截调用。默认情况下,允许使用插件来拦截的方法包括:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

自定义一个插件比较简单,只需实现Interceptor接口,并指定了想要拦截的方法:

@Intercepts({@Signature(type= Executor.class,method = "update",args = {MappedStatement.class, Object.class})})
public class ExamplePlugin implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {return invocation.proceed();}}

在mybatis-config.xml文件中,插件使用标签进行配置。例如:

<!-- mybatis-config.xml -->
<plugins><plugin interceptor="com.star.mybatis.plugin.ExamplePlugin"><property name="name" value="ExamplePlugin"/></plugin>
</plugins>

在Configuration组件中,组合了一个拦截器链,用于存放自定义的插件。

源码6org.apache.ibatis.session.Configurationprotected final InterceptorChain interceptorChain = new InterceptorChain();

借助Debug可知,Configuration组件最终会注册自定义的插件:

4.3.7 配置环境

MyBatis可以配置成适应多种环境,例如,开发、测试和生产环境有不同的配置。

但要注意,尽管可以配置多个环境,但每个SqlSessionFactory实例只能选择其中一个环境。因此,有几个数据库需要连接,就需要创建几个SqlSessionFactory实例。

在mybatis-config.xml文件中,配置环境使用标签进行配置。例如:

<!-- mybatis-config.xml -->
<environments default="dev"><environment id="dev"><transactionManager type="JDBC"><property name="..." value="..."/></transactionManager><dataSource type="POOLED"><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment><environment id="test">...</environment><environment id="prod">...</environment>...
</environments>

如例子所示,标签的default属性要和标签的id属性相匹配,选择出当前生效的环境,生效的环境才会注册到Configuration组件中的环境配置。

  • 事务管理器:

在MyBatis中,有两种事务管理器:JDBC、MANAGED。

(1)JDBC

这种事务管理器直接使用JDBC的提交和回滚设置,它依赖于从数据源得到的连接来管理事务。

(2)MANAGED

这种事务管理器相当于没有事务管理器,因为它从不提交或回滚一个连接,而是全权交给了容器来管理。

  • 数据源:

注意,这里使用${...}的方式,就是取用【4.3.1 属性】中配置的属性。

标签的type属性是指数据源类型,它的取值包括UNPOOLED、POOLED、JNDI。

(1)UNPOOLED

即非“池”类型的数据源,它的实现会在每次请求时打开和关闭连接。相比连接池,它虽然有一点慢,但对于没有性能要求的简单应用程序是一个很好的选择。

UNPOOLED类型的数据源仅需要配置以下5种属性:

  • driver– JDBC驱动的Java类的完全限定名。
  • url– 数据库的JDBC URL地址。
  • username– 登录数据库的用户名。
  • password– 登录数据库的密码。
  • defaultTransactionIsolationLevel– 默认的连接事务隔离级别。

(2)POOLED

即“池”类型的数据源,它的实现会将JDBC连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。这是一种使得并发Web应用快速响应请求的流行处理方式。

除了上述提到的5种属性,还有更多属性用来配置POOLED类型的数据源:

  • poolMaximumActiveConnections– 最大活动连接数,默认值:10。
  • poolMaximumIdleConnections– 最大空闲连接数。
  • poolMaximumCheckoutTime– 池中连接最大被检出时间,超时将被强制返回,默认值:20000毫秒。
  • poolTimeToWait– 获取连接如果超过这个时间,则会给连接池打印状态日志并重新尝试获取一个连接(避免在误配置的情况下一直失败但没有任何提示),默认值:20000毫秒。
  • poolPingQuery– 发送到数据库的心跳查询SQL语句,用来检验连接是否处在正常状态并准备接受请求。默认是NO PING QUERY SET,当数据库驱动失败时,返回一个错误消息。
  • poolPingEnabled– 是否启用心跳查询。若开启,必须使用一个可执行的SQL语句设置poolPingQuery属性(最好是一个非常快的SQL语句),默认值:false。
  • poolPingConnectionsNotUsedFor– 配置poolPingQuery的使用频度。可以设置成数据库连接超时时间,来避免不必要的检测,默认值:0(即所有连接每一时刻都被检测 — 当然仅当poolPingEnabled为true时适用)。

(3)JNDI

这种数据源的实现是为了能在如EJB或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个JNDI上下文的引用。

这种数据源配置只需要2个属性:

  • initial_context– 用来在InitialContext中寻找上下文。这是个可选属性。
  • data_source– 引用数据源实例位置的上下文的路径。提供了initial_context配置时会在其返回的上下文中进行查找,没有提供时则直接在InitialContext中查找。

在Configuration组件中,组合了一个Environment对象,用于存放被选中的环境配置。

源码7org.apache.ibatis.session.Configurationprotected Environment environment;

借助Debug可知,Configuration组件最终会注册一个Environment对象:

4.3.8 映射器

映射器用于配置SQL映射文件的位置,也就是告诉MyBatis到哪里去找SQL映射文件。

在mybatis-config.xml文件中,映射器使用标签进行配置。例如:

    <!--映射文件--><mappers><!--通过指定XML文件的类路径来注册--><mapper resource="mapper/UserMapper.xml"/><!--通过指定XML文件的完全限定资源定位符来注册--><!--<mapper url="file:///C:\workspace\mybatis_demo2\src\main\resources\mapper\UserMapper.xml"/>--><!--通过Mapper接口的类路径来注册--><!--<mapper class="com.star.mybatis.mapper.UserMapper"/>--><!--通过Mapper接口所在包路径类注册--><!--<package name="com.star.mybatis.mapper"/>--></mappers>

如上面的配置所示,配置SQL映射文件的位置有4种方法是:第一是使用XML文件的类路径;第二是使用XML文件的完全限定资源定位符(即包括 file:///的URL);第三是使用Mapper接口的类路径;第四是使用Mapper接口所在包路径。

在Configuration组件中,组合了一个Mapper注册器,用于注册Mapper接口信息:

源码:protected final MapperRegistry mapperRegistry;

借助Debug可知,Configuration组件最终会注册配置好的映射器:

本节完,更多内容请查阅分类专栏:MyBatis3源码深度解析

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

代码随想录训练营Day25:● 216.组合总和III ● 17.电话号码的字母组合

216.组合总和III 题目链接 https://leetcode.cn/problems/combination-sum-iii/description/ 题目描述 思路 自己写的效率会慢一些&#xff0c;而且没有用到剪枝 class Solution {List<List<Integer>> list new ArrayList<>();List<Integer> lis…

【C语言步行梯】各类操作符、类型转换与原码、反码、补码详谈

&#x1f3af;每日努力一点点&#xff0c;技术进步看得见 &#x1f3e0;专栏介绍&#xff1a;【C语言步行梯】专栏用于介绍C语言相关内容&#xff0c;每篇文章将通过图片代码片段网络相关题目的方式编写&#xff0c;欢迎订阅~~ 文章目录 算术运算符原码、反码、补码介绍移位运算…

下载程序到嵌入式开发板教程

一、设置共享目录 ubuntu与Window共同拥有的目录。 第一步&#xff1a;在Windows下创建一个文件夹share 第二部&#xff1a;点击虚拟机--->设置--->选项--->共享文件夹 进入共享目录的命令&#xff1a;cd/mnt/hgfs/share 二、C语言编译器 使用Linux平台下的gcc编…

LeetCode102题:二叉树的层序遍历(python3)

代码思路&#xff1a;使用队列先进先出的特性&#xff0c;queue[]不为空进入for循环&#xff0c;tmp存储每层的节点&#xff0c;将结果添加至res[]中。 python中使用collections中的双端队列deque()&#xff0c;其popleft()方法可达到O(1)时间复杂度。 class Solution:def lev…

【项目分享】RailTracker: 火车票务数据采集与分析

&#x1f684; RailTracker: 高铁票务数据采集与可视化 &#x1f31f; 从12306使用爬虫爬取火车站及车次信息、火车票价 项目地址&#xff1a;https://github.com/Zhu-Shatong/RailTracker 点击链接前往项目 通过本项目&#xff0c;我们将带领访问者手把手完成火车票数据采集…

【b站咸虾米】2 Vue基础(下) 2021最新Vue从基础到实例高级_vue2_vuecli脚手架博客案例

课程地址&#xff1a;【2021最新Vue从基础到实例高级_vue2_vuecli脚手架博客案例】 https://www.bilibili.com/video/BV1pz4y1S7bC/?share_sourcecopy_web&vd_sourceb1cb921b73fe3808550eaf2224d1c155 目录 2 Vue基础 下 2.8 计算属性 2.8.1 计算属性使用 2.8.2 计算…

大数据Doris(六十九):项目线上表现

文章目录 项目线上表现 一、查询响应时间

牛客网-SQL大厂面试题-2.平均播放进度大于60%的视频类别

题目&#xff1a;平均播放进度大于60%的视频类别 DROP TABLE IF EXISTS tb_user_video_log, tb_video_info; CREATE TABLE tb_user_video_log (id INT PRIMARY KEY AUTO_INCREMENT COMMENT 自增ID,uid INT NOT NULL COMMENT 用户ID,video_id INT NOT NULL COMMENT 视频ID,start…

【C++】了解一下编码

个人主页 &#xff1a; zxctscl 如有转载请先通知 文章目录 1. 前言2. ASCII编码3. unicode4. GBK5. 类型转换 1. 前言 看到string里面还有Template instantiations&#xff1a; string其实是basic_string<char>&#xff0c;它还是一个模板。 再看看wstring&#xff1…

Java中 链表的基础知识介绍

在 Java 中&#xff0c;链表是一种常见的数据结构&#xff0c;它由一系列节点组成&#xff0c;每个节点包含数据和指向链表中下一个节点的引用。链表不同于数组&#xff0c;它不要求在内存中连续存储&#xff0c;这使得链表在内存分配和动态扩展方面更加灵活。 基础概念 …

centos7磁盘管理,lvm挂载、扩容

一、centos7 磁盘挂载 默认盘符格式 centos7 默认文件格式xfscentos6 默认文件格式ext4centos5 默认文件格式ext3 1、/dev/vdb和/dev/mapper/lvm-data对比 1&#xff09;/dev/vdb /dev/vdb通常表示一个裸的块存储设备&#xff0c;比如一个硬盘或者虚拟机中的一个虚拟硬盘。…

软件测试之学习测试用例的设计(等价类法、边界值法、错误猜测法、场景法、因果图法、正交法)

1. 测试用例的概念 软件测试人员向被测试系统提供的一组数据的集合&#xff0c;包括 测试环境、测试步骤、测试数据、预期结果 2. 为什么在测试前要设计测试用例 测试用例是执行测试的依据 在回归测试的时候可以进行复用 是自动化测试编写测试脚本的依据 衡量需求的覆盖率…