亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Golang實現(xiàn)自己的orm框架實例探索

 更新時間:2024年01月24日 09:32:12   作者:紹納?nullbody筆記  
這篇文章主要為大家介紹了Golang實現(xiàn)自己的orm框架實例探索,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

引言

本項目相當于gorm的精簡版,通過學習本項目可以更好的理解orm框架每個函數(shù)都在做什么,以及為什么這么定義框架功能。

通過本項目學到什么?

  • 定義自己的日志庫logger
  • 如何將結(jié)構(gòu)體轉(zhuǎn)化成數(shù)據(jù)庫的表信息(字段/字段類型/表名)
  • 如何實現(xiàn)常用的CRUD?
  • 如何實現(xiàn)事務(wù)?
  • 如何實現(xiàn)鉤子?

Golang orm框架實現(xiàn)

該項目的核心數(shù)據(jù)結(jié)構(gòu)為 Session

type Session struct {
	db *sql.DB
	tx *sql.Tx

	// table
	tableMeta *table.TableMeta

	dial dialect.Dialect
	// clause

	clause clause.Clause

	// sql query
	sql strings.Builder
	// sql param
	sqlParam []interface{}
}

db: 負責執(zhí)行sql語句

tx: 通過事務(wù)執(zhí)行sql語句

tableMeta: Golang的結(jié)構(gòu)體轉(zhuǎn)成的 表信息

clause: sql語句構(gòu)造器(負責生成CRUD SQL 字符串 )

dial: 將Golang數(shù)據(jù)類型轉(zhuǎn)成 數(shù)據(jù)庫的類型

sql/sqlParam: 待執(zhí)行的sql和參數(shù)

定義自己的日志庫logger

特色:就是不同的日志級別有不同的顏色

如何將結(jié)構(gòu)體轉(zhuǎn)化成數(shù)據(jù)庫的表信息(字段/字段類型/表名)

// Parse 將結(jié)構(gòu)體轉(zhuǎn)化成 表/字段/字段類型
func Parse(dest interface{}, d dialect.Dialect) *TableMeta {
	// 是否為nil
	if dest == nil {
		returnnil
	}
	// (*User)(nil)
	value := reflect.ValueOf(dest)
	if value.Kind() == reflect.Ptr && value.IsNil() {
		value = reflect.New(value.Type().Elem()) // 取出類型,構(gòu)造新對象
	}
	meta := &TableMeta{
		Model:    value.Interface(), // 保存對象
		fieldMap: make(map[string]*Field),
	}
	destValue := reflect.Indirect(value)
	destType := destValue.Type()
	// 結(jié)構(gòu)體類型名:就是表名
	m, ok := value.Interface().(Tabler)
	if ok {
		meta.TableName = m.TableName()
	} else {
		meta.TableName = destType.Name()
	}
	for i := 0; i < destType.NumField(); i++ {
		fieldType := destType.Field(i)
		// 非匿名 && 可導(dǎo)出
		if !fieldType.Anonymous && fieldType.IsExported() {
			// 成員變量:就是字段名
			// 成員變量類型:就是字段類型
			field := &Field{
				FieldName: fieldType.Name,
				FieldType: d.ConvertType2DBType(destValue.Field(i)),
				FieldTag:  fieldType.Tag.Get("easyorm"),
			}
			meta.Fields = append(meta.Fields, field)
			meta.FieldsName = append(meta.FieldsName, field.FieldName)
			meta.fieldMap[field.FieldName] = field
		}
	}
	return meta
}

如何實現(xiàn)常用的CRUD

這里以新增為例:一般的調(diào)用方式為 s.Insert(&User{},&User{})

整個代碼其實就是基于傳入的values,通過 reflect的相關(guān)函數(shù)提取出其中的字段值,最終的目的在于拼接成 insert into $table ($field) values (?,?),(?,?) 標準的SQL語句,傳給底層的驅(qū)動執(zhí)行

// s.Insert(&User{},&User{})
func (s *Session) Insert(values ...interface{}) (int64, error) {
	iflen(values) == 0 {
		return0, errors.New("param is empty")
	}
	// init table
	s.Model(values[0])
	// clause insert:負責生成 insert into $tableName ($FieldName) 字符串
	s.clause.Set(clause.INSERT, s.TableMeta().TableName, s.TableMeta().FieldsName)

	valueSlice := []interface{}{}

	for _, value := range values {
		s.CallMethod(BeforeInsert, value)
        // 提取結(jié)構(gòu)體中對象字段的值,作為sql語言的參數(shù)
		valueSlice = append(valueSlice, s.TableMeta().ExtractFieldValue(value))
	}
	// clause values:負責生成 values (?,?,?),(?,?,?)
	s.clause.Set(clause.VALUES, valueSlice...)
    //s.clause.Build: 負責將 insert into $tableName ($FieldName)  拼接上 values (?,?,?),(?,?,?) 形成完整的sql語句
	sql, sqlParam := s.clause.Build(clause.INSERT, clause.VALUES)
	// exec sql : 實際執(zhí)行sql
	result, err := s.Raw(sql, sqlParam...).Exec()
	if err != nil {
		return0, err
	}
	s.CallMethod(AfterInsert, nil)
	return result.RowsAffected()
}

如何實現(xiàn)事務(wù)?

通過SessionBegin方法開啟事務(wù),在回調(diào)函數(shù) f TxFunc中進行具體的【數(shù)據(jù)庫業(yè)務(wù)邏輯】,最后基于  f TxFunc是否執(zhí)行返回 error來決定是Commit還是 Rollback

// TxFunc will be called between tx.Begin() and tx.Commit()
type TxFunc func(*session.Session) (interface{}, error)
// Transaction executes sql wrapped in a transaction, then automatically commit if no error occurs
func (engine *Engine) Transaction(f TxFunc) (result interface{}, err error) {
	s := engine.NewSession()
	if err := s.Begin(); err != nil {
		returnnil, err
	}
	deferfunc() {
		if p := recover(); p != nil {
			_ = s.Rollback()
			panic(p) // re-throw panic after Rollback
		} elseif err != nil {
			_ = s.Rollback() // err is non-nil; don't change it
		} else {
			err = s.Commit() // err is nil; if Commit returns error update err
		}
	}()
	return f(s)
}

如何實現(xiàn)鉤子?

其實就是利用reflect.MethodByName,讀取 value 對象的函數(shù),然后Call執(zhí)行該函數(shù),本質(zhì)就是回調(diào)。利用鉤子在獲取到數(shù)據(jù)以后,用戶可以在回調(diào)中對數(shù)據(jù)進行統(tǒng)一修改,對執(zhí)行結(jié)果進行收口

// CallMethod calls the registered hooks
func (s *Session) CallMethod(method string, value interface{}) {
	fm := reflect.ValueOf(s.TableMeta().Model).MethodByName(method)
	if value != nil {
		fm = reflect.ValueOf(value).MethodByName(method)
	}
	param := []reflect.Value{reflect.ValueOf(s)}
	if fm.IsValid() {
		if v := fm.Call(param); len(v) > 0 {
			if err, ok := v[0].Interface().(error); ok {
				logger.Error(err)
			}
		}
	}
}

項目拖過地址: https://github.com/gofish2020/easyorm 

以上就是Golang實現(xiàn)自己的orm框架實例探索的詳細內(nèi)容,更多關(guān)于Golang orm框架的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 基于Go?goroutine實現(xiàn)一個簡單的聊天服務(wù)

    基于Go?goroutine實現(xiàn)一個簡單的聊天服務(wù)

    對于聊天服務(wù),想必大家都不會陌生,因為在我們的生活中經(jīng)常會用到,本文我們用?Go?并發(fā)來實現(xiàn)一個聊天服務(wù)器,這個程序可以讓一些用戶通過服務(wù)器向其它所有用戶廣播文本消息,文中通過代碼示例介紹的非常詳細,需要的朋友可以參考下
    2023-06-06
  • go語言K8S?的?informer機制淺析

    go語言K8S?的?informer機制淺析

    這篇文章為大家主要介紹了go語言K8S?的?informer機制淺析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-10-10
  • Golang字符串拼接的性能以及原理詳解

    Golang字符串拼接的性能以及原理詳解

    最近在做性能優(yōu)化,有個函數(shù)里面的耗時特別長,看里面的操作大多是一些字符串拼接的操作,而字符串拼接在golang里面其實有很多種實現(xiàn),下面這篇文章主要給大家介紹了關(guān)于Golang字符串拼接的性能以及原理的相關(guān)資料,需要的朋友可以參考下
    2023-06-06
  • go?module化?import?調(diào)用本地模塊?tidy的方法

    go?module化?import?調(diào)用本地模塊?tidy的方法

    這篇文章主要介紹了go?module化?import?調(diào)用本地模塊?tidy的相關(guān)知識,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-09-09
  • Golang多線程刷票的實現(xiàn)代碼

    Golang多線程刷票的實現(xiàn)代碼

    這篇文章主要介紹了Golang多線程刷票的相關(guān)資料,這里實現(xiàn)刷票的功能,對于投票,刷票的很方便,并附實現(xiàn)代碼,需要的朋友可以參考下
    2017-07-07
  • Golang 中 omitempty的作用

    Golang 中 omitempty的作用

    這篇文章主要介紹了Golang 中 omitempty的作用,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考一下,需要的小伙伴可以參考一下
    2022-07-07
  • 一文教你如何快速學會Go的struct數(shù)據(jù)類型

    一文教你如何快速學會Go的struct數(shù)據(jù)類型

    結(jié)構(gòu)是表示字段集合的用戶定義類型。它可以用于將數(shù)據(jù)分組為單個單元而不是將每個數(shù)據(jù)作為單獨的值的地方。本文就來和大家聊聊Go中struct數(shù)據(jù)類型的使用,需要的可以參考一下
    2023-03-03
  • Go語言為什么很少使用數(shù)組原理解析

    Go語言為什么很少使用數(shù)組原理解析

    這篇文章主要為大家介紹了Go語言為什么很少使用數(shù)組原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • go語言環(huán)境搭建簡述

    go語言環(huán)境搭建簡述

    本文簡單記錄了下go語言環(huán)境的搭建流程,給小伙伴們一個參考,希望大家能夠喜歡。
    2015-01-01
  • sublime3+Golang+代碼補全的實現(xiàn)

    sublime3+Golang+代碼補全的實現(xiàn)

    本文主要介紹了sublime3+Golang+代碼補全的實現(xiàn),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01

最新評論