はじめに
RustからMSSQLを操作したいと思い、いい感じのcrateがないか探していました。
色々調べるとDB操作関連に関してはDieselというORMがよく使われているようでした。
https://github.com/diesel-rs/diesel
「情報もある程度ありそうだしこれを使ってみよう!」
と思っていたら‥
Supported databases:
1. PostgreSQL
2. MySQL
3. SQLite
だめやん‥
というわけで他の方法を探すことにしました。
tiberius
tiberiusというcrateがありました。
https://crates.io/crates/tiberius
スター数があまり多くないのは気になりますが、検証ということでとりあえずこちらを使ってみることにします。
注意
「rust tiberius」でググるとgithubのページが二つ出てくると思います。
前者が最新のリポジトリのようなので気をつけてください。
確認環境
今回はそれぞれ以下のバージョンを使用しました。
- rustc
- 1.45.0-nightly(dockerの「rustlang/rust:nightly」を使用)
- tiberius
- 0.4.0-alpha.6
- Crates.ioに公開されているバージョンを使いたかったのですが、いい感じのexampleが見つけられず現時点の最新版(2020/05/29 時点)を使っています。申し訳ありません‥
- 0.4.0-alpha.6
実装
ディレクトリ構造
今回作成したプロジェクトは以下の構造になっています。
├── Dockerfile
├── app
│ ├── Cargo.lock
│ ├── Cargo.toml
│ └── target ※このディレクトリ配下は省略
│ └── src
│ └── main.rs
└── docker-compose.yaml
それでは一つづつみていきましょう!
Dockerfile
今回はnightlyのバージョンを使います。
FROM rustlang/rust:nightly
docker-compose.yaml
docker-compose.yamlは以下の通りです。
接続するMSSQLは公式で配布されているdocker imageを使います。
また、あらかじめテスト用のデータを作成するためにアプリケーションとmssqlの他にmssqlのcliツールを使用するコンテナも作成します。
version: '3.7'
services:
app:
build: .
volumes:
- ./app:/app
working_dir: /app
tty: true
depends_on:
- db
db:
image: microsoft/mssql-server-linux:2017-GA
environment:
ACCEPT_EULA: Y
SA_PASSWORD: "P@ssw0rd!"
volumes:
- rust-mssql-data:/var/opt/mssql/
ports:
- "1433:1433"
mssql_cil_client:
image: node:alpine
tty: true
volumes:
rust-mssql-data:
driver: local
Cargo.toml
「Cargo.toml」はdependenciesだけ抜粋しています。
サンプルを動かすにはtiberiusの他にも幾つか必要なcrateがあるので全て追加してください。
[dependencies]
tiberius = { git = "https://github.com/prisma/tiberius.git" }
tokio = { version = "0.2", features = ["macros"] }
anyhow = "1.0.31"
futures = "0.3.5"
tiberiusについては「動作確認環境」にも書きましたが最新版を使いたかったのでgithubから直接ダウンロードするようにしています。
サンプル用確認用のテーブル
サンプルを実装する前にテスト用のデータベースを作成してサンプルデータを登録しておきます。
コンテナの起動
docker-compose up -d
MSSQLが起動するので、データベースやテーブルを作成します。
cli用のコンテナにログイン
docker-compose exec mssql_cil_client /bin/sh
sql-cliのinstall
npm install -g sql-cli
mssqlにログイン
mssql -s db -u sa -p P@ssw0rd!
データベースの作成
create database test;
use test;
テーブルの作成
create table users \
( \
id int not null, \
name nvarchar(128), \
constraint pk_users primary key (id) \
);
テストデータの登録
insert into users(id,name) values(1,'Taro');
insert into users(id,name) values(2,'Jiro');
insert into users(id,name) values(3,'Hanako');
テストデータの確認
想定通りにデータが登録されているか確認しましょう!
select * from users;
以下ように表示されればOKです!
id name
-- ------
1 Taro
2 Jiro
3 Hanako
3 row(s) returned
Executed in 1 ms
問題なければ、mssqlおよびコンテナからログアウトしましょう
.quit
exit
main.rs
それでは先ほど作成したテストデータをRustから取得してみます!
以下にテーブルを作成するサンプルが格納されています。
今回はこれをベースにしました。
https://github.com/prisma/tiberius/blob/master/examples/new.rs
use tiberius::{AuthMethod, Client};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let mut builder = Client::builder();
builder.host("db");
builder.port(1433);
builder.database("test");
builder.authentication(AuthMethod::sql_server("SA", "P@ssw0rd!"));
builder.trust_cert();
let mut conn = builder.build().await?;
let results = conn
.simple_query("select id, name from Users;")
.await?
.into_results()
.await?;
for val in results.iter() {
// 取得した件数分ループする
for inner in val.iter() {
// id列の情報を取得
if let Some(id) = inner.get::<i32, _>("id") {
print!("id = {} ", id);
}
// name列の情報を取得
if let Some(name) = inner.get::<&str, _>("name") {
println!("name = {}", name);
}
}
}
Ok(())
}
とりあえず使ってみるだけであれば、特に難しい点はなさそうです。
resultsが2次元配列になっている理由が今ひとつわからず気になりました。
細かいことは一旦気にせず上記コードを実行してみましょう!
docker-compose exec app cargo run
結果
id = 1 name = Taro
id = 2 name = Jiro
id = 3 name = Hanako
いい感じですね!
今回作ったサンプルは以下で公開しています。
https://github.com/shushutochako/tiberius_sample
さいごに
Rustでmssqlを操作するサンプルがあまり多くない印象で少し手こずってしまいました。
これから色々と実装例が増えてくることを切に願います(´·ω·`)
他にもRustからMSSQLを操作する場合はODBCのWrapperライブラリを使う方法などもあるようです。
ODBCクレートを使用する場合はこちらの記事が非常に参考になりました。
https://setsuna-no-matataki.hateblo.jp/entry/2020/04/30/182305
ZEROBILLBANKでは一緒に働く仲間を募集中です。
ZEROBILLBANK JAPAN Inc.