При использовании предложения OnConflict я устанавливаю флаг UpdateAll на true. В моей таблице также есть поле VersionoptmisticLock.Version.
Я ожидаю, что gorm обновит все столбцы, включая столбец версии, до новой версии в случае конфликта, но версия не обновляется автоматически.
Пример:
type TestEntity struct {
ID string `gorm:varchar(100);primary_key`
Name string
Version optimisticlock.Version
}
Таблица имеет одну строку с записями:
ID: "xyz", Name: "first", Version: 1
Я хочу обновить текущую строку:
testUpdateEntity := &TestEntity{
ID: "xyz",
Name: "second",
}
Когда я бегу:
dres := u.db.WithContext(context.TODO()).Clauses(clause.OnConflict{
UpdateAll: true,
}).Create(testUpdateEntity)
Затем он должен самостоятельно обновить версию до 2 после обнаружения конфликта.
DoUpdates, потому что в реальной таблице есть несколько столбцов.
Насколько мне известно, GORM в настоящее время не поддерживает автоматическое обновление столбца версии оптимистической блокировки при использовании предложения OnConflict.
Когда вы используете предложение OnConflict с UpdateAll, GORM генерирует оператор UPSERT, который пытается вставить новую строку, и в случае возникновения конфликта обновляет все столбцы существующей строки значениями из новой строки. Однако в этом сценарии GORM не обрабатывает автоматически столбец версии оптимистической блокировки.
Чтобы обработать столбец версии оптимистической блокировки в этой ситуации, вы можете явно указать столбцы для обновления, используя предложение DoUpdates.
Поскольку вы упомянули, что ваша таблица имеет несколько столбцов, и вы не хотите явно перечислять их все, попробуйте использовать приведенный ниже код для динамического создания списка столбцов.
// Define a function to get a list of columns to update excluding primary key and version
func getColumnsToUpdate(db *gorm.DB, entity interface{}) ([]string, error) {
var columnsToUpdate []string
// Retrieve table name
tableName := db.NamingStrategy.TableName("", db.Statement.Schema.Table)
// Retrieve column names
columnNames, err := db.Migrator().Columns(tableName)
if err != nil {
return nil, err
}
// Exclude primary key and version columns
for _, columnName := range columnNames {
if columnName != "ID" && columnName != "Version" {
columnsToUpdate = append(columnsToUpdate, columnName)
}
}
return columnsToUpdate, nil
}
затем обновите свой запрос
// Define update data
updateData := make(map[string]interface{})
for _, column := range columnsToUpdate {
updateData[column] = "updated_value" // Set your updated value here
}
// Add version update
updateData["Version"] = gorm.Expr("Version + 1")
// Apply update with OnConflict clause
dres := u.db.WithContext(context.TODO()).Clauses(clause.OnConflict{
UpdateAll: true,
}).Model(&TestEntity{}).Where("id = ?", testUpdateEntity.ID).Updates(updateData)
Также в настоящее время в методах Save() и Update() gorm не выдает OptimisticlockVersion.
Я только что обновил пример кода, чтобы увеличить версию при обновлении данных.
Спасибо за ответ. Это работает для случая обновления. Но я заметил одну вещь: gorm не выдает никаких ошибок, если одна транзакция не может обновиться из-за optmisticlock или даже если запись не найдена (когда версия уже увеличена).
Но в этом случае версия не будет постоянно обновляться. Допустим, две транзакции происходят одновременно, теперь в запросе должен присутствовать оператор версии
version=version+1.