@@ -117,8 +117,141 @@ method:
117
117
:meth: `~google.cloud.spanner.instance.Operation.finished `
118
118
will result in an :exc`ValueError` being raised.
119
119
120
+ Non-Admin Database Usage
121
+ ========================
120
122
121
- Next Step
122
- ---------
123
+ Use a Snapshot to Read / Query the Database
124
+ -------------------------------------------
123
125
124
- Next, learn about :doc: `session-crud-usage `.
126
+ A snapshot represents a read-only point-in-time view of the database.
127
+
128
+ Calling :meth: `~google.cloud.spanner.database.Database.snapshot ` with
129
+ no arguments creates a snapshot with strong concurrency:
130
+
131
+ .. code :: python
132
+
133
+ with database.snapshot() as snapshot:
134
+ do_something_with(snapshot)
135
+
136
+ See :class: `~google.cloud.spanner.snapshot.Snapshot ` for the other options
137
+ which can be passed.
138
+
139
+ .. note ::
140
+
141
+ :meth: `~google.cloud.spanner.database.Database.snapshot ` returns an
142
+ object intended to be used as a Python context manager (i.e., as the
143
+ target of a ``with `` statement). Use the instance, and any result
144
+ sets returned by its ``read `` or ``execute_sql `` methods, only inside
145
+ the block created by the ``with `` statement.
146
+
147
+ See :doc: `snapshot-usage ` for more complete examples of snapshot usage.
148
+
149
+ Use a Batch to Modify Rows in the Database
150
+ ------------------------------------------
151
+
152
+ A batch represents a bundled set of insert/upsert/update/delete operations
153
+ on the rows of tables in the database.
154
+
155
+ .. code :: python
156
+
157
+ with database.batch() as batch:
158
+ batch.insert_or_update(table, columns, rows)
159
+ batch.delete(table, keyset_to_delete)
160
+
161
+ .. note ::
162
+
163
+ :meth: `~google.cloud.spanner.database.Database.batch ` returns an
164
+ object intended to be used as a Python context manager (i.e., as the
165
+ target of a ``with `` statement). It applies any changes made inside
166
+ the block of its ``with `` statement when exiting the block, unless an
167
+ exception is raised within the block. Use the batch only inside
168
+ the block created by the ``with `` statement.
169
+
170
+ See :doc: `batch-usage ` for more complete examples of batch usage.
171
+
172
+ Use a Transaction to Query / Modify Rows in the Database
173
+ --------------------------------------------------------
174
+
175
+ A transaction represents the union of a "strong" snapshot and a batch:
176
+ it allows ``read `` and ``execute_sql `` operations, and accumulates
177
+ insert/upsert/update/delete operations.
178
+
179
+ Because other applications may be performing concurrent updates which
180
+ would invalidate the reads / queries, the work done by a transaction needs
181
+ to be bundled as a retryable "unit of work" function, which takes the
182
+ transaction as a required argument:
183
+
184
+ .. code :: python
185
+
186
+ def unit_of_work (transaction ):
187
+ result = transaction.execute_sql(QUERY )
188
+
189
+ for emp_id, hours, pay in _compute_pay(result):
190
+ transaction.insert_or_update(
191
+ table = ' monthly_hours' ,
192
+ columns = [' employee_id' , ' month' , ' hours' , ' pay' ],
193
+ values = [emp_id, month_start, hours, pay])
194
+
195
+ database.run_in_transaction(unit_of_work)
196
+
197
+ .. note ::
198
+
199
+ :meth: `~google.cloud.spanner.database.Database.run_in_transaction `
200
+ commits the transaction automatically if the "unit of work" function
201
+ returns without raising an exception.
202
+
203
+ .. note ::
204
+
205
+ :meth: `~google.cloud.spanner.database.Database.run_in_transaction `
206
+ retries the "unit of work" function if the read / query operatoins
207
+ or the commit are aborted due to concurrent updates
208
+
209
+ See :doc: `transaction-usage ` for more complete examples of transaction usage.
210
+
211
+ Configuring a session pool for a database
212
+ -----------------------------------------
213
+
214
+ Under the covers, the ``snapshot ``, ``batch ``, and ``run_in_transaction ``
215
+ methods use a pool of :class: `~google.cloud.spanner.session.Session ` objects
216
+ to manage their communication with the back-end. You can configure
217
+ one of the pools manually to control the number of sessions, timeouts, etc.,
218
+ and then passing it to the :class: `~google.cloud.spanner.database.Database `
219
+ constructor:
220
+
221
+ .. code-block :: python
222
+
223
+ from google.cloud.spanner import Client
224
+ from google.cloud.spanner import FixedSizePool
225
+ client = Client()
226
+ instance = client.instance(INSTANCE_NAME )
227
+ pool = FixedSizePool(size = 10 , default_timeout = 5 )
228
+ database = instanc.database(DATABASE_NAME , pool = pool)
229
+
230
+ Note that creating a database with a pool may presume that its database
231
+ already exists, as it may need to pre-create sessions (rather than creating
232
+ them on demand, as the default implementation does).
233
+
234
+ You can supply your own pool implementation, which must satisfy the
235
+ contract laid out in :class: `~google.cloud.spanner.pool.AbstractSessionPool `:
236
+
237
+ .. code-block :: python
238
+
239
+ from google.cloud.pool import AbstractSessionPool
240
+
241
+ class MyCustomPool (AbstractSessionPool ):
242
+
243
+ def __init__ (self , database , custom_param ):
244
+ super (MyCustomPool, self ).__init__ (database)
245
+ self .custom_param = custom_param
246
+
247
+ def get (self , read_only = False ):
248
+ ...
249
+
250
+ def put (self , session , discard_if_full = True ):
251
+ ...
252
+
253
+ database = instance.database(DATABASE_NAME , pool = pool)
254
+ pool = MyCustomPool(database, custom_param = 42 )
255
+
256
+ See :doc: `advanced-session-pool-topics ` for more advanced coverage of
257
+ session pools.
0 commit comments