moment of hit post API概述:
这是我的代码
func (s StudentServiceImpl) Create(ctx context.Context, request web.StudentCreateRequest) web.StudentResponse {
err := s.Validate.Struct(request)
helper.PanicIfError(err)
tx, err := s.DB.Begin()
helper.PanicIfError(err)
defer helper.CommitOrRollback(tx)
major, isExistMajor := s.MajorService.FindByMajorName(ctx, request.Major)
//fmt.Println(isExistMajor)
if isExistMajor == false {
major = s.MajorService.Create(ctx, request.Major)
}
student := domain.Student{
Name: request.Name,
Age: request.Age,
Gender: request.Gender,
CreatedAt: time.DateTime,
Major: major,
}
student = s.StudentRepository.Save(ctx, tx, student)
studentId := student.Id
hobbies := s.HobbyService.Creates(ctx, request.Hobbies)
fmt.Println(hobbies, studentId)
for i := 0; i < len(hobbies); i++ {
// todo this below service bug stuck in sending request...
//s.HobbyService.CreateStudentHobby(ctx, studentId, hobbies[i].Id)
}
return helper.ToStudentResponse(student)
}
怎么了,请帮帮我!链接我的仓库https://github.com/antoniusbunwiijaya/student-api-go/blob/master/service/student_service_impl.go#L39
1条答案
按热度按时间axr492tv1#
这是由死锁引起的。
如果你在数据库中执行
show engine innodb status;
,你会看到类似这样的东西:下面是
(StudentServiceImpl).Create
的调用序列:1.它启动外部事务。
1.它将记录插入表
students
。1.它调用
(HobbyServiceImpl).CreateStudentHobby
。该函数的序列为:3.1)它启动内部事务。
3.2)它试图将一条记录插入到
student_hobbies
表中。这里,由于外键约束(FOREIGN KEY (student_id) REFERENCES students(id)
),它要求在students
表上设置一个记录锁。3.3)提交或回滚内部事务。
1.提交或回滚外部事务。
步骤3.2无法完成,因为外部事务尚未结束;但是外部事务直到第4步才能结束。所以这里是死锁。
解决这类问题的一个简单解决方案是在设计中引入Unit of Work pattern。简单地说,对于用户操作,您为所有涉及的服务创建单个事务(而不是让每个服务创建自己的事务)。
例如,
(StudentServiceImpl).Create
可以是工作单元的条目。它负责管理事务并将事务传递给它调用的服务。我已经创建了a pull request,它使用此解决方案来解决这个问题。查看更多细节。请注意,这并不是最好的解决方案。事务是有成本的,请谨慎使用。也许您只是需要事务来执行一些关键操作。例如,您真的需要事务来执行简单的查询吗?请参阅这里的示例,其中在事务中执行简单的查询。