主頁 > 後端開發 > Go語言(Golang)資料庫編程

Go語言(Golang)資料庫編程

2023-05-12 07:29:07 後端開發

Go 資料庫編程

一、連接資料庫

準備連接到資料庫

  • 要想連接到 SQL 資料庫,首先需要加載目標資料庫的驅動,驅動里面包含著于該資料庫互動的邏輯,
  • sql.Open()
    • 資料庫驅動的名稱
    • 資料源名稱
    • 得到一個指向 sql.DB 這個 struct 的指標
  • sql.DB 是用來操作資料庫的,它代表了0個或者多個底層連接的池,這些連接由sql 包來維護,sql 包會自動的創建和釋放這些連接
    • 它對于多個 goroutine 并發的使用是安全的
package main

import (
  "context"
  "database/sql"
  "fmt"
  "log"
  
  _ "github.com/denisenkom/go-mssqldb"
)

var db *sql.DB

const (
  server = "xxxx.database.windows.net"
  port = 1433
  user = "xxxxx"
  password = "xxxxx"
  database = "go-db"
)

func main() {
  connStr := fmt.Sprintf("server=%s;user id=%s;password=%s;port=%d;database=%s;",
                        server, user, password, port, database)
  
  db, err := sql.Open("sqlserver", connStr)
  if err != nil {
    log.Fataln(err.Error())
  }
  
  ctx := context.Background()
  
  err = db.PingContext(ctx)
  if err != nil {
    log.Fataln(err.Error())
  }
  
  fmt.Println("Connected!")
}

Note

  • Open() 函式并不會連接資料庫,甚至不會驗證其引數,它只是把后續連接到資料庫所必需的 structs 給設定好了
  • 而真正的連接是在被需要的時候才進行懶設定的
  • sql.DB 不需要進行關閉(當然你想關閉也是可以的)
  • 它就是用來處理資料庫的,而不是實際的連接
  • 這個抽象包含了資料庫連接的池,而且會對此進行維護
  • 在使用 sql.DB 的時候,可以定義它的全域變數進行使用,也可以將它傳遞到函式/方法里,

如何獲得驅動

  • 正常的做法是使用 sql.Register() 函式、資料庫驅動的名稱和一個實作了 driver.Driver 介面的 struct,來注冊資料庫的驅動,例如:
    • sql.Register("sqlserver", &drv{})
  • 但是我們之前的例子卻沒寫這句話,為什么?
    • 因為 Sql Server 的驅動,是在這個包被引入的時候進行了自我注冊

驅動自動注冊

  • 當 go-mssqldb 包被引入的時候,它的 init 函式將會運行并進行自我注冊(在 Go 語言里,每個包的 init 函式都會在自動的呼叫)
  • 在引入 go-mssqldb 包的時候,把該包的名設定為下劃線 _,這是因為我們不直接使用資料庫驅動(只需要它的”副作用“),我們只使用 database/sql
    • 這樣,如果未來升級驅動,也無需改變代碼
  • Go 語言沒有提供官方的資料庫驅動,所有的資料庫驅動都是第三方驅動,但是它們都遵循 sql.driver 包里面定義的介面

安裝資料庫驅動

  • 這是安裝 Microsoft SQL Server 資料庫驅動的例子:
  • go get github.com/denisenkom/go-mssqldb

func(*DB) PingContext

  • 上例中的 db.PingContext() 函式是用來驗證與資料庫的連接是否仍然有效,如有必要則建立一個連接,
  • 這個函式需要一個 Context (背景關系)型別的引數,這種型別可以攜帶截止時間、取消信號和其它請求范圍的值,并且可以橫跨 API 邊界和行程,
  • 上例中,創建 context 使用的是 context.Background() 函式,該函式回傳一個非 nil 的空 Context,它不會被取消,它沒有值,沒有截止時間,
  • 它通常用在 main 函式、初始化或測驗中,作為傳入請求的頂級 Context,

Exercises

  • 使用 PostgreSQL 建立資料庫,使用 Go 語言進行連接,并 Ping 一下,
  • 使用 SQLite 建立資料庫,使用 Go 語言進行連接,并 Ping 一下,

連接MySQL

https://github.com/go-sql-driver/mysql

go get -u github.com/go-sql-driver/mysql

創建目錄

? mcd go_sql_demo

Code/go/go_sql_demo via ?? v1.20.3 via ?? base
? go mod init go_sql_demo
go: creating new go.mod: module go_sql_demo

Code/go/go_sql_demo via ?? v1.20.3 via ?? base
? c

Code/go/go_sql_demo via ?? v1.20.3 via ?? base
?

main.go

package main

import (
	"database/sql"
	"fmt"

	_ "github.com/go-sql-driver/mysql"
)

// 定義一個全域物件db
var db *sql.DB

// 定義一個初始化資料庫的函式
func initDB() (err error) {
	// DSN:Data Source Name
	dsn := "root:12345678@tcp(127.0.0.1:3306)/db_xuanke?charset=utf8mb4&parseTime=True"
	// 不會校驗賬號密碼是否正確
	// 注意!!!這里不要使用:=,我們是給全域變數賦值,然后在main函式中使用全域變數db
	db, err = sql.Open("mysql", dsn)
	if err != nil {
		return err
	}
	// 嘗試與資料庫建立連接(校驗dsn是否正確)
	err = db.Ping()
	if err != nil {
		return err
	}
	return nil
}

func main() {
	err := initDB() // 呼叫輸出化資料庫的函式
	if err != nil {
		fmt.Printf("init db failed,err:%v\n", err)
		return
	}
	fmt.Println("connect to database")
}

二、CRUD

查詢

  • sql.DB 型別上用于查詢的方法有:
    • Query
    • QueryRow
    • QueryContext
    • QueryRowContext

Query

  • 回傳的型別是:type Rows struct {}
  • Rows 的方法:
    • func (rs *Rows) Close() error
    • func (rs *Rows) ColumnTypes() ([]*ColumnType, error)
    • func (rs *Rows) Columns() ([]string, error)
    • func (rs *Rows) Err() error
    • func (rs *Rows) Next() bool
    • func (rs *Rows) NextResultSet() bool
    • func (rs *Rows) Scan(dest ...interface{}) error

QueryRow

  • 回傳型別是:type Row struct {}
  • Row 的方法有:
    • func (r *Row) Err() error
    • func (r *Row) Scan(dest ...interface{}) error

https://pkg.go.dev/database/[email protected]

services.go 檔案

package main

func getOne(id int) (a app, err error) {
  a = app{}
  log.Println(db == nil)
  err = db.QueryRow("SELECT Id, Name, Status, Level, [Order] FROM dbo.App WHERE Id=@Id", 				sql.Named("Id", id)).Scan(
    &a.ID, &a.name, &a.status, &a.level, &a.order)
  return
}

func getMany(id int) (apps []app, err error) {
  rows, err = db.Query("SELECT Id, Name, Status, Level, [Order] FROM dbo.App WHERE Id>@Id", 				sql.Named("Id", id))
  for rows.Next() {
    a := app{}
    err = rows.Scan(&a.ID, &a.name, &a.status, &a.level, &a.order)
    if err != nil {
      log.Fatalln(err.Error())
    }
    apps = append(apps, a)
  }
  return
}

models.go 檔案

package main

type app struct {
  ID int
  name string
  status int
  level int
  order int
}

main.go 檔案

package main

import (
  "context"
  "database/sql"
  "fmt"
  "log"
  
  _ "github.com/denisenkom/go-mssqldb"
)

var db *sql.DB

const (
  server = "xxxx.database.windows.net"
  port = 1433
  user = "xxxxx"
  password = "xxxxx"
  database = "go-db"
)

func main() {
  connStr := fmt.Sprintf("server=%s;user id=%s;password=%s;port=%d;database=%s;",
                        server, user, password, port, database)
  
  var err error
  db, err = sql.Open("sqlserver", connStr)
  if err != nil {
    log.Fataln(err.Error())
  }
  
  ctx := context.Background()
  
  err = db.PingContext(ctx)
  if err != nil {
    log.Fataln(err.Error())
  }
  
  fmt.Println("Connected!")
  
  log.Println(db == nil)
  // 查詢一筆
  one, err := getOne(103)
  if err != nil {
    log.Fatal(err.Error())
  }
  fmt.Println(one)
  
  apps, err := getMany(103)
  if err != nil {
    log.Fatalln(err.Error())
  }
  
  fmt.Println(apps)
}

更新

  • sql.DB 型別上用于更新(執行命令)的方法有:
    • Exec
    • ExecContext

services.go 檔案

func (a *app) Update() (err error) {
  _, err = db.Exec("UPDATE dbo.App SET Name=@Name, [Order]=@Order WHERE Id=@Id",
        sql.Named("Name", a.name), sql.Named("Order", a.order), sql.Named("Id", a.ID))
  if err != nil {
    log.Fatalln(err.Error())
  }
  return
}

main.go 檔案

a, _ := getOne(103)
fmt.Println(a)
a.name += " 1234"
a.order++

err = a.Update()
if err != nil {
  log.Fatalln(err.Error())
}
a1, _ := getOne(103)
fmt.Println(a1)

洗掉

services.go 檔案

func (a *app) Delete() (err error) {
  _, err = db.Exec("DELETE FROM dbo.App WHERE Id=@Id", sql.Named("Id", a.ID))
  if err != nil {
    log.Fatalln(err.Error())
  }
  return
}

其它

  • Ping
  • PingContext
  • Prepare
  • PrepareContext
  • Transactions
    • Begin
    • Begin Tx

services.go 檔案

func (a *app) Insert() (err error) {
  statement := `INSERT INTO dbo.App
  (Name, NickName, Status, Level, [Order], Pinyin) 
  VALUES (@Name, 'Nick', &Status, @Level, @Order, '...');
  SELE?T isNull(SCOPE_IDENTITY(), -1);`
  stmt, err := db.Prepare(statement)
  if err != nil {
    log.Fatalln(err.Error())
  }
  defer stmt.Close()
  err = stmt.QueryRow(
    sql.Named("Name", a.name), sql.Named("Status", a.status), 
    sql.Named("Level", a.level),
    sql.Named("Order", a.order)).Scan(&a.ID)
  
  if err != nil {
    log.Fatalln(err.Error())
  }
  
  return
}

main.go 檔案

a := app {
  name: "Test",
  order: 1123,
  level: 10,
  status: 1,
}

err = a.Insert()
if err != nil {
  log.Fatalln(err.Error())
}

one, _ := getOne(a.ID)
fmt.Println(one)

三、MySQL CRUD 實踐

在MySQL中創建一個名為sql_test的資料庫

mysql> create database sql_test;
Query OK, 1 row affected (0.01 sec)

mysql> use sql_test;
Database changed
mysql> CREATE TABLE `user` (
    ->     `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
    ->     `name` VARCHAR(20) DEFAULT '',
    ->     `age` INT(11) DEFAULT '0',
    ->     PRIMARY KEY(`id`)
    -> )ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
Query OK, 0 rows affected, 2 warnings (0.02 sec)

mysql> show tables;
+--------------------+
| Tables_in_sql_test |
+--------------------+
| user               |
+--------------------+
1 row in set (0.01 sec)

mysql>

main.go 檔案

package main

import (
	"database/sql"
	"fmt"

	_ "github.com/go-sql-driver/mysql"
)

// 定義一個全域物件db
var db *sql.DB

// 定義一個初始化資料庫的函式
func initDB() (err error) {
	// DSN:Data Source Name
	dsn := "root:12345678@tcp(127.0.0.1:3306)/sql_test?charset=utf8mb4&parseTime=True"
	// 不會校驗賬號密碼是否正確
	// 注意!!!這里不要使用:=,我們是給全域變數賦值,然后在main函式中使用全域變數db
	db, err = sql.Open("mysql", dsn)
	if err != nil {
		return err
	}
	// 嘗試與資料庫建立連接(校驗dsn是否正確)
	err = db.Ping()
	if err != nil {
		return err
	}
	return nil
}

func main() {
	err := initDB() // 呼叫輸出化資料庫的函式
	if err != nil {
		fmt.Printf("init db failed,err:%v\n", err)
		return
	}
	fmt.Println("connect to database")

	// one, err := queryRowDemo(1)
	// if err != nil {
	// 	log.Fatal(err.Error())
	// }
	// fmt.Println(one)

	// u := user{
	// 	name: "小喬1",
	// 	age:  13,
	// 	id:   0,
	// }
	// err = u.insertRowDemo()
	// if err != nil {
	// 	log.Fatalln(err.Error())
	// }

	// u, _ := queryRowDemo(1)
	// fmt.Println("u:", u)
	// u.name = "貂蟬"
	// u.age = 16

	// err = u.updateRowDemo()
	// if err != nil {
	// 	log.Fatalln(err.Error())
	// }

	// u1, _ := queryRowDemo(1)
	// fmt.Println("u1:", u1)

	last_row, _ := queryMultiRowDemo(0)
	fmt.Println("last_row:", last_row)

	// var u = new(user)
	// u.id = 3
	// err = u.deleteRowDemo()
	// if err != nil {
	// 	log.Fatalln(err.Error())
	// }
}

services.go 檔案

package main

import (
	"fmt"
)

// 查詢單條資料示例
func queryRowDemo(id int) (u user, err error) {
	sqlStr := "select id, name, age from user where id=?"
	// 非常重要:確保QueryRow之后呼叫Scan方法,否則持有的資料庫鏈接不會被釋放
	err = db.QueryRow(sqlStr, id).Scan(&u.id, &u.name, &u.age)
	if err != nil {
		fmt.Printf("scan failed, err:%v\n", err)
		return
	}
	fmt.Printf("id:%d name:%s age:%d\n", u.id, u.name, u.age)
	return
}

// 查詢多條資料示例
func queryMultiRowDemo(id int) (u user, err error) {
	sqlStr := "select id, name, age from user where id > ?"
	rows, err := db.Query(sqlStr, id)
	if err != nil {
		fmt.Printf("query failed, err:%v\n", err)
		return
	}
	// 非常重要:關閉rows釋放持有的資料庫鏈接
	defer rows.Close()
	// 回圈讀取結果集中的資料
	for rows.Next() {
		err = rows.Scan(&u.id, &u.name, &u.age)
		if err != nil {
			fmt.Printf("scan failed, err:%v\n", err)
			return
		}
		fmt.Printf("id:%d name:%s age:%d\n", u.id, u.name, u.age)
	}
	return
}

// 插入資料
func (u *user) insertRowDemo() (err error) {
	sqlStr := "insert into user(name, age) values (?,?)"
	ret, err := db.Exec(sqlStr, u.name, u.age)
	if err != nil {
		fmt.Printf("insert failed, err:%v\n", err)
		return
	}
	theID, err := ret.LastInsertId() // 新插入資料的id
	if err != nil {
		fmt.Printf("get lastinsert ID failed, err:%v\n", err)
		return
	}
	fmt.Printf("insert success, the id is %d.\n", theID)
	return
}

// 更新資料
func (u *user) updateRowDemo() (err error) {
	sqlStr := "update user set age=? where id = ?"
	ret, err := db.Exec(sqlStr, u.age, u.id)
	if err != nil {
		fmt.Printf("update failed, err:%v\n", err)
		return
	}
	n, err := ret.RowsAffected() // 操作影響的行數
	if err != nil {
		fmt.Printf("get RowsAffected failed, err:%v\n", err)
		return
	}
	fmt.Printf("update success, affected rows:%d\n", n)
	return
}

// 洗掉資料
func (u *user) deleteRowDemo() (err error) {
	sqlStr := "delete from user where id = ?"
	ret, err := db.Exec(sqlStr, u.id)
	if err != nil {
		fmt.Printf("delete failed, err:%v\n", err)
		return
	}
	n, err := ret.RowsAffected() // 操作影響的行數
	if err != nil {
		fmt.Printf("get RowsAffected failed, err:%v\n", err)
		return
	}
	fmt.Printf("delete success, affected rows:%d\n", n)
	return
}

models.go 檔案

package main

type user struct {
	id   int
	age  int
	name string
}

運行

Code/go/go_sql_demo via ?? v1.20.3 via ?? base 
? go build . && ./go_sql_demo
connect to database
id:1 name:小喬 age:16
id:2 name:小喬 age:12
last_row: {2 12 小喬}

Code/go/go_sql_demo via ?? v1.20.3 via ?? base took 3.3s 
? 

本文來自博客園,作者:QIAOPENGJUN,轉載請注明原文鏈接:https://www.cnblogs.com/QiaoPengjun/p/17390319.html

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/552180.html

標籤:Go

上一篇:openAI發布v0.2.0了

下一篇:返回列表

標籤雲
其他(158833) Python(38125) JavaScript(25413) Java(18025) C(15226) 區塊鏈(8264) C#(7972) AI(7469) 爪哇(7425) MySQL(7177) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5871) 数组(5741) R(5409) Linux(5338) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4570) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2432) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1972) 功能(1967) Web開發(1951) HtmlCss(1935) python-3.x(1918) C++(1915) 弹簧靴(1913) xml(1889) PostgreSQL(1875) .NETCore(1860) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Go語言(Golang)資料庫編程

    Go 資料庫編程 一、連接資料庫 準備連接到資料庫 要想連接到 SQL 資料庫,首先需要加載目標資料庫的驅動,驅動里面包含著于該資料庫互動的邏輯。 sql.Open() 資料庫驅動的名稱 資料源名稱 得到一個指向 sql.DB 這個 struct 的指標 sql.DB 是用來操作資料庫的,它代表了0 ......

    uj5u.com 2023-05-12 07:29:07 more
  • openAI發布v0.2.0了

    時隔20天,OpenAI從v0.0.1升級到了v0.2.0。與v0.0.1版相比,v0.2.0版主要做了以下改動: 把cmd目錄下微信公眾號的相關服務遷移到了這里 完善了cmd下的測驗服務,針對openAI庫里實作的各個介面都提供了回應的呼叫介面,服務運行后可以通過postman進行測驗 完成了Fi ......

    uj5u.com 2023-05-12 07:29:01 more
  • Linux網路編程:socket實作client/server通信

    一、問題引入 閱讀UNIX網路編程 卷1:套接字聯網API 第3版的前4個章節,覺得有必要對書籍上的原始碼案例進行復現,并推敲TCP的C/S通信程序。 二、解決程序 2-1 server #include <sys/types.h> #include <sys/socket.h> #include < ......

    uj5u.com 2023-05-12 07:23:18 more
  • 高效c語言2物件、函式和型別

    本章中,你將學習物件、函式和型別。我們將研究如何宣告變數(有識別符號的物件)和函式,獲取物件的地址,并對這些物件指標的解參考。你已經看到了C語言程式員可用的一些型別, C語言中的型別不是物件就是函式。 物件、函式、型別和指標 物件是你可以表示數值的存盤。準確地說,C標準(ISO/IEC 9899:20 ......

    uj5u.com 2023-05-12 07:23:01 more
  • C++ 入門

    001 c++ 如何作業 任何以 # 開頭的陳述句,都是預處理陳述句,所謂的預處理陳述句,在編譯之前,就已經被處理了 關鍵字 include:找到 <> 檔案(通常稱為“頭檔案”),然后將 <> 中的所有內容拷貝到現在的檔案里 main()比較特殊,雖然它的回傳值型別是 int,但它不一定需要回傳值,如果 ......

    uj5u.com 2023-05-12 07:21:48 more
  • 在 IDEA 中創建 Spring Boot 專案的方式(詳細步驟教程)

    開發環境 以下是我的開發環境 JDK 1.8 Maven 3.6.3 IDEA 2019(2019 無所畏懼,即使現在已經 2023 年了哈哈哈) 使用 Maven 的方式創建 Spring Boot 專案 下面的內容可能會因 IDEA 版本不同,而有些選項不同,但是大同小異。 1. 打開 IDEA ......

    uj5u.com 2023-05-11 07:32:53 more
  • Java for回圈標簽跳轉到指定位置

    大家是否見過這種for回圈,在for回圈前加了個標記的: outerLoop: for (; ; ) { for (; ; ) { break outerLoop; } } 我之前有一次在公司業務代碼中見過有這種寫法的,沒在意,今天在看JDK執行緒池的代碼時,又看到ThreadPoolExecutor ......

    uj5u.com 2023-05-11 07:32:35 more
  • 訊息推送平臺的實時數倉?!flink消費kafka訊息入到hive

    大家好,3y啊。好些天沒更新了,并沒有偷懶,只不過一直在安裝環境,差點都想放棄了。 上一次比較大的更新是做了austin的預覽地址,把企業微信的應用和機器人訊息各種的訊息型別和功能給完善了。上一篇文章也提到了,austin常規的功能已經更新得差不多了,剩下的就是各種細節的完善。 不知道大家還記不記得 ......

    uj5u.com 2023-05-11 07:32:30 more
  • Hibernate 基本操作、懶加載以及快取

    上一篇咱們介紹了 Hibernate 以及寫了一個 Hibernate 的工具類,快速入門體驗了一波 Hibernate 的使用,我們只需通過 Session 物件就能實作資料庫的操作了。

    現在,這篇介紹使用 Hibernate 進行基本的 CRUD、懶加載以及快取的知識。 ......

    uj5u.com 2023-05-11 07:32:24 more
  • 【Visual Leak Detector】核心原始碼剖析(VLD 2.5.1)

    使用 VLD 記憶體泄漏檢測工具輔助開發時整理的學習筆記。本篇對 VLD 2.5.1 原始碼做記憶體泄漏檢測的思路進行剖析。 ......

    uj5u.com 2023-05-11 07:32:18 more