Testing Database Transactions in Go
marvinblum.de
Testing Database Transactions in Go
1–10 of 22 posts
Re: Testing Database Transactions in Go
#2Re: Testing Database Transactions in Go
#3Hey guys, this is just a quick tip on how to make sure you don't screw up the database connection pool in Go. This might also apply to other languages and frameworks. I've seen dozens of articles about concurrency and multithreading, but not so many about this type of deadlocks, and I experienced some production bugs because of this.
Also, regarding writing tests against real PostgreSQL databases, isolated per test and without losing speed, I can recommend to take a look at https://github.com/allaboutapps/integresql - disclaimer, we are the authors.
Re: Testing Database Transactions in Go
#4Hey guys, this is just a quick tip on how to make sure you don't screw up the database connection pool in Go. This might also apply to other languages and frameworks. I've seen dozens of articles about concurrency and multithreading, but not so many about this type of deadlocks, and I experienced some production bugs because of this.
Great points! Any hints regarding preexisting linters for go code that errors if we execute outside (an already opened) db transaction? Also, regarding writing tests against real PostgreSQL databases, isolated per test and without losing speed, I can recommend to take a look at https://github.com/allaboutapps/integresql - disclaimer, we are the authors.
I'm limiting the open connections at the moment and using the default Goland linter. It won't show you these kind of errors though and I just remembered that I saw it somewhere else, but I don't remember where it was :D
Re: Testing Database Transactions in Go
#5IMO the standard library should provide something that wraps a `Tx` and a `Context` together, as usually I want every statement issued from a transaction bounded in lifetime by the same one I provided to `BeginTx`. This would provide even more incentive to pass around `Tx`s rather than `DB`s, since those functions also often need a context anyway.
Re: Testing Database Transactions in Go
#6Hey guys, this is just a quick tip on how to make sure you don't screw up the database connection pool in Go. This might also apply to other languages and frameworks. I've seen dozens of articles about concurrency and multithreading, but not so many about this type of deadlocks, and I experienced some production bugs because of this.
It is quite similar to other Go concepts. For example, you don't want to have circular dependencies between channels. The difference is that such a thing would fail very quickly whereas dependent DB connections would only fail after the connections are exhausted.
Re: Testing Database Transactions in Go
#7Hey guys, this is just a quick tip on how to make sure you don't screw up the database connection pool in Go. This might also apply to other languages and frameworks. I've seen dozens of articles about concurrency and multithreading, but not so many about this type of deadlocks, and I experienced some production bugs because of this.
Maybe I'm assuming too much but it wouldn't occur to me to let tx.Commit() depend on the outcome of another connection (here: db.Query()). Either use tx.Query() (which I guess is partly what you're advocating) or put db.Query() in a different goroutine and let tx.Commit() proceed. It is quite similar to other Go concepts. For example, you don't want to have circular dependencies between channels. The difference is th…
Re: Testing Database Transactions in Go
#8The easiest way I have found to avoid this error is simply not to pass the `db` around so much. Every data access function (even seemingly trivial ones) should take a `Tx` instead. This also makes your code "composition-ready" if necessary later. IMO the standard library should provide something that wraps a `Tx` and a `Context` together, as usually I want every statement issued from a transaction bounded in lifetime…
Re: Testing Database Transactions in Go
#9Re: Testing Database Transactions in Go
#10Hey guys, this is just a quick tip on how to make sure you don't screw up the database connection pool in Go. This might also apply to other languages and frameworks. I've seen dozens of articles about concurrency and multithreading, but not so many about this type of deadlocks, and I experienced some production bugs because of this.
Maybe I'm assuming too much but it wouldn't occur to me to let tx.Commit() depend on the outcome of another connection (here: db.Query()). Either use tx.Query() (which I guess is partly what you're advocating) or put db.Query() in a different goroutine and let tx.Commit() proceed. It is quite similar to other Go concepts. For example, you don't want to have circular dependencies between channels. The difference is th…
I don't think there's necessarily anything "special" about this, I think it's just a case where there's a lot of people with years or even decades of experience in that context, and it simply doesn't immediately occur to them that in a higher-concurrency world they need to modify these skills.
I suspect there's also rather a lot of database + application combinations out in the real world that, by coincidence and a bit of hacking around problems as they arise, "just happen to work" with the highly characteristic access patterns used by the web pages that can access the DB and the transaction isolation settings in the DB. Using any more concurrent and looser access to the DB is likely to expose a lot of problems that in some sense existed all along, but were just never quite uncovered before with the old access patterns.
(It isn't really Go. Threading an old-school C program will raise the same issues, or going async in a scripting language.)