{"id":13439062,"url":"https://github.com/blackbeam/mysql_async","last_synced_at":"2025-05-14T01:06:38.102Z","repository":{"id":12952373,"uuid":"70676032","full_name":"blackbeam/mysql_async","owner":"blackbeam","description":"Asyncronous Rust Mysql driver based on Tokio.","archived":false,"fork":false,"pushed_at":"2025-03-25T22:13:41.000Z","size":1247,"stargazers_count":385,"open_issues_count":28,"forks_count":125,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-04-03T01:42:55.447Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/blackbeam.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-10-12T07:47:07.000Z","updated_at":"2025-03-31T14:48:44.000Z","dependencies_parsed_at":"2023-02-17T18:10:16.379Z","dependency_job_id":"4ca33aa7-9ee5-4d07-bb9f-526c17e3733e","html_url":"https://github.com/blackbeam/mysql_async","commit_stats":{"total_commits":544,"total_committers":34,"mean_commits":16.0,"dds":"0.15073529411764708","last_synced_commit":"e6bbf7c776374d0067c0164245e9158b5c75f7e7"},"previous_names":[],"tags_count":58,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blackbeam%2Fmysql_async","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blackbeam%2Fmysql_async/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blackbeam%2Fmysql_async/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blackbeam%2Fmysql_async/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/blackbeam","download_url":"https://codeload.github.com/blackbeam/mysql_async/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248154571,"owners_count":21056540,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T03:01:10.813Z","updated_at":"2025-04-10T03:39:54.705Z","avatar_url":"https://github.com/blackbeam.png","language":"Rust","funding_links":[],"categories":["Libraries","库 Libraries","库","Database","Rust","Database libraries"],"sub_categories":["Database","数据库 Database","数据库"],"readme":"[![Gitter](https://badges.gitter.im/rust-mysql/community.svg)](https://gitter.im/rust-mysql/community?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge)\n\n[![Build Status](https://dev.azure.com/aikorsky/mysql%20Rust/_apis/build/status/blackbeam.mysql_async?branchName=master)](https://dev.azure.com/aikorsky/mysql%20Rust/_build/latest?definitionId=2\u0026branchName=master)\n[![](https://meritbadge.herokuapp.com/mysql_async)](https://crates.io/crates/mysql_async)\n[![](https://img.shields.io/crates/d/mysql_async.svg)](https://crates.io/crates/mysql_async)\n[![API Documentation on docs.rs](https://docs.rs/mysql_async/badge.svg)](https://docs.rs/mysql_async)\n\n# mysql_async\n\nTokio based asynchronous MySql client library for The Rust Programming Language.\n\n## Installation\n\nThe library is hosted on [crates.io](https://crates.io/crates/mysql_async/).\n\n```toml\n[dependencies]\nmysql_async = \"\u003cdesired version\u003e\"\n```\n\n## Crate Features\n\nBy default there are only two features enabled:\n\n*   `flate2/zlib` — choosing flate2 backend is mandatory\n*   `derive` — see [\"Derive Macros\" section in `mysql_common` docs][mysqlcommonderive]\n\n### List Of Features\n\n*   `minimal` – enables only necessary features (at the moment the only necessary feature\n    is `flate2` backend). Enables:\n\n    -   `flate2/zlib\"\n\n    **Example:**\n\n    ```toml\n    [dependencies]\n    mysql_async = { version = \"*\", default-features = false, features = [\"minimal\"]}\n    ```\n\n*   `minimal-rust` - same as `minimal` but with rust-based flate2 backend. Enables:\n\n    -    `flate2/rust_backend`\n\n*   `default` – enables the following set of features:\n\n    -   `flate2/zlib`\n    -   `derive`\n\n*   `default-rustls` – default set of features with TLS via `rustls/aws-lc-rs`\n\n*   `default-rustls-ring` – default set of features with TLS via `rustls/ring`\n\n    **Example:**\n\n    ```toml\n    [dependencies]\n    mysql_async = { version = \"*\", default-features = false, features = [\"default-rustls\"] }\n    ```\n\n*   `native-tls-tls` – enables TLS via `native-tls`\n\n    **Example:**\n\n    ```toml\n    [dependencies]\n    mysql_async = { version = \"*\", default-features = false, features = [\"minimal\", \"native-tls-tls\"] }\n\n*   `rustls-tls` - enables rustls TLS backend with no provider. You should enable one\n    of existing providers using `aws-lc-rs` or `ring` features:\n\n    **Example:**\n\n    ```toml\n    [dependencies]\n    mysql_async = { version = \"*\", default-features = false, features = [\"minimal-rust\", \"rustls-tls\", \"ring\"] }\n\n*   `tracing` – enables instrumentation via `tracing` package.\n\n    Primary operations (`query`, `prepare`, `exec`) are instrumented at `INFO` level.\n    Remaining operations, incl. `get_conn`, are instrumented at `DEBUG` level.\n    Also at `DEBUG`, the SQL queries and parameters are added to the `query`, `prepare`\n    and `exec` spans. Also some internal queries are instrumented at `TRACE` level.\n\n    **Example:**\n\n    ```toml\n    [dependencies]\n    mysql_async = { version = \"*\", features = [\"tracing\"] }\n    ```\n\n*   `binlog` - enables binlog-related functionality. Enables:\n\n    -   `mysql_common/binlog\"\n\n#### Proxied features (see [`mysql_common`` fatures][myslqcommonfeatures])\n\n*   `derive` – enables `mysql_common/derive` feature\n*   `chrono` = enables `mysql_common/chrono` feature\n*   `time` = enables `mysql_common/time` feature\n*   `bigdecimal` = enables `mysql_common/bigdecimal` feature\n*   `rust_decimal` = enables `mysql_common/rust_decimal` feature\n*   `frunk` = enables `mysql_common/frunk` feature\n\n[myslqcommonfeatures]: https://github.com/blackbeam/rust_mysql_common#crate-features\n[mysqlcommonderive]: https://github.com/blackbeam/rust_mysql_common?tab=readme-ov-file#derive-macros\n\n## TLS/SSL Support\n\nSSL support comes in two flavors:\n\n1.  Based on native-tls – this is the default option, that usually works without pitfalls\n    (see the `native-tls-tls` crate feature).\n\n2.  Based on rustls – TLS backend written in Rust (see the `rustls-tls` crate feature).\n\n    Please also note a few things about rustls:\n    -   it will fail if you'll try to connect to the server by its IP address,\n        hostname is required;\n    -   it, most likely, won't work on windows, at least with default server certs,\n        generated by the MySql installer.\n\n## Connection URL parameters\n\nThere is a set of url-parameters supported by the driver (see documentation on [`Opts`]).\n\n## Example\n\n```rust\nuse mysql_async::prelude::*;\n\n#[derive(Debug, PartialEq, Eq, Clone)]\nstruct Payment {\n    customer_id: i32,\n    amount: i32,\n    account_name: Option\u003cString\u003e,\n}\n\n#[tokio::main]\nasync fn main() -\u003e Result\u003c()\u003e {\n    let payments = vec![\n        Payment { customer_id: 1, amount: 2, account_name: None },\n        Payment { customer_id: 3, amount: 4, account_name: Some(\"foo\".into()) },\n        Payment { customer_id: 5, amount: 6, account_name: None },\n        Payment { customer_id: 7, amount: 8, account_name: None },\n        Payment { customer_id: 9, amount: 10, account_name: Some(\"bar\".into()) },\n    ];\n\n    let database_url = /* ... */\n    # get_opts();\n\n    let pool = mysql_async::Pool::new(database_url);\n    let mut conn = pool.get_conn().await?;\n\n    // Create a temporary table\n    r\"CREATE TEMPORARY TABLE payment (\n        customer_id int not null,\n        amount int not null,\n        account_name text\n    )\".ignore(\u0026mut conn).await?;\n\n    // Save payments\n    r\"INSERT INTO payment (customer_id, amount, account_name)\n      VALUES (:customer_id, :amount, :account_name)\"\n        .with(payments.iter().map(|payment| params! {\n            \"customer_id\" =\u003e payment.customer_id,\n            \"amount\" =\u003e payment.amount,\n            \"account_name\" =\u003e payment.account_name.as_ref(),\n        }))\n        .batch(\u0026mut conn)\n        .await?;\n\n    // Load payments from the database. Type inference will work here.\n    let loaded_payments = \"SELECT customer_id, amount, account_name FROM payment\"\n        .with(())\n        .map(\u0026mut conn, |(customer_id, amount, account_name)| Payment { customer_id, amount, account_name })\n        .await?;\n\n    // Dropped connection will go to the pool\n    drop(conn);\n\n    // The Pool must be disconnected explicitly because\n    // it's an asynchronous operation.\n    pool.disconnect().await?;\n\n    assert_eq!(loaded_payments, payments);\n\n    // the async fn returns Result, so\n    Ok(())\n}\n```\n\n## Pool\n\nThe [`Pool`] structure is an asynchronous connection pool.\n\nPlease note:\n\n* [`Pool`] is a smart pointer – each clone will point to the same pool instance.\n* [`Pool`] is `Send + Sync + 'static` – feel free to pass it around.\n* use [`Pool::disconnect`] to gracefuly close the pool.\n* ⚠️ [`Pool::new`] is lazy and won't assert server availability.\n\n## Transaction\n\n[`Conn::start_transaction`] is a wrapper, that starts with `START TRANSACTION`\nand ends with `COMMIT` or `ROLLBACK`.\n\nDropped transaction will be implicitly rolled back if it wasn't explicitly\ncommitted or rolled back. Note that this behaviour will be triggered by a pool\n(on conn drop) or by the next query, i.e. may be delayed.\n\nAPI won't allow you to run nested transactions because some statements causes\nan implicit commit (`START TRANSACTION` is one of them), so this behavior\nis chosen as less error prone.\n\n## `Value`\n\nThis enumeration represents the raw value of a MySql cell. Library offers conversion between\n`Value` and different rust types via `FromValue` trait described below.\n\n### `FromValue` trait\n\nThis trait is reexported from **mysql_common** create. Please refer to its\n[crate docs](https://docs.rs/mysql_common) for the list of supported conversions.\n\nTrait offers conversion in two flavours:\n\n*   `from_value(Value) -\u003e T` - convenient, but panicking conversion.\n\n    Note, that for any variant of `Value` there exist a type, that fully covers its domain,\n    i.e. for any variant of `Value` there exist `T: FromValue` such that `from_value` will never\n    panic. This means, that if your database schema is known, than it's possible to write your\n    application using only `from_value` with no fear of runtime panic.\n\n    Also note, that some convertions may fail even though the type seem sufficient,\n    e.g. in case of invalid dates (see [sql mode](https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html)).\n\n*   `from_value_opt(Value) -\u003e Option\u003cT\u003e` - non-panicking, but less convenient conversion.\n\n    This function is useful to probe conversion in cases, where source database schema\n    is unknown.\n\n## MySql query protocols\n\n### Text protocol\n\nMySql text protocol is implemented in the set of `Queryable::query*` methods\nand in the [`prelude::Query`] trait if query is [`prelude::AsQuery`].\nIt's useful when your query doesn't have parameters.\n\n**Note:** All values of a text protocol result set will be encoded as strings by the server,\nso `from_value` conversion may lead to additional parsing costs.\n\n### Binary protocol and prepared statements.\n\nMySql binary protocol is implemented in the set of `exec*` methods,\ndefined on the [`prelude::Queryable`] trait and in the [`prelude::Query`]\ntrait if query is [`QueryWithParams`]. Prepared statements is the only way to\npass rust value to the MySql server. MySql uses `?` symbol as a parameter placeholder.\n\n**Note:** it's only possible to use parameters where a single MySql value\nis expected, i.e. you can't execute something like `SELECT ... WHERE id IN ?`\nwith a vector as a parameter. You'll need to build a query that looks like\n`SELECT ... WHERE id IN (?, ?, ...)` and to pass each vector element as\na parameter.\n\n## Named parameters\n\nMySql itself doesn't have named parameters support, so it's implemented on the client side.\nOne should use `:name` as a placeholder syntax for a named parameter. Named parameters uses\nthe following naming convention:\n\n* parameter name must start with either `_` or `a..z`\n* parameter name may continue with `_`, `a..z` and `0..9`\n\n**Note:** this rules mean that, say, the statment `SELECT :fooBar` will be translated\nto `SELECT ?Bar` so please be careful.\n\nNamed parameters may be repeated within the statement, e.g `SELECT :foo, :foo` will require\na single named parameter `foo` that will be repeated on the corresponding positions during\nstatement execution.\n\nOne should use the `params!` macro to build parameters for execution.\n\n**Note:** Positional and named parameters can't be mixed within the single statement.\n\n## Statements\n\nIn MySql each prepared statement belongs to a particular connection and can't be executed\non another connection. Trying to do so will lead to an error. The driver won't tie statement\nto its connection in any way, but one can look on to the connection id, contained\nin the [`Statement`] structure.\n\n## LOCAL INFILE Handlers\n\n**Warning:** You should be aware of [Security Considerations for LOAD DATA LOCAL][1].\n\nThere are two flavors of LOCAL INFILE handlers – _global_ and _local_.\n\nI case of a LOCAL INFILE request from the server the driver will try to find a handler for it:\n\n1.  It'll try to use _local_ handler installed on the connection, if any;\n2.  It'll try to use _global_ handler, specified via [`OptsBuilder::local_infile_handler`],\n    if any;\n3.  It will emit [`LocalInfileError::NoHandler`] if no handlers found.\n\nThe purpose of a handler (_local_ or _global_) is to return [`InfileData`].\n\n### _Global_ LOCAL INFILE handler\n\nSee [`prelude::GlobalHandler`].\n\nSimply speaking the _global_ handler is an async function that takes a file name (as `\u0026[u8]`)\nand returns `Result\u003cInfileData\u003e`.\n\nYou can set it up using [`OptsBuilder::local_infile_handler`]. Server will use it if there is no\n_local_ handler installed for the connection. This handler might be called multiple times.\n\nExamles:\n\n1.  [`WhiteListFsHandler`] is a _global_ handler.\n2.  Every `T: Fn(\u0026[u8]) -\u003e BoxFuture\u003c'static, Result\u003cInfileData, LocalInfileError\u003e\u003e`\n    is a _global_ handler.\n\n### _Local_ LOCAL INFILE handler.\n\nSimply speaking the _local_ handler is a future, that returns `Result\u003cInfileData\u003e`.\n\nThis is a one-time handler – it's consumed after use. You can set it up using\n[`Conn::set_infile_handler`]. This handler have priority over _global_ handler.\n\nWorth noting:\n\n1.  `impl Drop for Conn` will clear _local_ handler, i.e. handler will be removed when\n    connection is returned to a `Pool`.\n2.  [`Conn::reset`] will clear _local_ handler.\n\nExample:\n\n```rust\n#\nlet pool = mysql_async::Pool::new(database_url);\n\nlet mut conn = pool.get_conn().await?;\n\"CREATE TEMPORARY TABLE tmp (id INT, val TEXT)\".ignore(\u0026mut conn).await?;\n\n// We are going to call `LOAD DATA LOCAL` so let's setup a one-time handler.\nconn.set_infile_handler(async move {\n    // We need to return a stream of `io::Result\u003cBytes\u003e`\n    Ok(stream::iter([Bytes::from(\"1,a\\r\\n\"), Bytes::from(\"2,b\\r\\n3,c\")]).map(Ok).boxed())\n});\n\nlet result = r#\"LOAD DATA LOCAL INFILE 'whatever'\n    INTO TABLE `tmp`\n    FIELDS TERMINATED BY ',' ENCLOSED BY '\\\"'\n    LINES TERMINATED BY '\\r\\n'\"#.ignore(\u0026mut conn).await;\n\nmatch result {\n    Ok(()) =\u003e (),\n    Err(Error::Server(ref err)) if err.code == 1148 =\u003e {\n        // The used command is not allowed with this MySQL version\n        return Ok(());\n    },\n    Err(Error::Server(ref err)) if err.code == 3948 =\u003e {\n        // Loading local data is disabled;\n        // this must be enabled on both the client and the server\n        return Ok(());\n    }\n    e @ Err(_) =\u003e e.unwrap(),\n}\n\n// Now let's verify the result\nlet result: Vec\u003c(u32, String)\u003e = conn.query(\"SELECT * FROM tmp ORDER BY id ASC\").await?;\nassert_eq!(\n    result,\n    vec![(1, \"a\".into()), (2, \"b\".into()), (3, \"c\".into())]\n);\n\ndrop(conn);\npool.disconnect().await?;\n```\n\n[1]: https://dev.mysql.com/doc/refman/8.0/en/load-data-local-security.html\n\n## Testing\n\nTests uses followin environment variables:\n* `DATABASE_URL` – defaults to `mysql://root:password@127.0.0.1:3307/mysql`\n* `COMPRESS` – set to `1` or `true` to enable compression for tests\n* `SSL` – set to `1` or `true` to enable TLS for tests\n\nYou can run a test server using doker. Please note that params related\nto max allowed packet, local-infile and binary logging are required\nto properly run tests (please refer to `azure-pipelines.yml`):\n\n```sh\ndocker run -d --name container \\\n    -v `pwd`:/root \\\n    -p 3307:3306 \\\n    -e MYSQL_ROOT_PASSWORD=password \\\n    mysql:8.0 \\\n    --max-allowed-packet=36700160 \\\n    --local-infile \\\n    --log-bin=mysql-bin \\\n    --log-slave-updates \\\n    --gtid_mode=ON \\\n    --enforce_gtid_consistency=ON \\\n    --server-id=1\n```\n\n\n## Change log\n\nAvailable [here](https://github.com/blackbeam/mysql_async/releases)\n\n## License\n\nLicensed under either of\n\n* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0)\n* MIT license ([LICENSE-MIT](LICENSE-MIT) or https://opensource.org/licenses/MIT)\n\nat your option.\n\n### Contribution\n\nUnless you explicitly state otherwise, any contribution intentionally\nsubmitted for inclusion in the work by you, as defined in the Apache-2.0\nlicense, shall be dual licensed as above, without any additional terms or\nconditions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblackbeam%2Fmysql_async","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fblackbeam%2Fmysql_async","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblackbeam%2Fmysql_async/lists"}