# kratosGormTransaction **Repository Path**: packagejava/kratos-gorm-transaction ## Basic Information - **Project Name**: kratosGormTransaction - **Description**: kratos项目中使用gorm的Transaction示例 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 2 - **Created**: 2025-06-16 - **Last Updated**: 2025-06-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 《ClickHouse原理解析与应用实践》百度云链接 链接: https://pan.baidu.com/s/1JofnHIzf2-PBZlpsPJ609A 提取码: v89c ## 1-1、博客链接 [kratos项目中使用gorm的Transaction的方法介绍](https://www.cnblogs.com/paulwhw/p/17087185.html) ## 1-2、个人ck学习笔记与一些知识点总结 - [❗️个人CK学习笔记.md](%E4%B8%AA%E4%BA%BACK%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0.md) - [❗循环外开启MySQL事务的问题.md](MySQL%E5%BE%AA%E7%8E%AF%E5%A4%96%E5%BC%80%E5%90%AF%E4%BA%8B%E5%8A%A1%E7%9A%84%E9%97%AE%E9%A2%98.md) - [❗MySQL并发开启事务与隔离级别相关.md](MySQL%E5%B9%B6%E5%8F%91%E5%BC%80%E5%90%AF%E4%BA%8B%E5%8A%A1%E4%B8%8E%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB%E7%9B%B8%E5%85%B3.md) - [❗MySQL并发事务逻辑出现问题的例子.md](MySQL%E5%B9%B6%E5%8F%91%E4%BA%8B%E5%8A%A1%E9%80%BB%E8%BE%91%E5%87%BA%E7%8E%B0%E9%97%AE%E9%A2%98%E7%9A%84%E4%BE%8B%E5%AD%90.md) ## 2、功能介绍 - ❗data层加上了初始化MySQL与CK客户端的操作,另外在初始化MySQL与CK客户端时加上`tracing`的配置,这样可以在trace中记录到grom查询的SQL语句(GetStaffsBySName与CreateStaffs方法可以从trace中看到SQL语句)!初始化Redis也可以做类似的操作 - boot包中加上了初始化`conf/log/trace`的操作 - Service/Biz/Data层加上了trace - 事务开始时使用tx - 事务的2种使用方法: 一种是在biz层通过`TM.InTx`使用事务然后data层的方法使用DB(ctx) 获取tx;另外一种是将事务的操作都放到data层(注意data层Data结构体的DB()方法定义时如果没有从ctx中获取到tx要返回mysqlDB) - 使用依赖注入初始化Transaction,将其封装到biz层的对象 - 使用ctx传递tx - 事务中使用子句构造器实现OnConflict效果 - 查询单个对象使用`Take`、`First`、`Last`方法,当数据不存在的时候会报`ErrRecordNotFound`错误,`Find`与`Scan`方法不会只会返回空结构体对象 - 不能在事务中开启并发去select否则会报 driver: bad connection - 可以在事务中开启并发去更新数据 - 可以并发去执行MySQL的事务,但是实际上会有限制,参考下面`并发去执行MySQL事务的问题`的说明 - 使用递归的方式查询无限极分类的数据(cell表的功能),2个相关的接口返回2种结构的数据 - tests目录中有无限极数据`tree_nodes`的处理例子,用的是sqlite数据库 - [❗循环外开启MySQL事务的问题.md](MySQL%E5%BE%AA%E7%8E%AF%E5%A4%96%E5%BC%80%E5%90%AF%E4%BA%8B%E5%8A%A1%E7%9A%84%E9%97%AE%E9%A2%98.md) - [❗MySQL并发开启事务与隔离级别相关.md](MySQL%E5%B9%B6%E5%8F%91%E5%BC%80%E5%90%AF%E4%BA%8B%E5%8A%A1%E4%B8%8E%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB%E7%9B%B8%E5%85%B3.md) - [❗MySQL并发事务逻辑出现问题的例子.md](MySQL%E5%B9%B6%E5%8F%91%E4%BA%8B%E5%8A%A1%E9%80%BB%E8%BE%91%E5%87%BA%E7%8E%B0%E9%97%AE%E9%A2%98%E7%9A%84%E4%BE%8B%E5%AD%90.md) ## 3、并发去执行MySQL事务的问题 ### 3-1、相关知识点 - [❗MySQL并发开启事务与隔离级别相关.md](MySQL%E5%B9%B6%E5%8F%91%E5%BC%80%E5%90%AF%E4%BA%8B%E5%8A%A1%E4%B8%8E%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB%E7%9B%B8%E5%85%B3.md) - [❗️数据库事务与MySQL事务总结以及各种隔离级别介绍](https://zhuanlan.zhihu.com/p/29166694) 在MySQL中,一个事务包含一系列的数据库操作,包括查询操作和修改操作(如插入、更新、删除等)。并发调用同一个事务可能会导致一些问题,具体取决于并发控制机制和事务隔离级别的设置。 在默认的事务隔离级别(可重复读)下,并发调用同一个事务通常不会引起问题。每个事务会创建一个独立的读取视图,该视图包含在事务开始时已经存在的数据。这意味着在事务执行期间,其他并发事务对数据的修改不会影响到该事务的查询操作。因此,并发调用同一个事务不会出现数据不一致的问题。 然而,在其他事务隔离级别(如读未提交、读已提交和可串行化)下,并发调用同一个事务可能会导致一些问题。例如,在读未提交隔离级别下,一个并发事务可能读取到另一个事务尚未提交的数据,导致脏读(Dirty Read)的问题。在可串行化隔离级别下,事务会被串行执行,避免了并发带来的问题,但可能会影响系统的并发性能。 因此,要确保并发调用同一个事务不会出现问题,可以采取以下措施: 设置合适的事务隔离级别,根据应用需求选择合适的隔离级别,以平衡数据一致性和并发性能。 在应用程序中使用适当的并发控制机制,如锁定或乐观并发控制,以避免数据竞争和冲突。 评估事务的执行时间和资源消耗,确保并发调用的事务不会长时间占用数据库连接和资源,导致其他请求的延迟或阻塞。 总之,如果正确地配置了事务隔离级别和并发控制机制,并发调用包含查询操作的事务通常不会引起问题。但仍需根据具体情况进行评估和测试,以确保系统的一致性和性能。 ### 3-2、项目中关于并发开启事务的例子 **❗️注意下,在实际业务中如果一个RPC或者HTTP接口中开了单个事务去处理数据,比如传入的参数是`id+stockChange+orderNo`,而我们的调用方有一批这样的数据,此时不要在调用方开并发去调用单查的RPC接口,因为这样对于被调用方来说会有很多`假流量`!** **❗️所以涉及到调用方有批量需要操作的数据的时候,我们最好在被调用方实现一个`批量接口`,在被调用方这个批量接口去实现相关的并发操作!** `BatchEditOrderWithCurrentTx`这个RPC接口中实现了并发开启事务执行业务逻辑操作的例子。 注意,因为`stock = stock + (changeStock)`这个操作是原子性的,所以这个接口不会有数据错乱的问题! RPC请求的参数如下: ```json { "TransOurOrderBatch": [ { "Id": 1, "StockChange": 20, "OrderNo": "Hello1" }, { "Id": 1, "StockChange": 20, "OrderNo": "Hello2" }, { "Id": 1, "StockChange": 20, "OrderNo": "Hello3" }, { "Id": 1, "StockChange": 20, "OrderNo": "Hello4" }, { "Id": 5, "StockChange": 20, "OrderNo": "Hello5" }, { "Id": 6, "StockChange": 20, "OrderNo": "Hello6" } ] } ``` ## 4、在一个事务中并发执行查询与更新语句的问题 参考: [一个事务中并发执行查询带来的问题](https://medium.com/@impopper_engineering/%E5%9C%A8%E4%B8%80%E4%B8%AA%E4%BA%8B%E5%8A%A1%E4%B8%AD%E5%B9%B6%E5%8F%91%E6%89%A7%E8%A1%8C%E6%9F%A5%E8%AF%A2%E6%89%80%E5%B8%A6%E6%9D%A5%E7%9A%84%E9%97%AE%E9%A2%98-46c77245b23f) ### 4-1、在一个事务中并发执行查询语句会报错 `GetOrderMains`这个RPC接口使用`a.bz.GetOrderMains2`方法会报错 ### 4-2、在一个接口中并发执行一个有查询的事务不会报错 `GetOrderMains`这个RPC接口使用`a.bz.GetOrderMains1`方法不会报错 `a.bz.GetOrderMains1`这个方法还可以演示配置文件中的`max_open_conns`,如果配置文件中最大开启的连接数是3,此时并发查5条数据,在事务中sleep 2秒模拟事务延迟,此时运行程序可以发现同一时间只会有3个查询结果,也就是说客户端与MySQL服务器开启的最大连接数是3 ### 4-3、在一个事务中执行并发更新不会报 有前提,具体看上面的说明 `TransOutOrderBatch`这个RPC接口使用`a.bz.TransOutOrderBatch`方法不会报错 ### 4-4、TODO 为什么在一个事务中并发执行查询语句时会遇到mysqlConn.closed关闭的情况,但是在一个事务中并发去执行updte语句就不会呢?具体的原理是什么呢?需要研究下项目中引入的mysql引擎包的代码 ## 5、无限极分类数据相关 - `tests`目录中有2个测试文件,主要看`tree_nodes_find`,它有获取无限极分类数据并构建返回结果的demo - `RecursionGetCellChildren`与`RecursionGetCellParents`这2个接口使用递归获取无限极分类的数据并构建返回结果