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.mzph.cn/news/25500.shtml

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

相关文章

Docker 安装 Tomcat

目录 一、查看 tomcat 版本 二、拉取 Tomcat Docker 镜像 三、创建 Tomcat 容器 四、访问 Tomcat 五、停止和启动容器 一、查看 tomcat 版本 访问 tomcat 镜像库地址&#xff1a;https://hub.docker.com/_/tomcat&#xff0c;可以通过 Tags 查看其他版本的 tomcat; 二、拉…

Android Studio 的Gradle版本修改

使用Android Studio构建项目时&#xff0c;需要配置Gradle&#xff0c;与Gradle插件。 Gradle是一个构建工具&#xff0c;用于管理和自动化Android项目的构建过程。它使用Groovy或Kotlin作为脚本语言&#xff0c;并提供了强大的配置能力来定义项目的依赖关系、编译选项、打包方…

HCIA---OSI/RM--开放式系统互联参考模型

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 一.OSI--开放式系统互联参考模型简介 OSI开放式系统互联参考模型是一种用于计算机网络通信…

解密Redis:应对面试中的缓存相关问题2

面试官&#xff1a;Redis集群有哪些方案&#xff0c;知道嘛&#xff1f; 候选人&#xff1a;嗯~~&#xff0c;在Redis中提供的集群方案总共有三种&#xff1a;主从复制、哨兵模式、Redis分片集群。 面试官&#xff1a;那你来介绍一下主从同步。 候选人&#xff1a;嗯&#xff…

Flutter iOS 集成使用 fluter boost

在 Flutter项目中集成完 flutter boost&#xff0c;并且已经使用了 flutter boost进行了路由管理&#xff0c;这时如果需要和iOS混合开发&#xff0c;这时就要到 原生端进行集成。 注意&#xff1a;之前建的项目必须是 Flutter module项目&#xff0c;并且原生项目和flutter m…

Baumer工业相机堡盟工业相机如何通过BGAPISDK获取相机接口数据吞吐量(C++)

Baumer工业相机堡盟工业相机如何通过BGAPISDK里函数来获取相机当前数据吞吐量&#xff08;C&#xff09; Baumer工业相机Baumer工业相机的数据吞吐量的技术背景CameraExplorer如何查看相机吞吐量信息在BGAPI SDK里通过函数获取相机接口吞吐量 Baumer工业相机通过BGAPI SDK获取数…

【微信小程序】van-uploader实现文件上传

使用van-uploader和wx.uploadFile实现文件上传&#xff0c;后端使用ThinkPHP。 1、前端代码 json&#xff1a;引入van-uploader {"usingComponents": {"van-uploader": "vant/weapp/uploader/index"} }wxml&#xff1a;deletedFile是删除文件函…

Xilinx FPGA电源设计与注意事项

1 引言 随着半导体和芯片技术的飞速发展&#xff0c;现在的FPGA集成了越来越多的可配置逻辑资源、各种各样的外部总线接口以及丰富的内部RAM资源&#xff0c;使其在国防、医疗、消费电子等领域得到了越来越广泛的应用。当采用FPGA进行设计电路时&#xff0c;大多数FPGA对上电的…

【计算机网络】12、frp 内网穿透

文章目录 一、服务端设置二、客户端设置 frp &#xff1a;A fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet。是一个专注于内网穿透的高性能的反向代理应用&#xff0c;支持 TCP、UDP、HTTP、HTTPS 等多种协议&#xff0c;且…

VUE框架:vue2转vue3全面细节总结(5)过渡动效

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a; lqj_本人_python人工智能视觉&#xff08;opencv&#xff09;从入门到实战,前端,微信小程序-CSDN博客 最新的uniapp毕业设计专栏也放在下方了&#xff1a; https://blog.csdn.net/lbcy…

ES6 数组的用法

1. forEach() 用来循环遍历的 for 数组名.forEach(function (item,index,arr) {})item:数组每一项 , index : 数组索引 , arr:原数组作用: 用来遍历数组 let arr [1, 2, 3, 4]; console.log(arr); let arr1 arr.forEach((item, index, arr) > {console.log(item, index…

HTTP——八、确认访问用户身份的认证

HTTP 一、何为认证二、BASIC认证BASIC认证的认证步骤 三、DIGEST认证DIGEST认证的认证步骤 四、SSL客户端认证1、SSL 客户端认证的认证步骤2、SSL 客户端认证采用双因素认证3、SSL 客户端认证必要的费用 五、基于表单认证1、认证多半为基于表单认证2、Session 管理及 Cookie 应…

Android network — iptables四表五链

Android network — iptables四表五链 1. iptables简介2. iptables的四表五链2.1 iptables流程图2.2 四表2.3 五链2.4 iptables的常见情况 3. NAT工作原理3.1 BNAT3.2 NAPT 4. iptables配置 本文主要介绍了iptables的基本工作原理和四表五链等基本概念以及NAT的工作原理。 1. i…

RocketMQ Learning

一、RocketMQ RocketMQ的产品发展 MetaQ&#xff1a;2011年&#xff0c;阿里基于Kafka的设计使用Java完全重写并推出了MetaQ 1.0版本 。 2012年&#xff0c;阿里对MetaQ的存储进行了改进&#xff0c;推出MetaQ 2.0&#xff0c;同年阿里把Meta2.0从阿里内部开源出来&am…

杂记 | 记录一次使用Docker安装gitlab-ce的过程(含配置交换内存)

文章目录 01 准备工作02 &#xff08;可选&#xff09;配置交换内存03 编辑docker-compose.yml04 启动并修改配置05 nginx反向代理06 &#xff08;可选&#xff09;修改配置文件07 访问并登录 01 准备工作 最近想自建一个gitlab服务来保存自己的项目&#xff0c;于是找到gitla…

使用XMLHttpRequest实现文件异步下载

1、问题描述 我想通过异步的方式实现下载文化&#xff0c;请求为post请求。一开始我打算用ajax。 $.ajax({type:post,contentType:application/json,url:http://xxx/downloadExcel,data:{data:JSON.stringify(<%oJsonResponse.JSONoutput()%>)},}).success(function(dat…

Linux远程连接mysql 出错plugin caching_sha2_password could not be loaded:

问题描述&#xff1a; 今天使用SQLyog远程连接mysql时出错plugin caching_sha2_password could not be loaded问题。 但在本地cmd 进入命令行窗口&#xff1a;输入命令连接远程连接mysql&#xff0c;发现可以顺利连接。 主要问题是 MySQL可视化工具&#xff08;如&#xff1a…

FL Studio Producer Edition 21 v21.0.3 Build 3517 Windows/mac官方中文版

FL Studio Producer Edition 21 v21.0.3 Build 3517 Windows FL Studio Producer Edition 21 v21.0.3 Build 3517 Windows/mac官方中文版是一个完整的软件音乐制作环境或数字音频工作站&#xff08;DAW&#xff09;。它代表了 25 多年的创新发展&#xff0c;将您创作、编曲、录…

python 合并多个excel文件

使用 openpyxl 思路&#xff1a; 读取n个excel的文件&#xff0c;存储在一个二维数组中&#xff0c;注意需要转置。将二维数组的数据写入excel。 安装软件&#xff1a; pip install openpyxl源代码&#xff1a; import os import openpyxl # 将n个excel文件数据合并到一个…

Android SystemServer中Service的创建和启动方式(基于Android13)

Android SystemServer创建和启动方式(基于Android13) SystemServer 简介 Android System Server是Android框架的核心组件&#xff0c;运行在system_server进程中&#xff0c;拥有system权限。它在Android系统中扮演重要角色&#xff0c;提供服务管理和通信。 system …