Struct mongodb::ClientSession
source · pub struct ClientSession { /* private fields */ }
Expand description
A MongoDB client session. This struct represents a logical session used for ordering sequential
operations. To create a ClientSession
, call start_session
on a Client
.
ClientSession
instances are not thread safe or fork safe. They can only be used by one thread
or process at a time.
Transactions
Transactions are used to execute a series of operations across multiple documents and collections atomically. For more information about when and how to use transactions in MongoDB, see the manual.
Replica set transactions are supported on MongoDB 4.0+. Sharded transactions are supported on
MongoDDB 4.2+. Transactions are associated with a ClientSession
. To begin a transaction, call
ClientSession::start_transaction
on a ClientSession
. The ClientSession
must be passed to
operations to be executed within the transaction.
use mongodb::{
bson::{doc, Document},
error::{Result, TRANSIENT_TRANSACTION_ERROR, UNKNOWN_TRANSACTION_COMMIT_RESULT},
options::{Acknowledgment, ReadConcern, TransactionOptions, WriteConcern},
ClientSession,
Collection,
};
let mut session = client.start_session(None).await?;
let options = TransactionOptions::builder()
.read_concern(ReadConcern::majority())
.write_concern(WriteConcern::builder().w(Acknowledgment::Majority).build())
.build();
session.start_transaction(options).await?;
// A "TransientTransactionError" label indicates that the entire transaction can be retried
// with a reasonable expectation that it will succeed.
while let Err(error) = execute_transaction(&coll, &mut session).await {
if !error.contains_label(TRANSIENT_TRANSACTION_ERROR) {
break;
}
}
async fn execute_transaction(coll: &Collection<Document>, session: &mut ClientSession) -> Result<()> {
coll.insert_one_with_session(doc! { "x": 1 }, None, session).await?;
coll.delete_one_with_session(doc! { "y": 2 }, None, session).await?;
// An "UnknownTransactionCommitResult" label indicates that it is unknown whether the
// commit has satisfied the write concern associated with the transaction. If an error
// with this label is returned, it is safe to retry the commit until the write concern is
// satisfied or an error without the label is returned.
loop {
let result = session.commit_transaction().await;
if let Err(ref error) = result {
if error.contains_label(UNKNOWN_TRANSACTION_COMMIT_RESULT) {
continue;
}
}
result?
}
}
Implementations§
source§impl ClientSession
impl ClientSession
sourcepub fn cluster_time(&self) -> Option<&ClusterTime>
pub fn cluster_time(&self) -> Option<&ClusterTime>
The highest seen cluster time this session has seen so far.
This will be None
if this session has not been used in an operation yet.
sourcepub fn options(&self) -> Option<&SessionOptions>
pub fn options(&self) -> Option<&SessionOptions>
The options used to create this session.
sourcepub fn advance_cluster_time(&mut self, to: &ClusterTime)
pub fn advance_cluster_time(&mut self, to: &ClusterTime)
Set the cluster time to the provided one if it is greater than this session’s highest seen
cluster time or if this session’s cluster time is None
.
sourcepub fn advance_operation_time(&mut self, ts: Timestamp)
pub fn advance_operation_time(&mut self, ts: Timestamp)
Advance operation time for this session. If the provided timestamp is earlier than this session’s current operation time, then the operation time is unchanged.
sourcepub fn operation_time(&self) -> Option<Timestamp>
pub fn operation_time(&self) -> Option<Timestamp>
The operation time returned by the last operation executed in this session.
sourcepub async fn start_transaction(
&mut self,
options: impl Into<Option<TransactionOptions>>
) -> Result<()>
pub async fn start_transaction( &mut self, options: impl Into<Option<TransactionOptions>> ) -> Result<()>
Starts a new transaction on this session with the given TransactionOptions
. If no options
are provided, the session’s defaultTransactionOptions
will be used. This session must
be passed into each operation within the transaction; otherwise, the operation will be
executed outside of the transaction.
Errors returned from operations executed within a transaction may include a
crate::error::TRANSIENT_TRANSACTION_ERROR
label. This label indicates that the entire
transaction can be retried with a reasonable expectation that it will succeed.
Transactions are supported on MongoDB 4.0+. The Rust driver currently only supports transactions on replica sets.
session.start_transaction(None).await?;
let result = coll.insert_one_with_session(doc! { "x": 1 }, None, &mut session).await?;
session.commit_transaction().await?;
sourcepub async fn commit_transaction(&mut self) -> Result<()>
pub async fn commit_transaction(&mut self) -> Result<()>
Commits the transaction that is currently active on this session.
This method may return an error with a crate::error::UNKNOWN_TRANSACTION_COMMIT_RESULT
label. This label indicates that it is unknown whether the commit has satisfied the write
concern associated with the transaction. If an error with this label is returned, it is
safe to retry the commit until the write concern is satisfied or an error without the label
is returned.
session.start_transaction(None).await?;
let result = coll.insert_one_with_session(doc! { "x": 1 }, None, &mut session).await?;
session.commit_transaction().await?;
This operation will retry once upon failure if the connection and encountered error support retryability. See the documentation here for more information on retryable writes.
sourcepub async fn abort_transaction(&mut self) -> Result<()>
pub async fn abort_transaction(&mut self) -> Result<()>
Aborts the transaction that is currently active on this session. Any open transaction will
be aborted automatically in the Drop
implementation of ClientSession
.
session.start_transaction(None).await?;
match execute_transaction(&coll, &mut session).await {
Ok(_) => session.commit_transaction().await?,
Err(_) => session.abort_transaction().await?,
}
async fn execute_transaction(coll: &Collection<Document>, session: &mut ClientSession) -> Result<()> {
coll.insert_one_with_session(doc! { "x": 1 }, None, session).await?;
coll.delete_one_with_session(doc! { "y": 2 }, None, session).await?;
Ok(())
}
This operation will retry once upon failure if the connection and encountered error support retryability. See the documentation here for more information on retryable writes.
sourcepub async fn with_transaction<R, C, F>(
&mut self,
context: C,
callback: F,
options: impl Into<Option<TransactionOptions>>
) -> Result<R>where
F: for<'a> FnMut(&'a mut ClientSession, &'a mut C) -> Pin<Box<dyn Future<Output = Result<R>> + Send + 'a>>,
pub async fn with_transaction<R, C, F>( &mut self, context: C, callback: F, options: impl Into<Option<TransactionOptions>> ) -> Result<R>where F: for<'a> FnMut(&'a mut ClientSession, &'a mut C) -> Pin<Box<dyn Future<Output = Result<R>> + Send + 'a>>,
Starts a transaction, runs the given callback, and commits or aborts the transaction.
Transient transaction errors will cause the callback or the commit to be retried;
other errors will cause the transaction to be aborted and the error returned to the
caller. If the callback needs to provide its own error information, the
Error::custom
method can accept an arbitrary payload that
can be retrieved via Error::get_custom
.
If a command inside the callback fails, it may cause the transaction on the server to be aborted. This situation is normally handled transparently by the driver. However, if the application does not return that error from the callback, the driver will not be able to determine whether the transaction was aborted or not. The driver will then retry the callback indefinitely. To avoid this situation, the application MUST NOT silently handle errors within the callback. If the application needs to handle errors within the callback, it MUST return them after doing so.
Because the callback can be repeatedly executed and because it returns a future, the rust
closure borrowing rules for captured values can be overly restrictive. As a
convenience, with_transaction
accepts a context argument that will be passed to the
callback along with the session:
let coll = client.database("mydb").collection::<Document>("mycoll");
let my_data = "my data".to_string();
// This works:
session.with_transaction(
(&coll, &my_data),
|session, (coll, my_data)| async move {
coll.insert_one_with_session(doc! { "data": *my_data }, None, session).await
}.boxed(),
None,
).await?;
/* This will not compile with a "variable moved due to use in generator" error:
session.with_transaction(
(),
|session, _| async move {
coll.insert_one_with_session(doc! { "data": my_data }, None, session).await
}.boxed(),
None,
).await?;
*/
Trait Implementations§
source§impl Debug for ClientSession
impl Debug for ClientSession
Auto Trait Implementations§
impl !RefUnwindSafe for ClientSession
impl Send for ClientSession
impl Sync for ClientSession
impl Unpin for ClientSession
impl !UnwindSafe for ClientSession
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> FmtForward for T
impl<T> FmtForward for T
source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where Self: Binary,
self
to use its Binary
implementation when Debug
-formatted.source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where Self: Display,
self
to use its Display
implementation when
Debug
-formatted.source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where Self: LowerExp,
self
to use its LowerExp
implementation when
Debug
-formatted.source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where Self: LowerHex,
self
to use its LowerHex
implementation when
Debug
-formatted.source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where Self: Octal,
self
to use its Octal
implementation when Debug
-formatted.source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where Self: Pointer,
self
to use its Pointer
implementation when
Debug
-formatted.source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where Self: UpperExp,
self
to use its UpperExp
implementation when
Debug
-formatted.source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where Self: UpperHex,
self
to use its UpperHex
implementation when
Debug
-formatted.source§impl<T> Instrument for T
impl<T> Instrument for T
source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere T: ?Sized,
source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere Self: Sized,
source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere R: 'a,
self
and passes that borrow into the pipe function. Read moresource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere R: 'a,
self
and passes that borrow into the pipe function. Read moresource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> Rwhere
Self: Borrow<B>,
B: 'a + ?Sized,
R: 'a,
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> Rwhere Self: Borrow<B>, B: 'a + ?Sized, R: 'a,
source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R
) -> Rwhere
Self: BorrowMut<B>,
B: 'a + ?Sized,
R: 'a,
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R ) -> Rwhere Self: BorrowMut<B>, B: 'a + ?Sized, R: 'a,
source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> Rwhere
Self: AsRef<U>,
U: 'a + ?Sized,
R: 'a,
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> Rwhere Self: AsRef<U>, U: 'a + ?Sized, R: 'a,
self
, then passes self.as_ref()
into the pipe function.source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> Rwhere
Self: AsMut<U>,
U: 'a + ?Sized,
R: 'a,
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> Rwhere Self: AsMut<U>, U: 'a + ?Sized, R: 'a,
self
, then passes self.as_mut()
into the pipe
function.source§impl<T> Tap for T
impl<T> Tap for T
source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Selfwhere
Self: Borrow<B>,
B: ?Sized,
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Selfwhere Self: Borrow<B>, B: ?Sized,
Borrow<B>
of a value. Read moresource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Selfwhere
Self: BorrowMut<B>,
B: ?Sized,
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Selfwhere Self: BorrowMut<B>, B: ?Sized,
BorrowMut<B>
of a value. Read moresource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Selfwhere
Self: AsRef<R>,
R: ?Sized,
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Selfwhere Self: AsRef<R>, R: ?Sized,
AsRef<R>
view of a value. Read moresource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Selfwhere
Self: AsMut<R>,
R: ?Sized,
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Selfwhere Self: AsMut<R>, R: ?Sized,
AsMut<R>
view of a value. Read moresource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Selfwhere
Self: Deref<Target = T>,
T: ?Sized,
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Selfwhere Self: Deref<Target = T>, T: ?Sized,
Deref::Target
of a value. Read moresource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Selfwhere
Self: DerefMut<Target = T> + Deref,
T: ?Sized,
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Selfwhere Self: DerefMut<Target = T> + Deref, T: ?Sized,
Deref::Target
of a value. Read moresource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap()
only in debug builds, and is erased in release builds.source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut()
only in debug builds, and is erased in release
builds.source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Selfwhere
Self: Borrow<B>,
B: ?Sized,
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Selfwhere Self: Borrow<B>, B: ?Sized,
.tap_borrow()
only in debug builds, and is erased in release
builds.source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Selfwhere
Self: BorrowMut<B>,
B: ?Sized,
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Selfwhere Self: BorrowMut<B>, B: ?Sized,
.tap_borrow_mut()
only in debug builds, and is erased in release
builds.source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Selfwhere
Self: AsRef<R>,
R: ?Sized,
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Selfwhere Self: AsRef<R>, R: ?Sized,
.tap_ref()
only in debug builds, and is erased in release
builds.source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Selfwhere
Self: AsMut<R>,
R: ?Sized,
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Selfwhere Self: AsMut<R>, R: ?Sized,
.tap_ref_mut()
only in debug builds, and is erased in release
builds.