MySQL-三大日志
前言
redo log:为了持久化数据,当内存中的数据还没写入到磁盘而宕机时,会读取该日志持久化数据到磁盘
undo log:为了保证原子性,事务的操作都会记录一条相反的sql到该日志,出现错误就会根据该文件恢复事务之前的数据
binlog:为了复制和恢复数据,mysql重启可以通过该日志恢复
以上三大日志是MySQL的原子性、持久性、数据一致性的保证。
bin log
bin log
全称binary log
,二进制日志文件,它记录了数据库所有执行的 DDL
和 DML
等数据库更新的语句,但是不包含select
或者show
等没有修改任何数据的语句。它是MySQL级别的日志,也就是说所有的存储引擎都会产生bin log
,而redo log
或者undo log
事务日志只有innoDB
存储引擎才有。
可以使用show binary logs; 命令查看所有二进制日志列表。可以看到binlog 日志文件名为 文件名.00000 形式。*
通过 show binlog events in ‘binlog.000008’ limit 10; 命令查看日志的具体内容。另外一定要指定 limit,不然查询出来的日志文件内容太多。另外, MySQL 内置了 binlog 查看工具 mysqlbinlog,可以解析二进制文件。
1、写入方式
binlog 通过追加的方式进行写入,大小没有限制。另外可以通过max_binlog_size参数设置每个 binlog 文件的最大容量,当文件大小达到给定值之后,会生成新的 binlog 文件来保存日志,不会出现前面写的日志被覆盖的情况。
写入流程
1)为了保证写的效率,会将事务的bin log
先写到binlog cache
中,这个cache
位于事务线程的内存中,主要是一个事务的bin log
不能被拆开,是一个整体。
**2)在提交事务的时候,将binlog cache
中的数据统一写到文件系统缓存page cache
中,**这个过程速度也很快
3)然后根据不同的策略,将文件系统缓存中的bin log
fsync刷到磁盘中,这里的策略后面详细讲解。
2、3种binlog 的格式
1)Statement 模式 :每一条会修改数据的sql都会被记录在binlog中,如inserts, updates, deletes。
**2)Row 模式 (推荐): 为了解决Statement缺点,记录具体哪一个分区中的、哪一个页中的、哪一行数据被修改了。**但是适用于数据量比较大的场景,否则记录分区信息,查找规则,磁盘IO、网络带宽开销很大。
3)Mixed 模式 :Statement 模式和 Row 模式的混合。
**默认使用 Statement 模式,少数特殊具体场景自动切换到 Row 模式。**MySQL 5.1.5 之前 binlog 的格式只有 STATEMENT,5.1.5 开始支持 ROW 格式的 binlog,从 5.1.8 版本开始,MySQL 开始支持 MIXED 格式的 binlog。MySQL 5.7.7 之前,默认使用 Statement 模式。MySQL 5.7.7 开始默认使用 Row 模式。
相比较于 Row 模式来说,Statement 模式下的日志文件更小,磁盘 IO 压力也较小,性能更好有些。不过其准确性相比于 Row 模式要差。可以使用 show variables like ‘%binlog_format%’; 查看 binlog 使用的格式。
3、应用场景
binlog 最主要的应用场景是 主从复制和数据恢复 ,主从复制常见是主备、主主、主从都离不开binlog,需要依靠 binlog 来同步数据,保证数据一致性。
可以使用show variables like ‘log_bin’;查看数据库是否启用 binlog 日志,默认是开启的。
1)主从复制的原理:
- 主库将数据库中数据的变化写入到 binlog
- 从库连接主库
- 从库会创建一个 I/O 线程向主库请求更新的 binlog
- 主库会创建一个 binlog dump 线程来发送 binlog ,从库中的 I/O 线程负责接收
- 从库的 I/O 线程将接收的 binlog 写入到 relay log 中。
- 从库的 SQL 线程读取 relay log 同步数据本地(也就是再执行一遍 SQL )。
2)Canal主从复制原理;
- Canal 模拟 MySQL Slave 节点与 MySQL Master 节点的交互协议,把自己伪装成一个 MySQL Slave 节点,向 MySQL Master 节点请求 binlog;
- MySQL Master 节点接收到请求之后,根据偏移量将新的 binlog 发送给 MySQL Slave 节点;
- Canal 接收到 binlog 之后,就可以对这部分日志进行解析,获取主库的结构及数据变更。
4、binlog 的刷盘时机
**对于InnoDB存储引擎而言,事务在执行过程中,会先把日志写入到binlog cache中,只有在事务提交的时候,才会把binlog cache中的日志持久化到磁盘上的binlog文件中。**写入内存的速度更快,这样做也是为了效率考虑。
因为一个事务的binlog不能被拆开,无论这个事务多大,也要确保一次性写入,所以系统会给每个线程分配一个块内存作为binlog cache。我们可以通过binlog_cache_size参数控制单个线程 binlog cache 大小,如果存储内容超过了这个参数,就要暂存到磁盘(Swap)。
刷盘策略
biglog有3种刷盘策略, bin log
的write和fsync时机是由参数 sync_binlog
控制。 MySQL5.7 之前, sync_binlog 默认值为 0。在 MySQL5.7 之后, sync_binlog默认值为 1。
- 0:不去强制要求。
表示每次提交事务都只 write
,由系统自行判断什么时候执行fsync
。虽然性能得到提升,但是机器宕机,page cache
里面的 binglog
会丢失。
- 1:每次提交事务的时候都要将binlog写入磁盘,也就是说都会执行
fsync
- N:每 N 个事务,才会将binlog写入磁盘(累积N个事务后才fsync)。
什么情况下会重新生成 binlog?
●MySQL服务器停止或重启;
●使用 flush logs 命令后;
●binlog 文件大小超过 max_binlog_size变量的阈值后。
bin log没写完,bin log 与redo log之间的一致性问题有什么解决方案?
InnoDB存储引擎使用两阶段提交方案。将redo log
的写入拆成了两个步骤prepare
和commit
。
假如现在写入bin log
时MySQL发生异常,这时候的redo log
还处于prepare
阶段,重启MySQL后,根据redo log
记录中的事务ID,发现没有对应的bin log
日志,回滚前面已写入的数据。
如果redo log
在commit
阶段发生移除,但是能通过事务id找到对应的bin log
日志,所以MySQL认为是完整的,就会提交事务恢复数据。
数据恢复?
通过使用 mysqlbinlog 工具来恢复数据。
redo log
MySQL InnoDB 引擎使用 redo log 来保证事务的持久性。redo log 主要做的事情就是记录页的修改,比如某个页面某个偏移量处修改了几个字节的值以及具体被修改的内容是什么。redo log 中的每一条记录包含了表空间号、数据页号、偏移量、具体修改的数据,甚至还可能会记录修改数据的长度(取决于 redo log 类型)。
redo log包含两部分:内存中的日志缓冲(redo log buffer)和磁盘上的日志文件(redo logfile)。内存层面,默认16M,通过innodb_log_buffer_size参数可修改。
MySQL 每执行一条 DML 语句,先将记录写入 redo log buffer,后续某个时间点再一次性将多个操作记录写到 redo log file。
写入过程
在计算机操作系统中,用户空间( user space )下的缓冲区数据一般情况下是无法直接写入磁盘的,中间必须经过操作系统内核空间( kernel space )缓冲区( OS Buffer )。因此, redo log buffer 写入 redo logfile 实际上是先写入 OS Buffer ,然后再通过系统调用 fsync() 将其刷到 redo log file中。
流程:
- 先将原始数据从磁盘中读入内存中来,修改数据的内存拷贝,产生脏数据
- 生成一条重做日志并写入redo log buffer,记录的是数据被修改后的值
- 默认在事务提交后将redo log buffer中的内容刷新到redo log file,对redo log file采用追加写的方式
- 定期将内存中修改的数据刷新到磁盘中(这里指的是内存缓冲池中的脏页 )
写入策略
当redo log空间满了之后又会从头开始以循环的方式进行覆盖式的写入。MySQL 支持三种将 redo log buffer 写入 redo log file 的时机,可以通过 innodb_flush_log_at_trx_commit 参数配置,各参数含义如下:
- 0(延迟写):表示每次事务提交时都只是把 redo log 留在 redo log buffer 中,开启一个后台线程,每1s刷新一次到磁盘中 ;
- 1(实时写,实时刷):表示每次事务提交时都将 redo log 直接持久化到磁盘,真正保证数据的持久性;
- 2(实时写,延迟刷):表示每次事务提交时都只是把 redo log 写到 page cache,具体的刷盘时机不确定。
除了上面几种机制外,还有其它两种情况会把redo log buffer中的日志刷到磁盘。
- 定时处理:有线程会定时(每隔 1 秒)把redo log buffer中的数据刷盘。
- 根据空间处理:redo log buffer 占用到了一定程度( innodb_log_buffer_size 设置的值一半)占,这个时候也会把redo log buffer中的数据刷盘。
重做日志缓冲(redo log)
重做日志(redo log)是数据库的重要组成,他保证了数据库宕机并重启后数据恢复的正确性。重做日志共有两个文件ib_logfile0和ib_logfile1。每个文件的大小一直且循环写入,也就是说先写ib_logfile0,写满之后再写ib_logfile1,又写满后,继续写ib_logfile0。
**redo log日志里面记录的主要是:表空间+数据页号+偏移量+修改几个字节的值+具体的值。**根据你修改了数据页里的几个字节的值,redo log就划分为了不同的类型,MLOG_1BYTE类型的日志指的就是修改了1个字节的值,MLOG_2BYTE类型的日志指的就是修改了2个字节的值,以此类推,还有修改了4个字节的值的日志类型,修改了8个字节的日志类型。如果修改了一大串的值,类型就是:MLOG_WRITE_STRING,就是代表你一下子在哪个数据页的某个偏移量的位置插入或者修改了一大串的值。
所以redo log看起来的结构如下:日志类型(类似MLOG_1BYTE之类的数据),表空间ID,数据页号,数据页中的偏移量,修改数据长度(MLOG_WRITE_STRING类型的才有),具体修改的数据。
当数据库修改页时,会将修改信息放入重做日志缓冲区,然后按一定频率(默认每秒一次)写入到重做日志文件,重做日志缓冲区一般不需要设置很大,只要保证每秒产生的事务量在这个缓冲区大小内即可,缓冲区大小可以通过参数innodb_log_buffer_size配置,默认为8MB。
写入触发
一般情况下,对于通常的事务提交,分为三个阶段:
- 事务准备提交:
- 事务提交过程中:
- 事务提交完成:
**主要过程是,在事务提交时候, 会发生强制的将 redo log buffer的日志缓存的数据,强制写入 redo log file中, 通常会调用一次操作系统的fsync()的操作。**其中还会经过操作系统的内核空间, OS buffer ,因为MySQL的进行和日志缓存都工作在操作系统中环境下
本质:
事务提交的过程中,必须将日志缓存的数据持久化到磁盘的日志文件中,期间还需要经过操作系统的 “内核空间缓存区”,也就是OS Buffer区域,Redo log从用户空间的 Log buffer 写入磁盘的Redo Log文件时,需要要内核空间的OS buffer;日志文件,没有使用 O_DIRECT标识,如果有这个标识,就可以不经过这个os buffer的内核空间,直接写入磁盘数据;
问题
1)为什么不直接修改磁盘中的数据?
因为直接修改磁盘数据的话,它是随机IO,修改的数据分布在磁盘中不同的位置,需要来回的查找,所以命中率低,消耗大,而且一个小小的修改就不得不将整个页刷新到磁盘,利用率低;
与之相对的是顺序IO,磁盘的数据分布在磁盘的一块,所以省去了查找的过程,节省寻道时间。使用后台线程以一定的频率去刷新磁盘可以降低随机IO的频率,增加吞吐量,这是使用buffer pool的根本原因。
2)redo log一定能保证事务的持久性吗?
不一定,这要根据redo log的刷盘策略决定,因为redo log buffer同样是在内存中,如果提交事务之后,redo log buffer还没来得及将数据刷新到redo log file进行持久化,此时发生宕机照样会丢失数据。
刷盘写入策略。
3)页修改之后为什么不直接刷盘呢?
InnoDB 页的大小一般为 16KB,而页又是磁盘和内存交互的基本单位。这就导致即使我们只修改了页中的几个字节数据,一次刷盘操作也需要将 16KB 大小的页整个都刷新到磁盘中。而且,这些修改的页可能并不相邻,也就是说这还是随机 IO。
采用 redo log 的方式就可以避免这种性能问题,因为 redo log 的刷盘性能很好。首先,redo log 的写入属于顺序 IO。 其次,一行 redo log 记录只占几十个字节。另外,Buffer Pool 中的页(脏页)在某些情况下(比如 redo log 快写满了)也会进行刷盘操作。不过这里的刷盘操作会合并写入,更高效地顺序写入到磁盘。
4)什么情况下会将缓冲区内容写入到重做日志中
1)主线程Master Thread每秒会写入一次
2)每个事务提交时会写入一次
3)当重做日志缓冲池剩余空间小于50%时,会写入一次
undo log
undo log也属于引擎层(innodb)的日志,由上可知,redo log 和undo log的核心是为了保证innodb事务机制中的持久性和原子性,事务提交成功由redo log保证数据持久性,而事务可以进行回滚从而保证事务操作原子性则是通过undo log 来保证的。
应用场景
1)事务回滚
后台线程会不定时的去刷新buffer pool中的数据到磁盘,但是如果该事务执行期间出现各种错误(宕机)或者执行rollback语句,那么前面刷进去的操作都是需要回滚的,保证原子性,undo log就是提供事务回滚的。
2)MVCC
**在内部实现中,InnoDB 通过数据行的 DB_TRX_ID 事务ID 和 Read View 来判断数据的可见性,如不可见,则通过数据行的 DB_ROLL_PTR 回滚指针 找到 undo log 的日志版本链做比较,即遍历链表中的事务ID,直到找到满足条件的DBTRXID,这个DBTRXID所在的旧记录就是当前事务能看到的最新老版本数据。**从中分析出该行记录以前的数据版本是怎样的,从而让用户能够读取到当前事务操作之前的数据——快照读。
MVCC
的实现依赖于:隐藏字段(自增ID、事务ID、回滚指针)、Read View、undo log。
undo log 数据格式
undo log 数据主要分两类:
1)insert undo log
insert 操作的记录,只对事务本身可见,对其他事务不可见(这是事务隔离性的要求),故该insert undo log可以在事务提交后直接删除,不需要进行purge操作。
2)update undo log
update undo log记录的是对delete和update操作产生的undo log。该undo log可能需要提供MVCC机制,因此不能在事务提交时就进行删除。提交时放入undo log链表,等待purge线程进行最后的删除。
在InnoDB存储引擎中,undo log使用rollback segment回滚段进行存储,每个回滚段包含了1024个undo log segment。MySQL5.5之后,一共有128个回滚段。即总共可以记录128 * 1024个undo操作。
问题
1)undo log 如何保证事务的原子性?
每一个事务对数据的修改都会被记录到 undo log ,当执行事务过程中出现错误或者需要执行回滚操作的话,MySQL 可以利用 undo log 将数据恢复到事务开始之前的状态。undo log 属于逻辑日志,记录的是 SQL 语句,比如说事务执行一条 DELETE 语句,那 undo log 就会记录一条相对应的 INSERT 语句。
2)除了保证事务的原子性,undo log 还有什么用?
InnoDB存储引擎中 MVCC 的实现用到了 undo log 。当用户读取一行记录时,若该记录已经被其他事务占用,当前事务可以通过undo log读取之前的行版本信息,以此实现非锁定读取。
总结
binlog 是MySQL server层的日志,而redo log 和undo log都是引擎层(InnoDB)的日志,要换其他数据引擎那么就未必有redo log和undo log了。
它的设计目标是支持innodb的“事务”的特性,事务ACID特性分别是原子性、一致性、隔离性、持久性, 一致性是事务的最终追求的目标。隔离性是通过MVCC+锁机制来实现的,而事务的原子性和持久性则是通过redo log 和undo log来保障的。
redo log让InnoDB有了崩溃恢复的能力,binlog保证了MySQL集群架构的数据一致性。
在执行更新语句过程,会记录redo log与binlog两块日志,以基本的事务为单位,redo log在事务执行过程中可以不断写入,而binlog只有在提交事务时才写入,所以redo log与binlog的写入时机不一样。
MySQL 三大日志中,bin log属于Server的,有缓冲buffer,缓冲区域在事务线程的内存中。redo log undo log 属于innoDB存储引擎,有缓冲buffer,在内存缓冲区域,由 LRU 链表和 Flush 链表管理。undo log 存储在引擎内部采用rollback segment回滚段进行存储。
相关文章:
MySQL-三大日志
前言 redo log:为了持久化数据,当内存中的数据还没写入到磁盘而宕机时,会读取该日志持久化数据到磁盘 undo log:为了保证原子性,事务的操作都会记录一条相反的sql到该日志,出现错误就会根据该文件恢…...

MySQL数据库详解 二:数据库的高级语言和操作
文章目录 1. 克隆表 ---- 将数据表的数据记录生成到新的表中1.1 方式一:先创建新表,再导入数据1.2方式二:创建的时候同时导入 2. 清空表 ---- 删除表内的所有数据2.1 delete删除2.2 truncate删除(重新记录)2.3 创建临时…...

基于springboot+vue的在线购房(房屋租赁)系统
博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容:毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…...

scikit-learn机器学习算法封装
K近邻算法 K-最近邻(KNN)是一种有监督的机器学习算法,可用于解决分类和回归问题。它基于一个非常简单的想法,数据点的值由它周围的数据点决定。考虑的数据点数量由k值确定。因此,k值是算法的核心。 我们现在已经知道。…...
信息化发展56
数据开发利用 通过数据集成、数据挖掘和数据服务(目录服务、查询服务、浏览和下载服务、数据分发服务)、数据可视化、信息检索等技术手段, 帮助数据用户从数据资源中找到所需要的数据, 并将数据以一定的方式展现出来,…...

外贸进销存ERP系统源码 多店ERP系统源码
外贸进销存ERP系统源码 多店ERP系统源码 ERP系统的主要优势在于它可以将企业的所有业务流程整合到一个中央化的系统中,并通过数据共享和集成来提高企业的效率。这样,各部门之间就可以相互协作,共同完成业务流程,而不会受到信息隔…...
旅游行业怎么做微信营销?
让我们分析一下现在的旅游业市场,一方面用户的旅游需求越来越旺盛,而另一方面旅游从业者却都在抱怨市场越来越难搞,线下旅行社说:好惨,游客都跑线上大门户去订购了,我们只能吃剩下的,线上旅行社…...
Linux下du指令详情介绍
磁盘空间使用统计,方便排行哪些文件占用内存大 1.统计指定目录磁盘空间使用情况 du 目录路径2.可读形式 du -h 目录路径3.显示所有文件和目录的磁盘使用情况 du -a [目录路径]4.仅统计目录的磁盘空间使用情况,不包括子目录: du -S [目录路…...

【刷题-牛客】链表内指定区间反转
链表定区间翻转链表 题目链接题目描述核心思想详细图解代码实现复杂度分析 题目链接 链表内指定区间反转_牛客题霸_牛客网 (nowcoder.com) 题目描述 核心思想 遍历链表的过程中在进行原地翻转 [m,n]翻转区间记作子链表,找到子链表的 起始节点 left 和 终止节点 right记录在…...

【MySQL】 MySQL索引事务
文章目录 🛫索引🎍索引的概念🌳索引的作用🎄索引的使用场景🍀索引的使用📌查看索引📌创建索引🌲删除索引 🌴索引保存的数据结构🎈B树🎈B树&#x…...

mybatis-plus异常:dynamic-datasource can not find primary datasource
现象 使用mybatis-plus多数据源配置时出现异常 com.baomidou.dynamic.datasource.exception.CannotFindDataSourceException: dynamic-datasource can not find primary datasource分析 异常原因是没有设置默认数据源,在类上没有使用DS指定数据源时,默…...

购物H5商城架构运维之路
一、引言 公司属于旅游行业,需要将旅游,酒店,购物,聚合到线上商城。通过对会员数据进行聚合,形成大会员系统,从而提供统一的对客窗口。 二、业务场景 围绕更加有效地获取用户,提升用户的LTV&a…...

【NAD NADPH; FMN FAD ; NMN -化学】
NAD Nicotinamide adenine dinucleotide nicotinamide 烟酰胺 NAD NADPH 烟酰胺腺嘌呤二核苷酸 nucleosidase Nicotinamide adenine dinucleotide NMN(烟酰胺单核苷酸)简介 NMN全名 nicotinamide mononucleotide,即 烟酰胺单…...
Shell脚本之if的用法
Shell脚本之if的用法 1、if语句的格式2、if语句的conditon介绍3、应用举例 1、if语句的格式 1) if-elif-else语法格式 if [ condition1 ]; then # 执行条件1的代码块 elif [ condition2 ]; then # 执行条件2的代码块 else # 执行条件都不满足时的代码块 …...

Java实验案例(一)
目录 案例一:买飞机票 案例二:开发验证码 案例三:评委打分 案例四:数字加密 案例五:数组拷贝 案例六:抢红包 案例七:找素数的三种方法 案例八:打印乘法口诀表 案例九&#x…...
Service Worker原理
Service Worker原理 1.基本概念与使用场景:a.什么是Service Worker?它的主要用途是什么?b.Service Worker和Web Worker有什么不同?c.预缓存和缓存的区别 2. 实现细节:a.描述Service Worker的生命周期。b.如何注册和注销一个Service Worker&am…...

MySQL集群高可用架构之MHA
MHA 一、MHA概述1.1 为什么要用MHA?1.2 什么是 MHA?1.3 MHA 的组成1.4 MHA 的特点1.5 故障切换备选主库的算法1.5 MHA工作原理 二、MySQL MHA高可用实例2.1 架构搭建部分1)所有节点服务器安装MySQL2)主从节点服务器添加域名映射3&…...

【算法专题突破】二分查找 - 704. 二分查找(16)
目录 1. 题目解析 2. 算法原理 3. 代码编写 写在最后: 1. 题目解析 题目链接:704. 二分查找 - 力扣(LeetCode) 题目非常简单,就是查找一个 target。 2. 算法原理 根据最基本的二分查找算法: 在一个…...

基于Docker_Nginx+LVS+Flask+MySQL的高可用Web集群
一.项目介绍 1.拓扑图 2.详细介绍 项目名称:基于Docker_NginxLVSFlaskMySQL的高可用Web集群 项目环境:centos7.9,docker24.0.5,mysql5.7.30,nginx1.25.2,mysqlrouter8.0.21,keepalived 1.3.5,…...
如何写一份出色的毕业设计任务书
title: 如何写一份出色的毕业设计任务书 date: 2023-09-20 毕业设计任务书是每个毕业生必须面对的关键文档。它不仅是你完成毕业设计的路线图,还是导师评估你工作的依据。因此,撰写一份清晰、详细且具体的任务书至关重要。本文将向你介绍如何编写一份出色…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...

地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...

Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...
深入理解Optional:处理空指针异常
1. 使用Optional处理可能为空的集合 在Java开发中,集合判空是一个常见但容易出错的场景。传统方式虽然可行,但存在一些潜在问题: // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...