1 eXtremeDB简介
全世界第一款全内存嵌入式实时数据库,特别为高性能、低开销、稳定可靠的极速实时数据管理而设计。
内存数据库:将数据以程序直接使用的格式保存在主内存之中,不仅剔除了文件I/O的开销,也剔除了文件系统数据库所需的缓冲和Cache机制。其结果是相比于磁盘数据库,其速度提高成百上千倍,以至普通PC平台的硬件条件下就可以达到每个交易1微秒甚至更小的极限速度。
嵌入式数据库:以链接库的形式包含在应用程序之中,其开销只有50KB~120KB,剔除了数据复制及数据翻译的开销,缩短了应用程序的代码执行路径。 应用定制的API 应用程序对eXtremeDB数据库的操作接口是根据应用数据库设计而产生,这些动态的API剔除了通常数据库应用程序所必不可少的动态内存分配,不仅提升了数据库的实时性能,也提高了应用系统的可靠性。
1.1 eXtremeDB特点
- 内存+嵌入式
- 跨平台的实时数据解决方案(对操作系统、编译器和处理器没有依赖性)
- 无动态内存分配,避免内存泄漏等问题
- 提供磁盘定时保存数据库的功能(增量式磁盘镜像的eXtremeLog模块和内存镜像的eXtremeHA模块)
1.2 与其他数据库比较
数据库服务器架构 :通过数据库驱动程序如JDBC、ODBC等访问数据库服务器,数据库服务器再操作数据库文件(Oracle、、MySQL和SQL Server等)。允许非开发人员操作数据与程序分离,便于控制需要独立安装部署和管理。
嵌入式数据库: 直接将数据库的库文件链接到应用程序中。应用程序通过API访问数据库,而不是TCP/IP。只允许应用程序对其进行访问控制数据访问控制权限完全交给应用程序不需要单独部署服务器,与应用程序一起发布。
2 eXtremeDB基本概念
2.1 创建应用程序步骤
2.2 基本数据类型
2.3 访问数据方法
访问存储在数据库中对象的过程,主要方法有使用oid或者autoid,使用散列或树索引,按顺序遍历和使用历史版本。
2.3.1 oid
指定了保存类时会同时保存为该类声明的oid类型的一个oid,eXtremeDB在数据库中为oid维护了一个特殊的索引,通过该索引便可以通过oid值定位数据库中的对象,oid在一个数据库模式文件中只能声明一次。
2.3.2 autoid
与oid类似,但是autoid是在运行时期决定的值,每个autoid的值在数据库中是唯一的。autoid通常是autoid_t类型。
2.3.3 索引
使用散列和树索引作为数据库中对象的唯一标识符,与oid不同,只需要保证在类中唯一即可。
2.3.4 链表
不关心特殊顺序的遍历。
2.3.5 历史记录
通过histroy关键字维护该对象的不同版本的历史记录,每次更新该类的对象事务都会创建一个新版本的对象。
class Person
{
string name;
string address;
uint4 salary;
autoid_t<Person> manager;
list; // 链表遍历
autoid[1000]; // autoid遍历
tree<name> pk; // 在name上建立树索引
histroy[10]; // 保存最近10个版本的对象
};
2.4 数据库基础操作
2.4.1 写操作
1 创建一个数据库并连接,得到数据库句柄 mco_db_open() mco_db_connect()
2 打开一个"写"事务,得到事务句柄 mco_trans_start()
3 使用事务句柄,创建一个新的类对象,获得类句柄 类对象名_new()
4 使用类句柄,通过不同形式的"put"方式经应用程序的值赋给对象字段 类对象名_参数名_put()
5 提交或回滚事务 mco_trans_commit()
2.4.2 读操作
1 创建一个数据库并连接,得到数据库句柄 mco_db_open() mco_db_connect()
2 打开一个“读”事务,得到事务句柄 mco_trans_start()
3 使用事务句柄,调用某中访问方法:oid、链表、散列或树索引,若搜索成功则获得类句柄 类对象名_oid_fin
4 通过类句柄,使用"get"方法将数据库中存储的值赋给程序变量 类对象名_参数名_get()
5 提交事务 mco_trans_commit()
3 Java JDBC示例
3.1 创建数据库配置文件xsql.cfg
database_name : xsqldb,
database_size : 64m,
schema : "
#define int1 signed<1>
#define int2 signed<2>
#define int4 signed<4>
#define int8 signed<8>
#define uint8 unsigned<8>
#define uint4 unsigned<4>
#define uint2 unsigned<2>
#define uint1 unsigned<1>
declare database xsql;
class S
{
char<5> sid;
nullable char<20> sname;
nullable int4 status;
date dat;
char<15> city;
list;
autoid[1000];
hash<sid> pk[1000];
tree<sname> snk;
tree<status> stk;
};
",
sql_port : 5001
3.2 启动数据库
进入eXtremeDB安装目录下的/target/bin目录,执行以下指令
xsql -c xsql.cfg
-c 使用指定目录的配置文件
3.3 应用程序中引入jar包
jar包位于eXtremeDB安装目录下的/target/bin目录
3.4 程序
import java.sql.*;
/**
* @author 苏若墨
*/
public class SimpleJDBC
{
/**
* 数据库连接
*/
Connection con;
/**
* 记录条数
*/
static final int nRecords = 5;
public static void main(String[] args) throws Exception
{
new SimpleJDBC("jdbc:extremedb:localhost");
}
/**
* 操作函数,完成数据库基本操作
* @param url
* @throws ClassNotFoundException
* @throws SQLException
*/
public SimpleJDBC(String url) throws ClassNotFoundException, SQLException
{
String user = null;
String password = null;
// 1.加载驱动
Class.forName("com.mcobject.jdbc.McoDriver");
// 2.连接数据库
System.out.println("Connecting to Database URL = " + url);
con = DriverManager.getConnection(url, user, password);
System.out.println("Connected...");
// 3.数据库基本操作
insert();
select();
update();
delete();
// 4.关闭数据库连接
System.out.println("Now closing the connection");
con.close();
}
/**
* 插入数据
* @throws SQLException
*/
void insert() throws SQLException {
con.setAutoCommit(false);
PreparedStatement stmt = con.prepareStatement("insert into S (sid,sname,status) values (?,?,?)");
for (int i = 0; i < nRecords; i++) {
stmt.setString(1, "S" + i);
stmt.setString(2, "SN" + i);
stmt.setInt(3, 1);
stmt.execute();
}
stmt.close();
con.commit();
}
/**
* 选择数据
* @throws SQLException
*/
void select() throws SQLException {
con.setAutoCommit(true);
PreparedStatement pstmt = con.prepareStatement("select sid,sname,status from S where sid=?");
System.out.println("SID\tSNAME\tStatus");
for (int i = 0; i < nRecords; i++) {
pstmt.setString(1, "S" + i);
ResultSet result = pstmt.executeQuery();
while (result.next()) {
System.out.println(result.getString(1) + "\t" + result.getString(2) + "\t" + result.getInt(3));
}
}
pstmt.close();
System.out.println("--------------");
}
/**
* 更新数据
* @throws SQLException
*/
void update() throws SQLException {
PreparedStatement pstmt = con.prepareStatement("update S set status=? where sid=?");
for (int i = 0; i < nRecords; i++) {
pstmt.setInt(1, i);
pstmt.setString(2, "S" + i);
pstmt.execute();
}
pstmt.close();
System.out.println("SID\tStatus\n");
Statement stmt = con.createStatement();
ResultSet result = stmt.executeQuery("select sid,status from S order by sid desc");
while (result.next()) {
System.out.println(result.getString(1) + "\t" + result.getInt(2));
}
stmt.close();
}
/**
* 删除数据
* @throws SQLException
*/
void delete() throws SQLException {
Statement stmt = con.createStatement();
int nDeleted = stmt.executeUpdate("delete from S");
System.out.println("Remove " + nDeleted + " records");
}
}
3.5 运行结果
4 C语言操作示例
4.1 创建数据库模式文件 simpledb.mco
declare database simpledb;
struct B {
signed<1> i1;
signed<2> i2;
signed<4> i4;
float f;
char<10> c10;
};
class A {
unsigned<1> ui1;
unsigned<2> ui2;
unsigned<4> ui4;
double d;
numeric<10,3> num;
decimal<10,3> dec;
B b;
string s;
list;
};
4.2 编译数据库模式文件
进入/host/bin目录下,执行以下指令
mcocomp simpledb.mco
生成数据库相应的头文件和接口文件simpledb.h和simpledb.c
simpledb.h
simpledb.c
4.3 将mcolib.lib等必要库文件和上述接口文件加入工程中
4.4 程序处理
#include <stdio.h>
#include <common.h>
#include <simpledb.h>
const char * db_name = "operations";
int main(int argc, char* argv[]) {
MCO_RET rc;
sample_memory_t dbmem;
sample_os_initialize(DEFAULT);
// 1.开启数据库运行环境
mco_runtime_start();
sample_header("Sample 'operations' performs basic insert, read, and update operations.\n" );
// 2.打开数据库
rc = sample_open_database( db_name, simpledb_get_dictionary(), DATABASE_SIZE, CACHE_SIZE,
MEMORY_PAGE_SIZE, PSTORAGE_PAGE_SIZE, 1, &dbmem );
sample_rc_check("\tOpen", rc );
if ( MCO_S_OK == rc ) { // 2.1 若数据库打开成功
mco_db_h connection; /* 数据库连接句柄 */
// 3.连接数据库
rc = mco_db_connect( db_name, &connection );
sample_rc_check("\tConnect", rc );
if ( MCO_S_OK == rc ) { // 3.1 若数据库连接成功
mco_trans_h t; /* 事务句柄 */
// 4.开启写事务,向数据库中插入数据
rc = mco_trans_start(connection, MCO_READ_WRITE, MCO_TRANS_FOREGROUND, &t);
sample_rc_check("\tOpen Transaction", rc );
if ( MCO_S_OK == rc ) { // 4.1 若事务开启成功
A a; /* Object handle */
A_fixed _a; /* Fixed size part of class A */
B b; /* Struct handle */
B_fixed _b; /* Fixed size part of struct B */
uint1 ui1; /* Value place holders */
uint2 ui2;
uint4 ui4;
int1 i1;
int2 i2;
int4 i4;
mco_int8 i8;
float f = (float)1.1;
double d = 2.2;
char buf[16]; /* String buffer */
mco_cursor_t csr; /* 游标 */
/* 5.创建对象,向对象中各属性赋值*/
A_new ( t, &a );
/* Put values to scalar fields */
A_ui1_put ( &a, 1 );
A_ui2_put ( &a, 2 );
A_ui4_put ( &a, 3 );
A_d_put ( &a, d );
/* Put value to string field using db_name as a value */
A_s_put ( &a, db_name, (uint2)strlen( db_name ) );
/* Put int8 value to numeric field */
A_num_from_chars( &i8, "1234567");
A_num_put ( &a, i8 );
/* Put char array value to decimal field */
A_dec_to_chars( 987654321, buf, sizeof(buf));
A_dec_put_chars( &a, buf );
/* Get struct handle to write it */
A_b_write_handle ( &a, &b );
/* Put values to the struct fields */
B_i1_put ( &b, 4 );
B_i2_put ( &b, 5 );
B_i4_put ( &b, 6 );
B_f_put ( &b, f );
B_c10_put( &b, db_name, (uint2)strlen( db_name ) );
// 6.提交事务
rc = mco_trans_commit( t );
sample_rc_check("\tCommit Transaction", rc );
// 7.开启一个读事务
rc = mco_trans_start(connection, MCO_READ_ONLY, MCO_TRANS_FOREGROUND, &t);
if ( MCO_S_OK == rc ) { // 7.1 若事务开启成功
rc = A_list_cursor(t, &csr); // 8.创建list遍历的游标
if ( MCO_S_OK == rc ) {
mco_cursor_first(t, &csr); // 9.游标置开始
A_from_cursor(t, &csr, &a); // 10.游标遍历数据库对象
printf("\n\tContents of first record A: \n");
// 11.从数据库中获取值,并赋值给变量
/* Get values from the object fields */
A_ui1_get ( &a, &ui1 );
A_ui2_get ( &a, &ui2 );
A_ui4_get ( &a, &ui4 );
A_d_get ( &a, &d );
printf("\t\tui1=%d, ui2=%d, ui4=%ld, d=%f\n", ui1, ui2, ui4, d );
/* Get values from numeric/decimal fields */
A_num_get( &a, &i8);
A_num_get_chars( &a, buf, sizeof(buf));
printf("\t\tnum=%lld, chars(%s)\n", i8, buf );
A_dec_get( &a, &i8);
A_dec_get_chars( &a, buf, sizeof(buf));
printf("\t\tdec=%lld, chars(%s)\n", i8, buf );
/* Get string value into the buf and the value length into ui2 */
/* Note: the _get() will null-terminate the string only if the buffer is long enough */
A_s_get( &a, buf, sizeof(buf), &ui2);
printf("\tstring s=(%s), (length = %d)\n", buf, ui2);
/* Get struct read-handle */
A_b_read_handle ( &a, &b );
/* Get values of the structs fields */
B_i1_get ( &b, &i1 );
B_i2_get ( &b, &i2 );
B_i4_get ( &b, &i4 );
B_f_get ( &b, &f );
B_c10_get( &b, buf, sizeof(buf) );
printf("\tStruct b: b.i1=%d, b.i2=%d, b.i4=%ld, b.f=%f, b.c10=(%s)\n", i1, i2, i4, f, buf );
/* Get field values from A_fixed */
printf("\n\tUsing A_fixed :\n" );
A_fixed_get(&a, &_a);
printf("\t\t_a.ui1=%d, _a.ui2=%d, _a.ui4=%ld, _a.d=%f\n", _a.ui1, _a.ui2, _a.ui4, _a.d );
/* Get field values from B_fixed */
printf("\n\tUsing B_fixed :\n" );
B_fixed_get(&b, &_b);
/* Copy and null terminate the character string in _b.c10 */
strncpy(buf, _b.c10, 10);
printf("\t\t_b.i1=%d, _b.i2=%d, _b.i4=%ld, _b.f=%f, _b.c10=(%s)\n", _b.i1, _b.i2, _b.i4, _b.f, buf );
}
}
// 12.提交事务
rc = mco_trans_commit( t );
}
/* 13.关闭数据库连接 */
rc = mco_db_disconnect( connection );
sample_rc_check("\tDisconnect", rc );
}
/* 14.关闭数据库 */
sample_close_database( db_name, &dbmem );
sample_rc_check("\tClose", rc );
}
/* 15.关闭运行环境 */
mco_runtime_stop();
sample_pause_end("\n\nPress any key to continue . . . ");
sample_os_shutdown();
return ( MCO_S_OK == rc ? 0 : 1 );
}
4.5 运行结果