MST

星途 面试题库

面试题:Go语言defer语句在复杂函数逻辑中的应用

假设有一个函数,它执行一系列复杂的数据库操作(如连接数据库、查询数据、插入数据、更新数据、关闭数据库连接),在这个函数中如何合理地使用defer语句来确保数据库连接正确关闭,以及资源在异常情况下也能得到妥善处理。请写出完整的Go代码实现,并解释每一处defer语句的作用和执行顺序。
23.0万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
package main

import (
    "database/sql"
    "fmt"
    _ "github.com/go-sql-driver/mysql"
)

func complexDBOperations() {
    // 连接数据库
    db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/test")
    if err != nil {
        panic(err.Error())
    }
    defer func() {
        // 无论函数如何结束,都会关闭数据库连接
        err := db.Close()
        if err != nil {
            fmt.Println("Error closing database:", err)
        }
    }()

    // 确保数据库可连接
    err = db.Ping()
    if err != nil {
        fmt.Println("Failed to ping database:", err)
        return
    }

    // 查询数据
    rows, err := db.Query("SELECT * FROM some_table")
    if err != nil {
        fmt.Println("Error querying data:", err)
        return
    }
    defer func() {
        // 无论查询操作是否成功,都会关闭查询结果集
        err := rows.Close()
        if err != nil {
            fmt.Println("Error closing rows:", err)
        }
    }()

    // 处理查询结果
    for rows.Next() {
        // 具体处理逻辑
    }
    if err := rows.Err(); err != nil {
        fmt.Println("Error iterating over rows:", err)
        return
    }

    // 插入数据
    result, err := db.Exec("INSERT INTO some_table (column1, column2) VALUES (?,?)", "value1", "value2")
    if err != nil {
        fmt.Println("Error inserting data:", err)
        return
    }
    // 这里也可以根据result做一些操作,例如获取插入的ID

    // 更新数据
    result, err = db.Exec("UPDATE some_table SET column1 =? WHERE column2 =?", "new_value", "value2")
    if err != nil {
        fmt.Println("Error updating data:", err)
        return
    }
    // 这里也可以根据result做一些操作,例如获取更新的行数
}

defer语句的作用和执行顺序:

  1. 数据库连接关闭的defer

    • 作用:确保在函数结束时,无论函数是正常结束还是因错误提前返回,数据库连接都会被关闭。这避免了资源泄露,因为数据库连接是有限资源。
    • 执行顺序:在函数返回或结束时执行。如果函数正常结束,在所有其他语句执行完毕后执行;如果函数因错误提前返回,在错误处理逻辑执行完毕后执行。
  2. 查询结果集关闭的defer

    • 作用:确保在查询操作完成后,查询结果集(rows)会被关闭。这释放了与结果集相关的资源,避免资源泄露。
    • 执行顺序:在查询相关操作完成后,当函数返回或结束时执行。例如,如果在处理查询结果过程中出现错误并提前返回,在错误处理逻辑执行完毕后,这个defer语句会关闭结果集。