面试题答案
一键面试-
定义数据库操作 trait:
use std::fmt::Debug; // 定义一个 trait 来抽象数据库操作 pub trait Database { // 查询方法,返回 Vec<T>,T 是结果类型 fn query<T: for<'a> serde::Deserialize<'a> + Debug>(&self, query: &str) -> Result<Vec<T>, Box<dyn std::error::Error>>; // 插入方法,T 是要插入的数据类型 fn insert<T: serde::Serialize + Debug>(&self, data: &T, insert_query: &str) -> Result<(), Box<dyn std::error::Error>>; // 更新方法 fn update(&self, update_query: &str) -> Result<(), Box<dyn std::error::Error>>; // 删除方法 fn delete(&self, delete_query: &str) -> Result<(), Box<dyn std::error::Error>>; }
-
实现具体数据库的 trait:
- MySQL 实现:
use mysql::{Pool, PooledConn, prelude::Queryable, params}; pub struct MySqlDatabase { pool: Pool, } impl Database for MySqlDatabase { fn query<T: for<'a> serde::Deserialize<'a> + Debug>(&self, query: &str) -> Result<Vec<T>, Box<dyn std::error::Error>> { let mut conn = self.pool.get_conn()?; let result = conn.query_map(query, |(row,): (mysql::Row,)| serde_json::from_slice::<T>(&row)?); Ok(result.collect()) } fn insert<T: serde::Serialize + Debug>(&self, data: &T, insert_query: &str) -> Result<(), Box<dyn std::error::Error>> { let mut conn = self.pool.get_conn()?; let json_data = serde_json::to_value(data)?; conn.exec(insert_query, params! {"data": json_data})?; Ok(()) } fn update(&self, update_query: &str) -> Result<(), Box<dyn std::error::Error>> { let mut conn = self.pool.get_conn()?; conn.exec(update_query, ())?; Ok(()) } fn delete(&self, delete_query: &str) -> Result<(), Box<dyn std::error::Error>> { let mut conn = self.pool.get_conn()?; conn.exec(delete_query, ())?; Ok(()) } }
- PostgreSQL 实现:
use postgres::{Client, Connection, SslMode}; use serde_json::Value; pub struct PostgresDatabase { client: Client, } impl Database for PostgresDatabase { fn query<T: for<'a> serde::Deserialize<'a> + Debug>(&self, query: &str) -> Result<Vec<T>, Box<dyn std::error::Error>> { let rows = self.client.query(query, &[])?; let mut results = Vec::new(); for row in rows { let json_str = row.get(0); let result: T = serde_json::from_str(&json_str)?; results.push(result); } Ok(results) } fn insert<T: serde::Serialize + Debug>(&self, data: &T, insert_query: &str) -> Result<(), Box<dyn std::error::Error>> { let json_data = serde_json::to_value(data)?; self.client.execute(insert_query, &[&json_data.to_string()])?; Ok(()) } fn update(&self, update_query: &str) -> Result<(), Box<dyn std::error::Error>> { self.client.execute(update_query, &[])?; Ok(()) } fn delete(&self, delete_query: &str) -> Result<(), Box<dyn std::error::Error>> { self.client.execute(delete_query, &[])?; Ok(()) } }
- MySQL 实现:
-
处理数据类型和语法差异:
- 数据类型差异:
- 在 Rust 中,使用
serde
库来处理数据的序列化和反序列化。不同数据库返回的数据格式可能不同,例如 MySQL 可以直接返回 JSON 格式数据,PostgreSQL 可能需要手动转换。在query
方法中,将数据库返回的数据转换为 JSON 格式,再使用serde
反序列化为 Rust 结构体。 - 对于插入数据,将 Rust 结构体序列化为 JSON 格式数据,再根据不同数据库的要求进行插入。例如 MySQL 可以直接使用 JSON 格式参数,PostgreSQL 可能需要将 JSON 转换为字符串。
- 在 Rust 中,使用
- 语法差异:
- 在
insert_query
、update_query
和delete_query
中,根据不同数据库的 SQL 语法编写相应的查询语句。例如 MySQL 的插入语法可能是INSERT INTO table (column1, column2) VALUES (?,?)
,而 PostgreSQL 可能是INSERT INTO table (column1, column2) VALUES ($1, $2)
。通过在不同数据库的Database
trait 实现中使用各自正确的语法来处理这种差异。
- 在
- 数据类型差异:
-
使用示例:
fn main() -> Result<(), Box<dyn std::error::Error>> { // MySQL 示例 let mysql_pool = Pool::new("mysql://user:password@localhost:3306/mydb")?; let mysql_db = MySqlDatabase { pool: mysql_pool }; let mysql_query_result = mysql_db.query::<u32>("SELECT some_column FROM some_table")?; println!("MySQL query result: {:?}", mysql_query_result); // PostgreSQL 示例 let (mut client, connection) = Connection::connect("host=localhost user=user password=password dbname=mydb sslmode=disable", SslMode::Disable)?; let postgres_db = PostgresDatabase { client }; let postgres_query_result = postgres_db.query::<u32>("SELECT some_column FROM some_table")?; println!("PostgreSQL query result: {:?}", postgres_query_result); Ok(()) }
以上代码通过定义 Database
trait 来抽象数据库操作,分别实现了 MySQL 和 PostgreSQL 的具体操作,并说明了如何处理数据类型和语法差异。实际应用中,还需要考虑更多细节,如连接池管理、错误处理的完善等。