添加 r2d2 和 r2d2_mysql 依赖,重构数据库连接池,更新用户服务接口以支持新的连接管理

This commit is contained in:
rsgl 2024-11-15 23:32:18 +08:00
parent fffc761108
commit 5c8ac42e8a
8 changed files with 239 additions and 129 deletions

12
.idea/dataSources.xml Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="test_server@122.152.201.90" uuid="23e14647-d640-43e8-a7af-9a251a179112">
<driver-ref>mysql.8</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
<jdbc-url>jdbc:mysql://122.152.201.90:9912/test_server</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>

6
.idea/sqldialects.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="SqlDialectMappings">
<file url="PROJECT" dialect="MySQL" />
</component>
</project>

32
Cargo.lock generated
View File

@ -698,6 +698,8 @@ dependencies = [
"actix-web", "actix-web",
"bcrypt", "bcrypt",
"mysql", "mysql",
"r2d2",
"r2d2_mysql",
"serde", "serde",
"serde_derive", "serde_derive",
"uuid", "uuid",
@ -1742,6 +1744,27 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "r2d2"
version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93"
dependencies = [
"log",
"parking_lot",
"scheduled-thread-pool",
]
[[package]]
name = "r2d2_mysql"
version = "25.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93963fe09ca35b0311d089439e944e42a6cb39bf8ea323782ddb31240ba2ae87"
dependencies = [
"mysql",
"r2d2",
]
[[package]] [[package]]
name = "radium" name = "radium"
version = "0.7.0" version = "0.7.0"
@ -1931,6 +1954,15 @@ dependencies = [
"windows-sys 0.59.0", "windows-sys 0.59.0",
] ]
[[package]]
name = "scheduled-thread-pool"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19"
dependencies = [
"parking_lot",
]
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.2.0" version = "1.2.0"

View File

@ -5,6 +5,8 @@ edition = "2021"
[dependencies] [dependencies]
mysql = "25.0.1" mysql = "25.0.1"
r2d2 = "0.8.10"
r2d2_mysql = "25.0.0"
actix-web = "4" actix-web = "4"
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"

View File

@ -1,109 +1,120 @@
use crate::models::user::User; use crate::models::user::User;
use mysql::params; use mysql::params;
use mysql::prelude::Queryable; use mysql::prelude::Queryable;
use r2d2::Pool;
use r2d2_mysql::MySqlConnectionManager;
/** pub struct UserRepository<'a> {
* pub pool: &'a mut Pool<MySqlConnectionManager>,
*/
pub fn create_user(conn: &mut mysql::PooledConn, user: &User) -> Result<(), mysql::Error> {
conn.exec_drop(
r"INSERT INTO users (id, name, age, email, password) VALUES (:id, :name, :age, :email, :password)",
params! {
"id" => &user.id,
"name" => &user.name,
"age" => &user.age,
"email" => &user.email,
"password" => &user.password,
},
)
} }
/** impl<'a> UserRepository<'a> {
* pub fn new(pool: &'a mut Pool<MySqlConnectionManager>) -> UserRepository {
*/ UserRepository { pool }
pub fn delete_user(conn: &mut mysql::PooledConn, user: &User) -> Result<(), mysql::Error> { }
conn.exec_drop(
r"DELETE FROM users WHERE id = :id",
params! {
"id" => &user.id,
},
)
}
/** /**
* *
*/ */
pub fn update_user(conn: &mut mysql::PooledConn, user: &User) -> Result<(), mysql::Error> { pub fn create_user(&mut self, user: &User) -> Result<(), mysql::Error> {
conn.exec_drop( let mut conn = self.pool.get().unwrap();
r"UPDATE users SET name = :name, age = :age, email = :email, password = :password WHERE id = :id", conn.exec_drop(
params! { r"INSERT INTO users (id, name, age, email, password) VALUES (:id, :name, :age, :email, :password)",
"id" => &user.id, params! {
"name" => &user.name, "id" => &user.id,
"age" => &user.age, "name" => &user.name,
"email" => &user.email, "age" => &user.age,
"password" => &user.password, "email" => &user.email,
}, "password" => &user.password,
) },
} )
}
/** /**
* *
*/ */
pub fn query_all_user(conn: &mut mysql::PooledConn) -> Result<Vec<User>, mysql::Error> { pub fn delete_user(&mut self, user: &User) -> Result<(), mysql::Error> {
conn.query_map( let mut conn = self.pool.get().unwrap();
"SELECT id, name, age, email, password FROM users", conn.exec_drop(
|(id, name, age, email, password)| User { r"DELETE FROM users WHERE id = :id",
id, params! {
name, "id" => &user.id,
age, },
email, )
password, }
},
)
}
/** /**
* ID查询用户 *
*/ */
pub fn query_user_by_id( pub fn update_user(&mut self, user: &User) -> Result<(), mysql::Error> {
conn: &mut mysql::PooledConn, let mut conn = self.pool.get().unwrap();
id: i32, conn.exec_drop(
) -> Result<Option<User>, mysql::Error> { r"UPDATE users SET name = :name, age = :age, email = :email, password = :password WHERE id = :id",
let result: Option<User> = conn.exec_first( params! {
"SELECT id, name, age, email, password FROM users WHERE id = :id", "id" => &user.id,
params! { "name" => &user.name,
"id" => id, "age" => &user.age,
}, "email" => &user.email,
)?; "password" => &user.password,
Ok(result) },
} )
}
/** /**
* *
*/ */
pub fn query_user_by_name(
conn: &mut mysql::PooledConn,
name: &str,
) -> Result<Option<User>, mysql::Error> {
conn.exec_first(
"SELECT id, name, age, email, password FROM users WHERE name = :name",
params! {
"name" => name,
},
)
}
/** pub fn query_all_user(&mut self) -> Result<Vec<User>, mysql::Error> {
* let mut conn = self.pool.get().unwrap();
*/ conn.query_map(
pub fn query_user_by_email( "SELECT id, name, age, email, password FROM users",
conn: &mut mysql::PooledConn, |(id, name, age, email, password)| User {
email: &str, id,
) -> Result<Option<User>, mysql::Error> { name,
conn.exec_first( age,
"SELECT id, name, age, email, password FROM users WHERE email = :email", email,
params! { password,
"email" => email, },
}, )
) }
/**
* ID查询用户
*/
pub fn query_user_by_id(&mut self, id: i32) -> Result<Option<User>, mysql::Error> {
let mut conn = self.pool.get().unwrap();
let result: Option<User> = conn.exec_first(
"SELECT id, name, age, email, password FROM users WHERE id = :id",
params! {
"id" => id,
},
)?;
Ok(result)
}
/**
*
*/
pub fn query_user_by_name(&mut self, name: &str) -> Result<Option<User>, mysql::Error> {
let mut conn = self.pool.get().unwrap();
conn.exec_first(
"SELECT id, name, age, email, password FROM users WHERE name = :name",
params! {
"name" => name,
},
)
}
/**
*
*/
pub fn query_user_by_email(&mut self, email: &str) -> Result<Option<User>, mysql::Error> {
let mut conn = self.pool.get().unwrap();
conn.exec_first(
"SELECT id, name, age, email, password FROM users WHERE email = :email",
params! {
"email" => email,
},
)
}
} }

View File

@ -2,6 +2,7 @@ use crate::models::user::User;
use crate::services::user_service; use crate::services::user_service;
use crate::utils::pool; use crate::utils::pool;
use actix_web::{get, post, web, HttpResponse, Responder}; use actix_web::{get, post, web, HttpResponse, Responder};
use serde::Deserialize;
pub(crate) fn register(config: &mut web::ServiceConfig) { pub(crate) fn register(config: &mut web::ServiceConfig) {
config.service(register_user); config.service(register_user);
@ -13,10 +14,18 @@ pub(crate) fn register(config: &mut web::ServiceConfig) {
config.service(delete_user); config.service(delete_user);
} }
#[derive(Deserialize)]
struct RegisterUser {
name: String,
age: i32,
email: String,
password: String,
}
#[post("/user/register")] #[post("/user/register")]
async fn register_user(user: web::Json<User>) -> impl Responder { async fn register_user(user: web::Json<RegisterUser>) -> impl Responder {
let pool = pool::get_db_pool(); let pool = pool::get_database_pool().unwrap();
let mut conn = pool.get_conn().unwrap(); let mut conn = pool.get().unwrap();
let mut new_user = User { let mut new_user = User {
id: 0, id: 0,
name: user.name.clone(), name: user.name.clone(),
@ -25,13 +34,13 @@ async fn register_user(user: web::Json<User>) -> impl Responder {
password: user.password.clone(), password: user.password.clone(),
}; };
user_service::create_user(&mut conn, &mut new_user).unwrap(); user_service::create_user(&mut conn, &mut new_user).unwrap();
HttpResponse::Ok().json("User registered successfully") HttpResponse::Ok().json("SUCCESS")
} }
#[get("/user/query_all_user")] #[get("/user/query_all_user")]
async fn query_all_user() -> impl Responder { async fn query_all_user() -> impl Responder {
let pool = pool::get_db_pool(); let pool = pool::get_database_pool().unwrap();
let mut conn = pool.get_conn().unwrap(); let mut conn = pool.get().unwrap();
let users = user_service::query_all_user(&mut conn).unwrap(); let users = user_service::query_all_user(&mut conn).unwrap();
HttpResponse::Ok().json(users) HttpResponse::Ok().json(users)
} }
@ -39,8 +48,8 @@ async fn query_all_user() -> impl Responder {
#[get("/user/{id}")] #[get("/user/{id}")]
async fn query_user_by_id(path: web::Path<i32>) -> impl Responder { async fn query_user_by_id(path: web::Path<i32>) -> impl Responder {
let id = path.into_inner(); let id = path.into_inner();
let pool = pool::get_db_pool(); let pool = pool::get_database_pool().unwrap();
let mut conn = pool.get_conn().unwrap(); let mut conn = pool.get().unwrap();
match user_service::query_user_by_id(&mut conn, id) { match user_service::query_user_by_id(&mut conn, id) {
Ok(user) => HttpResponse::Ok().json(user), Ok(user) => HttpResponse::Ok().json(user),
@ -50,8 +59,8 @@ async fn query_user_by_id(path: web::Path<i32>) -> impl Responder {
#[get("/user/{email}")] #[get("/user/{email}")]
async fn query_user_by_email(path: web::Path<String>) -> impl Responder { async fn query_user_by_email(path: web::Path<String>) -> impl Responder {
let pool = pool::get_db_pool(); let pool = pool::get_database_pool().unwrap();
let mut conn = pool.get_conn().unwrap(); let mut conn = pool.get().unwrap();
let email = path.into_inner(); let email = path.into_inner();
match user_service::query_user_by_email(&mut conn, email.as_str()) { match user_service::query_user_by_email(&mut conn, email.as_str()) {
Ok(user) => HttpResponse::Ok().json(user), Ok(user) => HttpResponse::Ok().json(user),
@ -61,8 +70,8 @@ async fn query_user_by_email(path: web::Path<String>) -> impl Responder {
#[get("/user/{name}")] #[get("/user/{name}")]
async fn query_user_by_name(path: web::Path<String>) -> impl Responder { async fn query_user_by_name(path: web::Path<String>) -> impl Responder {
let pool = pool::get_db_pool(); let pool = pool::get_database_pool().unwrap();
let mut conn = pool.get_conn().unwrap(); let mut conn = pool.get().unwrap();
let name = path.into_inner(); let name = path.into_inner();
match user_service::query_user_by_name(&mut conn, name.as_str()) { match user_service::query_user_by_name(&mut conn, name.as_str()) {
Ok(user) => HttpResponse::Ok().json(user), Ok(user) => HttpResponse::Ok().json(user),
@ -72,16 +81,16 @@ async fn query_user_by_name(path: web::Path<String>) -> impl Responder {
#[post("/user/update")] #[post("/user/update")]
async fn update_user(user: web::Json<User>) -> impl Responder { async fn update_user(user: web::Json<User>) -> impl Responder {
let pool = pool::get_db_pool(); let pool = pool::get_database_pool().unwrap();
let mut conn = pool.get_conn().unwrap(); let mut conn = pool.get().unwrap();
user_service::update_user(&mut conn, &user).unwrap(); user_service::update_user(&mut conn, &user).unwrap();
HttpResponse::Ok().json("User updated successfully") HttpResponse::Ok().json("User updated successfully")
} }
#[post("/user/delete")] #[post("/user/delete")]
async fn delete_user(user: web::Json<User>) -> impl Responder { async fn delete_user(user: web::Json<User>) -> impl Responder {
let pool = pool::get_db_pool(); let pool = pool::get_database_pool().unwrap();
let mut conn = pool.get_conn().unwrap(); let mut conn = pool.get().unwrap();
user_service::delete_user(&mut conn, &user).unwrap(); user_service::delete_user(&mut conn, &user).unwrap();
HttpResponse::Ok().json("User deleted successfully") HttpResponse::Ok().json("User deleted successfully")
} }

View File

@ -2,39 +2,58 @@ use crate::models::user::User;
use crate::repositories::user_repository; use crate::repositories::user_repository;
use bcrypt::{hash, DEFAULT_COST}; use bcrypt::{hash, DEFAULT_COST};
use mysql; use mysql;
use mysql::PooledConn; use r2d2::PooledConnection;
use r2d2_mysql::{MySqlConnectionManager, mysql::PooledConn};
/** /**
* *
*/ */
pub fn create_user(conn: &mut PooledConn, user: &mut User) -> Result<(), mysql::Error> { pub fn create_user(
user.password = hash(&user.password, DEFAULT_COST).unwrap(); conn: &mut PooledConn,
user_repository::create_user(conn, user) user: &mut User,
) -> Result<(), mysql::Error> {
let mut new_user = User {
password: hash(&user.password, DEFAULT_COST).unwrap(),
..user.clone()
};
user_repository::create_user(conn, &mut new_user)
} }
/** /**
* *
*/ */
pub fn query_all_user(conn: &mut PooledConn) -> Result<Vec<User>, mysql::Error> { pub fn query_all_user(
conn: &mut PooledConnection<MySqlConnectionManager>,
) -> Result<Vec<User>, mysql::Error> {
user_repository::query_all_user(conn) user_repository::query_all_user(conn)
} }
pub fn query_user_by_id(conn: &mut PooledConn, id: i32) -> Result<Option<User>, mysql::Error> { pub fn query_user_by_id(
conn: &mut PooledConnection<MySqlConnectionManager>,
id: i32,
) -> Result<Option<User>, mysql::Error> {
user_repository::query_user_by_id(conn, id) user_repository::query_user_by_id(conn, id)
} }
pub fn query_user_by_email( pub fn query_user_by_email(
conn: &mut PooledConn, conn: &mut PooledConnection<MySqlConnectionManager>,
email: &str, email: &str,
) -> Result<Option<User>, mysql::Error> { ) -> Result<Option<User>, mysql::Error> {
user_repository::query_user_by_email(conn, email) user_repository::query_user_by_email(conn, email)
} }
pub fn query_user_by_name(conn: &mut PooledConn, name: &str) -> Result<Option<User>, mysql::Error> { pub fn query_user_by_name(
conn: &mut PooledConnection<MySqlConnectionManager>,
name: &str,
) -> Result<Option<User>, mysql::Error> {
user_repository::query_user_by_name(conn, name) user_repository::query_user_by_name(conn, name)
} }
pub fn update_user(conn: &mut PooledConn, user: &User) -> Result<(), mysql::Error> { pub fn update_user(
conn: &mut PooledConnection<MySqlConnectionManager>,
user: &User,
) -> Result<(), mysql::Error> {
if user_repository::query_user_by_id(conn, user.id)?.is_none() { if user_repository::query_user_by_id(conn, user.id)?.is_none() {
return Err(mysql::Error::MySqlError(mysql::MySqlError { return Err(mysql::Error::MySqlError(mysql::MySqlError {
code: 1062, code: 1062,
@ -46,7 +65,10 @@ pub fn update_user(conn: &mut PooledConn, user: &User) -> Result<(), mysql::Erro
user_repository::update_user(conn, user) user_repository::update_user(conn, user)
} }
pub fn delete_user(conn: &mut PooledConn, user: &User) -> Result<(), mysql::Error> { pub fn delete_user(
conn: &mut PooledConnection<MySqlConnectionManager>,
user: &User,
) -> Result<(), mysql::Error> {
if user_repository::query_user_by_id(conn, user.id)?.is_none() { if user_repository::query_user_by_id(conn, user.id)?.is_none() {
return Err(mysql::Error::MySqlError(mysql::MySqlError { return Err(mysql::Error::MySqlError(mysql::MySqlError {
code: 1062, code: 1062,

View File

@ -1,9 +1,25 @@
use mysql::*; // use mysql::*;
/** // /**
* // * 获取数据库连接池
*/ // */
pub fn get_db_pool() -> Pool { // pub fn get_database_pool().unwrap -> Pool {
// let url = "mysql://root:0andrx@122.152.201.90:9912/test_server";
// Pool::new(url).expect("TODO: panic message")
// }
use r2d2::Pool;
use r2d2_mysql::MySqlConnectionManager;
pub fn get_database_pool() -> Result<Pool<MySqlConnectionManager>, r2d2::Error> {
let url = "mysql://root:0andrx@122.152.201.90:9912/test_server"; let url = "mysql://root:0andrx@122.152.201.90:9912/test_server";
Pool::new(url).expect("TODO: panic message") let opts =
r2d2_mysql::mysql::OptsBuilder::from_opts(r2d2_mysql::mysql::Opts::from_url(url).unwrap());
let manager = r2d2_mysql::MySqlConnectionManager::new(opts);
let pool = Pool::builder()
.max_size(10)
.min_idle(Some(5))
.build(manager)
.unwrap();
Ok(pool)
} }