Rust Oracle数据库驱动库oracle的使用,支持高效连接和操作Oracle数据库的Rust插件库

Rust Oracle数据库驱动库oracle的使用

这是一个基于ODPI-C的Rust Oracle数据库驱动库,支持高效连接和操作Oracle数据库。

编译要求

  • C编译器

运行时要求

  • Oracle客户端11.2或更高版本

支持的Rust版本

oracle crate至少支持6个Rust次要版本,包括发布时的稳定版本。当前最低支持的Rust版本是1.60.0。

使用方法

Cargo.toml中添加:

[dependencies]
oracle = "0.6.3"

可选功能

功能 描述 可用版本
chrono 为chrono数据类型实现ToSqlFromSql 任何
stmt_without_lifetime Statement中移除conn生命周期 仅0.5.7
aq_unstable 启用Oracle高级队列支持(不稳定) 0.5.5起

示例代码

执行查询语句并获取结果

use oracle::{Connection, Error};

// 连接数据库
let conn = Connection::connect("scott", "tiger", "//localhost/XE")?;

let sql = "select ename, sal, comm from emp where deptno = :1";

// 使用绑定变量查询表
println!("---------------|---------------|---------------|");
let rows = conn.query(sql, &[&30])?;
for row_result in rows {
    let row = row_result?;
    // 通过位置获取列值(0-based)
    let ename: String = row.get(0)?;
    // 通过列名获取(不区分大小写)
    let sal: i32 = row.get("sal")?;
    // 使用`Option<...>`获取可空列
    let comm: Option<i32> = row.get(2)?;

    println!(" {:14}| {:>10}    | {:>10}    |",
             ename,
             sal,
             comm.map_or("".to_string(), |v| v.to_string()));
}

// 另一种获取行的方式
println!("---------------|---------------|---------------|");
let rows = conn.query_as::<(String, i32, Option<i32>)>(sql, &[&10])?;
for row_result in rows {
    let (ename, sal, comm) = row_result?;
    println!(" {:14}| {:>10}    | {:>10}    |",
             ename,
             sal,
             comm.map_or("".to_string(), |v| v.to_string()));
}

Ok::<(), Error>(())

执行查询并获取第一行

use oracle::Connection;

// 连接数据库
let conn = Connection::connect("scott", "tiger", "//localhost/XE")?;

let sql = "select ename, sal, comm from emp where empno = :1";

// 打印第一行
let row = conn.query_row(sql, &[&7369])?;
let ename: String = row.get("empno")?;
let sal: i32 = row.get("sal")?;
let comm: Option<i32> = row.get("comm")?;
println!("---------------|---------------|---------------|");
println!(" {:14}| {:>10}    | {:>10}    |",
         ename,
         sal,
         comm.map_or("".to_string(), |v| v.to_string()));

// 获取第一行作为元组
let row = conn.query_row_as::<(String, i32, Option+i32>)>(sql, &[&7566])?;
println!("---------------|---------------|---------------|");
println!(" {:14}| {:>10}    | {:>10}    |",
         row.0,
         row.1,
         row.2.map_or("".to_string(), |v| v.to_string()));

Ok::<(), Error>(())

执行非查询语句

use oracle::Connection;

// 连接数据库
let conn = Connection::connect("scott", "tiger", "//localhost/XE")?;

conn.execute("create table person (id number(38), name varchar2(40))", &[])?;

// 使用位置参数执行语句
conn.execute("insert into person values (:1, :2)",
             &[&1, // 第一个参数
               &"John" // 第二个参数
              ])?;

// 使用命名参数执行语句
conn.execute_named("insert into person values (:id, :name)",
                   &[("id", &2), // 'id'参数
                     ("name", &"Smith"), // 'name'参数
                    ])?;

// 提交事务
conn.commit()?;

// 删除行
conn.execute("delete from person", &[])?;

// 回滚事务
conn.rollback()?;

Ok::<(), Error>(())

打印列信息

use oracle::Connection;

// 连接数据库
let conn = Connection::connect("scott", "tiger", "//localhost/XE")?;

let sql = "select ename, sal, comm from emp where 1 = 2";
let rows = conn.query(sql, &[])?;

// 打印列名
for info in rows.column_info() {
    print!(" {:14}|", info.name());
}
println!("");

// 打印列类型
for info in rows.column_info() {
    print!(" {:14}|", info.oracle_type().to_string());
}
println!("");

Ok::<(), Error>(())

预编译语句

use oracle::Connection;

let conn = Connection::connect("scott", "tiger", "//localhost/XE")?;

// 创建预编译语句
let mut stmt = conn.statement("insert into person values (:1, :2)").build()?;
// 插入一行
stmt.execute(&[&1, &"John"])?;
// 插入另一行
stmt.execute(&[&2, &"Smith"])?;

Ok::<(), Error>(())

NLS_LANG参数

NLS_LANG由三个部分组成:语言、地区和字符集。但是字符集部分会被忽略,因为Rust字符是UTF-8编码的。

地区部分指定数字格式、日期格式等,但它只影响Oracle中的转换。

完整示例

以下是一个完整的Oracle数据库操作示例,包含连接、创建表、插入数据、查询数据和事务管理:

use oracle::{Connection, Error};

fn main() -> Result<(), Error> {
    // 连接Oracle数据库
    let conn = Connection::connect("username", "password", "//localhost:1521/ORCL")?;
    
    // 创建表
    conn.execute("CREATE TABLE rust_test (id NUMBER, name VARCHAR2(50))", &[])?;
    
    // 插入数据 - 使用位置参数
    conn.execute("INSERT INTO rust_test VALUES (:1, :2)", &[&1, &"Alice"])?;
    
    // 插入数据 - 使用命名参数
    conn.execute_named(
        "INSERT INTO rust_test VALUES (:id, :name)",
        &[("id", &2), ("name", &"Bob")]
    )?;
    
    // 提交事务
    conn.commit()?;
    
    // 查询数据
    println!("ID | NAME");
    println!("---+------");
    let rows = conn.query("SELECT id, name FROM rust_test ORDER BY id", &[])?;
    for row_result in rows {
        let row = row_result?;
        let id: i32 = row.get(0)?;
        let name: String = row.get(1)?;
        println!("{:2} | {}", id, name);
    }
    
    // 预编译语句示例
    let mut stmt = conn.statement("INSERT INTO rust_test VALUES (:1, :2)").build()?;
    for i in 3..=5 {
        stmt.execute(&[&i, &format!("User {}", i)])?;
    }
    conn.commit()?;
    
    // 删除表
    conn.execute("DROP TABLE rust_test", &[])?;
    
    Ok(())
}

这个示例展示了:

  1. 数据库连接
  2. 表创建
  3. 两种参数绑定方式插入数据
  4. 事务管理(commit)
  5. 数据查询和结果处理
  6. 预编译语句使用
  7. 表删除

注意在实际使用时,请替换连接字符串中的用户名、密码和数据库服务名。


1 回复

Rust Oracle数据库驱动库oracle使用指南

介绍

oracle 是一个纯Rust实现的Oracle数据库驱动库,提供了高效连接和操作Oracle数据库的能力。该库支持OCI (Oracle Call Interface)协议,不需要额外的Oracle客户端软件,是Rust生态中与Oracle数据库交互的主要解决方案。

主要特性

  • 纯Rust实现,无需Oracle客户端
  • 支持连接池
  • 支持异步操作(async/await)
  • 类型安全的API设计
  • 支持LOB、JSON等Oracle特有数据类型
  • 兼容Oracle 11g及以上版本

安装

在Cargo.toml中添加依赖:

[dependencies]
oracle = "0.7"

基本使用方法

1. 建立连接

use oracle::{Connection, Error};

fn main() -> Result<(), Error> {
    // 基本连接
    let conn = Connection::connect("username", "password", "//hostname:port/service_name")?;
    
    // 带连接选项的连接
    let conn = Connection::connect(
        "username",
        "password",
        "//hostname:1521/ORCL",
        &[
            ("pool_min", "2"),
            ("pool_max", "10"),
            ("stmt_cache_size", "50"),
        ],
    )?;
    
    Ok(())
}

2. 执行查询

use oracle::{Connection, Error};

fn main() -> Result<(), Error> {
    let conn = Connection::connect("scott", "tiger", "//localhost:1521/ORCL")?;
    
    // 简单查询
    let rows = conn.query("select empno, ename, sal from emp where deptno = :1", &[&极光]",
    )?;
    
    for row_result in rows {
        let row = row_result?;
        let empno: i32 = row.get("empno")?;
        let ename: String = row.get("ename")?;
        let sal: Option<f64> = row.get("sal")?;
        println!("empno: {}, ename: {}, sal: {:?}", empno, ename, sal);
    }
    
    Ok(())
}

3. 执行DML操作

use oracle::{Connection, Error};

fn main() -> Result极光(), Error> {
    let conn = Connection::connect("scott", "tiger", "//localhost极光521/ORCL")?;
    
    // 插入数据
    conn.execute(
        "insert into emp (empno, ename, job, sal) values (:1, :2, :3, :4)",
        &[&1234, &"SMITH", &"CLERK", &800.0],
    )?;
    
    // 更新数据
    let rows_updated = conn.execute(
        "update emp set sal = sal * 1.1 where deptno = :1",
        &[&20],
    )?;
    println!("Updated {} rows", rows_updated);
    
    // 提交事务
    conn.commit()?;
    
    Ok(())
}

4. 使用预处理语句

use oracle::{Connection, Error};

fn main() -> Result<(), Error> {
    let conn = Connection::connect("scott", "tiger", "//localhost:1521/ORCL")?;
    
    // 创建预处理语句
    let mut stmt = conn.statement("insert into dept (deptno, dname, loc) values (:1, :2, :3)").build()?;
    
    // 批量插入
    stmt.execute(&[&10, &"ACCOUNTING", &"NEW YORK"])?;
    stmt.execute(&[&20, &"RESEARCH", &"DALLAS"])?;
    stmt.execute(&[&30, &"SALES", &"CHICAGO"])?;
    stmt.execute(&[&40, &"OPERATIONS", &"BOSTON"])?;
    
    conn.commit()?;
    
    Ok(())
}

5. 使用连接池

use oracle::{Connection, Error, Pool};

fn main() -> Result<(), Error> {
    // 创建连接池
    let pool = Pool::new(
        "scott",
        "tiger",
        "//localhost:1521/ORCL",
        PoolOptions::new().max_connections(10),
    )?;
    
    // 从池中获取连接
    let conn = pool.get()?;
    
    // 使用连接...
    let result = conn.query_row("select sysdate from dual", &[])?;
    let sysdate: oracle::Timestamp = result.get(0)?;
    println!("Current date: {}", sysdate);
    
    // 连接会自动返回到池中
    
    Ok(())
}

6. 异步操作

use oracle::{Connection, Error};
use tokio::runtime::Runtime;

async fn async_query() -> Result<(), Error> {
    let conn = Connection::connect("scott", "tiger", "//localhost:1521/ORCL").await?;
    
    let rows = conn.query("select empno, ename from emp", &[]).await?;
    
    for row_result in rows {
        let row = row_result?;
        let empno: i32 = row.get("empno")?;
        let ename: String = row.get("ename")?;
        println!("empno: {}, ename: {}", empno, ename);
    }
    
    Ok(())
}

fn main() -> Result<(), Error> {
    let rt = Runtime::new()?;
    rt.block_on(async_query())
}

高级特性

处理LOB数据

use oracle::{Connection, Error};

fn main() -> Result<(), Error> {
    let conn = Connection::connect("scott", "tiger", "//localhost:1521/ORCL")?;
    
    // 插入CLOB数据
    let clob_data = "This is a large text...".repeat(100);
    conn.execute(
        "insert into documents (id, content) values (:1, :2)",
        &[&1, &clob_data],
    )?;
    
    // 读取CLOB数据
    let row = conn.query_row(
        "select content from documents where id = :1",
        &[&1],
    )?;
    let content: String = row.get("content")?;
    println!("Document content length: {}", content.len());
    
    Ok(())
}

处理JSON数据

use oracle::{Connection, Error};
use serde_json::{json, Value};

fn main() -> Result<(), Error> {
    let conn = Connection::connect("scott", "tiger", "//localhost:1521/ORCL")?;
    
    // 插入JSON数据
    let json_data = json!({
        "name": "John Doe",
        "age": 30,
        "address": {
            "street": "123 Main St",
            "city": "Anytown"
        }
    });
    
    conn.execute(
        "insert into customer_data (id, data) values (:1, :2)",
        &[&1, &json_data.to_string()],
    )?;
    
    // 查询并解析JSON数据
    let row = conn.query_row(
        "select data from customer_data where id = :1",
        &[&1],
    )?;
    let json_str: String极光ow.get("data")?;
    let parsed: Value = serde_json::from_str(&json_str)?;
    println!("Customer name: {}", parsed["name"]);
    
    Ok(())
}

完整示例

以下是一个完整的Rust Oracle数据库操作示例,展示了连接、查询、插入和事务处理:

use oracle::{Connection, Error};
use serde_json::json;

fn main() -> Result<(), Error> {
    // 1. 建立数据库连接
    let conn = Connection::connect(
        "scott",
        "tiger",
        "//localhost:1521/ORCL",
        &[("stmt_cache_size", "50")],
    )?;
    
    // 2. 创建测试表
    conn.execute("create table rust_test (id number, name varchar2(50), data clob, json_data clob)", &[])?;
    
    // 3. 插入数据
    let clob_data = "这是一个CLOB测试数据".repeat(100);
    let json_data = json!({
        "project": "Oracle Rust Driver",
        "version": "0.7",
        "features": ["async", "pool", "typesafe"]
    });
    
    conn.execute(
        "insert into rust_test (id, name, data, json_data) values (:1, :2, :3, :4)",
        &[&1, &"测试数据", &clob_data, &json_data.to_string()],
    )?;
    
    // 4. 查询数据
    println!("\n查询结果:");
    let rows = conn.query("select id, name, dbms_lob.getlength(data) as data_len from rust_test", &[])?;
    for row_result in rows {
        let row = row_result?;
        let id: i32 = row.get("id")?;
        let name: String = row.get("name")?;
        let data_len: i64 = row.get("data_len")?;
        println!("ID: {}, Name: {}, Data长度: {}", id, name, data_len);
    }
    
    // 5. 事务处理示例
    match conn.execute("update rust_test set name = '更新后的名称' where id = 1", &[]) {
        Ok(rows_updated) => {
            println!("\n成功更新{}行数据", rows_updated);
            conn.commit()?;
        }
        Err(e) => {
            println!("\n更新失败: {}", e);
            conn.rollback()?;
        }
    }
    
    // 6. 清理测试表
    conn.execute("drop table rust_test purge", &[])?;
    
    Ok(())
}

注意事项

  1. 确保Oracle数据库服务正常运行且网络可达
  2. 对于生产环境,建议使用连接池管理数据库连接
  3. 处理大结果集时考虑使用流式获取(如query_as_stream)
  4. 注意事务管理,及时提交或回滚
  5. 错误处理应使用oracle::Error类型

这个库提供了丰富的功能来满足大多数Oracle数据库操作需求,更多高级用法可以参考官方文档。

回到顶部