Transaction

Transaction

This type of transaction is the only way to write data into Cloud Spanner. These transactions rely on pessimistic locking and, if necessary, two-phase commit. Locking read-write transactions may abort, requiring the application to retry.

Calling either Transaction#commit or Transaction#rollback signals that the transaction is finished and no further requests will be made. If for some reason you decide not to call one of the aformentioned methods, call Transaction#end to release the underlying Session.

Running a transaction via Database#runTransaction or Database#runTransactionAsync automatically re-runs the transaction on ABORTED errors.

Database#getTransaction returns a plain Transaction object, requiring the user to retry manually.

Constructor

new Transaction(session)

Parameters:
Name Type Description
session Session

The parent Session object.

Examples
const {Spanner} = require('@google-cloud/spanner');
const spanner = new Spanner();

const instance = spanner.instance('my-instance');
const database = instance.database('my-database');

database.runTransaction(function(err, transaction) {
  // The `transaction` object is ready for use.
});

To manually control retrying the transaction, use the `getTransaction` method.

database.getTransaction(function(err, transaction) {
  // The `transaction` object is ready for use.
});

Extends

Members

(nullable) commitTimestamp :external:PreciseDate

Timestamp at which the transaction was committed. Will be populated once Transaction#commit is called.

(nullable) commitTimestampProto :google.protobuf.Timestamp

The protobuf version of Transaction#commitTimestamp. This is useful if you require microsecond precision.

ended :boolean

Whether or not the transaction has ended. If true, make no further requests, and discard the transaction.

Overrides:

(nullable) id :string|Buffer

The transaction ID.

Overrides:

(nullable) metadata :TransactionResponse

The raw transaction response object. It is populated after Snapshot#begin is called.

Overrides:

(nullable) readTimestamp :external:PreciseDate

Snapshot only The timestamp at which all reads are performed.

Overrides:

(nullable) readTimestampProto :google.protobuf.Timestamp

Snapshot only The protobuf version of Snapshot#readTimestamp. This is useful if you require microsecond precision.

Overrides:

runUpdate

Execute a DML statement and get the affected row count.

See:
Example
const query = 'UPDATE Account SET Balance = 1000 WHERE Key = 1';

transaction.runUpdate(query, (err, rowCount) => {
  if (err) {
    // Error handling omitted.
  }
});

Methods

batchUpdate(query, gaxOptionsopt, callbackopt) → {Promise.<RunUpdateResponse>}

Execute a series of DML statements and get the affected row counts.

If any of the DML statements fail, the returned error will contain a list of results for all successfully executed statements.

Parameters:
Name Type Attributes Description
query Array.<string> | Array.<object>

A DML statement or ExecuteSqlRequest object.

Properties
Name Type Attributes Description
params object <optional>

A map of parameter name to values.

types object <optional>

A map of parameter types.

gaxOptions object <optional>

Request configuration options, outlined here: https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.

callback RunUpdateCallback <optional>

Callback function.

Examples
const queries = [
  {
    sql: 'INSERT INTO MyTable (Key, Value) VALUES (@key, @value)',
    params: {key: 'my-key', value: 'my-value'},
  },
  {
    sql: 'UPDATE MyTable t SET t.Value = @value WHERE t.KEY = @key',
    params: {key: 'my-other-key', value: 'my-other-value'}
  }
];

transaction.batchUpdate(queries, (err, rowCounts, apiResponse) => {
  if (err) {
    // Error handling omitted.
  }
});

If the callback is omitted, we'll return a Promise.

const [rowCounts, apiResponse] = await transaction.batchUpdate(queries);

begin(gaxOptionsopt, callbackopt) → {Promise.<TransactionBeginResponse>}

Begin a new transaction. Typically, you need not call this unless manually creating transactions via Session objects.

Parameters:
Name Type Attributes Description
gaxOptions object <optional>

Request configuration options, outlined here: https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.

callback TransactionBeginCallback <optional>

Callback function.

Overrides:
See:
Examples
transaction.begin(function(err) {
  if (!err) {
    // transaction began successfully.
  }
});

If the callback is omitted, the function returns a Promise

transaction.begin()
  .then(function(data) {
    const apiResponse = data[0];
  });

commit(gaxOptionsopt, callbackopt) → {Promise.<CommitPromiseResponse>}

Commit the transaction.

Wrapper around v1.SpannerClient#commit.

Parameters:
Name Type Attributes Description
gaxOptions object <optional>

Request configuration options, outlined here: https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.

callback CommitCallback <optional>

Callback function.

See:
Example
database.runTransaction(function(err, transaction) {
  if (err) {
    // Error handling omitted.
  }

  // Queue a mutation (note that there is no callback passed to `insert`).
  transaction.insert('Singers', {
    SingerId: 'Id3b',
    Name: 'Joe West'
  });

  // Commit the transaction.
  transaction.commit(function(err, apiResponse) {
    if (!err) {
      // Get the commit timestamp on successful commits.
      const {commitTimestamp} = apiResponse;
    }
  });
});

createReadStream(table, query) → {ReadableStream}

Create a readable object stream to receive rows from the database using key lookups and scans.

Wrapper around v1.SpannerClient#streamingRead.

Parameters:
Name Type Description
table string

The table to read from.

query ReadRequest

Configuration object. See official ReadRequest. API documentation.

Overrides:
See:
Fires:
  • PartialResultStream#event:response
  • PartialResultStream#event:stats
Examples
transaction.createReadStream('Singers', {
    keys: ['1'],
    columns: ['SingerId', 'name']
  })
  .on('error', function(err) {})
  .on('data', function(row) {
    // row = [
    //   {
    //     name: 'SingerId',
    //     value: '1'
    //   },
    //   {
    //     name: 'Name',
    //     value: 'Eddie Wilson'
    //   }
    // ]
  })
  .on('end', function() {
    // All results retrieved.
  });

Provide an array for `query.keys` to read with a composite key.

const query = {
  keys: [
    [
      'Id1',
      'Name1'
    ],
    [
      'Id2',
      'Name2'
    ]
  ],
  // ...
};

Rows are returned as an array of object arrays. Each object has a `name` and `value` property. To get a serialized object, call `toJSON()`.

transaction.createReadStream('Singers', {
    keys: ['1'],
    columns: ['SingerId', 'name']
  })
  .on('error', function(err) {})
  .on('data', function(row) {
    // row.toJSON() = {
    //   SingerId: '1',
    //   Name: 'Eddie Wilson'
    // }
  })
  .on('end', function() {
    // All results retrieved.
  });

Alternatively, set `query.json` to `true`, and this step will perform automatically.

transaction.createReadStream('Singers', {
    keys: ['1'],
    columns: ['SingerId', 'name'],
    json: true,
  })
  .on('error', function(err) {})
  .on('data', function(row) {
    // row = {
    //   SingerId: '1',
    //   Name: 'Eddie Wilson'
    // }
  })
  .on('end', function() {
    // All results retrieved.
  });

If you anticipate many results, you can end a stream early to prevent unnecessary processing and API requests.

transaction.createReadStream('Singers', {
    keys: ['1'],
    columns: ['SingerId', 'name']
  })
  .on('data', function(row) {
    this.end();
  });

deleteRows(table, keys)

Delete rows from a table.

Parameters:
Name Type Description
table string

The name of the table.

keys array

The keys for the rows to delete. If using a composite key, provide an array within this array. See the example below.

See:
Examples
const keys = ['Id1', 'Id2', 'Id3'];

database.runTransaction(function(err, transaction) {
  if (err) {
    // Error handling omitted.
  }

  // Queue this mutation until later calling `commit`.
  // Note that a callback is not passed to `deleteRows`.
  transaction.deleteRows('Singers', keys);

  // Commit the transaction.
  transaction.commit(function(err) {
    if (!err) {
      // The rows were deleted successfully.
    }
  });
});

Provide an array for `keys` to delete rows with a composite key.

const keys = [
  [
    'Id1',
    'Name1'
  ],
  [
    'Id2',
    'Name2'
  ]
];

end()

Let the client know you're done with a particular transaction. This should mainly be called for Snapshot objects, however in certain cases you may want to call them for Transaction objects as well.

Overrides:
Examples

Calling `end` on a read only snapshot

database.getSnapshot((err, transaction) => {
  if (err) {
    // Error handling omitted.
  }

  transaction.run('SELECT * FROM Singers', (err, rows) => {
    if (err) {
      // Error handling omitted.
    }

    // End the snapshot.
    transaction.end();
  });
});

Calling `end` on a read/write transaction

database.runTransaction((err, transaction) => {
  if (err) {
    // Error handling omitted.
  }

  const query = 'UPDATE Account SET Balance = 1000 WHERE Key = 1';

  transaction.runUpdate(query, err => {
    if (err) {
      // In the event of an error, there would be nothing to rollback,
so
      // instead of continuing, discard the
transaction. transaction.end(); return;
    }

    transaction.commit(err => {});
  });
});

insert(table, rows)

Insert rows of data into this table.

Parameters:
Name Type Description
table string

The name of the table.

rows object | Array.<object>

A map of names to values of data to insert into this table.

See:
Examples
const row = {
  SingerId: 'Id3',
  Name: 'Eddie Wilson'
};

database.runTransaction(function(err, transaction) {
  if (err) {
    // Error handling omitted.
  }

  // Queue this mutation until later calling `commit`.
  // Note that a callback is not passed to `insert`.
  transaction.insert('Singers', row);

  // Commit the transaction.
  transaction.commit(function(err) {
    if (!err) {
      // The row was inserted successfully.
    }
  });
});

Multiple rows can be inserted at once.

const row2 = {
  SingerId: 'Id3b',
  Name: 'Joe West'
};

database.runTransaction(function(err, transaction) {
  if (err) {
    // Error handling omitted.
  }

  // Queue multiple mutations until later calling `commit`.
  // Note that a callback is not passed to `insert`.
  transaction.insert('Singers', [
    row,
    row2
  ]);

  // Commit the transaction.
  transaction.commit(function(err) {
    if (!err) {
      // The rows were inserted successfully.
    }
  });
});

read(table, query, callbackopt) → {Promise.<TransactionRequestReadResponse>}

Performs a read request against the specified Table.

Wrapper around v1.SpannerClient#read.

Parameters:
Name Type Attributes Description
table string

The table to read from.

query ReadRequest

Configuration object. See official ReadRequest. API documentation.

callback TransactionRequestReadCallback <optional>

Callback function.

Overrides:
See:
Examples
const query = {
  keys: ['1'],
  columns: ['SingerId', 'name']
};

transaction.read('Singers', query, function(err, rows) {
  if (err) {
    // Error handling omitted.
  }

  const firstRow = rows[0];

  // firstRow = [
  //   {
  //     name: 'SingerId',
  //     value: '1'
  //   },
  //   {
  //     name: 'Name',
  //     value: 'Eddie Wilson'
  //   }
  // ]
});

Provide an array for `query.keys` to read with a composite key.

const query = {
  keys: [
    [
      'Id1',
      'Name1'
    ],
    [
      'Id2',
      'Name2'
    ]
  ],
  // ...
};

Rows are returned as an array of object arrays. Each object has a `name` and `value` property. To get a serialized object, call `toJSON()`.

transaction.read('Singers', query, function(err, rows) {
  if (err) {
    // Error handling omitted.
  }

  const firstRow = rows[0];

  // firstRow.toJSON() = {
  //   SingerId: '1',
  //   Name: 'Eddie Wilson'
  // }
});

Alternatively, set `query.json` to `true`, and this step will perform automatically.

query.json = true;

transaction.read('Singers', query, function(err, rows) {
  if (err) {
    // Error handling omitted.
  }

  const firstRow = rows[0];

  // firstRow = {
  //   SingerId: '1',
  //   Name: 'Eddie Wilson'
  // }
});

replace(table, rows)

Replace rows of data within a table.

Parameters:
Name Type Description
table string

The table to read from.

rows object | Array.<object>

A map of names to values of data to insert into this table.

See:
Example
const row = {
  SingerId: 'Id3',
  Name: 'Joe West'
};

database.runTransaction(function(err, transaction) {
  if (err) {
    // Error handling omitted.
  }

  // Queue this mutation until later calling `commit`.
  // Note that a callback is not passed to `replace`.
  transaction.replace('Singers', row);

  // Commit the transaction.
  transaction.commit(function(err) {
    if (!err) {
      // The row was replaced successfully.
    }
  });
});

rollback(gaxOptionsopt, callbackopt) → {Promise.<BasicResponse>}

Roll back a transaction, releasing any locks it holds. It is a good idea to call this for any transaction that includes one or more queries that you decide not to commit.

Wrapper around v1.SpannerClient#rollback.

Parameters:
Name Type Attributes Description
gaxOptions object <optional>

Request configuration options, outlined here: https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.

callback BasicCallback <optional>

Callback function.

See:
Example
database.runTransaction(function(err, transaction) {
  if (err) {
    // Error handling omitted.
  }

  transaction.rollback(function(err) {
    if (!err) {
      // Transaction rolled back successfully.
    }
  });
});

run(query, callbackopt) → {Promise.<RunResponse>}

Execute a SQL statement on this database inside of a transaction.

Performance Considerations:

This method wraps the streaming method, Snapshot#run for your convenience. All rows are stored in memory before releasing to your callback. If you intend to receive a lot of results from your query, consider using the streaming method, so you can free each result from memory after consuming it.

Wrapper around v1.SpannerClient#executeStreamingSql.

Parameters:
Name Type Attributes Description
query string | ExecuteSqlRequest

A SQL query or ExecuteSqlRequest object.

callback RunCallback <optional>

Callback function.

Overrides:
See:
Examples
transaction.run(query, function(err, rows) {
  if (err) {
    // Error handling omitted.
  }

  // rows = [
  //   {
  //     SingerId: '1',
  //     Name: 'Eddie Wilson'
  //   }
  // ]
});

The SQL query string can contain parameter placeholders. A parameter placeholder consists of '@' followed by the parameter name.

const query = {
  sql: 'SELECT * FROM Singers WHERE name = @name',
  params: {
    name: 'Eddie Wilson'
  }
};

transaction.run(query, function(err, rows) {
  if (err) {
    // Error handling omitted.
  }
});

If you need to enforce a specific param type, a types map can be provided. This is typically useful if your param value can be null.

const query = {
  sql: 'SELECT * FROM Singers WHERE name = @name AND id = @id',
  params: {
    id: spanner.int(8),
    name: null
  },
  types: {
    id: 'int64',
    name: 'string'
  }
};

transaction.run(query, function(err, rows) {
  if (err) {
    // Error handling omitted.
  }
});

runStream(query) → {ReadableStream}

Create a readable object stream to receive resulting rows from a SQL statement.

Wrapper around v1.SpannerClient#executeStreamingSql.

Parameters:
Name Type Description
query string | ExecuteSqlRequest

A SQL query or ExecuteSqlRequest object.

Overrides:
See:
Fires:
  • PartialResultStream#event:response
  • PartialResultStream#event:stats
Examples
const query = 'SELECT * FROM Singers';

transaction.runStream(query)
  .on('error', function(err) {})
  .on('data', function(row) {
    // row = {
    //   SingerId: '1',
    //   Name: 'Eddie Wilson'
    // }
  })
  .on('end', function() {
    // All results retrieved.
  });

The SQL query string can contain parameter placeholders. A parameter placeholder consists of '@' followed by the parameter name.

const query = {
  sql: 'SELECT * FROM Singers WHERE name = @name',
  params: {
    name: 'Eddie Wilson'
  }
};

transaction.runStream(query)
  .on('error', function(err) {})
  .on('data', function(row) {})
  .on('end', function() {});

If you anticipate many results, you can end a stream early to prevent unnecessary processing and API requests.

transaction.runStream(query)
  .on('data', function(row) {
    this.end();
  });

update(table, rows)

Update rows of data within a table.

Parameters:
Name Type Description
table string

The table to read from.

rows object | Array.<object>

A map of names to values of data to insert into this table.

See:
Example
const row = {
  SingerId: 'Id3',
  Name: 'Joe West'
};

database.runTransaction(function(err, transaction) {
  if (err) {
    // Error handling omitted.
  }

  // Queue this mutation until later calling `commit`.
  // Note that a callback is not passed to `update`.
  transaction.update('Singers', row);

  // Commit the transaction.
  transaction.commit(function(err) {
    if (!err) {
      // The row was updated successfully.
    }
  });
});

upsert(table, rows)

Insert or update rows of data within a table.

Parameters:
Name Type Description
table string

The table to read from.

rows object | Array.<object>

A map of names to values of data to insert into this table.

See:
Example
const row = {
  SingerId: 'Id3',
  Name: 'Joe West'
};

database.runTransaction(function(err, transaction) {
  if (err) {
    // Error handling omitted.
  }

  // Queue this mutation until later calling `commit`.
  // Note that a callback is not passed to `upsert`.
  transaction.upsert('Singers', row);

  // Commit the transaction.
  transaction.commit(function(err) {
    if (!err) {
      // The row was updated or inserted successfully.
    }
  });
});