rust-shentong操作指南¶
数据库连接¶
普通连接¶
有两种方式进行数据库的连接:
第一种:时用Connection::connect方法
let conn = Connection::connect(user, password, connect_string);
User为用户名;
password为密码;
connect_string为连接字符串格式为:host:port/dbname,比如:localhost:2003/osrdb。
需要引入Connection:use shentong::{Connection}
第二种用Connector::new创建
let conn = Connector::new(user,password,connect_string);
需要引入Connector:use shentong::{Connector}
注解
- conn的status方法可以获得连接的连接的状态,比如:
- assert_eq!(conn.status()?, ConnStatus::Normal);
- conn.close()?;
- assert_eq!(conn.status()?, ConnStatus::Closed);
连接池¶
// 创建一个连接池
let pool = PoolBuilder::new(username, password, connect_string)
.max_connections(20)
.build()?;
// 获得一个连接.
let conn1 = pool.get()?;
let conn2 = pool.get()?;
// 将连接归还连接池.
conn1.close()?;
conn2.close()?;
安全连接¶
rust-shentong依赖aci驱动,aci驱动支持了ssl安全通信,且可以通过连接字符串设置,因此rust-shentong也可以在连接字符串设置ssl通信相关配置,多个参数之间用“;”间隔,比如:
let conn = Connection::connect("sysdba", "szoscar55", "localhost:2003/osrdb?ssl_wallet_enable=1;ssl_wallet_path=/opt/wallet/;ssl_wallet_pwd=szoscar55$")?;
详细可以设置的参数,可参考 《ACI (C/C++)程序员开发手册-->ACI编程概述-->参数配置文件-->参数说明》 中的参数及参数功能描述。
执行有结果的语句¶
query方式执行并获得结果¶
query方法会查询获得查询的所有结果,需要在执行后用result对象接收结果集,在循环中获取结果集中的每一行的数据。示例如下:
use shentong::{Connection, Error};
let conn = Connection::connect("sysdba", "szoscar55", "localhost:2003/osrdb")?;
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?;
let ename: String = row.get(0)?;
let sal: i32 = row.get("sal")?;
let comm: Option<i32> = row.get(2)?;
println!(" {:14}| {:>10} | {:>10} |",
ename,
sal,
comm.map_or("".to_string(), |v| v.to_string()));
}
query_name方式执行并获得结果¶
query_named方法会查询获得查询的所有结果,需要在执行后用result对象接收结果集,在循环中获取结果集中的每一行的数据。同时,如果语句中有参数的情况下,通过参数名称的方式指定参数值。示例如下:
use shentong::{Connection, Error};
let conn = Connection::connect("sysdba", "szoscar55", "localhost:2003/osrdb")?;
let sql = "select ename, sal, comm from emp where deptno = :icol";
println!("---------------|---------------|---------------|");
let rows = conn.query_named(sql, &[("icol", &30)])?;
for row_result in rows {
let row = row_result?;
let ename: String = row.get(0)?;
let sal: i32 = row.get("sal")?;
let comm: Option<i32> = row.get(2)?;
println!(" {:14}| {:>10} | {:>10} |",
ename,
sal,
comm.map_or("".to_string(), |v| v.to_string()));
}
query_as方式执行并获得结果¶
query_as方法可以在执行查询时设置每个列的返回类型,这样在获取结果时就不用指定类型了,示例如下:
use shentong::{Connection, Error};
let conn = Connection::connect("sysdba", "szoscar55", "localhost:2003/osrdb")?;
let sql = "select ename, sal, comm from emp where deptno = :1";
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()));
}
query_as_named方式执行并获得结果¶
query_as_named方法可以在执行查询时设置每个列的返回类型,这样在获取结果时就不用指定类型了,同时,如果语句中有参数的情况下,通过参数名称的方式指定参数值。示例如下:
use shentong::{Connection, Error};
let conn = Connection::connect("sysdba", "szoscar55", "localhost:2003/osrdb")?;
let sql = "select ename, sal, comm from emp where deptno = :icol";
println!("---------------|---------------|---------------|");
let rows = conn.query_as::<(String, i32, Option<i32>)>(sql, &[("icol", &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()));
}
query_row方式执行并获得结果¶
query_row方法执行查询后只返回一条数据(第一条),示例如下:
use shentong::Connection;
let conn = Connection::connect("sysdba", "szoscar55", "localhost:2003/osrdb")?;
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()));
query_row_named方式执行并获得结果¶
query_row_named方法执行查询后只返回一条数据(第一条),同时如果语句中有参数的情况下,通过参数名称的方式指定参数值。示例如下:
use shentong::Connection;
let conn = Connection::connect("sysdba", "szoscar55", "localhost:2003/osrdb")?;
let sql = "select ename, sal, comm from emp where empno = :icol";
let row = conn.query_row_named(sql, &[("icol", &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()));
query_row_as方式执行并获得结果¶
query_row_as方法执行查询后只返回一条数据(第一条),且在执行时指定各个列的返回类型,示例如下:
use shentong::Connection;
let conn = Connection::connect("sysdba", "szoscar55", "localhost:2003/osrdb")?;
let sql = "select ename, sal, comm from emp where empno = :icol";
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()));
query_row_as_named方式执行并获得结果¶
query_row_as_named方法执行查询后只返回一条数据(第一条),且在执行时指定各个列的返回类型,同时如果语句中有参数的情况下,通过参数名称的方式指定参数值.示例如下:
use shentong::Connection;
let conn = Connection::connect("sysdba", "szoscar55", "localhost:2003/osrdb")?;
let sql = "select ename, sal, comm from emp where empno = :icol";
let row = conn.query_row_as_named::<(String, i32, Option<i32>)>(sql, &[("icol", &7369)])?;
println!("---------------|---------------|---------------|");
println!(" {:14}| {:>10} | {:>10} |",
row.0,
row.1,
row.2.map_or("".to_string(), |v| v.to_string()));
语句准备执行¶
通过Connection的prepare方法准备一条SQL语句,然后再用Statement的execute方法进行执行。Prepare时如果有参数,则在执行时需要给定参数值;一个sql语句被一次prepare后,可多次执行execute方法进行执行。
let conn = Connection::connect("sysdba", "szoscar55", "localhost:2003/osrdb")?;
// 创建要给prepare语句
let mut stmt = conn.prepare("insert into person values (:1, :2)", &[])?;
// 给定参数并执行插入
stmt.execute(&[&1, &"John"])?;
// 给定参数并执行插入另外一条数据
stmt.execute(&[&2, &"Smith"])?;
注意:如果prepare是查询语句,Statement对象也有query、query_named等系列执行查询的方法,用法与connection下的这些方法类似。 Statement结构的execute_named方法用于执行通过参数名称给参数绑定值的方式,比如:
let conn = Connection::connect("scott", "tiger", "")?;
let mut stmt = conn.prepare("insert into emp(empno, ename) values (:id, :name)", &[])?;
stmt.execute_named(&[("id", &114), ("name", &"Smith")])?;
stmt.execute_named(&[("id", &115),("name", &"Paul")])?; //
获取语句类型¶
当我们用preapre准备一条sql语句后,语句对象的statement_type方法就可获得语句的类型,比如:
let stmt = conn.prepare("SELECT ...", &[])?;
let stmt_type = stmt.statement_type();
assert_eq!(stmt_type, StatementType::Select);
StatementType中有很多类型的枚举,比如:
StatementType::Select
StatementType::Insert
StatementType::Update
StatementType::Delete
StatementType::Merge
StatementType::Create
StatementType::Alter
StatementType::Drop
StatementType::Begin
StatementType::Declare
StatementType::Commit
StatementType::Rollback
开发这还可以用一些方法来判定是否是期望的类型,比如:
assert_eq!(stmt.is_query(), true);
assert_eq!(stmt.is_plsql(), false);
assert_eq!(stmt.is_ddl(), false);
assert_eq!(stmt.is_dml(), false);
assert_eq!(stmt.is_returning(), false);
获得查询结果的列信息¶
获得查询结果的列信息,有助于开发者在程序中通过代码逻辑实现类型的判定来获取数据,开发者在获取结果时不必很清楚每个列的类型等信息。
use shentong::Connection;
// 创建数据库连接.
let conn = Connection::connect("sysdba", "szoscar55", "localhost:2003/osrdb")?;
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!("");
参数信息获取¶
用语句对象的bind_count的方法获得参数个数,用bind_names方法获得参数的集合。、
let stmt = conn.prepare("select * from test where id = :idval", &[])?;
assert_eq!(stmt.bind_count(), 1);
let bind_names = stmt.bind_names();
assert_eq!(bind_names.len(), 1);
assert_eq!(bind_names[0], "idval");
执行无结果语句¶
执行insert、update以及DDL语句时,时没有结果集返回的,因此可以直接调用Connection的execute方法执行语句。
use shentong::Connection;
// 创建数据库连接.
let conn = Connection::connect("sysdba", "szoscar55", "localhost:2003/osrdb")?;
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), ("name", &"Smith"), ])?;
// 提交事务
conn.commit()?;
// 删除数据
conn.execute("delete from person", &[])?;
//回滚事务
conn.rollback()?;
大对象的处理¶
小大对象可以用普通数据类型方式进行获取,也可以用专属的类型处理结构来操作,比如数据库中的BLOB类型,可以用Blob结构来处理:
use shentong::sql_type::Blob;
use shentong::sql_type::Lob;
use std::io::BufReader;
use std::io::Read;
let sql = "select BLOBCol from TestBLOBS where IntCol = 1";
let mut stmt = conn.statement(sql).lob_locator().build()?;
let blob = stmt.query_row_as::<Blob>(&[])?;
let mut buf_reader = BufReader::with_capacity(blob.chunk_size()? * 16, blob);
let mut buf = [0u8; 4];
assert_eq!(buf_reader.read(&mut buf)?, 4); // read the first four bytes
assert_eq!(&buf, b"BLOB");
assert_eq!(buf_reader.read(&mut buf)?, 4); // read the next four bytes
assert_eq!(&buf, b" DAT");
assert_eq!(buf_reader.read(&mut buf)?, 1); // read the last one byte
assert_eq!(&buf[0..1], b"A");
assert_eq!(buf_reader.read(&mut buf)?, 0); // end of blob
事务处理¶
conn对象上有commit和rollback方法进行事务的提交和回滚;默认情况下,事务是是需要手动提交的,如果想设置为自动提交,需要执行:
conn.set_autocommit(true);
Returning语句执行¶
支持returning into语法的执行,同时支持将into的值返回,通过语句对象的returned_values方法返回。
let sql = "update TestStrings set StringCol = StringCol where IntCol >= :1 returning IntCol into :icol";
let mut stmt = conn.prepare(sql, &[])?;
assert_eq!(stmt.is_returning(), true);
//用bind方法将参数2设置为out参数绑定
stmt.bind(2, &None::<i32>)?;
// 更新一行
stmt.execute(&[&10])?;
let updated_int_col: Vec<i32> = stmt.returned_values(2)?;
assert_eq!(updated_int_col, vec![10]);
NULL值绑定¶
如果我们执行语句时,参数绑定如果想传入一个NULL,则可以在执行语句时,参数的值给None,比如:&None::<i32>:
conn.execute(
"insert into TestNumbers values (:1, :2, :3, :4, :5)",
&[&100, &9.2, &10.14, &7.14, &None::<i32>],
)?;
获得影响行数¶
对于update、insert等语句,执行成功后会有影响行数,通过语句对象的row_count方法可以获得影响行数;如果时select语句,获得时已经获取到的行数。
let stmt = conn.execute(
"update TestStrings set StringCol = StringCol where IntCol >= :1",
&[&6],
)?;
assert_eq!(stmt.row_count()?, 5); //update语句更新的行数
//获取到的行数
let mut stmt = conn.prepare("select * from TestStrings where IntCol >= :1", &[])?;
assert_eq!(stmt.row_count()?, 0); //未获取前
for _row in stmt.query(&[&6])? {}
assert_eq!(stmt.row_count()?, 5); //获取后