@@ -117,8 +117,141 @@ method:
117117 :meth: `~google.cloud.spanner.instance.Operation.finished `
118118 will result in an :exc`ValueError` being raised.
119119
120+ Non-Admin Database Usage
121+ ========================
120122
121- Next Step
122- ---------
123+ Use a Snapshot to Read / Query the Database
124+ -------------------------------------------
123125
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