Gorm事务错误:错误=事务已经提交或回滚。

huangapple go评论107阅读模式
英文:

Gorm Transaction Error error = transaction has already been committed or rolled back

问题

我正在尝试在下面的代码中进行事务管理。如果其中一个策略出现错误,我尝试进行回滚操作。在测试代码时,我注意到如果回滚或提交命令成功执行一次,第二次执行时会出现错误,提示"事务已经被提交或回滚"。我该如何解决这个错误?

func (d *DistributeService) Distribute(vehicleNumberPlate string, request model.DistributeRequest) (*model.DistributeResponse, error) {
	var response model.DistributeResponse
	response.Vehicle = vehicleNumberPlate
	var routeList []model.RouteResponse
	tx := d.repo.BeginTransaction()
	for _, routes := range request.RouteRequest {
		var routeResponse model.RouteResponse
		strategy, isStrategyExists := d.strategies[routes.DeliveryPoint]
		if isStrategyExists {
			resp, err := strategy.Distribute(routes.Deliveries, vehicleNumberPlate, tx)
			if err != nil {
				tx.Rollback()
				logrus.Errorf("Error while distributing: %v", err)
				return nil, err
			}
			routeResponse.DeliveryPoint = routes.DeliveryPoint
			routeResponse.Deliveries = *resp
			routeList = append(routeList, routeResponse)
		} else {
			logrus.Errorf("Invalid delivery point: %v", routes.DeliveryPoint)
			return nil, errors.New("invalid delivery point")
		}
	}
	response.RouteResponse = routeList
	err := d.checkSackPackagesAreUnloaded()
	tx.Commit()
	if err != nil {
		return nil, err
	}
	return &response, nil
}

以上是你要翻译的内容。

英文:

I'm aiming to do transaction management in the code below. If there is an error in one of the strategies, I am trying to rollback. While testing the code, I noticed that if the rollback or commit command works once, it gives error = transaction has already been committed or rolled back the second time. How can I resolve this error?

func (d *DistributeService) Distribute(vehicleNumberPlate string, request model.DistributeRequest) (*model.DistributeResponse, error) {
	var response model.DistributeResponse
	response.Vehicle = vehicleNumberPlate
	var routeList []model.RouteResponse
	tx := d.repo.BeginTransaction()
	for _, routes := range request.RouteRequest {
		var routeResponse model.RouteResponse
		strategy, isStrategyExists := d.strategies[routes.DeliveryPoint]
		if isStrategyExists {
			resp, err := strategy.Distribute(routes.Deliveries, vehicleNumberPlate, tx)
			if err != nil {
				tx.Rollback()
				logrus.Errorf("Error while distributing: %v", err)
				return nil, err
			}
			routeResponse.DeliveryPoint = routes.DeliveryPoint
			routeResponse.Deliveries = *resp
			routeList = append(routeList, routeResponse)
		} else {
			logrus.Errorf("Invalid delivery point: %v", routes.DeliveryPoint)
			return nil, errors.New("invalid delivery point")
		}
	}
	response.RouteResponse = routeList
	err := d.checkSackPackagesAreUnloaded()
	tx.Commit()
	if err != nil {
		return nil, err
	}
	return &response, nil
}

答案1

得分: 1

你可能在每次调用中使用相同的事务对象。
如果它被关闭了一次 - 不管出于什么原因 - 你需要创建一个新的事务对象。

你为什么会问我说你可能在使用相同的事务对象呢?
因为你基本上是在传递一个指向 d *DistributeService 的指针。
然后使用 tx := d.repo.BeginTransaction()。我们无法确定这段代码的具体作用,但我很确定你在这里返回的是相同的事务对象,用于后续的运行。

解决方法是在每次调用该方法时创建一个新的事务对象,例如使用 tx := db.Begin(),如文档所述。

英文:

You're probably using the same transaction object in each call.
If it was closed once - for whatever reason - you need to create a new transaction object.

Why do I say you are probably using the same transaction object you ask?
Because you're basically passing a pointer to d *DistributeService.
And then use tx := d.repo.BeginTransaction(). We can't tell what that code does, but I'm pretty sure you're returning the same transaction object here for subsequent runs.

The solution is to create a new transaction object every time this method is called, f.e. with tx := db.Begin() as described in the docs.

huangapple
  • 本文由 发表于 2023年5月13日 18:54:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/76242351.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定