@@ -16,6 +16,7 @@ import (
16
16
"database/sql/driver"
17
17
"fmt"
18
18
"reflect"
19
+ "sync"
19
20
"testing"
20
21
"time"
21
22
)
@@ -468,3 +469,100 @@ func TestContextCancelBegin(t *testing.T) {
468
469
}
469
470
})
470
471
}
472
+
473
+ func TestContextBeginIsolationLevel (t * testing.T ) {
474
+ runTests (t , dsn , func (dbt * DBTest ) {
475
+ dbt .mustExec ("CREATE TABLE test (v INTEGER)" )
476
+ ctx , cancel := context .WithCancel (context .Background ())
477
+ defer cancel ()
478
+
479
+ // Waitgroup syncing BeginTx
480
+ beginWg := sync.WaitGroup {}
481
+ beginWg .Add (2 )
482
+
483
+ // Waitgroup syncing insert in writer transaction
484
+ insertWg := sync.WaitGroup {}
485
+ insertWg .Add (1 )
486
+
487
+ // Waitgroup syncing writer transaction commit before reader reads
488
+ readWg := sync.WaitGroup {}
489
+ readWg .Add (1 )
490
+
491
+ // Waitgroup syncing commit in writer transaction
492
+ commitWg := sync.WaitGroup {}
493
+ commitWg .Add (1 )
494
+
495
+ // Waitgroup syncing end of both goroutines
496
+ testDoneWg := sync.WaitGroup {}
497
+ testDoneWg .Add (2 )
498
+
499
+ repeatableReadGoroutine := func () {
500
+ tx , err := dbt .db .BeginTx (ctx , & sql.TxOptions {
501
+ Isolation : sql .LevelRepeatableRead ,
502
+ })
503
+ if err != nil {
504
+ dbt .Fatal (err )
505
+ }
506
+ beginWg .Done ()
507
+ // Wait until other session will begin it's transaction
508
+ beginWg .Wait ()
509
+
510
+ _ , err = tx .ExecContext (ctx , "INSERT INTO test VALUES (1)" )
511
+ if err != nil {
512
+ dbt .Fatal (err )
513
+ }
514
+ insertWg .Done ()
515
+
516
+ // Wait until reader transaction finish reading
517
+ readWg .Wait ()
518
+
519
+ err = tx .Commit ()
520
+ if err != nil {
521
+ dbt .Fatal (err )
522
+ }
523
+ commitWg .Done ()
524
+
525
+ testDoneWg .Done ()
526
+ }
527
+
528
+ readCommitedGoroutine := func () {
529
+ tx , err := dbt .db .BeginTx (ctx , & sql.TxOptions {
530
+ Isolation : sql .LevelReadCommitted ,
531
+ })
532
+ if err != nil {
533
+ dbt .Fatal (err )
534
+ }
535
+ beginWg .Done ()
536
+ // Wait until writer transaction will begin
537
+ beginWg .Wait ()
538
+ // Wait until writer transaction will insert value
539
+ insertWg .Wait ()
540
+ var v int
541
+ row := tx .QueryRowContext (ctx , "SELECT COUNT(*) FROM test" )
542
+ if err := row .Scan (& v ); err != nil {
543
+ dbt .Fatal (err )
544
+ }
545
+ // Because writer transaction wasn't commited yet, it should be available
546
+ if v != 0 {
547
+ dbt .Errorf ("expected val to be 0, got %d" , v )
548
+ }
549
+ readWg .Done ()
550
+ // Wait until writer transaction will commit
551
+ commitWg .Wait ()
552
+ row = tx .QueryRowContext (ctx , "SELECT COUNT(*) FROM test" )
553
+ if err := row .Scan (& v ); err != nil {
554
+ dbt .Fatal (err )
555
+ }
556
+ // Data written by writer transaction is already commited, it should be selectable
557
+ if v != 1 {
558
+ dbt .Errorf ("expected val to be 1, got %d" , v )
559
+ }
560
+ tx .Commit ()
561
+ testDoneWg .Done ()
562
+ }
563
+
564
+ go repeatableReadGoroutine ()
565
+ go readCommitedGoroutine ()
566
+ testDoneWg .Wait ()
567
+ })
568
+ }
0 commit comments