在Go中使用事务
当用户注册时,我的应用程序会做两件事——将用户添加到数据库并发送验证电子邮件:在Go中使用事务,go,Go,当用户注册时,我的应用程序会做两件事——将用户添加到数据库并发送验证电子邮件: ... err := collection("users").Insert(&u); if err != nil { WriteServerError(w, err) return } if err = sendVerificationEmail(&u); err != nil { WriteServerError(w, err) } ... 如果电子邮件未被发送,我不想将
...
err := collection("users").Insert(&u);
if err != nil {
WriteServerError(w, err)
return
}
if err = sendVerificationEmail(&u); err != nil {
WriteServerError(w, err)
}
...
如果电子邮件未被发送,我不想将用户添加到数据库中;如果用户未被添加到数据库中,我也不想发送电子邮件(后者当然会按此顺序处理代码块)
假设Go支持事务,那么像这样的东西值得费心吗?如果是这样的话,那么有人能给我一些建议,告诉我如何转换上面的代码吗
我可以使用嵌套语句,但这可能会变得非常难看。Go中没有“事务”。您最好按照正确的顺序执行以下步骤:
也就是说,一般来说,没有必要转到步骤4。解决此问题的常用方法是在注册/登录页面的某个位置设置一个“我没有收到验证电子邮件,请再发送一封。”按钮。即使发送正确,您甚至无法确定您的电子邮件是否已送达:它可能会被反垃圾邮件过滤,被误点击删除,等等。我认为首先您必须问问自己,为什么会出现数据库/电子邮件发送错误。如果您的数据库不可靠,并且有2%的时间插入失败,那么您可能必须选择其他数据库。如果问题是数据库出现故障,那么您必须担心的问题远不止几个未发送的电子邮件 如果数据库是可靠的,并且问题在于发送电子邮件,因为您使用了一些第三方提供商,而且有时API会失败,那么您可以使用以下方法
for {
if err = sendVerificationEmail(&u); err != nil {
WriteServerError(w, err)
} else {
break
}
}
另一种方法是将应保存在数据库中的电子邮件信息保存,并使用另一个进程(每X秒运行一次)检查并发送所有未发送的电子邮件。发送电子邮件后,从表中删除条目。最好将用户添加到未验证状态的数据库中。如果他们从未验证过,你可以在几周后将其清除 您可以为此使用数据库事务
package main
import (
"database/sql"
_ "github.com/lib/pq"
"log"
"net/smtp"
)
func main() {
db, err := sql.Open("postgres", "user=user dbname=postgres")
if err != nil {
log.Fatal(err)
return
}
defer db.Close()
tnx, err := db.Begin()
if err != nil {
log.Fatal(err)
return
}
user := "test"
password := "testpassword"
res, err := tnx.Exec("INSERT INTO users(login, password) VALUES (?, ?)", user, value)
if err != nil {
log.Fatal(err)
err := tnx.Rollback()
if err != log.Fatal(err) {
log.Fatal(err)
}
return
}
err := smtp.SendMail(
"smpt.google.com", smtp.Auth{}, "test@from.com",
[]string{"test@to.com"}, []byte("Hello"))
if err != nil {
log.Fatal(err)
err := tnx.Rollback()
if err != log.Fatal(err) {
log.Fatal(err)
}
return
}
err := tnx.Commit()
if err != nil {
log.Fatal(err)
return
}
}
是的,您可以在提交事务时捕获死锁或数据库连接丢失,但这种情况非常罕见,您不必担心。或者,如果您希望获得100%的成功保证,请使用临时用户创建方案。在这种特殊情况下,将用户存储在数据库中,稍后在另一个进程中发送电子邮件不是更好吗?您可以在用户上设置一个“状态”列,指示消息是否已成功发送。即使电子邮件尚未发送,您似乎也希望存储该用户。