Use channel to make gorm faster

This commit is contained in:
Jinzhu 2013-11-17 09:50:34 +08:00
parent 88917aa2ef
commit bf1db1534e
5 changed files with 52 additions and 35 deletions

View File

@ -13,6 +13,7 @@ type Field struct {
Value interface{} Value interface{}
model *Model model *Model
dbName string dbName string
isBlank bool
isPrimaryKey bool isPrimaryKey bool
autoCreateTime bool autoCreateTime bool
autoUpdateTime bool autoUpdateTime bool
@ -23,8 +24,8 @@ type Field struct {
structField reflect.StructField structField reflect.StructField
} }
func (f *Field) isBlank() bool { func (f *Field) parseBlank() {
return isBlank(f.reflectValue) f.isBlank = isBlank(f.reflectValue)
} }
func (f *Field) isScanner() bool { func (f *Field) isScanner() bool {

View File

@ -1365,7 +1365,7 @@ func TestQueryChain(t *testing.T) {
} }
func BenchmarkGorm(b *testing.B) { func BenchmarkGorm(b *testing.B) {
b.N = 5000 b.N = 2000
for x := 0; x < b.N; x++ { for x := 0; x < b.N; x++ {
e := strconv.Itoa(x) + "benchmark@example.org" e := strconv.Itoa(x) + "benchmark@example.org"
email := BigEmail{Email: e, UserAgent: "pc", RegisteredAt: time.Now()} email := BigEmail{Email: e, UserAgent: "pc", RegisteredAt: time.Now()}
@ -1388,7 +1388,7 @@ func BenchmarkRawSql(b *testing.B) {
update_sql := "UPDATE emails SET email = $1, updated_at = $2 WHERE id = $3" update_sql := "UPDATE emails SET email = $1, updated_at = $2 WHERE id = $3"
delete_sql := "DELETE FROM orders WHERE id = $1" delete_sql := "DELETE FROM orders WHERE id = $1"
b.N = 5000 b.N = 2000
for x := 0; x < b.N; x++ { for x := 0; x < b.N; x++ {
var id int64 var id int64
e := strconv.Itoa(x) + "benchmark@example.org" e := strconv.Itoa(x) + "benchmark@example.org"

View File

@ -2,7 +2,6 @@ package gorm
import ( import (
"database/sql" "database/sql"
"github.com/jinzhu/gorm/dialect" "github.com/jinzhu/gorm/dialect"
) )
@ -139,7 +138,7 @@ func (s *DB) Delete(value interface{}) *DB {
} }
func (s *DB) Exec(sql string) *DB { func (s *DB) Exec(sql string) *DB {
return s.do(nil).exec(sql).db return s.clone().do(nil).exec(sql).db
} }
func (s *DB) Model(value interface{}) *DB { func (s *DB) Model(value interface{}) *DB {

View File

@ -63,47 +63,65 @@ func getStructs(typ reflect.Type) (fs []reflect.StructField) {
} }
func (m *Model) fields(operation string) (fields []*Field) { func (m *Model) fields(operation string) (fields []*Field) {
if len(m._cache_fields[operation]) > 0 {
return m._cache_fields[operation]
}
indirect_value := m.reflectData() indirect_value := m.reflectData()
if !indirect_value.IsValid() { if !indirect_value.IsValid() {
return return
} }
for _, filed_struct := range getStructs(indirect_value.Type()) { structs := getStructs(indirect_value.Type())
var field Field c := make(chan *Field, len(structs))
field.Name = filed_struct.Name for _, field_struct := range structs {
field.dbName = toSnake(filed_struct.Name) go func(field_struct reflect.StructField, c chan *Field) {
field.isPrimaryKey = m.primaryKeyDb() == field.dbName var field Field
value := indirect_value.FieldByName(filed_struct.Name) field.Name = field_struct.Name
field.model = m field.dbName = toSnake(field_struct.Name)
field.isPrimaryKey = m.primaryKeyDb() == field.dbName
value := indirect_value.FieldByName(field_struct.Name)
field.model = m
if time_value, is_time := value.Interface().(time.Time); is_time { if time_value, is_time := value.Interface().(time.Time); is_time {
field.autoCreateTime = "created_at" == field.dbName field.autoCreateTime = "created_at" == field.dbName
field.autoUpdateTime = "updated_at" == field.dbName field.autoUpdateTime = "updated_at" == field.dbName
switch operation { switch operation {
case "create": case "create":
if (field.autoCreateTime || field.autoUpdateTime) && time_value.IsZero() { if (field.autoCreateTime || field.autoUpdateTime) && time_value.IsZero() {
value.Set(reflect.ValueOf(time.Now())) value.Set(reflect.ValueOf(time.Now()))
} }
case "update": case "update":
if field.autoUpdateTime { if field.autoUpdateTime {
value.Set(reflect.ValueOf(time.Now())) value.Set(reflect.ValueOf(time.Now()))
}
} }
} }
} field.structField = field_struct
field.reflectValue = value
field.structField = filed_struct field.Value = value.Interface()
field.reflectValue = value field.parseAssociation()
field.Value = value.Interface() field.parseBlank()
field.parseAssociation() c <- &field
fields = append(fields, &field) }(field_struct, c)
} }
for i := 0; i < len(structs); i++ {
fields = append(fields, <-c)
}
close(c)
if len(m._cache_fields) == 0 {
m._cache_fields = map[string][]*Field{}
}
m._cache_fields[operation] = fields
return return
} }
func (m *Model) columnsHasValue(operation string) (fields []*Field) { func (m *Model) columnsHasValue(operation string) (fields []*Field) {
for _, field := range m.fields(operation) { for _, field := range m.fields(operation) {
if !field.isBlank() { if !field.isBlank {
fields = append(fields, field) fields = append(fields, field)
} }
} }
@ -236,7 +254,7 @@ func (m *Model) setValueByColumn(name string, value interface{}, out interface{}
func (m *Model) beforeAssociations() (fields []*Field) { func (m *Model) beforeAssociations() (fields []*Field) {
for _, field := range m.fields("null") { for _, field := range m.fields("null") {
if field.beforeAssociation && !field.isBlank() { if field.beforeAssociation && !field.isBlank {
fields = append(fields, field) fields = append(fields, field)
} }
} }
@ -245,7 +263,7 @@ func (m *Model) beforeAssociations() (fields []*Field) {
func (m *Model) afterAssociations() (fields []*Field) { func (m *Model) afterAssociations() (fields []*Field) {
for _, field := range m.fields("null") { for _, field := range m.fields("null") {
if field.afterAssociation && !field.isBlank() { if field.afterAssociation && !field.isBlank {
fields = append(fields, field) fields = append(fields, field)
} }
} }

View File

@ -3,7 +3,6 @@ package gorm
import ( import (
"bytes" "bytes"
"database/sql" "database/sql"
"reflect" "reflect"
"strconv" "strconv"
"strings" "strings"