db session mngmnt in go: typo + addition

This commit is contained in:
Wouter Groeneveld 2024-06-12 19:42:26 +02:00
parent f29a1268d9
commit 5d13699271
1 changed files with 5 additions and 3 deletions

View File

@ -25,7 +25,7 @@ public void SaveInvoice(Invoice invoice) {
If the method fails, the transaction is automatically rolled back. If `SaveInvoice()` is called upon multiple times in parallel, the behind-the-scenes transaction manager that the annotation `@Transactional` uses still works: it usually relies on a thread-static session that's unique for each incoming request.
This seems so simple and obvious, but let's still ask the question: how do you do this in Go? Use an unexported global variable? Create something new for each request? Rely on `context.Context`?
This seems so simple and obvious, but let's still ask the question: how do you do this in Go? Use an unexported global variable? Create something new for each request? Leverage the current `context.Context`?
We rely on [GORM](https://gorm.io/docs/transactions.html), an ORM framework that could be compared to Hibernate except that it's much more lightweight---and as a result, leaves the transaction management up to you. The GORM way to open a transaction is perhaps weird: it returns a new pointer with the same type of `*gorm.DB`[^er]:
@ -92,7 +92,9 @@ func (c *invoiceCmd) Save(invoice Invoice) error {
}
```
This allows us to use GORM's `Transaction()` convenience wrapper in true [Transaction Script](https://martinfowler.com/eaaCatalog/transactionScript.html) style as Martin Fowler likes to call it---or, if we really need to, manage transactions manually.
This allows us to use GORM's `Transaction()` convenience wrapper in true [Transaction Script](https://martinfowler.com/eaaCatalog/transactionScript.html) style as Martin Fowler likes to call it---or, if we really need to, manage transactions manually[^trs].
[^trs]: Although it is technically possible to use a thread-static variable bound to the current goroutine that was spun up with the request, there is no way to resolve the current thread using something like Java's `Thread.currentThread()`. Again, that's [considered bad code design](https://pkg.go.dev/github.com/davecheney/junk/id?utm_source=godoc).
Still, it just bugs me that (1) this code is much more cluttered (thank you [Go error handling](/post/2024/03/error-handling-no-goes-in-go/)) and (2) you have to pass in `tx`, although that can be solved by creating your repositories within the `Transaction()` func. What about unit testability then? I suppose writing an integration test against an in-memory SQLite database is your only option then, as there's no way to inject other behaviour.