提问人:Abdelaziz Said 提问时间:6/20/2022 最后编辑:smitopAbdelaziz Said 更新时间:9/3/2022 访问量:1232
无法安全地在线程之间发送具有lazy_static的 SQLx MySQL 连接
SQLx MySQL connection with lazy_static cannot be sent between threads safely
问:
我使用 sqlx 初始化 mysql 连接(异步),但发生了奇怪的错误。lazy_static
这是我写的代码:
use actix_web::middleware::Logger;
use actix_web::web::{Data, JsonConfig};
use actix_web::{App, HttpServer};
lazy_static::lazy_static! {
static ref MYSQL_DB: async_once::AsyncOnce<sqlx::Pool<sqlx::MySql>> = async_once::AsyncOnce::new(async {
dotenv::dotenv().expect("Failed to read .env file");
let uri = std::env::var("DATABASE_URL").unwrap();
sqlx::MySqlPool::connect(uri.as_str()).await.unwrap()
});
static ref DB_CLIENT : DBClient = DBClient{};
}
#[derive(Clone, Copy)]
pub struct DBClient;
impl DBClient {
pub fn get() -> &'static DBClient {
&DB_CLIENT
}
pub async fn mysql_pool(self) -> &'static sqlx::Pool<sqlx::MySql> {
MYSQL_DB.get().await
}
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
// start_tracing();
let db_client = Data::new(DBClient::get());
dotenv::dotenv().expect("Failed to read .env file");
HttpServer::new(move || {
App::new()
.wrap(Logger::default())
.app_data(Data::new(JsonConfig::default().limit(4096)))
.app_data(db_client.clone())
})
.bind(format!(
"{}:{}",
std::env::var("HOST").unwrap(),
std::env::var("PORT").unwrap()
))
.expect("Server binding exception")
.run()
.await
}
这是我的 Cargo.toml 文件:
[package]
name = "untitled"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
actix-web = "4.0.1"
sqlx = { version = "0.5.*", features = ["mysql", "runtime-async-std-native-tls"] }
actix-rt = "2.*"
juniper = { version = "0.15.9", features = ["chrono"] }
uuid = { version = "=0.8", features = ["serde", "v4"] }
chrono = { version = "0.4", features = ["serde"] }
serde = { version = "1.0", features = ["derive"] }
dotenv = "0.15.0"
lazy_static = "1.4.*"
async_once = "0.2.6"
validator = { version = "0.12", features = ["derive"] }
这是我的.env文件:
DATABASE_URL=mysql://user_name:password@localhost:3306/db_name
HOST=127.0.0.1
PORT=3000
这些是我的错误:
error[E0277]: `*const Pool<MySql>` cannot be sent between threads safely
--> src/main.rs:6:1
|
6 | / lazy_static::lazy_static! {
7 | | static ref MYSQL_DB: async_once::AsyncOnce<sqlx::Pool<sqlx::MySql>> = async_once::AsyncOnce::new(async {
8 | | dotenv::dotenv().expect("Failed to read .env file");
9 | | let uri = env::var("DATABASE_URL").unwrap();
... |
12 | | static ref DB_CLIENT : DBClient = DBClient{};
13 | | }
| |_^ `*const Pool<MySql>` cannot be sent between threads safely
|
= help: the trait `Send` is not implemented for `*const Pool<MySql>`
= note: required because of the requirements on the impl of `Send` for `Cell<*const Pool<MySql>>`
= note: required because it appears within the type `AsyncOnce<Pool<MySql>>`
= note: required because of the requirements on the impl of `Sync` for `spin::once::Once<AsyncOnce<Pool<MySql>>>`
= note: required because it appears within the type `lazy_static::lazy::Lazy<AsyncOnce<Pool<MySql>>>`
= note: shared static variables must have a type that implements `Sync`
= note: this error originates in the macro `__lazy_static_create` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: `(dyn std::future::Future<Output = Pool<MySql>> + 'static)` cannot be sent between threads safely
--> src/main.rs:6:1
|
6 | / lazy_static::lazy_static! {
7 | | static ref MYSQL_DB: async_once::AsyncOnce<sqlx::Pool<sqlx::MySql>> = async_once::AsyncOnce::new(async {
8 | | dotenv::dotenv().expect("Failed to read .env file");
9 | | let uri = env::var("DATABASE_URL").unwrap();
... |
12 | | static ref DB_CLIENT : DBClient = DBClient{};
13 | | }
| |_^ `(dyn std::future::Future<Output = Pool<MySql>> + 'static)` cannot be sent between threads safely
|
= help: the trait `Send` is not implemented for `(dyn std::future::Future<Output = Pool<MySql>> + 'static)`
= note: required because of the requirements on the impl of `Send` for `Unique<(dyn std::future::Future<Output = Pool<MySql>> + 'static)>`
= note: required because it appears within the type `Box<(dyn std::future::Future<Output = Pool<MySql>> + 'static)>`
= note: required because it appears within the type `Pin<Box<(dyn std::future::Future<Output = Pool<MySql>> + 'static)>>`
= note: required because it appears within the type `Result<Pool<MySql>, Pin<Box<(dyn std::future::Future<Output = Pool<MySql>> + 'static)>>>`
= note: required because of the requirements on the impl of `Send` for `Mutex<Result<Pool<MySql>, Pin<Box<(dyn std::future::Future<Output = Pool<MySql>> + 'static)>>>>`
= note: required because it appears within the type `AsyncOnce<Pool<MySql>>`
= note: required because of the requirements on the impl of `Sync` for `spin::once::Once<AsyncOnce<Pool<MySql>>>`
= note: required because it appears within the type `lazy_static::lazy::Lazy<AsyncOnce<Pool<MySql>>>`
= note: shared static variables must have a type that implements `Sync`
= note: this error originates in the macro `__lazy_static_create` (in Nightly builds, run with -Z macro-backtrace for more info)
I don't know the reason of the errors, but when I do the following it builds successfully:
Replace the connection with
Pool<Postgres>
Change the to in sqlx's section in Cargo.toml.
mysql
postgres
features
Change in the .env file to Postgres URI
DATABASE_URL
I got help from this question in stackoverflow: Rust lazy_static with async/await?
答:
0赞
Jeremy Meadows
6/21/2022
#1
正如评论中所讨论的那样,我用(同步)OnceCell
替换了 /。通过这些更改,您的程序能够编译:lazy_static!
AsyncOnce
use actix_web::middleware::Logger;
use actix_web::web::{Data, JsonConfig};
use actix_web::{App, HttpServer};
use once_cell::sync::OnceCell;
use sqlx::{Pool, MySql};
static MYSQL_DB: OnceCell<Pool<MySql>> = OnceCell::new();
static DB_CLIENT: DBClient = DBClient {};
#[derive(Clone, Copy)]
pub struct DBClient;
impl DBClient {
pub fn get() -> &'static DBClient {
&DB_CLIENT
}
pub async fn mysql_pool(self) -> &'static sqlx::Pool<sqlx::MySql> {
MYSQL_DB.get().unwrap()
}
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
MYSQL_DB.set({
dotenv::dotenv().expect("Failed to read .env file");
let uri = std::env::var("DATABASE_URL").unwrap();
sqlx::MySqlPool::connect(uri.as_str()).await.unwrap()
}).unwrap();
// start_tracing();
let db_client = Data::new(DBClient::get());
dotenv::dotenv().expect("Failed to read .env file");
HttpServer::new(move || {
App::new()
.wrap(Logger::default())
.app_data(Data::new(JsonConfig::default().limit(4096)))
.app_data(db_client.clone())
})
.bind(format!(
"{}:{}",
std::env::var("HOST").unwrap(),
std::env::var("PORT").unwrap()
))
.expect("Server binding exception")
.run()
.await
}
我不认为我能很好地解释为什么你所拥有的东西不起作用。
评论
0赞
Abdelaziz Said
6/21/2022
相同的错误错误[E0277]:无法安全地在线程之间共享 --> rest-service/src/main.rs:16:18 |16 |静态MYSQL_DB: OnceCell<MysqlPool> = OnceCell::new(); |^^^^^^^^^^^^^^^^^^^ 无法安全地在线程之间共享 |= help: within ,该特征未实现 = 注意:必需,因为它出现在 type = 注意:共享静态变量必须具有实现UnsafeCell<Option<Pool<MySql>>>
UnsafeCell<Option<Pool<MySql>>>
OnceCell<Pool<MySql>>
Sync
UnsafeCell<Option<Pool<MySql>>>
OnceCell<Pool<MySql>>
Sync
0赞
Jeremy Meadows
6/21/2022
你在用@AbdelazizSaid?该错误消息与我得到的错误消息相匹配(注意同步与不同步)。我把它复制粘贴回我的编辑器中,它仍然对我有用once_cell::sync::OnceCell
once_cell::unsync::OnceCell
0赞
Abdelaziz Said
7/4/2022
当我需要其他数据库时,我发现服务器抛出此错误!!线程“main”在“建立 MySql 登录连接时出错!!: 池 { 大小:1,num_idle:1,is_closed:false,选项:PoolOptions { max_connections:10,min_connections:0,connect_timeout:30s,max_lifetime:Some(1800s),idle_timeout:Some(600s),test_before_acquire:true } }',
0赞
Abdelaziz Said
7/4/2022
我在main中添加了这个函数,就像你所做的一样,并抛出了一个异常。LoginDBClient::one_cell_mysql_pool().set({ dotenv::d otenv().expect(“无法读取 .env 文件”); let uri = env::var(“LOGIN_DATABASE_URL”).unwrap(); println!(”login_uri: {}“, uri);MysqlPool::connect(uri.as_str()).await.unwrap() }).expect(“建立MySql登录连接时出错!!”);
评论
lazy_static
once_cell
Send
Arc
MYSQL_DB: AsyncOnce<Pool<MySql>>
MYSQL_DB: Arc<AsyncOnce<Pool<MySql>>>
where T: Send + Sync