海山数据库(He3DB)源码详解:两阶段提交(2PC)事务块内核函数执行过程

结合MATLAB/Simulink和多体动力学仿真软件UM(Universal Mechanism),建立高速列车轴箱轴承的动力学模型,并通过联合仿真分析其正常运行特性和典型故障模式 高速列车是现代交通运输的重要组成部分,其运行速度高、载客量大,对安全性和可靠性提出了极高的要求。轴箱轴承作为高速列车的关键部件之一,承担着传递载荷和支撑车轴的重要作用。然而,由于长期运行在高速、重载和复杂工况下,轴箱轴承容易出现疲劳磨损、润滑失效和裂纹等故障,从而影响列车的安全性。本项目旨在结合MATLAB/Simulink和多体动力学仿真软件UM(Universal Mechanism),建立高速列车轴箱轴承的动力学模型,并通过联合仿真分析其正常运行特性和典型故障模式。 阅读详情

海山数据库(He3DB)源码详解:两阶段提交(2PC)事务块内核函数执行过程

本文介绍了两阶段提交(2PC)事务执行过程中,主要讲解事务的prepare阶段和commit阶段的内核函数执行过程。

前言

两阶段提交(2PC)是一种用于分布式系统的事务处理协议,旨在确保事务的原子性。以下是2PC从事务准备到提交或放弃的执行流程图:

graph TD
    A[开始] --> B[事务发起者请求所有参与者准备]
    B --> C{所有参与者是否准备好?}
    C -- 是 --> D[事务发起者发送提交请求]
    C -- 否 --> E[事务发起者发送放弃请求]
    D --> F{所有参与者是否同意提交?}
    F -- 是 --> G[所有参与者提交事务]
    F -- 否 --> H[所有参与者放弃事务]
    E --> I[所有参与者放弃事务]
    G --> J[事务提交完成]
    H --> J
    I --> J
    J --> K[结束]

流程说明:

  1. 开始:事务发起者(协调者)开始一个新的分布式事务。
  2. 事务发起者请求所有参与者准备:协调者向所有参与者发送准备请求,询问它们是否准备好提交事务。
  3. 所有参与者是否准备好?:这是一个决策点,需要等待所有参与者的响应。
    • 是:如果所有参与者都准备好了,协调者将发送提交请求。
    • 否:如果任何一个参与者没有准备好,协调者将发送放弃请求。
  4. 事务发起者发送提交请求:协调者向所有参与者发送提交事务的请求。
  5. 所有参与者是否同意提交?:这是另一个决策点,需要等待所有参与者的响应。
    • 是:如果所有参与者都同意提交,它们将执行提交操作。
    • 否:如果任何一个参与者拒绝提交,所有参与者将放弃事务。
  6. 所有参与者提交事务:参与者执行实际的提交操作,使事务永久生效。
  7. 所有参与者放弃事务:参与者执行回滚操作,撤销所有事务相关的更改。
  8. 事务提交完成:事务要么成功提交,要么被放弃,分布式事务到此结束。
  9. 结束:2PC过程完成。

处理TRANS_STMT_PREPARE

当终端输入PREPARE TRANSACTION xxx语句时,这时一个会发起2PC的事务提交准备过程。处理过程首先会调用PrepareTransactionBlock()函数,并根据返回值判断是否时错误结束发生回滚。

PrepareTransactionBlock()函数执行过程:

  1. 首先,该函数会调用EndTransactionBlock()函数,获得一个事务结束的返回值;
    TransactionState s;
	bool		result;

	/* Set up to commit the current transaction */
	result = EndTransactionBlock(false);
  1. 然后,判断result的值,如果为true,修改其他block的状态;如果为false,表示事务出错,准备进行回滚;
	if (result)
	{
		s = CurrentTransactionState;

		while (s->parent != NULL)
			s = s->parent;

		if (s->blockState == TBLOCK_END)
		{
			/* Save GID where PrepareTransaction can find it again */
			prepareGID = MemoryContextStrdup(TopTransactionContext, gid);

			s->blockState = TBLOCK_PREPARE;
		}
		else
		{
			/*
			 * ignore case where we are not in a transaction;
			 * EndTransactionBlock already issued a warning.
			 */
			Assert(s->blockState == TBLOCK_STARTED ||
				   s->blockState == TBLOCK_IMPLICIT_INPROGRESS);
			/* Don't send back a PREPARE result tag... */
			result = false;
		}
	}
  • 首先,获得当前事务的状态结构体,并找到事务的根节点;
  • 之后,判断节点的状态是否为END,如果是,则将当前的gid深拷贝一份,交给全局静态变量prepareGID,并修改事务块的状态为TBLOCK_PREPARE;否则,将返回结构result改为false,准备进行回滚。

根据PrepareTransactionBlock()返回值对事务进行标记

如果PrepareTransactionBlock()函数的返回值为false,则会将事务标记为CMDTAG_ROLLBACK,这意味着当前的事务将被中止,并且事务所作的所有更新都会被丢弃,回到事务开始之前的状态。调用SetQueryCompletion()函数对传入参数qc进行修改,完成事务的标记。

处理TRANS_STMT_COMMIT_PREPARED

当终端输入COMMIT PREPARED xxx语句时,这时会发起一个2PC的事务提交过程。处理过程首先会调用PreventInTransactionBlock()函数,检查当前分布式事务和事务块的状态。然后调用FinishPreparedTransaction()函数,执行分布式事务提交操作。

PreventInTransactionBlock()函数执行过程

  1. 调用IsTransactionBlock()检查全局结构体变量CurrentTransactionState中的blockState成员值,如果blockState等于TBLOCK_DEFAULT或者TBLOCK_STARTED,表示不存在事务块,返回false,其他返回true:
	if (IsTransactionBlock())
		ereport(ERROR,
				(errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
		/* translator: %s represents an SQL statement name */
				 errmsg("%s cannot run inside a transaction block",
						stmtType)));
  1. 调用IsSubTransaction()检查全局结构体变量CurrentTransactionState中的nestingLevel成员值,如果≥2表示有子事务嵌套,返回true,否则返回false:
    if (IsSubTransaction())
		ereport(ERROR,
				(errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
		/* translator: %s represents an SQL statement name */
				 errmsg("%s cannot run inside a subtransaction",
						stmtType)));
  1. 检查全局int变量MyXactFlag的值,如果等于XACT_FLAGS_PIPELINING,表示事务处于管道模式。
	if (MyXactFlags & XACT_FLAGS_PIPELINING)
		ereport(ERROR,
				(errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
		/* translator: %s represents an SQL statement name */
				 errmsg("%s cannot be executed within a pipeline",
						stmtType)));
  • 补充: 管道模式和2PC(两阶段提交)之间的冲突主要体现在以下几个方面:
  1. 检查是否为TopLevel:
	if (!isTopLevel)
		ereport(ERROR,
				(errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
		/* translator: %s represents an SQL statement name */
				 errmsg("%s cannot be executed from a function", stmtType)));
  1. 检查当前事务块状态:
	if (CurrentTransactionState->blockState != TBLOCK_DEFAULT &&
		CurrentTransactionState->blockState != TBLOCK_STARTED)
		elog(FATAL, "cannot prevent transaction chain");
  1. 将全局int变量MyXactFlag的与XACT_FLAGS_NEEDIMMEDIATECOMMIT做位或操作
    MyXactFlags |= XACT_FLAGS_NEEDIMMEDIATECOMMIT;

FinishPreparedTransaction()函数执行过程

  1. 首先,申请执行过程所需要的所有变量:
	GlobalTransaction gxact;
	PGPROC	   *proc;
	TransactionId xid;
	char	   *buf;
	char	   *bufptr;
	TwoPhaseFileHeader *hdr;
	TransactionId latestXid;
	TransactionId *children;
	RelFileNode *commitrels;
	RelFileNode *abortrels;
	RelFileNode *delrels;
	int			ndelrels;
	xl_xact_stats_item *commitstats;
	xl_xact_stats_item *abortstats;
	SharedInvalidationMessage *invalmsgs;
  • GlobalTransaction gxact;

    • 这是一个结构体,用于表示全局事务数据的类型,主要跟踪prepared transactions(即那些已经被准备好但尚未提交的事务)。
  • PGPROC *proc;

    • PGPROC 是 PostgreSQL 中的一个结构体,代表一个后端进程。这个指针用于指向当前事务的后端进程结构。
  • TransactionId xid;

    • TransactionId 是 PostgreSQL 中用于唯一标识一个事务的类型。这个变量存储了当前事务的 ID。
  • char *buf;

    • 这是一个字符指针,用于存储事务日志记录的缓冲区。
  • char *bufptr;

    • 这是另一个字符指针,用作 buf 的游标或指针,用于在缓冲区中移动和处理数据。
  • TwoPhaseFileHeader *hdr;

    • TwoPhaseFileHeader 是一个结构体,用于存储两阶段提交协议的文件头信息。这个指针可能指向一个这样的结构体实例,包含有关两阶段提交的元数据。
  • TransactionId latestXid;

    • 这个变量存储了最新的事务 ID,用于跟踪事务日志中的最新事务。
  • TransactionId *children;

    • 这是一个指向 TransactionId 的指针数组,用于存储当前事务的子事务 ID。
  • RelFileNode *commitrels;

    • 这是一个指向 RelFileNode 的指针数组,用于存储需要在事务提交时处理的关联关系文件节点。
  • RelFileNode *abortrels;

    • 类似于 commitrels,这个指针数组用于存储需要在事务中止时处理的关联关系文件节点。
  • RelFileNode *delrels;

    • 这个指针数组用于存储需要删除的关联关系文件节点。
  • int ndelrels;

    • 这个整数变量表示 delrels 数组中的元素数量。
  • xl_xact_stats_item *commitstats;

    • 这是一个指针,指向存储提交事务统计信息的结构体。
  • xl_xact_stats_item *abortstats;

    • 类似于 commitstats,这个指针指向存储中止事务统计信息的结构体。
  • SharedInvalidationMessage *invalmsgs;

    • 这是一个指针,指向共享无效消息,用于在事务处理过程中通知其他节点或进程某些数据已失效。
  1. 验证GID并锁定GXACT,获取对应GXACT的后端proc,获取GXACT的xid。
	/*
	 * Validate the GID, and lock the GXACT to ensure that two backends do not
	 * try to commit the same GID at once.
	 */
	gxact = LockGXact(gid, GetUserId());
	proc = &ProcGlobal->allProcs[gxact->pgprocno];
	xid = gxact->xid;
  • 验证GID: GID 通常指的是全局事务标识符(Global Transaction Identifier)。验证 GID 意味着检查这个标识符是否有效,是否存在于系统中,以及是否对应于一个已经准备好但尚未提交的事务。这是为了确保你正在处理的是一个有效的、待提交的事务。

  • 锁定GXACT: GXACT 可能是指全局事务数据结构(Global Transaction Actor)。锁定 GXACT 是为了防止多个后端(backend)进程或线程同时尝试提交同一个 GID 对应的事务。这种锁定机制是必要的,因为在一个分布式系统中,可能同时有多个节点或进程参与事务的处理。

  • 保两个后端不会尝试一次提交相同的 GID: 这句话的意思是确保不会有两次提交操作同时对同一个 GID 进行。在分布式系统中,不同的后端可能指的是不同的数据库节点、不同的事务管理器或不同的服务实例。它们可能都参与了同一个全局事务的处理,但是由于网络分区、节点故障恢复或其他原因,可能会出现多个节点尝试提交同一个事务的情况。为了防止数据不一致或其他问题,需要确保对于任何一个给定的 GID,在同一时间内只有一个后端可以进行提交操作。

  1. 检查gxact->ondisk,如果成立就从磁盘上读取2PC状态数据,如果不成立就从Xlog日志中读取2PC状态数据。
	if (gxact->ondisk)
		buf = ReadTwoPhaseFile(xid, false);
	else
		XlogReadTwoPhaseData(gxact->prepare_start_lsn, &buf, NULL);
  1. 从buf中读取数据并初始化申请的变量。
	hdr = (TwoPhaseFileHeader *) buf;
	Assert(TransactionIdEquals(hdr->xid, xid));
	bufptr = buf + MAXALIGN(sizeof(TwoPhaseFileHeader));
	bufptr += MAXALIGN(hdr->gidlen);
	children = (TransactionId *) bufptr;
	bufptr += MAXALIGN(hdr->nsubxacts * sizeof(TransactionId));
	commitrels = (RelFileNode *) bufptr;
	bufptr += MAXALIGN(hdr->ncommitrels * sizeof(RelFileNode));
	abortrels = (RelFileNode *) bufptr;
	bufptr += MAXALIGN(hdr->nabortrels * sizeof(RelFileNode));
	commitstats = (xl_xact_stats_item *) bufptr;
	bufptr += MAXALIGN(hdr->ncommitstats * sizeof(xl_xact_stats_item));
	abortstats = (xl_xact_stats_item *) bufptr;
	bufptr += MAXALIGN(hdr->nabortstats * sizeof(xl_xact_stats_item));
	invalmsgs = (SharedInvalidationMessage *) bufptr;
	bufptr += MAXALIGN(hdr->ninvalmsgs * sizeof(SharedInvalidationMessage));
  1. 获取主xact及其子项中的最新XID,并关闭中断。
    latestXid = TransactionIdLatest(xid, hdr->nsubxacts, children);
    HOLD_INTERRUPTS();
  1. 判断isCommit值,根据判断结果选择执行提交(commit)还是放弃(abort)。
	if (isCommit)
		RecordTransactionCommitPrepared(xid,
										hdr->nsubxacts, children,
										hdr->ncommitrels, commitrels,
										hdr->ncommitstats,
										commitstats,
										hdr->ninvalmsgs, invalmsgs,
										hdr->initfileinval, gid);
	else
		RecordTransactionAbortPrepared(xid,
									   hdr->nsubxacts, children,
									   hdr->nabortrels, abortrels,
									   hdr->nabortstats,
									   abortstats,
									   gid);
    ProcArrayRemove(proc, latestXid);
    gxact->valid = false;
  • 当isCommit为true时,会调用RecordTransactionCommitPrepared函数记录事务提交日志;
  • 当isCommit为false时,会调用RecordTransactionAbortPrepared函数记录事务放弃日志;
  • 从全局 ProcArray 中移除 PGPROC,移除 PGPROC 条目意味着该事务不再被视为活跃,TransactionIdIsInProgress函数将不再报告该事务正在进行中;
  • 将全局事务的valid成员值改为false,表示该事务不在后端进程中。
  1. 判断isCommit值,根据判断结果对变量delrels和ndelrels进行赋值,然后进行对应Relation文件的的删除,以及执行计划内的删除。
	if (isCommit)
	{
		delrels = commitrels;
		ndelrels = hdr->ncommitrels;
	}
	else
	{
		delrels = abortrels;
        ndelrels = hdr->nabortrels;
    }
    DropRelationFiles(delrels, ndelrels, false);
    
	if (isCommit)
		pgstat_execute_transactional_drops(hdr->ncommitstats, commitstats, false);
	else
		pgstat_execute_transactional_drops(hdr->nabortstats, abortstats, false);
  • 当isCommit为true时,调用commitrels和hdr的ncommitrels成员两个值对变量进行赋值,表示进行提交的节点删除;
  • 当isCommit为false时,调用abortrels和hdr的nabortrels成员两个值对变量进行赋值,表示进行放弃的节点删除;
  • DropRelationFiles函数会调用smgrdounlinkall函数,作用是将给定的所有SMgrRelation对象的所有分支(forks)从磁盘中移除,确保数据库系统中不再需要的文件被彻底清除,以释放存储空间,并保持文件系统的整洁。执行 smgrdounlinkall 函数的具体步骤通常包括:
    1. 从共享缓冲池中移除所有相关的数据页。
    2. 关闭所有 SMgrRelation 对象的所有分支。
    3. 注册 SMgrRelation 对象与物理文件的无效映射信息,并告知其他进程。
    4. 删除所有 SMgrRelation 对象的所有分支所对应的物理文件。
  • 根据isCommit的值,调用pgstat_execute_transactional_drops函数执行计划内的删除,主要是一些被标记为删除的对象(如表、索引、视图等)能够从实际统计信息中移除,具体来说,pgstat_execute_transactional_drops会执行以下操作:
    • 在事务提交时,它会删除那些在事务中被删除的对象的统计信息。
    • 在事务回滚时,它会撤销对统计信息的任何修改,因为事务中的更改没有实际发生。
    • 这个函数确保了统计信息的一致性,避免了因为事务中的删除操作而导致的统计信息不一致的问题。
  1. 当事务提交时,确保所有相关的缓存和共享数据结构都被正确地更新或失效,以反映事务中所做的更改。
	if (isCommit)
	{
		if (hdr->initfileinval)
			RelationCacheInitFilePreInvalidate();
		SendSharedInvalidMessages(invalmsgs, hdr->ninvalmsgs);
		if (hdr->initfileinval)
			RelationCacheInitFilePostInvalidate();
	}

  • 检查是否需要初始化文件失效(initfileinval):

    • hdr->initfileinval 检查是否需要进行初始化文件失效的操作。如果为真,表示需要在事务提交前处理相关的缓存失效。
  • 执行初始化文件预失效(PreInvalidate)操作:

    • RelationCacheInitFilePreInvalidate() 函数被调用,以处理在发送共享失效消息(Shared Invalid Messages)之前需要进行的缓存失效操作。这通常涉及到关系缓存(relation cache)的初始化文件,确保在事务提交过程中,相关的缓存信息是最新的。
  • 发送共享失效消息:

    • SendSharedInvalidMessages(invalmsgs, hdr->ninvalmsgs) 函数被调用,发送共享失效消息。这些消息通知其他数据库进程,某些数据或结构已经改变,需要更新它们的缓存。invalmsgs 是一个包含失效消息的数组,hdr->ninvalmsgs 是这个数组中的元素数量。
  • 执行初始化文件后失效(PostInvalidate)操作:

    • 如果 hdr->initfileinval 为真,RelationCacheInitFilePostInvalidate() 函数被调用,以处理在发送共享失效消息之后需要进行的缓存失效操作。这确保了在事务提交后,相关的缓存信息也是最新的。

共享失效消息(Shared Invalidation Messages)是 PostgreSQL 中用于维护缓存一致性的一种机制。当数据库中的某些数据被修改时,这些修改可能会影响到其他数据库进程中的缓存数据。为了确保所有进程中的缓存数据保持一致,PostgreSQL 通过共享失效消息来通知其他进程,某些缓存数据已经不再有效,需要被刷新或更新。

这些失效消息通过一个共享内存中的队列(shmInvalBuffer)来传递,这个队列被所有数据库进程共享。当一个事务提交时,它会发送这些失效消息到其他后端进程,以便它们可以更新自己的缓存。这种机制确保了在高并发环境下,不同事务对同一数据的修改不会导致缓存不一致的问题。

  1. 加锁处理事务提交或者放弃阶段的回调函数过程,释放事务所持有的谓词锁以及清理全局事务的共享内存。
	LWLockAcquire(TwoPhaseStateLock, LW_EXCLUSIVE);

	/* And now do the callbacks */
	if (isCommit)
		ProcessRecords(bufptr, xid, twophase_postcommit_callbacks);
	else
		ProcessRecords(bufptr, xid, twophase_postabort_callbacks);

	PredicateLockTwoPhaseFinish(xid, isCommit);

	/* Clear shared memory state */
	RemoveGXact(gxact);

	/*
	 * Release the lock as all callbacks are called and shared memory cleanup
	 * is done.
	 */
	LWLockRelease(TwoPhaseStateLock);
  • ProcessRecords 回调函数的作用是处理事务日志中记录的各种操作。这些操作可能包括数据的修改、锁的获取和释放、存储管理器(storage manager)的操作等。ProcessRecords 回调函数会被调用来遍历事务日志中的每一条记录,并执行相应的操作来提交或回滚事务。
    具体来说,ProcessRecords 回调函数可能执行以下类型的操作:
    1. 数据修改:将事务中对数据的修改应用到数据库中,或者在回滚时撤销这些修改。
    2. 锁处理:在事务提交时释放锁,或者在回滚时保持锁的状态。
    3. 存储管理器操作:处理与物理存储相关的操作,如文件的创建、删除等。
    4. 系统目录更新:更新系统目录信息,以反映事务对数据库结构的更改。
  • PredicateLockTwoPhaseFinish处理和释放一个准备好的事务在提交或中止时持有的谓词锁,无论是成功提交还是由于某种原因中止,都需要确保之前设置的谓词锁被释放,以避免死锁和其他事务的不一致性问题。
  • RemoveGXact会处理共享内存中的全局事务,注意:这里的全局事务必须以及从Proc Array中移除了。
  1. 更新和清理事务的统计信息,处理2PC文件,将该进程的全局事务指针置空,开放终端,释放内存,结束函数。
	/* Count the prepared xact as committed or aborted */
	AtEOXact_PgStat(isCommit, false);

	/* And now we can clean up any files we may have left. */
	if (gxact->ondisk)
		RemoveTwoPhaseFile(xid, true);

	MyLockedGxact = NULL;

	RESUME_INTERRUPTS();

	pfree(buf);
  • AtEOXact_PgStat主要负责更新统计信息,这些统计信息包括但不限于表和索引的访问统计、函数调用统计等,具体来说会执行以下操作:
    • 更新表和索引的统计信息,如访问次数、行数变化等。
    • 更新函数调用的统计信息,如调用次数和执行时间。
    • 清理事务中产生的临时统计信息。
    • 确保统计信息的准确性和及时性,以便查询优化器可以使用这些信息来优化查询计划。
      与pgstat_execute_transactional_drops函数的区别:
    • AtEOXact_PgStat 函数更关注于更新和清理事务中的统计信息;
    • pgstat_execute_transactional_drops 函数则专注于处理事务中对象的创建和删除对统计信息的影响。
  • 调用RemoveTwoPhaseFile函数处理2PC文件。每个事务在进行两阶段提交时,会创建一个临时文件来记录事务的状态,直到事务最终提交或中止。这个文件被称为两阶段提交文件(2PC 文件),它包含了完成两阶段提交协议所需的信息。
  • 当前由本进程锁定的全局事务条目指针MyLockedGxact置为空;
  • 放开中断,并释放buf对应的内存空间。

处理TRANS_STMT_ROLLBACK_PREPARED

当终端输入ABORT PREPARED xxx语句时,这时会发起一个2PC的事务放弃过程。整体流程和2PC的提交过程类似,所以这里不做过多的讲解。

财务惊呼“不可能”!Python 自动识别 PDF 发票,数据秒级录入系统 电子发票(原生 PDF):这种最爽,文字是可以选中的。我们用 PyPDF2 直接提取文本,速度快,准确率 100%。 纸质扫描/拍照发票:这种是图片。必须上 OCR(光学字符识别)。我们要用百度开源的 PaddleOCR,这是目前中文识别效果最好的开源库之一,吊打早已过气的 Tesseract。 阅读详情

相关推荐

从Delta Delay到Timing Window:详解数字芯片后端时序差异的那些坑

本文深入剖析了数字芯片后端设计中,模块级与系统级时序分析结果不一致的核心原因。重点解释了Delta Delay如何导致模块级分析的乐观假设,以及Timing Window(时序窗口)差异如何通过影响串扰噪声计算,在顶层集成时引发新的时序违例,尤其是保持时间问题。文章为工程师提供了从约束建模到签核策略的系统性应对方案。

beer8的博客 498

海山数据库(He3DB)源码解读:2PC

两阶段提交(2PC)是一种用于分布式系统的事务处理协议,旨在确保事务的原子性。以下是2PC从事务准备到提交或放弃的执行流程图:开始:事务发起者(协调者)开始一个新的分布式事务。事务发起者请求所有参与者准备:协调者向所有参与者发送准备请求,询问它们是否准备好提交事务。所有参与者是否准备好?:这是一个决策点,需要等待所有参与者的响应。是:如果所有参与者都准备好了,协调者将发送提交请求。否:如果任何一个参与者没有准备好,协调者将发送放弃请求。事务发起者发送提交请求。

weixin_51457815的博客 981

libiec61850实战:手把手教你用C语言动态获取IED设备模型(附完整代码解析)

本文详细介绍了如何使用libiec61850库通过C语言动态获取IED设备模型,包括环境配置、连接建立、模型遍历及错误处理等关键步骤。通过完整的代码示例和实战案例,帮助开发者掌握智能变电站通信中的核心技术,提升工业自动化系统的开发效率。

weixin_42519985的博客 433

Spring Boot 数据源与 MyBatis(-Plus) 自定义配置详解

本文详解 Spring Boot 中单数据源环境下 HikariCP 与 MyBatis-Plus 的自定义配置。通过手动声明 SqlSessionFactory,实现下划线转驼峰、日志输出、一级缓存策略等精细化控制。结合 HikariCP 核心参数调优(如最大连接数、连接生命周期),确保高性能与稳定性。适用于仅需访问单一数据库的场景,避免多数据源复杂性,兼顾性能与可维护性。

BADAO_LIUMANG_QIZHI的博客 195

Ubuntu关闭更新提醒的三层控制方法:从GUI到APT配置

Linux系统更新机制本质上是包管理器(APT)驱动的自动化运维流程,其核心原理在于分离‘元数据刷新’、‘安全补丁安装’和‘用户通知’三个职能。这种分层设计既保障了基础安全性,又为系统管理员提供了策略定制空间。技术价值体现在提升生产环境稳定性、规避未经验证的内核/驱动升级风险,并支持ROS、Blender渲染、工业控制等对时序敏感的应用场景。本文聚焦Ubuntu系统入门教程中高频需求——科学关闭软件更新提醒,覆盖Ubuntu 20.04及LTS版本的GUI设置、systemd服务禁用与APT配置修改三大实操

weixin_29698641的博客 394

12V转5V稳压电路详细分析(7805三端稳压,LM2596稳压)

7805线性三端稳压 DCDC的意思是直流变到直流(不同直流电源值的转换),只要符合这个定义都可以叫DCDC转换器,或称之为开关电源或开关调整器。 7805属于常用的线性三端稳压器,输入电压范围不大于35V,输入输出压差2V,最大输出电流1.5A,下图为原理图,其原理简单,使 用方便,深受很多用户的喜爱。但是其不足之处就是效率低,特别是压差越大时其效率越低。比如这里12V转5V的效率为 5V/12V≈41.7%。 如上电路是最经典的7805稳压5V电路,电路中有两个电容,电容的作用如下: ...

a2001444的博客 9万+

在Codex 让AI模型 拥有长期智能记忆

本文介绍Claude-Mem V15新功能——智能记忆召回,解决AI遗忘、重复提示、执行不一致等问题。通过本地部署claude-mem,实现自动记录决策(如数据库选型)、跨会话智能召回,支持记忆写入、检索、遗忘全流程闭环。相比传统记忆方案,其基于Hooks自动捕获工具调用,结构化存储,可追溯、可共享、可清理,显著提升工程效率与协作一致性,是长期项目中理想的“工作黑匣子”与“工程脑”。

米莱虾 265

CTS实战:如何用set_sense优化时钟树平衡(附ICC2避坑指南)

本文深入探讨了在时钟树综合(CTS)中,如何正确使用`set_sense`命令优化时钟树平衡,并对比了其与`set_disable_timing`的本质区别。通过实战案例详细解析了`-stop_propagation`和`-clock_leaf`参数的应用场景,并提供了ICC2工具中的关键避坑指南,帮助后端工程师精准控制时钟拓扑,避免时序分析漏洞。

weixin_28933797的博客 457

Java EE 进阶:8.MyBatis 操作数据库(入门)(第一弹)

Java EE 进阶:8.MyBatis 操作数据库(入门)(第一弹)

要努力去发光,而不是被照亮~ 117

伺服系统控制原理深度解析

摘要:本文系统阐述了伺服系统的控制原理与应用。首先介绍了伺服系统的定义、组成及其在工业自动化中的重要性;然后详细分析了反馈控制机制、稳定性判据和性能指标;重点推导了传递函数和状态空间两种数学模型,并通过LaTeX公式展示了二阶系统建模过程;进而对比了PID控制、状态反馈及自适应控制等方法的优缺点;最后结合数控机床等案例,验证了理论方法的有效性,并展望了伺服系统智能化发展趋势。全文兼顾理论深度与实践指导性,为控制工程领域提供了系统的技术参考。

技术工作者 1264

阿里云 Docker 镜像加速收费后:这些免费替代方案值得收藏

阿里云Docker镜像加速服务收费后,国内开发者急需免费替代方案。本文推荐2025年仍可用的7个免费镜像源,包括轩辕镜像、DaoCloud、网易云等,并提供多源配置方案以提高稳定性。建议开发者在CI/CD环境中配置多个镜像源,避免构建失败。文章还提供了详细的配置步骤和使用建议,适合个人和团队开发者参考。

sg_knight的专栏 1928

Docker Compose:搭建本地多服务开发环境

从一个 Java API、PostgreSQL 和 Redis 开始,配置服务名、端口、环境变量、健康检查、数据卷和依赖关系。理解 Compose 文件如何被解析、项目如何隔离,以及哪些数据不能依赖“重建容器”保留,能够把个人开发环境整理成团队可复用的启动入口。

m0_62221377的博客 428

Windows11安装配置openclaw+deepseek(大龙虾)

密码可以随便设置(注意wsl系统本质上是linux系统,设置密码系统是不会像windows一样显示*点位符的),输入密码后敲回车再次输入密码,输入后敲回车。如果不小心关闭这个界面,可以再次进入powershell,输入wsl进行系统。在powershell中输入:curl -fssL https://openclaw.ai/install.sh | bash。下面是否通过第3方平台和openclaw交互,我选择j最后一项:skip for now。到下面这一步,可以通过键盘的左箭头选择Yes.

mahailiang的专栏 343

45-存储过程与函数

匿名块跑完就没了,想下次再用只能复制粘贴。给块起个名字存进数据库,就成了存储过程与函数:一次编译、处处调用、权限收口,还能让 Java 侧少拼 SQL。这篇讲封装、调用、限制与排错的完整套路。CREATE OR REPLACE 覆盖式创建,事务由调用方控制;参数三模式 IN 只进、OUT 只出、IN OUT 双向,OUT 参数调用时要备好变量接;调用三姿势 EXEC、CALL、匿名块,命名传参=>最清晰;函数必有 RETURN,想在 SQL 里调用就不能碰 DML 和事务控制;

yuhou25的博客 152

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

AI全栈实战 | 3.9-01 爬虫入门:requests 加 BeautifulSoup 三分钟跑通,但 90% 的人栽在这 4 个“礼貌“问题上

⚠️:本文内容仅用于。请遵守目标站点的服务条款与相关法律法规,不得对目标服务造成负担,不得采集、传播个人隐私数据。技术是中性的,边界在你手里。爬虫的入门技术(requests 发请求 + BeautifulSoup 解析)三分钟就能学会。真正区分"会用爬虫"和"会做爬虫的人"的,是这篇我们跑通"请求→解析→存储"的最小闭环,然后重点把"合规与礼貌"这根弦给你绷上。

源码获取 | 运行部署 | 定制二开修改,如果回复不及时请耐心等待,请见谅。 393

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

上一篇: 海山数据库(He3DB)源码解读:T_GrantRoleStmt原理浅析
下一篇: 海山数据库(He3DB)源码详解:事务块执行过程及内核函数
DAWN1221
博客等级 码龄7年 893粉丝 95原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值