当前位置: 首页 > ops >正文

MySQL事务的一些奇奇怪怪知识

Gorm事务有error却不返回会发生什么

Gorm包是大家比较高频使用。正常的用法是,如果有失败返回error,整体rollback,如果不返回error则commit。下面是Transaction的源码:

// Transaction start a transaction as a block, return error will rollback, otherwise to commit. Transaction executes an
// arbitrary number of commands in fc within a transaction. On success the changes are committed; if an error occurs
// they are rolled back.
func (db *DB) Transaction(fc func(tx *DB) error, opts ...*sql.TxOptions) (err error) {panicked := trueif committer, ok := db.Statement.ConnPool.(TxCommitter); ok && committer != nil {// nested transactionif !db.DisableNestedTransaction {err = db.SavePoint(fmt.Sprintf("sp%p", fc)).Errorif err != nil {return}defer func() {// Make sure to rollback when panic, Block error or Commit errorif panicked || err != nil {db.RollbackTo(fmt.Sprintf("sp%p", fc))}}()}err = fc(db.Session(&Session{NewDB: db.clone == 1}))} else {tx := db.Begin(opts...)if tx.Error != nil {return tx.Error}defer func() {// Make sure to rollback when panic, Block error or Commit errorif panicked || err != nil {tx.Rollback()}}()if err = fc(tx); err == nil {panicked = falsereturn tx.Commit().Error}}panicked = falsereturn
}

神奇用法

但如果我瞎搞呢?如果有error我仍然返回nil,会发生什么?

err := db.Transaction(func(tx *gorm.DB) error {var err errorisInserted, err = d.TxCreate(tx, record)if err != nil {return nil}err = d.TxUpdate(tx, opt)if err != nil {return errors.Wrap(err, "failed to update")}return nil})

解释

这种情况下,本质看MySQL自身的设计。事务具有原子性,理论上应该要么全部成功,要么全部失败。但如果在一条语句失败后执行COMMIT,MySQL 会尽力提交已成功执行的语句。例如:

START TRANSACTION;
INSERT INTO test (id, value) VALUES (2, 'data3'); 
INSERT INTO test (id, value) VALUES (3, 'data4'); 
-- 故意让这条语句失败(假设id冲突)
INSERT INTO test (id, value) VALUES (2, 'data5'); 
COMMIT; 

在上述例子中,前两条INSERT语句可能已经成功执行并修改了数据库,而第三条失败。执行COMMIT后,前两条语句的修改会被永久保存到数据库中,而失败的语句不会回滚整个事务。

其实十分不建议这么用。数据库状态可能会出现部分操作生效,部分未生效的情况,破坏了事务的原子性。这可能导致数据不一致问题,例如业务逻辑上要求某些数据必须同时存在或不存在,但由于这种部分提交的情况,无法保证这种一致性。

MySQL表数据时间的记录时刻

假设数据库是这样的

CREATE TABLE `conversation_new_message` (`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',`conversation_new_id` bigint unsigned NOT NULL COMMENT '自增id',`message` json DEFAULT NULL COMMENT 'conversation history, a json map',`turn` bigint NOT NULL COMMENT '轮数',`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '上一次更新时间',PRIMARY KEY (`id`),
) ENGINE=InnoDB

起一个事务,按照下面的时间点执行,最终的创建时间是多少?是按照insert时刻的时间来的(不同记录不一样),还是按照真正落库的时间来的(不同记录一样)?

在这里插入图片描述

发现是按照真正写入的时间来的。其实也比较好理解,虽然我们没有直接赋值,但CURRENT_TIMESTAMP本身在记录创建的时候就已经设置好值了。

在这里插入图片描述

http://www.xdnf.cn/news/6956.html

相关文章:

  • linux本地部署ollama+deepseek过程
  • 大模型为什么学新忘旧(大模型为什么会有灾难性遗忘)?
  • EasyExcel动态表头
  • 【Java ee初阶】jvm(2)
  • 【Qt mainwindow 】窗口在启动时自动调整为适应屏幕大小
  • 正则表达式与文本处理的艺术
  • Selenium-Java版(css表达式)
  • go语法大赏
  • btc交易所关键需求区 XBIT反弹与上涨潜力分析​​
  • 深入理解Java中的Minor GC、Major GC和Full GC
  • 组态王|组态王中如何添加西门子1200设备
  • 2.2.4
  • 【数据结构】1-3 算法的时间复杂度
  • Zookeeper 入门(二)
  • Elasticsearch基础篇-java程序通过RestClient操作es
  • HarmonyOS 影视应用APP开发--配套的后台服务go-imovie项目介绍及使用
  • [创业之路-361]:企业战略管理案例分析-2-战略制定-使命、愿景、价值观的失败案例
  • VueUse/Core:提升Vue开发效率的实用工具库
  • 牛客网NC210769: 字母大小写转换问题解析
  • 灵光一现的问题和常见错误1
  • c++ 仿函数
  • [Android] 奇妙扫描 V1.0.7
  • Linux系统之----重定向
  • 基于OpenCV的SIFT特征和FLANN匹配器的指纹认证
  • 泛微对接金蝶云星空实战案例技术分享
  • C++:C++内存管理
  • DeerFlow试用
  • 一周学会Pandas2 Python数据处理与分析-Pandas2数据添加修改删除操作
  • 使用python进行人员轨迹跟踪
  • 打造动效按钮平台 ButtonCraft:我和 CodeBuddy 的协作旅程