go-txdb icon indicating copy to clipboard operation
go-txdb copied to clipboard

Add support for the driver.Connector interface.

Open flimzy opened this issue 4 years ago • 4 comments

Fixes #40

flimzy avatar Apr 09 '21 10:04 flimzy

Hi it is very important what dsn is used for txdb return d.Open("connector") it serves as an identifier for transaction, that way, it can open separate transactions and run tests in parallel. If the dsn is hardcoded, it means no concurrent support with Connector.

Also, we cannot just increment the number there, since in some cases it is rather important to reuse same connection. since in applications it sometimes uses same database at the same time but with different connections.

So it must be possible to specify the dsn in a clean way and reuse or create a separate transaction based on it. But given the way it is handled now, it may not be that easy to come up with good implementation

l3pp4rd avatar Apr 10 '21 07:04 l3pp4rd

Hi it is very important what dsn is used for txdb return d.Open("connector") it serves as an identifier for transaction, that way, it can open separate transactions and run tests in parallel. If the dsn is hardcoded, it means no concurrent support with Connector.

Also, we cannot just increment the number there, since in some cases it is rather important to reuse same connection. since in applications it sometimes uses same database at the same time but with different connections.

So it must be possible to specify the dsn in a clean way and reuse or create a separate transaction based on it. But given the way it is handled now, it may not be that easy to come up with good implementation

Based on my reading of the code, that dsn is only used as a map in the *txDriver object, and not globally.

So the way I envision enabling separate transactions here is by making separate calls to txdb.New(). I.e:

txn1, err := sql.OpenDB(txdb.New("mysql", "root@/txdb_test"))
/* ... */
txn2, err := sql.OpenDB(txdb.New("mysql", "root@/txdb_test"))

This should be equivalent to the old way:

txdb.Register("txdb", "mysql", "root@/txdb_test")
/* ... */
txn1, err := sql.Open("txdb", "unique_string_1")
/* ... */
txn2, err := sql.Open("txdb", "unique_string_2")

Or maybe there's some implication of the dsn I'm not seeing immediately?

flimzy avatar Apr 10 '21 07:04 flimzy

txdb.Register in go, creates txdriver instance only once. Every time db.open is called with dsn, the driver looks into the dsn to transaction connection map based on that dsn it either opens a new transaction or reuses the transaction which is already open (in this case every action to that transaction is protected with mutex) With connector implementation, it would do only one way, exactly as you explain. Create the separate txdriver instance every time with that dsn to connection map with single and only dsn in it. If your tested service lets say opens db in two or more places, it would start two separate transactions and would not be usable.

l3pp4rd avatar Apr 10 '21 20:04 l3pp4rd

txdb.Register in go, creates txdriver instance only once. Every time db.open is called with dsn, the driver looks into the dsn to transaction connection map based on that dsn it either opens a new transaction or reuses the transaction which is already open (in this case every action to that transaction is protected with mutex) With connector implementation, it would do only one way, exactly as you explain. Create the separate txdriver instance every time with that dsn to connection map with single and only dsn in it. If your tested service lets say opens db in two or more places, it would start two separate transactions and would not be usable.

Are you saying there's a difference in behavior between these two approaches? I don't see any difference.

It's already possible, using the Register method, to create multiple simultaneous transactions, by providing different dsns. This is no different than creating multiple Connector instances with New. (It's also no different than registering multiple txdb drivers to the same db, which is also possible today).

The only difference I see is where the connection disambiguation occurs. With the Register approach, the conns map is used in conjunction with the dsn value passed to Open. With the Connector approach, it's handled by the instantiation of the Connector instance.

Logically, I believe these are identical.

The mutexes I see only protect the members of txDriver and conn respectively. I don't see any mutexes protecting transactions, per se. Maybe I'm misunderstanding the point you were making about mutexes, though.

flimzy avatar Apr 10 '21 20:04 flimzy

@flimzy would you be open to recover this? It seems that Connector is the new way to go and that the drivers should start using that pattern instead.

https://pkg.go.dev/database/sql/driver

lopezator avatar Nov 22 '23 14:11 lopezator

@l3pp4rd Any objection to me updating this PR to get it merged?

flimzy avatar Nov 22 '23 14:11 flimzy

Any objection to me updating this PR to get it merged?

That was fast! Truly appreciated.

lopezator avatar Nov 22 '23 14:11 lopezator

@lopezator This project has seemingly gone without a lot of attention for quite a while. I'm sure this PR just got lost when attention was focused on other tasks at DATA-DOG. Hopefully we can get this ball rolling again.

flimzy avatar Nov 22 '23 14:11 flimzy

@flimzy Looks good, would be better if adding some unit tests, or refactoring current tests to also init db using sql.OpenDB method

Yiling-J avatar Nov 23 '23 02:11 Yiling-J

@Yiling-J Good suggestion. I've added a very simple test to exercise just the new code. WDYT?

flimzy avatar Nov 23 '23 08:11 flimzy

Should we take the opportunity to implement the DriverContext interface as well? But maybe that's a separate PR.

lopezator avatar Nov 23 '23 10:11 lopezator

Should we take the opportunity to implement the DriverContext interface as well? But maybe that's a separate PR.

I agree on both counts. It sounds like something we should definitely support, and it should be a separate PR.

flimzy avatar Nov 23 '23 10:11 flimzy