Go 项目如何集成类似mybatisPlus插件呢?GORM走起!!

导读:

在 Go 项目中,虽然没有像 MyBatis Plus 这样特定的 ORM 插件,但可以使用功能相似的 Go ORM 框架,比如 GORM,它支持链式查询、自动迁移、预加载等功能,与 MyBatis Plus 有相似之处。通过一些插件或扩展,可以实现更丰富的功能,比如软删除、分页查询等。下面是 GORM 集成的一些步骤和相关插件的推荐,本文以之前集成的项目Go语言?IDEA能支持吗?增删查走起?_go idea-CSDN博客为模版在此基础上进行迭代。

目录

 一、引入GORM

二、GORM能力:

2.1分页查询:

2.2软删除

2.3分页拓展

 2.4链式查询

2.5自定义拓展

三、源码改造

3.1改造数据库连接类database.go

3.2改造中间件DBMiddleware

3.3 改造userDao.go

3.4 改造userService.go

3.5 改造router.go

3.6 改造main.go

四、启动

 五、异常情况:

5.1解决思路:

 六、复杂查询拓展:

6.1实体类Orders.go

 6.2新增OrderInfoDTO.go

6.3新增GetUserWithOrders方法:


 一、引入GORM

先在项目中引入 GORM:

go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql  # 根据你的数据库类型选择驱动

二、GORM能力:

GORM 提供了一些类似 MyBatis Plus 的功能,比如:

  • 软删除:通过 gorm.Model 或自定义字段来实现软删除。
  • 条件查询:可以通过链式查询构建条件查询。
  • 分页插件:可以手动实现分页,或使用封装的分页插件。

2.1分页查询:

go 一遍集成GORM 的 LimitOffset 方法实现分页查询:

var users []User
db.Limit(10).Offset(20).Find(&users)  // 查询第 21-30 条数据

2.2软删除

例如:通过 gorm.Model 或自定义字段来实现软删除。

type User struct {
    gorm.Model
    Name string
    Age  int
}

db.Delete(&user) // 软删除

2.3分页拓展

可以手动实现分页,或使用封装的分页插件比如分页器 github.com/biezhi/gorm-paginator 

 2.4链式查询

GORM 支持链式调用来构建复杂的查询:

var users []User
db.Where("age > ?", 18).Find(&users)

2.5自定义拓展

如果需要类似 MyBatis Plus 的扩展功能,你可以通过自定义 GORM 的钩子函数(Hooks)或中间件,来实现数据插入、更新时自动添加字段等逻辑。GORM 提供了生命周期回调接口,可以在执行操作前后进行拦截和处理。

三、源码改造

3.1改造数据库连接类database.go

  • 引入 GORM:通过 gorm.io/gormgorm.io/driver/mysql 代替原来的 database/sql

  • 初始化数据库连接:使用 gorm.Open() 方法替代 sql.Open(),并且支持更多的配置参数,比如 charset=utf8mb4parseTime=True

  • GetDB 函数:返回 *gorm.DB 类型的数据库实例,供其他模块使用。

  • 这边删除了原先的func GetDB() *sql.DB { return DB } 方法

package config

import (
	"fmt"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"log"
)

var DB *gorm.DB

// InitGormDatabase 初始化 GORM 数据库连接并返回 *gorm.DB
func InitGormDatabase() *gorm.DB {
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
		AppConfig.Database.User,
		AppConfig.Database.Password,
		AppConfig.Database.Host,
		AppConfig.Database.Port,
		AppConfig.Database.DBName,
	)

	var err error
	DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
		Logger: logger.Default.LogMode(logger.Info),
	})

	if err != nil {
		log.Fatalf("Failed to connect to database: %v", err)
		return nil
	}

	log.Println("GORM database successfully connected")
	return DB
}

3.2改造中间件DBMiddleware

这边说明一下,中间件的引入是刚搭建项目时想从java中的切面编程来实现跨功能关注点的处理。比如数据库的连接。但是呢go没有内置切面的支持。所以就引入了中间件模式,每次调用数据库操作都通过中间件来处理。下面是优化前的中间件:

package middleware

import (
	"database/sql"
	"go_tas/dao/database"
	"log"
)

type DBMiddleware struct {
	db *sql.DB
}

func NewDBMiddleware() *DBMiddleware {
	return &DBMiddleware{
		db: database.GetDB(),
	}
}

func (mw *DBMiddleware) ExecuteQuery(query string, args ...interface{}) (*sql.Rows, error) {
	rows, err := mw.db.Query(query, args...) // 使用中间件中保存的 db
	if err != nil {
		return nil, mw.logError("Failed to execute query", err)
	}
	return rows, nil
}

func (mw *DBMiddleware) ExecuteExec(query string, args ...interface{}) (int64, error) {
	result, err := mw.db.Exec(query, args...) // 使用中间件中保存的 db
	if err != nil {
		return 0, mw.logError("Failed to execute exec", err)
	}
	insertID, err := result.LastInsertId()
	if err != nil {
		return 0, mw.logError("Failed to get last insert ID", err)
	}
	return insertID, nil
}

func (mw *DBMiddleware) BeginTransaction() (*sql.Tx, error) {
	tx, err := mw.db.Begin() // 使用中间件中保存的 db
	if err != nil {
		return nil, mw.logError("Failed to begin transaction", err)
	}
	return tx, nil
}

func (mw *DBMiddleware) logError(message string, err error) error {
	log.Printf("%s: %v", message, err)
	return err
}

使用原生的 database/sql 改造为使用 GORM,可以直接使用 GORM 的功能来处理查询、事务等操作。GORM 已经封装了这些常见的操作,并且支持更简洁的 API。

下面是改造后的 middleware 模块,使用 GORM 替代 database/sql

  1. gorm.DB 替换 sql.DBDBMiddleware 中的 db 现在使用 *gorm.DB,所有的数据库操作通过 GORM 进行。

  2. ExecuteQuery 方法

    • 使用 GORM 的 Raw 方法执行原生 SQL 查询,并通过 Scan 将结果映射到传入的 model 结构体。
    • 原生 SQL 查询返回的结果可以映射到结构体切片中。
    var users []User
    middleware.ExecuteQuery(&users, "SELECT * FROM users WHERE age > ?", 18)
    

  3. ExecuteExec 方法

    • 使用 GORM 的 Exec 方法执行修改(插入、更新、删除)语句。
    • 返回执行后影响的行数,而不是插入 ID。
  4. 事务管理

    • 使用 GORM 的 Begin 方法开启事务,返回事务对象 *gorm.DB
    tx, err := middleware.BeginTransaction()
    if err != nil {
        // handle error
    }
    // 在事务中执行操作
    err = tx.Create(&user).Error
    if err != nil {
        tx.Rollback()
    } else {
        tx.Commit()
    }
    

    中间件现在可以使用 GORM 的功能,简化数据库操作并支持复杂的 ORM 功能。

package middleware

import (
    "go_tas/dao/database"
    "log"
    "gorm.io/gorm"
)

type DBMiddleware struct {
    db *gorm.DB
}

func NewDBMiddleware() *DBMiddleware {
    return &DBMiddleware{
        db: database.GetDB(), // 使用 GORM 的 DB 实例
    }
}

// ExecuteQuery 执行查询语句
func (mw *DBMiddleware) ExecuteQuery(model interface{}, query string, args ...interface{}) error {
    result := mw.db.Raw(query, args...).Scan(model) // 使用 GORM 的 Raw 方法
    if result.Error != nil {
        return mw.logError("Failed to execute query", result.Error)
    }
    return nil
}

// ExecuteExec 执行修改语句(插入、更新、删除)
func (mw *DBMiddleware) ExecuteExec(query string, args ...interface{}) (int64, error) {
    result := mw.db.Exec(query, args...) // 使用 GORM 的 Exec 方法
    if result.Error != nil {
        return 0, mw.logError("Failed to execute exec", result.Error)
    }
    return result.RowsAffected, nil // 返回影响的行数
}

// BeginTransaction 开启事务
func (mw *DBMiddleware) BeginTransaction() (*gorm.DB, error) {
    tx := mw.db.Begin() // 使用 GORM 的事务支持
    if tx.Error != nil {
        return nil, mw.logError("Failed to begin transaction", tx.Error)
    }
    return tx, nil
}

// logError 记录错误信息
func (mw *DBMiddleware) logError(message string, err error) error {
    log.Printf("%s: %v", message, err)
    return err
}

3.3 改造userDao.go

使用原生 SQL 改造为使用 GORM,可以直接利用 GORM 的模型操作方法来简化数据库操作。GORM 允许直接对结构体进行增删改查,而不需要手动编写 SQL 查询

package dao

import (
    "go_tas/entity"
    "gorm.io/gorm"
    "log"
)

type UserDAO struct {
    db *gorm.DB
}

// NewUserDAO 创建新的 UserDAO 实例
func NewUserDAO(db *gorm.DB) *UserDAO {
    return &UserDAO{db: db}
}

// GetAllUsers 获取所有用户
func (dao *UserDAO) GetAllUsers() ([]entity.User, error) {
    var users []entity.User

    // 使用 GORM 查询所有用户
    if err := dao.db.Find(&users).Error; err != nil {
        log.Printf("Failed to get users: %v", err)
        return nil, err
    }

    return users, nil
}

// CreateUser 创建新用户
func (dao *UserDAO) CreateUser(user *entity.User) (int64, error) {
    // 使用 GORM 创建用户
    if err := dao.db.Create(user).Error; err != nil {
        log.Printf("Failed to create user: %v", err)
        return 0, err
    }

    // 返回创建的用户 ID
    return int64(user.ID), nil
}

3.4 改造userService.go

使用 GORM 替代原生 SQL 操作来进行数据处理。可以将事务处理和数据库操作使用 GORM 的特性进行简化和改造

package service

import (
    "encoding/json"
    "go_tas/dao"
    "go_tas/entity"
    "go_tas/utils"
    "gorm.io/gorm"
    "net/http"
)

// GetUsers 获取所有用户
func GetUsers(w http.ResponseWriter, r *http.Request, db *gorm.DB) {
    userDAO := dao.NewUserDAO(db)
    users, err := userDAO.GetAllUsers()
    if err != nil {
        utils.HandleError(w, http.StatusInternalServerError, "Failed to retrieve users", err)
        return
    }

    respondWithJSON(w, http.StatusOK, users)
}

// CreateUser 创建新用户
func CreateUser(w http.ResponseWriter, r *http.Request, db *gorm.DB) {
    var user entity.User
    if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
        utils.HandleError(w, http.StatusBadRequest, "Invalid request payload", err)
        return
    }

    // 开始一个事务
    tx := db.Begin()
    if tx.Error != nil {
        utils.HandleError(w, http.StatusInternalServerError, "Failed to begin transaction", tx.Error)
        return
    }
    defer func() {
        if r := recover(); r != nil {
            tx.Rollback() // 回滚事务
            utils.HandleError(w, http.StatusInternalServerError, "Internal server error", nil)
        }
    }()

    // 插入用户数据
    userDAO := dao.NewUserDAO(tx)
    if _, err := userDAO.CreateUser(&user); err != nil {
        tx.Rollback() // 回滚事务
        utils.HandleError(w, http.StatusInternalServerError, "Failed to create user", err)
        return
    }

    // 提交事务
    if err := tx.Commit().Error; err != nil {
        utils.HandleError(w, http.StatusInternalServerError, "Failed to commit transaction", err)
        return
    }

    respondWithJSON(w, http.StatusCreated, user)
}

// respondWithJSON 处理JSON响应
func respondWithJSON(w http.ResponseWriter, status int, payload interface{}) {
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(status)
    if err := json.NewEncoder(w).Encode(payload); err != nil {
        utils.HandleError(w, http.StatusInternalServerError, "Failed to encode response data", err)
    }
}

3.5 改造router.go

router 中的数据库操作从 dbMiddleware 改为使用 GORM 数据库连接,并清理代码逻辑

package router

import (
	"github.com/gorilla/mux"
	httpSwagger "github.com/swaggo/http-swagger"
	"go_tas/controller"
	"go_tas/middleware"
	"go_tas/service"
	"gorm.io/gorm"
	"net/http"
)

func InitRouter(authMiddleware *middleware.CustomAuthMiddleware, db *gorm.DB) *mux.Router {
	r := mux.NewRouter()
	
	// 添加身份验证中间件
	r.Use(authMiddleware.Middleware)
	
	// 使用 GORM 数据库连接
	r.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) {
		service.GetUsers(w, r, db)
	}).Methods("GET")

	r.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) {
		service.CreateUser(w, r, db)
	}).Methods("POST")
	
	// 设备控制接口
	r.HandleFunc("/tas/control", controller.Control).Methods("POST")
	r.HandleFunc("/tas/adminControl", controller.AdminControl).Methods("POST")
	
	// Swagger Handler
	r.PathPrefix("/swagger/").Handler(httpSwagger.WrapHandler)
	
	return r
}

3.6 改造main.go

main 函数中,可以将原本使用的 dbMiddleware 改为直接使用 GORM 初始化的数据库连接,以便与前面改造的代码保持一致

package main

import (
	"go_tas/config"
	"go_tas/logger"
	"go_tas/middleware"
	"go_tas/router"
	"log"
	"net/http"
)

func main() {
	// 初始化配置
	config.InitConfig()
	log.Println("Config initialized")

	// 初始化数据库,获取 GORM 数据库连接
	db := config.InitGormDatabase()
	if db == nil {
		log.Fatal("Failed to initialize database")
	}
	log.Println("Database initialized with GORM")

	// 初始化 Redis
	config.InitRedis()
	log.Println("Redis initialized")

	// 初始化日志
	logger.InitLogger()

	// 初始化认证中间件
	appCode := config.AppConfig.AppCode
	appSecret := config.AppConfig.AppSecret
	authMiddleware := middleware.NewCustomAuthMiddleware(appCode, appSecret)

	// 初始化路由并传递 GORM 数据库连接
	r := router.InitRouter(authMiddleware, db)
	log.Println("authMiddleware initialized")

	// 启动服务器
	log.Println("Starting server on :8080")
	log.Fatal(http.ListenAndServe(":8080", r))
}

四、启动

 五、异常情况:

如果提示Table 'go_data_base.users' doesn't exist这种情况可以查看一下实体类,原因可能是由于查询时表名不匹配造成的。GORM 默认会使用复数形式表名进行查询,因此它在查找 users 表,而你的实际表名是 user

5.1解决思路:

可以通过在 GORM 模型中设置表名

package entity

type User struct {
	ID    int    `json:"id"`
	Name  string `json:"name"`
	Email string `json:"email"`
}

// TableName 指定表名为 user
func (User) TableName() string {
	return "user"
}

 六、复杂查询拓展:

如果涉及多表关联查询则可使用Joins来进行SQL联表查询,下面举个栗子:

6.1实体类Orders.go

package entity

type Orders struct {
	ID          int    `json:"id"`
	UserId      int    `json:"user_id"`
	Amount      int    `json:"amount"`
	Description string `json:"description"`
}

func (Orders) TableName() string {
	return "orders"
}

 6.2新增OrderInfoDTO.go

package dto

type OrderInfoDTO struct {
	ID          int    `json:"id"`
	Name        string `json:"name"`
	Email       string `json:"email"`
	Amount      int    `json:"amount"`
	Description string `json:"description"`
}

6.3新增GetUserWithOrders方法:

在userDao.go 新增一个GetUserWithOrders方法,Joins 用于执行 SQL 联表查Select("users.*, orders.amount") 指定返回的字段,你可以选择返回哪些表的字段Scan(&users) 将查询结果扫描到 users 切片中。

func (dao *UserDAO) GetUsersWithOrderInfo() ([]dto.OrderInfoDTO, error) {
	var userInfo []dto.OrderInfoDTO

	err := dao.db.Table("user").
		Joins("LEFT JOIN orders ON orders.user_id = user.id").
		Select("user.*, orders.*").
		Scan(&userInfo).Error
	if err != nil {
		log.Printf("Failed to get users with order info: %v", err)
		return nil, err
	}

	return userInfo, nil
}

最后将数据库的语句:

DROP TABLE IF EXISTS `orders`;
CREATE TABLE `orders`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) NULL DEFAULT NULL COMMENT '用户ID',
  `amount` int(10) NULL DEFAULT NULL COMMENT '支付金额/分',
  `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '商品描述',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

如果需要源码的同学评论区把邮箱放置一下哈!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/895454.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

常用API

Object类: instanceof:java中的关键字,判断左边的对象是否是右面类的实例。 它的作用是判断其左边对象是否为其右边类的实例,返回boolean类型的数据。 getClass():得到调用者的数据类型; 进行对象内容比较…

016_基于python+django网络爬虫及数据分析可视化系统2024_kyz52ks2

目录 系统展示 开发背景 代码实现 项目案例 获取源码 博主介绍:CodeMentor毕业设计领航者、全网关注者30W群落,InfoQ特邀专栏作家、技术博客领航者、InfoQ新星培育计划导师、Web开发领域杰出贡献者,博客领航之星、开发者头条/腾讯云/AW…

盘点现代浏览器的各种神奇能力,功能令人惊讶

盘点现代浏览器的各种神奇能力,功能令人惊讶😮 浏览器的进化 一个运行在浏览器里面的操作系统。一个炫酷的量子纠缠网页。内嵌在浏览器里面的AI大模型。 随着web技术的迅猛发展,现代浏览器已经不仅仅是一个浏览网页的工具了。它的功能早已进…

【判断推理】逻辑论证之归因论证

2.1 归因论证概述 归因:指人们对 他人或自己行为的原因的推论过程。具体而言,就是观察者对他人的行为过程或自己的行为过程所进行的因果解释和推论。(通俗而言,归因就是对已经发生的事实,在众多可能的原因中找出一个原…

Cesium 实战 - 自定义纹理材质 - 立体墙(旋转材质)

Cesium 实战 - 自定义纹理材质 - 立体墙(旋转材质) 核心代码完整代码在线示例Cesium 给实体对象(Entity)提供了很多实用的样式,基本满足普通项目需求; 但是作为 WebGL 引擎,肯定不够丰富,尤其是动态效果样式。 对于实体对象(Entity),可以通过自定义材质,实现各种…

CLion和Qt 联合开发环境配置教程(Windows和Linux版)

需要安装的工具CLion 和Qt CLion下载链接 :https://www.jetbrains.com.cn/clion/ 这个软件属于直接默认安装就行,很简单,不多做介绍了 Qt:https://mirrors.tuna.tsinghua.edu.cn/qt/official_releases/online_installers/ window 直接点exe Linux 先c…

【2024软著申请】软著申请到发放全流程(附带教程+工具+撰写建议)

目录 总时间线材料准备1、计算机软件著作权登记申请表4页2、身份证明文件3、软件鉴别材料4、文档鉴别材料 唠叨两句 总时间线 时间关键节点20240811电子材料提交进入待受理阶段20240826受理阶段审查通过,进入审查中20240930发放完成 材料准备 版权登记链接(https…

用柔性神经k-Opt学习搜索路径问题的可行和不可行区域(未完,先看前驱文章L2S)

文章目录 Abstract1 IntroductionAbstract 介绍了一种名为 Neural k-Opt(NeuOpt)的新型学习搜索(L2S)求解器,用于解决路径问题。它学习执行基于定制的动作分解方法和定制的循环双流(Recurrent Dual-Stream)解码器的灵活 k-opt 交换。 作为一项开创性的工作,我们绕过了…

华山论剑之Rust的Trait

华山论剑,群雄荟萃,各显神通。武林中人,各有所长,或剑法飘逸,或掌法刚猛,或轻功绝顶。这就好比Rust中的trait,它定义了一种武功套路,而不同的门派、不同的人,可以将这套武…

All-reduce,AIl-to-all

目录 跨中心架构下的大模型并行训练 优化All-reduce通信效率 优化AIl-to-all通信效率 跨中心架构下的大模型并行训练 优化All-reduce通信效率 All-reduce是一种在分布式计算中广泛使用的通信操作,用于将多个节点的数据聚合成一个全局结果,并将该结果分发回所有节点。优化…

sv标准研读第十五章-进程间同步与通信

书接上回: sv标准研读第十四章-clocking block 第15章 进程间的同步和通信 15.1 概览 -semaphores -mailboxes -named events 15.2 综述 简单的进程间通信可以通过named events来实现,有event trigger和event control过程,分别需要依…

Elasticsearch基本使用及介绍

Elasticsearch 1. 关于各种数据库的使用 关于MySQL:是关系型数据库,能清楚的表示数据之间的关系,并且,是基于磁盘存储的,可以使用相对较低的成本存储大量的数据 关于Redis:是基于K-V结构的在内存中读写数…

2011年国赛高教杯数学建模B题交巡警服务平台的设置与调度解题全过程文档及程序

2011年国赛高教杯数学建模 B题 交巡警服务平台的设置与调度 有困难找警察”,是家喻户晓的一句流行语。警察肩负着刑事执法、治安管理、交通管理、服务群众四大职能。为了更有效地贯彻实施这些职能,需要在市区的一些交通要道和重要部位设置交巡警服务平台…

【jQuery】jQuery 处理 Ajax 以及解决跨域问题的方式

文章目录 HTTP原生创建 AjaxjQuery 处理 Ajax$.ajax()$().load()$.get()$.post() 跨域CORSJSONPiframeweb sockets HTTP 超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。设计 HTTP 最初的目的是为了提供一种发…

QT中中文显示乱码问题

在VS2013中用QT开发GUI应用程序&#xff0c;Qt中显示中文乱码 一&#xff1a; //解决QT中中文显示乱码问题 #pragma execution_character_set("utf-8") 二&#xff1a;在main函数中添加以下代码&#xff1a; #include <QTextCodec>void main() {QTextCod…

javaweb-mybatis之动态sql

(1).if标签 编写好方法之后&#xff0c;选中方法名&#xff0c;alt回车&#xff0c;选第一个generate statement快捷生成xml里的标签 (2).foreach标签 用于批量删除 (3)sql和include标签

别再犯这些Java并发编程的常见错误!你中了几个?

你好&#xff0c;我是忆~遂愿&#xff0c;全网2w粉丝&#xff0c;《遂愿盈创》社群主理人。 副业启航① | 遂愿盈创&#xff08;对副业感兴趣免费可入&#xff0c;多种赚钱实战项目等你来&#xff0c;一起探寻副业快速变现的途径&#xff1b;以及对接互联网大厂商务合作&#x…

YOLO11改进 | 主干网络 | 将backbone替换为Swin-Transformer结构【论文必备】

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 本文给大家带来的教程是将YOLO11的backb…

二百六十八、Kettle——同步ClickHouse清洗数据到Hive的DWD层静态分区表中(每天一次)

一、目的 实时数仓用的是ClickHouse&#xff0c;为了避免Hive还要清洗数据&#xff0c;因此就直接把ClickHouse中清洗数据同步到Hive中就行 二、所需工具 ClickHouse&#xff1a;clickhouse-client-21.9.5.16 Kettle&#xff1a;kettle9.2 Hadoop&#xff1a;hadoop-3.1.3…

AI金融攻防赛:YOLO理论学习及赛题进阶思路(DataWhale组队学习)

引言 大家好&#xff0c;我是GISer Liu&#x1f601;&#xff0c;一名热爱AI技术的GIS开发者。本系列文章是我跟随DataWhale 2024年10月学习赛的AI金融攻防赛学习总结文档。本文主要讲解如何在金融场景凭证篡改检测中应用YOLO算法。我们将从模型概述、数据准备、训练流程以及模…