-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Boost 1.87: new discussion and examples (part 1)
Added tutorials 2, 3 and 4 Changed most of the discussion to use any_connection Added examples on disabling TLS, multi-function operations, multi-queries and transactions All examples now use any_connection Automate parts of example qbk generation Partially addresses #365 and #366
- Loading branch information
Showing
101 changed files
with
6,058 additions
and
6,738 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
[/ | ||
Copyright (c) 2019-2024 Ruben Perez Hidalgo (rubenperez038 at gmail dot com) | ||
|
||
Distributed under the Boost Software License, Version 1.0. (See accompanying | ||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
] | ||
|
||
[section:tutorial_sync Tutorial 1: hello world!] | ||
|
||
In this first tutorial, we will write a simple program | ||
to demonstrate the basic concepts. We will connect to the server | ||
and issue the query `SELECT "Hello World!"`. | ||
|
||
To run this tutorial, you need a running MySQL server listening | ||
in localhost on port 3306 (the default one). You should have | ||
the credentials of a valid MySQL user (username and password). | ||
No further setup is needed. | ||
|
||
The full program listing for this tutorial can be found [link mysql.examples.tutorial_sync here]. | ||
|
||
We will follow these steps: | ||
|
||
# Create a connection object. | ||
# Establish a session with the server. | ||
# Issue the query. | ||
# Use the rows generated by the query. | ||
# Close the connection. | ||
|
||
This tutorial uses synchronous functions with exceptions, | ||
as they're easy to use. In subsequent tutorials, we will | ||
learn how to use asynchronous functions, which are more versatile. | ||
|
||
[heading Namespace conventions] | ||
|
||
All functions and classes reside within the `boost::mysql` namespace. | ||
To reduce verbosity, all examples and code samples use the following namespace aliases: | ||
|
||
[tutorial_sync_namespaces] | ||
|
||
|
||
|
||
|
||
[heading Connection object] | ||
|
||
Like most Asio-based applications, we need to create a | ||
[asioreflink io_context io_context] object before anything else. | ||
An `io_context` is an execution context: it contains an event loop, | ||
file descriptor states, timers and other items required to perform I/O. | ||
Most applications should only create a single `io_context`, even when | ||
multiple MySQL connections are needed. | ||
|
||
We then create an [reflink any_connection], which represents a single connection | ||
to a MySQL server: | ||
|
||
[tutorial_sync_connection] | ||
|
||
|
||
|
||
|
||
[heading Connecting to the server] | ||
|
||
[refmem any_connection connect] establishes a client session with the server. | ||
It takes a [reflink connect_params] object with the required | ||
information to establish a session: | ||
|
||
[tutorial_sync_connect] | ||
|
||
|
||
|
||
|
||
[heading Issuing the SQL query] | ||
|
||
[refmem any_connection execute] accepts a string containing | ||
the SQL query to run and sends it to the server for execution. | ||
It returns a [reflink results] object, containing the rows returned by the query: | ||
|
||
[tutorial_sync_query] | ||
|
||
|
||
|
||
|
||
[heading Obtaining the results] | ||
|
||
[reflink results] is a class that holds the result of a query in memory. | ||
To obtain the value we selected, we can write: | ||
|
||
[tutorial_sync_results] | ||
|
||
Let's break this into steps: | ||
|
||
* [refmem results rows] returns all the rows that this object contains. | ||
It returns a [reflink rows_view], which is a 2D matrix-like structure. | ||
* `result.rows().at(0)` returns the first row, represented as a [reflink row_view]. | ||
* `result.rows().at(0).at(0)` returns the first field in the first row. This is a | ||
[reflink field_view], a variant-like class that can hold any type allowed in MySQL. | ||
* The obtained `field_view` is streamed to `std::cout`. | ||
|
||
|
||
|
||
|
||
[heading Closing the connection] | ||
|
||
Once we are done with the connection, we can close it by calling | ||
[refmem any_connection close]. Note that | ||
this will send a final quit packet to the MySQL server to notify | ||
we are closing the connection, and thus may fail. | ||
|
||
[tutorial_sync_close] | ||
|
||
|
||
|
||
|
||
[heading Next steps] | ||
|
||
Full program listing for this tutorial is [link mysql.examples.tutorial_sync here]. | ||
|
||
You can now proceed to [link mysql.tutorial_async the next tutorial]. | ||
|
||
[endsect] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
[/ | ||
Copyright (c) 2019-2024 Ruben Perez Hidalgo (rubenperez038 at gmail dot com) | ||
|
||
Distributed under the Boost Software License, Version 1.0. (See accompanying | ||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
] | ||
|
||
[section:tutorial_async Tutorial 2: going async with C++20 coroutines] | ||
|
||
In the [link mysql.tutorial_sync previous tutorial] we used | ||
synchronous functions. They are simple, but have a number of limitations: | ||
|
||
* They aren't as versatile as async functions. For example, there is no way | ||
to set a timeout to a sync operation. | ||
* They don't scale well. Since sync functions block the calling thread until they complete, | ||
you need to create OS threads to achieve parallelism. This doesn't scale well | ||
and leads to the inherent complexities of multi-threaded programs. | ||
* Some classes (like [reflink connection_pool]) only offer an async interface. | ||
|
||
For this reason, we recommend to always use async functions. | ||
All Asio-compatible libraries (including this one) allow async | ||
programming using a variety of styles. In this chapter, we will | ||
explain how to use C++20 coroutines because they are the simplest to use. | ||
|
||
[note | ||
Still not using C++20? Don't worry, you can use | ||
[link mysql.examples.coroutines_cpp11 stackful coroutines] and | ||
[link mysql.examples.callbacks callbacks] even in C++11. | ||
] | ||
|
||
|
||
|
||
[heading What is a coroutine?] | ||
|
||
Roughly speaking, it's a function that can suspend and resume, keeping local variables | ||
alive in the process. Suspension happens when reaching a `co_await` expression. | ||
These usually appear when the program performs an I/O operation. | ||
When an expression like this is encountered, the following happens: | ||
|
||
# The coroutine initiates the I/O operation. | ||
# The coroutine suspends, passing control back to the `io_context` (that is, the event loop). | ||
# While the I/O operation is in progress, the `io_context` may run other operations, | ||
like other coroutines. | ||
# When the I/O operation completes, the `io_context` resumes the coroutine | ||
immediately after the `co_await` expression. | ||
|
||
|
||
|
||
|
||
|
||
[heading Transforming sync code into coroutines] | ||
|
||
Recall the following code from our previous tutorial: | ||
|
||
[tutorial_sync_main] | ||
|
||
To transform this code into a coroutine, we need to: | ||
|
||
* Extract it to a separate function returning `boost::asio::awaitable<void>`. | ||
* Replace sync functions (like [refmem any_connection connect]) by async ones | ||
(like [refmem any_connection async_connect]). | ||
* Place a `co_await` operator in front of each I/O operation. | ||
|
||
Doing this, we have: | ||
|
||
[tutorial_async_coro] | ||
|
||
Note that the coroutine doesn't create or return explicitly any | ||
`boost::asio::awaitable<void>` object - this is handled by the compiler. | ||
The return type actually marks the function as being a coroutine. | ||
`void` here means that the coroutine doesn't return anything. | ||
|
||
If any of the above I/O operations fail, an exception is thrown. | ||
You can prevent this by [link mysql.overview.errors using `asio::redirect_error`]. | ||
|
||
|
||
|
||
|
||
[heading Running our coroutine] | ||
|
||
As in the previous tutorial, we first need to create an `io_context` and a connection: | ||
|
||
[tutorial_async_connection] | ||
|
||
To run a coroutine, use [asioreflink co_spawn co_spawn]: | ||
|
||
[tutorial_async_co_spawn] | ||
|
||
Note that this will only schedule the coroutine. To actually run | ||
it, we need to call `io_context::run`. This will block the calling | ||
thread until all the scheduled coroutines and I/O operations complete: | ||
|
||
[tutorial_async_run] | ||
|
||
|
||
|
||
|
||
|
||
[heading Next steps] | ||
|
||
Full program listing for this tutorial is [link mysql.examples.tutorial_async here]. | ||
|
||
You can now proceed to [link mysql.tutorial_with_params the next tutorial]. | ||
|
||
[endsect] |
Oops, something went wrong.