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{}
model *Model
dbName string
isBlank bool
isPrimaryKey bool
autoCreateTime bool
autoUpdateTime bool
@ -23,8 +24,8 @@ type Field struct {
structField reflect.StructField
}
func (f *Field) isBlank() bool {
return isBlank(f.reflectValue)
func (f *Field) parseBlank() {
f.isBlank = isBlank(f.reflectValue)
}
func (f *Field) isScanner() bool {

View File

@ -1365,7 +1365,7 @@ func TestQueryChain(t *testing.T) {
}
func BenchmarkGorm(b *testing.B) {
b.N = 5000
b.N = 2000
for x := 0; x < b.N; x++ {
e := strconv.Itoa(x) + "benchmark@example.org"
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"
delete_sql := "DELETE FROM orders WHERE id = $1"
b.N = 5000
b.N = 2000
for x := 0; x < b.N; x++ {
var id int64
e := strconv.Itoa(x) + "benchmark@example.org"

View File

@ -2,7 +2,6 @@ package gorm
import (
"database/sql"
"github.com/jinzhu/gorm/dialect"
)
@ -139,7 +138,7 @@ func (s *DB) Delete(value interface{}) *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 {

View File

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

View File

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