Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存二级缓存

Mybatis一级缓存&二级缓存

    • 概述
    • 一级缓存
      • 特点
      • 演示前准备
      • 效果演示
        • 在同一个SqlSession中
        • 在不同的SqlSession中
      • 源代码
      • 怎么禁止使用一级缓存
      • 一级缓存在什么情况下会被清除
    • 二级缓存
      • 特点
      • 演示前准备
      • 效果演示
        • 在不同的SqlSession中
      • 源代码
      • 怎么关闭二级缓存
    • 一级缓存(Spring整合Mybatis)
      • 演示前准备
      • 效果演示
        • 不开启事务,调用多次接口
        • 开启事务,调用多次接口
        • 不开启事务,接口中多次调用查询方法
        • 开启事务,接口中多次调用查询方法
        • 总结
      • 源代码

概述

缓存越小,查询速度越快,缓存数据越少
缓存越大,查询速度越慢,缓存数据越多

在多级缓存中,一般常见的是先查询一级缓存,再查询二级缓存,但在Mybatis中是先查询二级缓存,再查询一级缓存。

在Mybatis中,BaseExecutor属于一级缓存执行器,CachingExecutor属于二级缓存执行器,二者采用了装饰器设计模式。

一级缓存:默认情况下一级缓存是开启的,而且是不能关闭的,一级缓存是指SqlSession级别的缓存,当在同一个SqlSession中使用相同的SQL语句进行查询时,第二次以及之后的查询都不会从数据库查询,而是直接从缓存中获取,一级缓存最多缓存1024条SQL。
二级缓存:二级缓存是指可以跨SqlSession的缓存。是mapper级别的缓存,对于mapper级别的缓存不同的SqlSession是可以共享的,需要额外整合第三方缓存,例如Redis、MongoDB、oscache、ehcache等。

注:本文代码演示基于《Mybatis环境搭建与使用》中的“基于XML方式-mapper代理开发”的代码进行调整。

一级缓存

特点

一级缓存也叫本地缓存,在Mybatis中,一级缓存是在会话层面(SqlSession)实现的,这就说明一级缓存的作用范围只能在同一个SqlSession中,在多个不同的SqlSession中是无效的。

在Mybatis中,一级缓存是默认开启的,不需要任何额外的配置。

演示前准备

为了能够看到演示的效果,需要在mybatis-config.xml文件中加上以下配置

<settings><!-- 打印sql日志 --><setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

在这里插入图片描述

效果演示

在同一个SqlSession中

MybatisTest03.java

package com.mybatis.test;import com.mybatis.entity.UserEntity;
import com.mybatis.mapper.UserMapper;
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.InputStream;
import java.util.List;/*** @author honey* @date 2023-08-01 16:23:53*/
public class MybatisTest03 {public static void main(String[] args) throws IOException {// 1.读取加载mybatis-config.xml(数据源、mybatis等配置)InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);// 2.获取sqlSessionSqlSession sqlSession = sqlSessionFactory.openSession();// 3.根据mapper(namespace="UserMapper全限定名" + id="listUser")执行sql语句,并将查询到的数据映射成对象(orm)UserMapper mapper1 = sqlSession.getMapper(UserMapper.class);System.out.println("【一级缓存-在同一个SqlSession中】第一次查询");List<UserEntity> list1 = mapper1.listUser();System.out.println("list1:" + list1);UserMapper mapper2 = sqlSession.getMapper(UserMapper.class);System.out.println("【一级缓存-在同一个SqlSession中】第二次查询");List<UserEntity> list2 = mapper2.listUser();System.out.println("list2:" + list2);sqlSession.close();}
}

运行上面的代码可以看到,在同一个SqlSession中,第二次查询是没有去查询数据库的,而是直接读取的缓存数据。

在这里插入图片描述

源码Debug分析

BaseExecutor.java

在这里插入图片描述
在这里插入图片描述

在不同的SqlSession中

MybatisTest04.java

package com.mybatis.test;import com.mybatis.entity.UserEntity;
import com.mybatis.mapper.UserMapper;
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.InputStream;
import java.util.List;/*** @author honey* @date 2023-08-01 16:23:53*/
public class MybatisTest04 {public static void main(String[] args) throws IOException {// 1.读取加载mybatis-config.xml(数据源、mybatis等配置)InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);// 2.获取sqlSessionSqlSession sqlSession1 = sqlSessionFactory.openSession();SqlSession sqlSession2 = sqlSessionFactory.openSession();// 3.根据mapper(namespace="UserMapper全限定名" + id="listUser")执行sql语句,并将查询到的数据映射成对象(orm)UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);System.out.println("【一级缓存-在不同的SqlSession中】第一次查询");List<UserEntity> list1 = mapper1.listUser();System.out.println("list1:" + list1);UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);System.out.println("【一级缓存-在不同的SqlSession中】第二次查询");List<UserEntity> list2 = mapper2.listUser();System.out.println("list2:" + list2);sqlSession1.close();sqlSession2.close();}
}

运行上面的代码可以看到,在不同的SqlSession中,两次查询都是查询的数据库,也就是说一级缓存并没有生效。

在这里插入图片描述

源代码

在这里插入图片描述
在这里插入图片描述

怎么禁止使用一级缓存

  1. 在SQL语句上加上随机生成的参数;(不推荐)
  2. 开启二级缓存;
  3. 使用SqlSession强制清除缓存;
  4. 每次查询都使用新的SqlSession;
  5. 通过配置清除缓存;

一级缓存在什么情况下会被清除

  1. 提交事务/回滚事务/强制清除缓存
sqlSession.commit();
sqlSession.rollback();
sqlSession.clearCache()

以提交事务为例,回滚事务/强制清除缓存同理

MybatisTest03.java

在这里插入图片描述

DefaultSqlSession.java

在这里插入图片描述

BaseExecutor.java

在这里插入图片描述
在这里插入图片描述

  1. 在执行insert、update、delete语句时

BaseExecutor.java

在这里插入图片描述

  1. 使用配置清除一级缓存
<!-- 设置一级缓存作用域 -->
<setting name="localCacheScope" value="STATEMENT"/>

mybatis-config.xml

在这里插入图片描述

BaseExecutor.java

在这里插入图片描述

二级缓存

特点

二级缓存是mapper级别的缓存,通过整合第三方缓存实现,二级缓存的作用范围可以在不同的SqlSession中。

在Mybatis中,二级缓存默认是开启的,但还需要做一些额外的配置才能生效。

演示前准备

在这里插入图片描述

  1. 启动Redis

在这里插入图片描述

  1. 添加pom依赖

pom.xml

<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.0.1</version>
</dependency>
  1. 实现Cache类

RedisCache.java

package com.mybatis.cache;import com.mybatis.utils.SerializeUtil;
import org.apache.ibatis.cache.Cache;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;/*** @author honey* @date 2023-08-01 23:44:10*/
public class RedisCache implements Cache {private final Jedis redisClient = createRedis();private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();private final String id;public RedisCache(final String id) {if (id == null) {throw new IllegalArgumentException("Cache instances require an ID");}this.id = id;}@Overridepublic String getId() {return id;}@Overridepublic void putObject(Object key, Object value) {System.out.printf("【存入缓存数据】key:%s,value:%s%n", key, value);redisClient.set(SerializeUtil.serialize(key), SerializeUtil.serialize(value));}@Overridepublic Object getObject(Object key) {byte[] bytes = redisClient.get(SerializeUtil.serialize(key));if (bytes == null) {return null;}Object value = SerializeUtil.deserialize(bytes);System.out.printf("【读取缓存数据】key:%s,value:%s%n", key, value);return value;}@Overridepublic Object removeObject(Object key) {return redisClient.expire(String.valueOf(key), 0);}@Overridepublic void clear() {redisClient.flushDB();}@Overridepublic int getSize() {return Integer.parseInt(redisClient.dbSize().toString());}@Overridepublic ReadWriteLock getReadWriteLock() {return readWriteLock;}protected static Jedis createRedis() {JedisPool pool = new JedisPool("127.0.0.1", 6379);return pool.getResource();}
}

SerializeUtil.java

package com.mybatis.utils;import java.io.*;/*** @author honey* @date 2023-08-02 00:50:37*/
public class SerializeUtil {public static byte[] serialize(Object object) {ObjectOutputStream oos = null;ByteArrayOutputStream baos = null;try {// 序列化baos = new ByteArrayOutputStream();oos = new ObjectOutputStream(baos);oos.writeObject(object);return baos.toByteArray();} catch (Exception e) {e.printStackTrace();} finally {close(oos);close(baos);}return null;}public static Object deserialize(byte[] bytes) {ByteArrayInputStream bais = null;ObjectInputStream ois = null;try {// 反序列化bais = new ByteArrayInputStream(bytes);ois = new ObjectInputStream(bais);return ois.readObject();} catch (Exception e) {e.printStackTrace();} finally {close(bais);close(ois);}return null;}/*** 关闭io流对象** @param closeable closeable*/public static void close(Closeable closeable) {if (closeable != null) {try {closeable.close();} catch (Exception e) {e.printStackTrace();}}}
}

注意:UserEntity需要实现序列化接口

UserEntity.java

在这里插入图片描述

  1. 添加配置(userMapper.xml)

userMapper.xml

<cache eviction="LRU" type="com.mybatis.cache.RedisCache"/>

在这里插入图片描述

效果演示

在不同的SqlSession中

MybatisTest05.java

package com.mybatis.test;import com.mybatis.entity.UserEntity;
import com.mybatis.mapper.UserMapper;
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.InputStream;
import java.util.List;/*** @author honey* @date 2023-08-01 16:23:53*/
public class MybatisTest05 {public static void main(String[] args) throws IOException {// 1.读取加载mybatis-config.xml(数据源、mybatis等配置)InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);// 2.获取sqlSessionSqlSession sqlSession1 = sqlSessionFactory.openSession();SqlSession sqlSession2 = sqlSessionFactory.openSession();// 3.根据mapper(namespace="UserMapper全限定名" + id="listUser")执行sql语句,并将查询到的数据映射成对象(orm)UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);System.out.println("【二级缓存-在不同的SqlSession中】第一次查询");List<UserEntity> list1 = mapper1.listUser();System.out.println("list1:" + list1);sqlSession1.close();UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);System.out.println("【二级缓存-在不同的SqlSession中】第二次查询");List<UserEntity> list2 = mapper2.listUser();System.out.println("list2:" + list2);sqlSession2.close();}
}

运行上面的代码可以看到,在不同的SqlSession中,第一次查询读取的是数据库中的数据,而第二次查询读取的是缓存中的数据。

在这里插入图片描述

注意:查询到的数据并不是在第一时间就存入缓存,而是在提交事务(sqlSession1.close())的时候才存入缓存。

在这里插入图片描述

源代码

CachingExecutor.java

在这里插入图片描述

在这里插入图片描述

TransactionalCacheManager.java

在这里插入图片描述

在这里插入图片描述


根据Cache(id=“mapper全限定名”)获取对应的TransactionalCache对象,并将数据临时存放在该对象中。

在这里插入图片描述


TransactionalCache.java

在这里插入图片描述

在执行sqlSession1.close()这行代码时,会将临时存放的数据存入缓存。

DefaultSqlSession.java

在这里插入图片描述

CachingExecutor.java

在这里插入图片描述

  1. 如果是提交事务,则会先将临时存放的数据存入缓存,再将临时存放的数据清空

TransactionalCacheManager.java

在这里插入图片描述

TransactionalCache.java

在这里插入图片描述

在这里插入图片描述

  1. 如果是回滚事务,则只会将临时存放的数据清空

TransactionalCacheManager.java

在这里插入图片描述

TransactionalCache.java

在这里插入图片描述

在这里插入图片描述

怎么关闭二级缓存

修改配置文件(mybatis-config.xml)

<setting name="cacheEnabled" value="false"/>

在这里插入图片描述

一级缓存(Spring整合Mybatis)

在未开启事务的情况下,每次查询Spring都会关闭旧的SqlSession而创建新的SqlSession,因此此时的一级缓存是没有生效的;
在开启事务的情况下,Spring模板使用threadLocal获取当前资源绑定的同一个SqlSession,因此此时一级缓存是有效的;

演示前准备

项目结构

在这里插入图片描述

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com</groupId><artifactId>springboot-mybatis</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.9.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><dependencies><!-- web组件 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- mysql --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.11</version></dependency><!-- mybatis --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.1.1</version></dependency><!-- lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency></dependencies></project>

application.yml

server:port: 8080spring:datasource:username: rootpassword: adminurl: jdbc:mysql://localhost:3306/db_mybatis?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghaidriver-class-name: com.mysql.cj.jdbc.Driverhikari:connection-timeout: 10000

UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mybatis.mapper.UserMapper"><select id="listUser" resultType="com.mybatis.entity.UserEntity">select * from tb_user</select>
</mapper>

AppMybatis.java

package com.mybatis;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/*** @author honey* @date 2023-08-02 02:58:16*/
@SpringBootApplication
public class AppMybatis {public static void main(String[] args) {SpringApplication.run(AppMybatis.class);}
}

UserEntity.java

package com.mybatis.entity;import lombok.Data;/*** @author honey* @date 2023-08-02 03:03:19*/
@Data
public class UserEntity {private Long id;private String name;
}

UserMapper.java

package com.mybatis.mapper;import com.mybatis.entity.UserEntity;
import org.apache.ibatis.annotations.Mapper;import java.util.List;/*** @author honey* @date 2023-07-26 21:04:23*/
@Mapper
public interface UserMapper {/*** 查询用户列表** @return List<UserEntity>*/List<UserEntity> listUser();
}

UserController.java

package com.mybatis.controller;import com.mybatis.entity.UserEntity;
import com.mybatis.mapper.UserMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;/*** @author honey* @date 2023-08-02 03:09:13*/
@RestController
@RequiredArgsConstructor
public class UserController {private final UserMapper userMapper;@RequestMapping("listUser")public void listUser(){List<UserEntity> list = userMapper.listUser();System.out.println(list);}
}

效果演示

不开启事务,调用多次接口

在这里插入图片描述

第一次调用

在这里插入图片描述

第二次调用

在这里插入图片描述

两次调用获取到的是不同的SqlSession,一级缓存不生效

开启事务,调用多次接口

在这里插入图片描述

第一次调用

在这里插入图片描述

第二次调用

在这里插入图片描述

两次调用获取到的也是不同的SqlSession,一级缓存不生效

不开启事务,接口中多次调用查询方法

在这里插入图片描述

第一次调用

在这里插入图片描述

第二次调用

在这里插入图片描述

两次调用获取到的依然是不同的SqlSession,一级缓存不生效

开启事务,接口中多次调用查询方法

在这里插入图片描述

第一次调用

在这里插入图片描述

第二次调用

在这里插入图片描述

两次调用获取到的是相同的SqlSession,一级缓存生效

总结

只有在同一个事务内执行查询,一级缓存才会生效。

源代码

MapperMethod.java
在这里插入图片描述

在Spring整合Mybatis的代码中,新增了SqlSessionTemplate类对DefaultSqlSession类的功能进行增强。

SqlSessionTemplate.java

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

SqlSessionUtils.java

在这里插入图片描述

在这里插入图片描述

能获取到SqlSessionHolder对象的前提是开启了事务。如果当前线程开启了事务,则不会直接关闭SqlSession对象,而是在下一次调用时复用SqlSession对象。

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

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

相关文章

抖音seo矩阵系统源码搭建开发详解

抖音SEO矩阵系统是一个用于提高抖音视频在搜索引擎排名的工具。如果你想开发自己的抖音SEO矩阵系统&#xff0c;以下是详细的步骤&#xff1a; 开发步骤详解&#xff1a; 确定你需要的功能和算法 抖音SEO矩阵系统包含很多功能&#xff0c;比如关键词研究、内容优化、链接建设、…

TypeScript【enum 枚举】

导语 在 TypeScript 中&#xff0c;新增了很多具有特性的一些数据类型处理方法&#xff0c;enum 【枚举】就是其中&#xff0c;很具有代表性的一种&#xff0c;所以本章节就来聊聊 在 TypeScript 中如何去运用 enum 【枚举】。 枚举的概念&#xff1a; 枚举&#xff08;Enum&am…

MySql UNION 一行转多列

背景:DataEase饼图有特定格式&#xff0c;并且报表要求全部使用SQL语句获取数据 原先数据格式如下&#xff0c;需要行转换列 转换后结果&#xff1a; 原理 字段1&#xff0c;target作为一个不存在的字段&#xff0c;用于命名。 字段2&#xff0c;count字段是关键&#xff0c;…

基于Java的中国文化传承网站系统的设计与实现(编号S65)

基于Java的中国文化传承网站系统的设计与实现&#xff08;编号S65&#xff09; 大家好&#xff0c;小辰今天给大家介绍一个基于Spring Springboot MyBatis实现的中国文化传承网站系统&#xff0c;演示视频文章末尾公众号对号查询观看即可 文章目录 基于Java的中国文化传承网站…

Dockerfile构建Tomcat镜像(源码)

Dockerfile构建Tomcat镜像 目录 Dockerfile构建Tomcat镜像 1、建立工作目录 2、编写Dockerfile文件 3、构建镜像 4、测试容器 5、浏览器访问测试&#xff1a; 1、建立工作目录 [roothuyang1 ~]# mkdir tomcat[roothuyang1 ~]# cd tomcat/[roothuyang1 tomcat]# lsapach…

架构训练营学习笔记:5-1 计算架构模式之多级缓存架构

序 本节主要是计算架构。 多级缓存架构 缓存与缓冲&#xff1a;通常场景是读缓存&#xff0c;写缓冲。 缓存技术的本质&#xff1a;空间换时间&#xff0c;因此缓存架构属于高性能计算 架构。 缓存设计框架 主要考虑存什么&#xff1f;存多久&#xff1f;存哪里&#xff1f;如…

初识网络(JavaEE初阶系列9)

目录 前言&#xff1a; 1.网络的发展史 1.1独立模式 1.2网络互联 1.3局域网LAN 1.4广域网WAN 2.网络通信基础 2.1IP地址 2.2端口号 3.认识协议 3.1协议分层 3.2分层的作用 3.3TCP/IP五层&#xff08;或四层&#xff09;模型 3.4OSI七层模型 3.5网络设备所在分层 …

【Elasticsearch】Elasticsearch快速入门,掌握这些刚刚好!(官网入门案例)

文章目录 1. 简介2. 相关概念3. 安装4. 集群状态查看5. 索引操作6. 文档操作7. 数据搜索数据准备搜索入门(match_all)条件搜索(match)组合搜索(bool)过滤搜索(filter)搜索聚合(aggs) 8. 参考资料 本文的主要功能是带领从0到1入门Elasticsearch的基础使用&#xff0c;重点是Elas…

springboot+vue农产品特产商城销售平台_50kf2 多商家

随着我国经济的高速发展与人们生活水平的日益提高&#xff0c;人们对生活质量的追求也多种多样。尤其在人们生活节奏不断加快的当下&#xff0c;人们更趋向于足不出户解决生活上的问题&#xff0c;南阳特产销售平台展现了其蓬勃生命力和广阔的前景。与此同时&#xff0c;为解决…

Meta开源AI音频和音乐生成模型

在过去的几年里&#xff0c;我们看到了AI在图像、视频和文本生成方面的巨大进步。然而&#xff0c;音频生成领域的进展却相对滞后。MetaAI这次再为开源贡献重磅产品&#xff1a;AudioCraft&#xff0c;一个支持多个音频生成模型的音频生成开发框架。 AudioCraft开源地址 开源地…

【JavaEE】简单了解JVM

目录 一、JVM中的内存区域划分 二、JVM的类加载机制 1、类加载的触发时机 2、双亲委派模型 1.1、向上委派 1.2、向下委派 三、JVM中的垃圾回收机制&#xff08;GC&#xff09; 1、确认垃圾 1.1、引用计数&#xff08;Java实际上没有使用这个方案&#xff0c;但是Pytho…

SpringBoot核心内容梳理

1.SpringBoot是什么? Spring Boot是一个基于Spring框架的快速开发应用程序的工具。它简化了Spring应用程序的创建和开发过程&#xff0c;使开发人员能够更快速地创建独立的、生产就绪的Spring应用程序。它采用了“约定优于配置”的原则&#xff0c;尽可能地减少开发人员需要进…

vue使用拖拽功能实现仓库存放货物的需求

效果&#xff1a; 代码 <template><div><div class"bigTitle">xxxxxxxxxxxxxx仓库拖拽系统</div><div class"container2 flex-j-space-between"><div class"product-list"><div class"leftTree h…

利用线程池多线程并发实现TCP两端通信交互,并将服务端设为守护进程

文章目录 实现目标实现步骤封装日志类封装线程池封装线程封装锁封装线程池 TCP通信的接口和注意事项accept TCP封装任务客户端Client.hppClient.cc 服务端Server.hpp Server.cc实现效果 守护进程服务端守护进程化 实现目标 利用线程池多线程并发实现基于TCP通信的多个客户端与…

Java Collection接口详解

Collection 接口 Collection接口是Java集合框架的根接口。 Collection 接口是 List、Set 和 Queue 接口的父接口&#xff0c;通常情况下不被直接使用。 Collection 接口定义了一些通用的方法&#xff0c;通过这些方法可以实现对集合的基本操作。定义的方法既可用于操作 Set …

docker创建镜像并上传云端服务器

docker创建镜像并上传云端服务器 docker容器与镜像的关系1.基本镜像相关文件创建1.1 创建dockerfile文件1.2.创建do.sh文件1.3 创建upload_server_api.py文件1.4 创建upload_server_webui.py文件1.5 文件保存位置 2. 创建镜像操作2.1 创建镜像2.3 创建容器2.2 进入环境容器2.3 …

【2023年电赛国一必备】A题报告模板--可直接使用

任务 图1 任务内容 要求 图2 基本要求内容 图3 发挥部分内容 说明 图4 说明内容 评分标准 图5 评分内容 正文 &#xff08;部分&#xff09; 摘要 本实验旨在设计和制作一个由两个单相逆变器组成的并联系统&#xff0c;用于为电阻负载供电或并入220V电网。采用基于STM…

【react】react生命周期钩子函数:

文章目录 一、生命周期概念:二、生命周期:三、挂载阶段&#xff08;constructor > render > componentDidMount&#xff09;&#xff1a;四、更新阶段&#xff08;render > componentDidUpdate&#xff09;&#xff1a;五、卸载阶段&#xff08;componentWillUnmount …

il汇编整数相加

在这里尝试了IL汇编字符串连接&#xff1b; IL汇编字符串连接_bcbobo21cn的博客-CSDN博客 下面来看一下IL汇编整数相加&#xff1b; 大概的看一下一些资料&#xff0c;下面语句&#xff0c; ldc.i4 20 ldc.i4 30 add 看上去像是&#xff0c;装载整数20到一个类似于…

VK1056B 液晶LCD显示驱动IC/14x4com工作电压2.4-5.2V稳定测试

LCD液晶显示驱动芯片VK1056B 14x4位的显示RAM适用于各种LED应用产品 产品型号&#xff1a;VK1056B (兼容替代TM系列驱动) 产品品牌&#xff1a;VINKA永嘉微电 封装形式&#xff1a;SOP24 SSOP24 产品年份&#xff1a;新年份 提供专业工程服务&#xff0c…