34
34
import com .google .cloud .spanner .Struct ;
35
35
import com .google .cloud .spanner .TimestampBound ;
36
36
import com .google .cloud .spanner .TransactionContext ;
37
+ import com .google .cloud .spanner .Value ;
37
38
import com .google .spanner .admin .database .v1 .CreateDatabaseMetadata ;
39
+ import com .google .spanner .admin .database .v1 .UpdateDatabaseDdlMetadata ;
38
40
import java .util .ArrayList ;
39
41
import java .util .Arrays ;
40
42
import java .util .List ;
48
50
* <li> Writing, reading and executing SQL queries.
49
51
* <li> Writing data using a read-write transaction.
50
52
* <li> Using an index to read and execute SQL queries over data.
53
+ * <li> Using commit timestamp for tracking when a record was last updated.
51
54
* </ul>
52
55
*/
53
56
public class SpannerSample {
@@ -84,6 +87,24 @@ static class Album {
84
87
}
85
88
}
86
89
90
+ /**
91
+ * Class to contain performance sample data.
92
+ */
93
+ static class Performance {
94
+
95
+ final long singerId ;
96
+ final long venueId ;
97
+ final String eventDate ;
98
+ final long revenue ;
99
+
100
+ Performance (long singerId , long venueId , String eventDate , long revenue ) {
101
+ this .singerId = singerId ;
102
+ this .venueId = venueId ;
103
+ this .eventDate = eventDate ;
104
+ this .revenue = revenue ;
105
+ }
106
+ }
107
+
87
108
// [START spanner_insert_data]
88
109
static final List <Singer > SINGERS =
89
110
Arrays .asList (
@@ -102,6 +123,14 @@ static class Album {
102
123
new Album (2 , 3 , "Terrified" ));
103
124
// [END spanner_insert_data]
104
125
126
+ // [START spanner_insert_data_with_timestamp_column]
127
+ static final List <Performance > PERFORMANCES =
128
+ Arrays .asList (
129
+ new Performance (1 , 4 , "2017-10-05" , 11000 ),
130
+ new Performance (1 , 19 , "2017-11-02" , 15000 ),
131
+ new Performance (2 , 42 , "2017-12-23" , 7000 ));
132
+ // [END spanner_insert_data_with_timestamp_column]
133
+
105
134
// [START spanner_create_database]
106
135
static void createDatabase (DatabaseAdminClient dbAdminClient , DatabaseId id ) {
107
136
Operation <Database , CreateDatabaseMetadata > op = dbAdminClient
@@ -126,6 +155,48 @@ static void createDatabase(DatabaseAdminClient dbAdminClient, DatabaseId id) {
126
155
}
127
156
// [END spanner_create_database]
128
157
158
+ // [START spanner_create_table_with_timestamp_column]
159
+ static void createTableWithTimestamp (DatabaseAdminClient dbAdminClient , DatabaseId id ) {
160
+ Operation <Void , UpdateDatabaseDdlMetadata > op = dbAdminClient
161
+ .updateDatabaseDdl (
162
+ id .getInstanceId ().getInstance (),
163
+ id .getDatabase (),
164
+ Arrays .asList (
165
+ "CREATE TABLE Performances (\n "
166
+ + " SingerId INT64 NOT NULL,\n "
167
+ + " VenueId INT64 NOT NULL,\n "
168
+ + " EventDate Date,\n "
169
+ + " Revenue INT64, \n "
170
+ + " LastUpdateTime TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true)\n "
171
+ + ") PRIMARY KEY (SingerId, VenueId, EventDate),\n "
172
+ + " INTERLEAVE IN PARENT Singers ON DELETE CASCADE" ), null );
173
+ op .waitFor ().getResult ();
174
+ System .out .println ("Created Performances table in database: [" + id + "]" );
175
+ }
176
+ // [END spanner_create_table_with_timestamp_column]
177
+
178
+ // [START spanner_insert_data_with_timestamp_column]
179
+ static void writeExampleDataWithTimestamp (DatabaseClient dbClient ) {
180
+ List <Mutation > mutations = new ArrayList <>();
181
+ for (Performance performance : PERFORMANCES ) {
182
+ mutations .add (
183
+ Mutation .newInsertBuilder ("Performances" )
184
+ .set ("SingerId" )
185
+ .to (performance .singerId )
186
+ .set ("VenueId" )
187
+ .to (performance .venueId )
188
+ .set ("EventDate" )
189
+ .to (performance .eventDate )
190
+ .set ("Revenue" )
191
+ .to (performance .revenue )
192
+ .set ("LastUpdateTime" )
193
+ .to (Value .COMMIT_TIMESTAMP )
194
+ .build ());
195
+ }
196
+ dbClient .write (mutations );
197
+ }
198
+ // [END spanner_insert_data_with_timestamp_column]
199
+
129
200
// [START spanner_insert_data]
130
201
static void writeExampleData (DatabaseClient dbClient ) {
131
202
List <Mutation > mutations = new ArrayList <>();
@@ -422,6 +493,98 @@ static void readStaleData(DatabaseClient dbClient) {
422
493
}
423
494
// [END spanner_read_stale_data]
424
495
496
+ // [START spanner_add_timestamp_column]
497
+ static void addCommitTimestamp (DatabaseAdminClient adminClient , DatabaseId dbId ) {
498
+ adminClient .updateDatabaseDdl (dbId .getInstanceId ().getInstance (),
499
+ dbId .getDatabase (),
500
+ Arrays .asList (
501
+ "ALTER TABLE Albums ADD COLUMN LastUpdateTime TIMESTAMP "
502
+ + "OPTIONS (allow_commit_timestamp=true)" ),
503
+ null ).waitFor ();
504
+ System .out .println ("Added LastUpdateTime as a commit timestamp column in Albums table." );
505
+ }
506
+ // [END spanner_add_timestamp_column]
507
+
508
+ // Before executing this method, a new column MarketingBudget has to be added to the Albums
509
+ // table by applying the DDL statement "ALTER TABLE Albums ADD COLUMN MarketingBudget INT64".
510
+ // In addition this update expects the LastUpdateTime column added by applying the DDL statement
511
+ // "ALTER TABLE Albums ADD COLUMN LastUpdateTime TIMESTAMP OPTIONS (allow_commit_timestamp=true)"
512
+ // [START spanner_update_data_with_timestamp_column]
513
+ static void updateWithTimestamp (DatabaseClient dbClient ) {
514
+ // Mutation can be used to update/insert/delete a single row in a table. Here we use
515
+ // newUpdateBuilder to create update mutations.
516
+ List <Mutation > mutations =
517
+ Arrays .asList (
518
+ Mutation .newUpdateBuilder ("Albums" )
519
+ .set ("SingerId" )
520
+ .to (1 )
521
+ .set ("AlbumId" )
522
+ .to (1 )
523
+ .set ("MarketingBudget" )
524
+ .to (1000000 )
525
+ .set ("LastUpdateTime" )
526
+ .to (Value .COMMIT_TIMESTAMP )
527
+ .build (),
528
+ Mutation .newUpdateBuilder ("Albums" )
529
+ .set ("SingerId" )
530
+ .to (2 )
531
+ .set ("AlbumId" )
532
+ .to (2 )
533
+ .set ("MarketingBudget" )
534
+ .to (750000 )
535
+ .set ("LastUpdateTime" )
536
+ .to (Value .COMMIT_TIMESTAMP )
537
+ .build ());
538
+ // This writes all the mutations to Cloud Spanner atomically.
539
+ dbClient .write (mutations );
540
+ }
541
+ // [END spanner_update_data_with_timestamp_column]
542
+
543
+ // [START spanner_query_data_with_timestamp_column]
544
+ static void queryMarketingBudgetWithTimestamp (DatabaseClient dbClient ) {
545
+ // Rows without an explicit value for MarketingBudget will have a MarketingBudget equal to
546
+ // null.
547
+ ResultSet resultSet =
548
+ dbClient
549
+ .singleUse ()
550
+ .executeQuery (Statement .of (
551
+ "SELECT SingerId, AlbumId, MarketingBudget, LastUpdateTime FROM Albums"
552
+ + " ORDER BY LastUpdateTime DESC" ));
553
+ while (resultSet .next ()) {
554
+ System .out .printf (
555
+ "%d %d %s %s\n " ,
556
+ resultSet .getLong ("SingerId" ),
557
+ resultSet .getLong ("AlbumId" ),
558
+ // We check that the value is non null. ResultSet getters can only be used to retrieve
559
+ // non null values.
560
+ resultSet .isNull ("MarketingBudget" ) ? "NULL" : resultSet .getLong ("MarketingBudget" ),
561
+ resultSet .isNull ("LastUpdateTime" ) ? "NULL" : resultSet .getTimestamp ("LastUpdateTime" ));
562
+ }
563
+ }
564
+ // [END spanner_query_data_with_timestamp_column]
565
+
566
+ static void queryPerformancesTable (DatabaseClient dbClient ) {
567
+ // Rows without an explicit value for Revenue will have a Revenue equal to
568
+ // null.
569
+ ResultSet resultSet =
570
+ dbClient
571
+ .singleUse ()
572
+ .executeQuery (Statement .of (
573
+ "SELECT SingerId, VenueId, EventDate, Revenue, LastUpdateTime FROM Performances"
574
+ + " ORDER BY LastUpdateTime DESC" ));
575
+ while (resultSet .next ()) {
576
+ System .out .printf (
577
+ "%d %d %s %s %s\n " ,
578
+ resultSet .getLong ("SingerId" ),
579
+ resultSet .getLong ("VenueId" ),
580
+ resultSet .getDate ("EventDate" ),
581
+ // We check that the value is non null. ResultSet getters can only be used to retrieve
582
+ // non null values.
583
+ resultSet .isNull ("Revenue" ) ? "NULL" : resultSet .getLong ("Revenue" ),
584
+ resultSet .getTimestamp ("LastUpdateTime" ));
585
+ }
586
+ }
587
+
425
588
static void run (DatabaseClient dbClient , DatabaseAdminClient dbAdminClient , String command ,
426
589
DatabaseId database ) {
427
590
switch (command ) {
@@ -470,6 +633,24 @@ static void run(DatabaseClient dbClient, DatabaseAdminClient dbAdminClient, Stri
470
633
case "readstaledata" :
471
634
readStaleData (dbClient );
472
635
break ;
636
+ case "addcommittimestamp" :
637
+ addCommitTimestamp (dbAdminClient , database );
638
+ break ;
639
+ case "updatewithtimestamp" :
640
+ updateWithTimestamp (dbClient );
641
+ break ;
642
+ case "querywithtimestamp" :
643
+ queryMarketingBudgetWithTimestamp (dbClient );
644
+ break ;
645
+ case "createtablewithtimestamp" :
646
+ createTableWithTimestamp (dbAdminClient , database );
647
+ break ;
648
+ case "writewithtimestamp" :
649
+ writeExampleDataWithTimestamp (dbClient );
650
+ break ;
651
+ case "queryperformancestable" :
652
+ queryPerformancesTable (dbClient );
653
+ break ;
473
654
default :
474
655
printUsageAndExit ();
475
656
}
@@ -484,6 +665,44 @@ static void printUsageAndExit() {
484
665
" SpannerExample createdatabase my-instance example-db" );
485
666
System .err .println (
486
667
" SpannerExample write my-instance example-db" );
668
+ System .err .println (
669
+ " SpannerExample query my-instance example-db" );
670
+ System .err .println (
671
+ " SpannerExample read my-instance example-db" );
672
+ System .err .println (
673
+ " SpannerExample addmarketingbudget my-instance example-db" );
674
+ System .err .println (
675
+ " SpannerExample update my-instance example-db" );
676
+ System .err .println (
677
+ " SpannerExample writetransaction my-instance example-db" );
678
+ System .err .println (
679
+ " SpannerExample querymarketingbudget my-instance example-db" );
680
+ System .err .println (
681
+ " SpannerExample addindex my-instance example-db" );
682
+ System .err .println (
683
+ " SpannerExample readindex my-instance example-db" );
684
+ System .err .println (
685
+ " SpannerExample queryindex my-instance example-db" );
686
+ System .err .println (
687
+ " SpannerExample addstoringindex my-instance example-db" );
688
+ System .err .println (
689
+ " SpannerExample readstoringindex my-instance example-db" );
690
+ System .err .println (
691
+ " SpannerExample readonlytransaction my-instance example-db" );
692
+ System .err .println (
693
+ " SpannerExample readstaledata my-instance example-db" );
694
+ System .err .println (
695
+ " SpannerExample addcommittimestamp my-instance example-db" );
696
+ System .err .println (
697
+ " SpannerExample updatewithtimestamp my-instance example-db" );
698
+ System .err .println (
699
+ " SpannerExample querywithtimestamp my-instance example-db" );
700
+ System .err .println (
701
+ " SpannerExample createtablewithtimestamp my-instance example-db" );
702
+ System .err .println (
703
+ " SpannerExample writewithtimestamp my-instance example-db" );
704
+ System .err .println (
705
+ " SpannerExample queryperformancestable my-instance example-db" );
487
706
System .exit (1 );
488
707
}
489
708
0 commit comments