1、前言
SinoDB为适应IT技术的发展,引入支持JSON类型数据,用以支持NoSQL技术,使其将结构化数据和非结构化数据融合在一起,提供了一种混合数据库系统。SinoDB支持MongoDB的接口,可以使用MongoDB API来存储和操作NoSQL的JSON格式数据和关系型数据。SinoDB对SQL、NoSQL混合型应用支持灵活,应用平台广泛,可以实现关系型和非关系型数据库共存,减少迁移等带来的工作量,是应对超大规模和高并发数据的理想选择。
NoSQL是非关系型数据存储的广义定义,它打破了长久以来关系型数据库与ACID理论大一统的局面。NoSQL数据存储不需要固定的表结构,其数据存储方式满足横向伸缩的应用体系结构需求。
SinoDB支持使用SQL语句来存取NoSQL的JSON数据,也支持通过使用Mongo API来存取NoSQL的JSON数据,二者在数据库中的存储都是采用BSON(binaryJSON)类型。
SinoDB提供如下函数,用于支持使用SQL语句来操作NoSQL的JSON数据,如下:
bson_value_int(lvarchar doc, lvarchar key) returns bigint
bson_value_bigint(lvarchar doc, lvarchar key) returns bigint
bson_value_double(lvarchar doc, lvarchar key) returns float
bson_value_lvarchar(lvarchar doc, lvarchar key) returns lvarchar as string
bson_value_document(lvarchar doc, lvarchar key) returns lvarchar as BSON object
bson_value_array(lvarchar doc, lvarchar key) returns lvarchar as BSON array
bson_value_binary(lvarchar doc, lvarchar key) returns lvarchar as binary
bson_value_objectid(lvarchar doc, lvarchar key) returns lvarchar as string
bson_value_boolean(lvarchar doc, lvarchar key) returns boolean
bson_value_date(lvarchar doc, lvarchar key) returns datetime
bson_value_code(lvarchar doc, lvarchar key) returns lvarchar as string
bson_value_timestamp(lvarchar doc, lvarchar key) returns datetime
bson_key_exists(lvarchar doc, lvarchar key) returns Boolean
SinoDB提供Wire Protocol Listener程序,用于支持服务器上的MongoDB驱动。在SinoDB中,Wire Protocol Listener就像一个开关,打开数据库服务器上的监听程序后,可以使用Java、PHP、Python等语言通过MongoDB API来操作JSON数据。在应用层,数据操作采用JSON格式,Wire Protocol Listener程序会把接收到的JSON数据转换成SQL的形式,然后让数据库服务进行处理。
3 、SinoDB 操作NoSQL操作实践
3.1 SQL语句访问NoSQL的JSON数据
SinoDB支持JSON数据类型。这个新的数据类型可以通过SinoDB提供的内部函数,使其能被普通的SQL语句操作。例如:一个旅游系统中,某张表用来存储不同游客的观光信息,可以用JSON的数据来记录其观光地点——访问的城市、地区、岛屿、景点等。我们可以定义如下表:
create table places (
place_id SERIAL,
place BSON);
INSERT INTO places VALUES (1, '{city: "fuzhou", country: "China", population: 38000000}'::JSON);
INSERT INTO places VALUES (2, '{mountain: "Wuyishan", country: "China", height: 1000}'::JSON);
INSERT INTO places VALUES (3, '{national_park: "Summer Palace", country: "China"}'::JSON);
SELECT place_id, place::JSON FROM places
结果:
place_id1
(expression) {"city":"fuzhou","country":"China","population":38000000}
place_id2
(expression) {"mountain":"Wuyishan","country":"China","height":1000}
place_id3
(expression) {"national_park":"Summer Palace","country":"China"}
也可以在where条件中使用SinoDB提供的内部函数对NoSQL的JSON数据进行过滤:
SELECT *, place::JSON FROM places
WHERE bson_value_lvarchar (place, 'country') = 'China';
SELECT *, place::JSON FROM places
WHERE bson_value_lvarchar (place, 'country') IS NULL;
SELECT *, place::JSON FROM places
WHERE bson_value_lvarchar (place, 'mountain') IS NOT NULL
AND bson_value_int (place, 'height') >= 1000;
SELECT *, place::JSON FROM places
WHERE bson_value_lvarchar (place, 'country') = 'China'
AND bson_value_lvarchar (place, 'national_park') IS NOT NULL;
另外,SinoDB提供一个genBSON函数,用于从关系型数据中生成JSON的数据,这样就可以把关系型数据迁移到NoSQL中。例如:
create table cities (
city_id SERIAL,
city CHAR(30),
population INT,
country CHAR(30));
INSERT INTO places
SELECT 0, genBSON(ROW(city, country, population), 0, 1)::JSON
FROM cities;
当然,如果为了保持数据各自的独立性,我们也可以采用创建视图的方式:
CREATE VIEW places_and_cities (place) AS
SELECT place::JSON FROM places
UNION
SELECT genBSON(ROW(city, country, population), 0, 1)::JSON FROM cities;
SinoDB提供Wire Protocol Listener程序,用于支持服务器上的MongoDB驱动。通过使用JSON Wire Listener线程来访问JSON数据,使用的网络协议与MongoDB相同。该线程可将对JSON数据的操作转换成SQL语句及相应的函数调用。JSON Wire Listener原理图如下:
3.2.1 Wire Protocol Listener配置
在SinoDB安装目录的etc目录下,复制jsonListener-example.properties文件为jsonListener.properties文件,并修改文件中的URL及security.sql.passthrough参数。例如:
cp etc/jsonListener-example.properties etc/jsonListener.properties
vi jsonListener.properties
url=jdbc:informix-sqli://IP:port/sysmaster:INFORMIXSERVER=sinoregal;USER=informix;PASSWORD=informix
security.sql.passthrough=true
3.2.2 启动监听程序
java -cp $INFORMIXDIR/bin/jsonListener.jar com.ibm.nosql.server.ListenerCLI -config $INFORMIXDIR/etc/jsonListener.properties –start
3.2.3 Mongo Shell操作SinoDB NoSQL
在SinoDB中,创建table1集合,并用Mongo Shell插入数据到table1中。
创建集合指令:
db.createCollection("table1")
在集合table1中写入数据:
db.table1.insert({id:1, name:’mongo’});
db.table1.insert({id:2, name:’sinoregal’});
db.table1.insert({id:3, name:’DB2’});
db.table1.insert({id:4, name:’oracle’});
db.table1.insert({id:5, name:’mysql’});
查询table1集合指令:
db.table1.find(),返回如下结果:
{“_id”:ObjectId(“531d9a8b12w8wvb666d3442a”),”id”:1, “name”:”mongo”}
{“_id”:ObjectId(“531d9a8b12w8wvb666d3442b”),”id”:2, “name”:”sinoregal”}
{“_id”:ObjectId(“531d9a8b12w8wvb666d3442c”),”id”:3, “name”:”DB2”}
{“_id”:ObjectId(“531d9a8b12w8wvb666d3442d”),”id”:4, “name”:”oracle”}
{“_id”:ObjectId(“531d9a8b12w8wvb666d3442e”),”id”:5, “name”:”mysql”}
从以上可以看出,使用Mongo Shell操作SinoDB的NoSQL,可以直接采用MongoDB的指令。
3.2.4 MongoDB Java API操作NoSQL数据
通过MongoDB Java API操作NoSQL数据除了启动Wire Protocol Listener外,只需要在代码中引入mongo-java-driver-*.*.*.jar依赖包即可。用MongoDB Java API操作NoSQL数据只要按照MongoDB的语法即可,无需做任何变动。下面给出采用MongoDB Java API操作NoSQL的具体示例:
a、在java类中引用MongoDB相关类:
import com.mongodb.MongoClient;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
b、连接数据库,获取tab1的Collection
//连接到Mongodb服务
MongoClient mongoClient = new MongoClient("192.168.216.123",27017);
// 连接到数据库
MongoDatabase db = mongoClient.getDatabase("stores_demo");
//获取tab1的Collection
MongoCollection<Document> collection = db.getCollection("tab1");
c、插入数据
MongoCollection<Document> collection = mongoDatabase.getCollection("tab1");
//插入文档/**
* 1. 创建文档 org.bson.Document 参数为key-value的格式
* 2. 创建文档集合List<Document>
* 3. 将文档集合插入数据库集合中 mongoCollection.insertMany(List<Document>)
* 插入单个文档可以用 mongoCollection.insertOne(Document)**/
Document document = new Document("title", "mongo")
.append("description", "database")
.append("likes", 100).append("by", "Fly");
List<Document> documents = new ArrayList<Document>();
documents.add(document);
collection.insertMany(documents);
d、查询数据
MongoCollection<Document> collection = mongoDatabase.getCollection("tab1");
//检索所有文档/**
*1. 获取迭代器FindIterable<Document>
*2. 获取游标MongoCursor<Document>
*3. 通过游标遍历检索出的文档集合 **/
FindIterable<Document> findIterable = collection.find();
MongoCursor<Document> mongoCursor = findIterable.iterator();
while(mongoCursor.hasNext()){
System.out.println(mongoCursor.next());}
e、删除数据
MongoCollection<Document> collection = mongoDatabase.getCollection("tab1");
//删除符合条件的个文档
collection.deleteOne(Filters.eq("likes", 200));
//删除所有符合条件的文档
collection.deleteMany(Filters.eq("likes", 200));
f、更新数据
MongoCollection<Document> collection = mongoDatabase.getCollection("tab1");
//更新文档 将文档中likes=100的文档修改为likes=200
collection.updateMany(Filters.eq("likes", 100), new Document("$set",new Document("likes",200)));
SinoDB通过引入支持JSON类型数据,使结构化和非结构化数据能够在一个数据库中统一共存,提供了一种混合数据库系统,并支持绝大部分NoSQL功能。由此可见,SinoDB适用于混合型数据应用场景,开拓了新的业务模式,同时也为开发带来便捷。