hbgjh 发表于 2021-02-14 22:35
一直用c#去年开始rust边学边练,一直期待和MSSQL连接案例。
连接SQL Server目前比较成熟的方案是使用Tiberius,async/await, 用bb8做pool, bb8-tiberius的作者好像没再维护这个项目了,我pr了一次也没理我。crates.io上的bb8-tiberius目前还停留在tiberius0.4, 需要自己改一下, 下面是配合tiberius 0.5.8使用的bb8-tiberius,可以在自己的项目中作为一个mod直接使用:
#![allow(dead_code)] /// The error container #[derive(Debug, thiserror::Error)] pub enum Error { #[error(transparent)] Tiberius(#[from] tiberius::error::Error), #[error(transparent)] Io(#[from] std::io::Error), } /// Implemented for `&str` (ADO-style string) and `tiberius::Config` pub trait IntoConfig { fn into_config(self) -> tiberius::Result<tiberius::Config>; } impl<'a> IntoConfig for &'a str { fn into_config(self) -> tiberius::Result<tiberius::Config> { tiberius::Config::from_ado_string(self) } } impl IntoConfig for tiberius::Config { fn into_config(self) -> tiberius::Result<tiberius::Config> { Ok(self) } } /// Implements `bb8::ManageConnection` pub struct ConnectionManager { config: tiberius::Config, modify_tcp_stream: Box<dyn Fn(&tokio::net::TcpStream) -> tokio::io::Result<()> + Send + Sync + 'static>, } impl ConnectionManager { /// Create a new `ConnectionManager` pub fn new(config: tiberius::Config) -> Self { Self { config, modify_tcp_stream: Box::new(|tcp_stream| tcp_stream.set_nodelay(true)), } } /// Build a `ConnectionManager` from e.g. an ADO string pub fn build<I: IntoConfig>(config: I) -> Result<Self, Error> { Ok(config.into_config().map(Self::new)?) } } /// The connection type pub type Client = tiberius::Client<tokio_util::compat::Compat<tokio::net::TcpStream>>; impl ConnectionManager { /// Perform some configuration on the TCP stream when generating connections pub fn with_modify_tcp_stream<F>(mut self, f: F) -> Self where F: Fn(&tokio::net::TcpStream) -> tokio::io::Result<()> + Send + Sync + 'static, { self.modify_tcp_stream = Box::new(f); self } pub(crate) async fn connect_inner(&self) -> Result<Client, Error> { use tokio::net::TcpStream; use tokio_util::compat::TokioAsyncWriteCompatExt; //Tokio02AsyncWriteCompatExt; let tcp = TcpStream::connect(self.config.get_addr()).await?; (self.modify_tcp_stream)(&tcp)?; let client = tiberius::Client::connect(self.config.clone(), tcp.compat_write()).await?; Ok(client) } } #[async_trait::async_trait] impl bb8::ManageConnection for ConnectionManager { type Connection = Client; type Error = Error; async fn connect(&self) -> Result<Self::Connection, Self::Error> { Ok(self.connect_inner().await?) } async fn is_valid<'a, 'b, 'c>( &'a self, conn: &'b mut bb8::PooledConnection<'c, Self>, ) -> Result<(), Self::Error> { conn.simple_query("SELECT 1").await?; Ok(()) } fn has_broken(&self, _conn: &mut Self::Connection) -> bool { false } }
另外可以用来连接SQL Server的是odbc和sqlx, odbc不能await, sqlx 0.5.1中的sql server驱动还没有完全实现。期待sqlx的完整实现,未来可能是一个不错的选择,能够用一套代码连接多种数据库。
评论区
写评论连接SQL Server目前比较成熟的方案是使用Tiberius,async/await, 用bb8做pool, bb8-tiberius的作者好像没再维护这个项目了,我pr了一次也没理我。crates.io上的bb8-tiberius目前还停留在tiberius0.4, 需要自己改一下, 下面是配合tiberius 0.5.8使用的bb8-tiberius,可以在自己的项目中作为一个mod直接使用:
另外可以用来连接SQL Server的是odbc和sqlx, odbc不能await, sqlx 0.5.1中的sql server驱动还没有完全实现。期待sqlx的完整实现,未来可能是一个不错的选择,能够用一套代码连接多种数据库。