总览
介绍
DB2JSON可用于DB2 Linux,Unix和Windows 10.5以及用于z / OS V3.1的IBM DB2 Accessories Suite与DB2 for z / OS V10一起使用。 它提供以下功能:
- 用于管理和查询JSON数据的命令行外壳
- 用于应用程序开发的Java™API
- 有线侦听器接受并响应通过网络发送的请求。
图1. DB2 JSON组件
本文介绍了如何使用Java接口来管理和查询DB2 JSON文档存储中的JSON文档。 它还讨论了可用的ACID支持的某些方面以及将事务支持选项与增加吞吐量的选项结合使用的限制。
先决条件
要运行示例应用程序,您必须在系统上至少安装了Linux,UNIX和Windows的IBM DB2 10.5,或者使用IBM DB2 Accessories Suite for z / OS V3.1来启用DB2 for z / OS。 V10作为JSON数据存储区。
如果您已经具有可用于运行示例的启用JSON的DB2数据库,请记下主机名或IP地址和端口号,然后继续Terminology 。 否则,请根据您的数据库平台检查并完成以下步骤。
Linux,UNIX和Windows上的IBM DB2
- 查看环境变量:
- 确保PATH中包含Java运行时环境(最低JRE 1.5),
- 并且CLASSPATH包含db2nosql.jar和JDBC驱动程序(3.66或更高版本的db2jcc.jar或db2jcc4.jar)。
- 创建一个数据库。
- 启用数据库。
以下示例显示了如何创建和启用数据库。
清单1.创建并启用数据库
CREATE DATABASE jsondb automatic storage yes using codeset utf-8
territory US collate using system pagesize 32 k
db2nosql -user bob -hostName bobshost -port 50000 -db jsondb -password mypwd -setup enable
另请参阅本系列的第2部分, 使用命令行界面 。
IBM DB2 z / OS版
应用程序可以在分布式系统平台上使用DB2 JSON API或DB2 JSON WireListener,并使用DB2 Connect JDBC驱动程序将DB2 for z / OS用作JSON数据存储。
此部署方案需要以下组件:
- 带有DB2 JSON和DB2驱动程序组件的DB2 10.5 FP3(或更高版本),用于Linux,Unix和Windows服务器或客户机安装。 安装后,这些组件位于SQLLIB / json中。
- DB2附件套件V3.1。
- 具有必需的APAR的DB2 for z / OS版本10:有关先决条件和DB2 JSON与DB2 for z / OS一起安装的详细信息,请参阅APAR II14727。
使用DB2 for z / OS,启用数据库将由DB2 for z / OS数据库或系统管理员作为一次性安装任务执行。 z / OS不支持通过db2nosql命令行工具启用该功能。 有关使用DB2 z / OS版启用DB2 JSON的详细信息,请参见APAR PM98357。
在分布式系统上对数据库进行分类,并记下用于DB2 JSON客户端的z / OS上的连接信息或DB2数据库的URL。
术语
- JSON存储:充当JSON文档存储的DB2数据库。 在开始使用IBM JSON解决方案来处理JSON文档之前,您需要获取必要的连接和授权信息,以访问作为JSON存储的DB2数据库服务器。
- JSON名称空间: DB2 SQL模式用于完全限定集合,并且在概念上类似于MongoDB数据库。
- JSON集合:集合包含一组文档,并在DB2表中表示。 JSON集合支持灵活的文档架构; 他们不执行结构。
一个简单的Java应用程序样本
从本文的可下载资源部分下载Sample.java。 要在db2cmd窗口中运行此示例程序,请完成以下步骤:
- 设置CLASSPATH:将nosqljson.jar和db2jcc.jar或db2jcc4.jar包含到类路径中。
- 在Windows上:
假设db2jcc.jar位于C:\ Program Files \ IBM \ SQLLIB \ java目录中,而nosqljson.jar位于C:\ Program Files \ IBM \ SQLLIB \ json \ lib目录中,则按如下所示设置CLASSPATH:set CLASSPATH=.;C:\Program Files\IBM\SQLLIB\java\db2jcc.jar; C:\Program Files\IBM\SQLLIB\json\lib\nosqljson.jar
- 在UNIX上:
假设db2jcc.jar位于/ sqllib / java目录中,而nosqljson.jar位于/ sqllib / json / lib目录中,则按如下所示设置CLASSPATH:export CLASSPATH=.:/sqllib/java/db2jcc.jar:/sqllib/json/lib/nosqljson.jar
- 在Windows上:
- 创建一个测试目录,并将示例程序复制到该测试目录中。
- 修改示例程序以适应数据库名称和连接信息。
- 在此测试目录中编译并运行Java示例程序。
- 编译示例程序:
javac Sample.java
- 要运行Java示例程序:
java Sample
- 编译示例程序:
带注释的Java示例程序
此示例程序插入一个文档,并提交查询以再次找到它。 有关完整的示例代码,请参见Sample.java 。
- 获取
DB
对象。
请注意,DB2使用SQL模式作为JSON名称空间来构建完全限定的集合名称。 因此,应该使用连接信息和所需的名称空间(DB2模式)来获取DB
对象。DB db = NoSQLClient.getDB (databaseUrl, user, password, ns);
- 获取收集句柄。
该集合在DB2中表示为一个表。 但是,将不会通过获取集合句柄来创建集合。 相反,如果该集合不存在,则将在插入第一个文档时自动创建该集合。 在此示例中,稍后将使用此隐式方法创建集合。 要显式创建一个集合,请使用方法db.createCollection(name, indexSpec)
。DBCollection col = db.getCollection ("books");
- 插入文件。
尝试插入文档时,如果集合不存在,则会自动创建该集合。 还要注意,如果文档不包含_id字段,则将使用具有生成的二进制标识符的主键来创建集合。 如果随后插入的文档包含_id字段,则该_id字段的数据类型必须与生成的_id的数据类型匹配。BasicDBObject json = new BasicDBObject (); json.append ("author", "Smith"); json.append ("title", "My first book"); System.out.println ("Inserting: " + json); col.insert (json);
- 提交查询。
使用所需的搜索条件构建一个对象,并为该集合调用find方法。 在第一次调用hasNext()时执行查询,结果可通过游标获得。 请注意,查询没有投影列表,因此结果将包括所有属性,包括生成的标识符。DBCursor cursor = col.find (new BasicDBObject ("author", "Smith")); try { while (cursor.hasNext ()) { DBObject obj = cursor.next (); System.out.println ("Retrieved: " + obj); } } finally { cursor.close (); } } }
预期样本输出:
- 插入:
{"author":"Smith","title":"My first book"}
- 检索:
{"_id":"$oid":"51bf710b416e9107ff9bc734"}, "author":"Smith","title":"My first book"}
基本概念
DB2 JSON Java API中的JSON对象
JSON命名空间: DB
对象
获取DB
对象的句柄以访问JSON存储。 DB
对象代表一个特定的JSON名称空间(DB2模式)。 例如,它可用于创建和删除集合,启动和提交事务,批量插入JSON文档等。 所有DB
对象都在内部缓存,因此可以重复使用。
有几种方法可以通过编程方式获取DB
对象的句柄。
- 使用JDBC DataSource对象:
javax.sql.DataSource ds =(javax.sql.DataSource)InitialContext.lookup("jdbc/DB2"); com.ibm.json.nosql.DB db = NoSQLClient.getDB (ds);
数据库对象基于数据源作为键在内部缓存。
- 使用JDBC URL:
com.ibm.json.nosql.DB db = getDB(jdbcUrl);
数据库对象基于url + user作为键在内部缓存。
- 使用JDBC连接对象:
java.sql.Connection con = java.sql.DriverManager.getConnection(jdbcurl, user, password); com.ibm.json.nosql.DB db = NoSQLClient.getDB(con);
数据库对象基于url + user作为键在内部缓存。
JSON集合: Collection
对象
使用DB2 JSON功能,JSON文档被组织在集合中。 JSON集合不强制执行文档结构,只是需要文档标识符才能唯一标识每个文档。 因此,不必像关系表一样为集合定义表结构。 尽管如此,集合中的文档通常具有共同的特征,以使其更易于查找和分组数据。
- 获取集合对象的句柄
实际的集合可能会或可能不会实际存在。 例如:DBCollection coll = db.getCollection( "employee" );
- 隐式创建集合
如果不存在集合,则在插入第一个JSON文档时将使用默认设置自动创建该集合。 在示例中,该员工的名字为“ Joe”。 插入操作返回一个
WriteResult
,其中包装了执行状态和消息。 例如:DBCollection employee = db.getCollection( "employee" );
BasicDBObject operson = new BasicDBObject("firstname", "Joe");
WriteResult wr = employee.insert(operson); - 显式创建一个集合
可以使用默认设置自动创建收藏集。 但是,通常需要使用自定义设置显式创建集合。 要创建一个集合,请使用
createCollection()
方法,如下所示。 可选特征可以包括用于标识符,表空间和缓冲池使用,压缩等数据类型的指令。注意,DB2 for z / OS中的JSON集合不支持双向功能和时间旅行查询。 一些限制也适用于集合存储特征,例如,DB2 for z / OS的createCollection命令当前不支持TABLESPACE选项。
有关详细信息,请参见参考文档。 例如:
// create a collection with this name and default characteristics DBCollection em1 = db.createCollection( "employee1" ); // create a collection "employee1" with integer identifiers DBCollection dtc = _db.getCollection ("employee1"); dtc.createCollection ("{_id:'$int'}");
- 重命名集合
可以将现有集合重命名为新名称。 例如:
DBCollection em1 = db.getCollection( "employee1" );
DBCollection em2 = em1.rename("employee2"); - 删除收藏集
可以从JSON存储中删除现有集合。 例如:
DBCollection c = db.getCollection( "employee" ); c.drop();
JSON字段: DBObject
对象
DBObject
可用于从键值对构建JSON文档。 API将数据转换为类似BSON的格式,然后将其发送以存储到数据库服务器。 检索后,API会将类似于BSON的二进制数据转换回DBObjects,从而保留数据类型。
注:存储格式严格遵循BSON规范,但包含某些IBM特定的扩展。
DBObject
中的键始终为String类型。 对于数据值,DB2 JSON API支持多种数据类型,如下表所示。
表1.数据类型
数据类型 | JSON格式的示例 |
---|---|
java.lang.String | “串” |
java.lang.Integer | 3 |
java.lang.Long | 4294967296 |
java.lang.Double | 6.2 |
java.lang.Boolean | 真假 |
java.lang.Byte [] | {“ $ binary”:“(base64编码的值)”,“ $ type”:“ 0”} |
java.util.Date(毫秒精度,UTC) | {“ $ date”:“ 1998-03-11T17:14:12.456Z”} |
java.util.regex.Pattern | {“ $ regex”:“ ab *”,“ $ options”:“”} |
java.util.UUID | {“ $ uuid”:“ fb46f9a6-13df-41a2-a4e3-c77e85e747dd”} |
com.ibm.nosql.bson.types.ObjectId | {“ $ oid”:“ 51d2f200eefac17ea91d6831”} |
com.ibm.nosql.bson.types.Code | {“ $ code”:“ mycode”} |
com.ibm.nosql.bson.types.CodeWScope | {“ $ code”:“ i = i + 1”,“ $ scope”:{}} |
com.ibm.nosql.json.api.BasicDBObject | {“ a”:1,“ b”:{“ c”:2}} |
com.ibm.nosql.json.api.BasicDBList | [1、2,“ 3”,“ abc”,5] |
对于日期字符串值,客户机将值转换为UTC以存储在DB2中,并且还以UTC格式将其检索为Date。
下面的示例演示如何插入具有不同数据类型的字段值。
清单2.将具有各种数据类型的JSON文档作为DBObject
BasicDBObject jsonObj = new BasicDBObject ();
jsonObj.append ("_id", new ObjectId ("51d2f200eefac17ea91d6831"));
SimpleDateFormat df = new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
df.setCalendar (Calendar.getInstance (TimeZone.getTimeZone ("UTC")));
try {
jsonObj.append ("date", df.parse ("1998-03-11T17:14:12.456Z"));
}
catch (ParseException e) {
e.printStackTrace();
}
jsonObj.append ("pattern", Pattern.compile ("ab*", BSON.regexFlags ("")));
jsonObj.append ("code", new Code ("mycode"));
jsonObj.append ("codews", new CodeWScope ("i=i+1", new BasicBSONObject ()));
jsonObj.append ("null", null);
jsonObj.append ("uuid",
UUID.fromString ("fb46f9a6-13df-41a2-a4e3-c77e85e747dd"));
jsonObj.append ("str", new String ("hello world"));
jsonObj.append ("int", new Integer (3));
jsonObj.append ("long", new Long (4294967296L));
jsonObj.append ("double", new Double (6,2));
jsonObj.append ("bool", new Boolean (true));
jsonObj.append ("subobject",
new BasicDBObject ()
.append ("a", 1)
.append ("b", new BasicDBObject ().append ("c", 2))
);
jsonObj.append ("array",
new BasicDBList (1, 2, "3", "abc", 5)
);
jsonObj.append ("objarray",
new BasicDBList (
new BasicDBObject ().append ("name", "Joe").append ("age", 5),
new BasicDBObject ().append ("name", "Mary").append ("age", 4)
));
System.out.println ("Inserting: " + jsonObj);
c.insert (jsonObj);
除了将键值对创建为DBObjects之外,还可以以字符串格式插入JSON文档。 API将在内部将输入字符串解析为对象。 下面的示例演示如何在字符串表示中插入具有不同数据类型的字段值。
清单3.插入具有各种数据类型的JSON文档作为字符串
String jsonString =
"{"
+ "_id : { $oid : \"51d2f200eefac17ea91d6831\" },"
+ "date : { $date : \"1998-03-11T17:14:12.456Z\" },"
+ "pattern : { $regex : \"ab*\" , \"$options\" : \"\" },"
+ "code : { $code : \"mycode\"},"
+ "codews : { $code : \"i=i+1\" , \"$scope\" : { }},"
+ "null : null,"
+ "uuid : { $uuid : \"fb46f9a6-13df-41a2-a4e3-c77e85e747dd\" },"
+ "str : \"hello world\","
+ "int: 3,"
+ "long : 4294967296,"
+ "double : 6.2,"
+ "bool : true,"
+ "subobject:{ a:1, b:{ c: 2 } },"
+ "array : [1 , 2, \"3\", \"abc\", 5],"
+ "objarray : [{name:\"Joe\", age:5}, {name:\"Mary\", age:4}]"
+ "}";
System.out.println ("Inserting: " + jsonString);
c.insert (jsonString);
输出(为便于阅读而格式化):
清单4.将JSON文档作为字符串插入的输出
Inserting: {_id : { $oid : "51d2f200eefac17ea91d6831" },
date : { $date : "1998-03-11T17:14:12.456Z" },
pattern : { $regex : "ab*" , "$options" : "" },
code : { $code : "mycode"},
codews : { $code : "i=i +1" , "$scope" : { }},
null : null,
uuid : { $uuid : "fb46f9a6-13df-41a2-a4e3-c77e85e747dd" },
str : "hello world",
int: 3,
long : 4294967296,
double : 6.2,
bool : true,
subobject:{ a:1, b:{ c: 2 } },
array : [1 , 2, "3", "abc", 5],
objarray : [{name:"Joe", age:5}, {name:"Mary", age:4}]}
文件操作
插入JSON文档
DB2 JSON API提供了DBCollection.insert()
函数,用于在DB2中插入JSON文档。 每个文档都以类似于BSON的格式存储为BLOB,并且具有唯一的标识符。
当将文档插入集合中时,DB2 JSON API将自动创建表(如果该表不存在)。 在这种情况下,如果插入的第一个文档包含_id字段,则该字段将用作唯一标识符。 如果第一个文档不包含_id字段,则将自动生成一个唯一标识符,并使用该生成的_id插入文档。 无论哪种情况,随后插入的文档都必须还包含相同数据类型的唯一_id字段。 例如:
清单5.将文档插入集合
DB db = NoSQLClient.getDB (jdbcUrl, user, pass);
DBCollection c = db.getCollection ("books");
// Create a document to insert
BasicDBObject json = new BasicDBObject ();
json.append ("isbn", "123-456-789");
json.append ("author", "Verne, Jules");
json.append ("title", "Journey to the Center of the Earth");
json.append ("abstract", "Classic science fiction novel in an unusual setting");
json.append ("price", 6.00);
json.append ("pages", 276);
json.append ("category", "Fantasy");
System.out.println ("Inserting: " + json);
// If the table "books" does not exist, it is automatically created
c.insert (json);
输出(为便于阅读而格式化):
清单6.格式化的输出
Inserting: {"isbn":"123-456-789",
"author":"Verne, Jules",
"title":"Journey to the Center of the Earth",
"abstract":"Classic science fiction novel in an unusual setting",
"price":6.0,
"pages":276,
"category":"Fantasy"}
查找JSON文档
DBCollection
提供了几个选项来对集合中的数据进行计数,查找和聚合。 您可以指定文档需要匹配的条件(查询),并确定应检索哪些属性(投影列表)。
要指定投影列表,请使用0排除属性,使用1包括属性。 您不能混合使用包含和排除,除非要排除_id,否则_id总是自动包含在内。
返回DBCursor
方法还允许通过游标指令控制结果集,包括设置结果集的最大大小( limit(n)
)和分页( skip(n)
)。
请注意, DBCursor
对象表示只对游标进行迭代的结果,并且仅与next
/ hasNext
一起执行。
以下清单显示了一些如何搜索JSON文档的示例。 有关受支持的比较运算符和布尔运算符的列表,请参阅参考文档,还请参阅使用命令行界面系列的第2部分。
清单7.搜索文档
// Find all documents with author 'Verne, Jules'
DBCursor cursor = col.find (new BasicDBObject ("author", "Verne, Jules"));
// Find all documents with author 'Smith' and price greater 6.20;
// include title and price (the _id is automatically included)
BasicDBObject match = new BasicDBObject();
match.append("author", "Smith");
match.append("price", new BasicDBObject("$gt", 6.20));
BasicDBObject projection = new BasicDBObject();
projection.append("title", 1);
projection.append("price", 1);
DBCursor cursor2 = col.find (match, projection);
// Re-use the query, but exclude the _id
projection.append("_id", 0);
cursor = col.find (match, projection);
// Find books with sales greater 1000, sort by sales, get first 2 only
BasicDBObject fproject = new BasicDBObject("author", 1);
fproject.put ("title", 1);
fproject.put ("sales", 1);
fproject.put ("rating", 1);
BasicDBObject cond = new BasicDBObject("sales", new BasicDBObject("$gt",1000));
DBCursor fcursor = dtc.find(cond, fproject);
fcursor.sort (new BasicDBObject("sales", 1));
fcursor.limit (2);
while (fcursor.hasNext()) {
System.out.println(fcursor.next());
}
// Count entries where sales are less than 1000
long count = dtc.getCount (new BasicDBObject ("sales",
new BasicDBObject("$lt",1000)));
// Find distinct authors
List result = dtc.distinct("author");
// Get distinct data sorted by author, get first 2 entries only
BasicDBObject query = new BasicDBObject ("topic", "Mystery");
BasicDBObject keyObject = new BasicDBObject("author", 1);
keyObject.put ("rating", 1);
DBCursor dcursor = dtc.distinctAsCursor(keyObject, query);
dcursor.sort (new BasicDBObject("author", 1));
while (dcursor.hasNext()) {
System.out.println(dcursor.next());
}
要访问嵌套对象或数组中的值,请对数组值使用点符号,即属性名称后跟位置(从0开始)。 例如,对于数组[1,2,“ 3”,“ abc”,5],array.3的值为“ abc”。
要访问嵌套对象中的值,请用点符号指定完整路径。 例如,对于像{customer:{name:{“ Joe”},{state:“ AZ”}}这样的嵌套文档,customer.state的值为“ AZ”。
更新JSON文档
DB2 JSON API还提供DBCollection.update()
函数来更新满足搜索条件的JSON文档。 文档中的特定字段可以更新或附加,也可以替换整个文档。 下面的示例显示对“ isbn”为“ 123-456-789”的文档的“页面”字段的更新。
清单8.使用$ set运算符更新特定字段
DB db = NoSQLClient.getDB (jdbcUrl, user, pass);
DBCollection c = db.getCollection ("books");
// Update
c.update (new BasicDBObject ("isbn", "123-456-789"),
new BasicDBObject ("$set", new BasicDBObject ("pages", 299)),
false,
true);
// Find document
cursor = c.find (new BasicDBObject ("isbn", "123-456-789"));
System.out.println ("Retrieved: " + cursor.next ());
cursor.close ();
清单9.输出(为便于阅读而格式化)
Retrieved: {"_id":{"$oid":"51a7a4d9cd862910f0992b33"},
"isbn":"123-456-789",
"author":"Verne, Jules",
"title":"Journey to the Center of the Earth",
"abstract":"Classic science fiction novel in an unusual setting",
"price":6.0,
"pages":299,
"category":"Fantasy"}
如果将update(upsert)的第三个参数设置为true,则文档将为:
- 如果文档存在则更新,或者
- 如果不存在则插入。
如果将update(multi)的第四个参数设置为true,则将更新与查询匹配的所有文档。 如果将其设置为false,则仅更新与查询匹配的第一个文档。
如果该字段存在,则$set
运算符将旧值替换为新值; 否则,它将字段插入文档中。 $unset
运算符可用于删除特定字段。
警告:不使用$ set或$ unset运算符使用更新将用指定的字段替换文档的内容。 如果打算在文档中保留其他字段,请确保使用$ set或$ unset。
删除或删除JSON文档
DBCollection.remove()
函数从集合中删除JSON文档。 remove
功能还使用查询对象来定义条件,以指定要删除的文档子集。 集合和所有索引都会保留。
例如,要从集合“书”中删除所有文档,请使用:
DB db = NoSQLClient.getDB (jdbcUrl, user, pass);
DBCollection c = db.getCollection ("books");
c.remove ();
导入或导出JSON文件
可以将集合数据导入到集合中,也可以从集合中导出数据。 使用的格式是JSON,文件使用.js扩展名。
要导入集合,请使用importFile
方法:
DBCollection dtc = dtc.getCollection("docs");
dtc.importFile("C:/docs.js",10);
该方法找到名为docs.js的文件,并以10的提交频率导入内容。减少提交频率,即降低提交频率,可以提高导入性能。
导入逐行读取每个文件; 因此,在文档中必须避免回车和此类行结束符。 对于不符合JSON格式标准的每一行,对于包含重复标识符或标识符与数据类型与集合所期望的数据类型不同的文档,都将引发错误。 但是,处理将继续到下一行并导入有效数据。
用当前文档中的这个结构集合:
Row 1:
{
"_id":1,
"x":1
}
...以及导入文件中的文档,如下所示:
{"_id":"abc","abstract":"Spiders and Dragons","author":"Tolkien, JR","isbn":"122-456-789","pages":216, "price":5.0,"title":"The Hobbit"}
...导入将引发转换错误,因为集合的_id是整数,书的_id是字符串。
导入期间将保留文档的结构,包括任何嵌套的文档。
要将集合导出到文件中,请调用exportFile
方法:
DBCollection dtc = dtc.getCollection("docs");
dtc.exportFile("C:/exported.js")
这会将“ docs”集合导出到名为“ exported.js”的文件中。 导出的文件将是标准的JSON文件。
使用索引
当JSON文档中的字段经常用作查询中的选择条件时,在该字段上创建索引可以加快较大工作量的数据检索时间。
为了使索引有效,它应该具有高度的选择性(字段值应该大部分是唯一的)。 更具选择性的字段需要较少的索引读取才能找到满足查询条件的文档。
索引可以提高检索性能,但是会降低写入和存储的速度。 由于每次操作都需要更新索引,因此频繁更新的文档上的索引太多会减慢插入,更新和删除的速度。
创建索引
创建集合时,标识符上的索引会自动创建为唯一索引。 要为其他字段添加索引,请使用DBCollection.ensureIndex()
函数。 可以在单个字段或多个字段上创建索引。
注:对于Linux,Unix和Windows上的DB2,索引可以按升序和降序排列,并且支持索引数组中的元素。 使用DB2 for z / OS,索引只能以升序排列,并且不支持阵列上的索引。
要创建索引,需要指定要建立索引的字段的数据类型。 如果查询中的搜索值的类型不同于索引所指定的类型,则该索引将不用于查询执行。
在下面的示例中,由于字段“ copy”不是数组或包含在数组中,因此索引选项array
设置为false
。
清单10.在整数类型为“ copy”的字段上创建一个升序索引
DB db = NoSQLClient.getDB (jdbcUrl, user, pass);
DBCollection c = db.getCollection ("books");
// insert 100 books, with different values for field 'copy'
for (int i = 1; i <= 100; i++)
{
BasicDBObject json = new BasicDBObject ();
json.append ("isbn", "123-456-711");
json.append ("author", "Verne, Jules");
json.append ("title", "Journey to the Center of the Earth");
json.append ("abstract", "Classic science fiction novel in an unusual setting");
json.append ("price", 6.00);
json.append ("pages", 276 + i);
json.append ("category", "Fantasy");
json.append ("copy", i);
System.out.println ("Inserting: " + json);
c.insert (json);
}
// create index on field 'copy'
c.ensureIndex (
// 1 for ascending, $int is data type
new BasicDBObject ("copy", new BasicDBList (1, "$int")),
// index option 'array' explicitly set to false
new BasicDBObject ("array", false));
// find document where 'copy' = 1
DBCursor cursor = c.find (new BasicDBObject ("copy", 1));
// call to DBCursor.next() will execute the query and utilize the index
System.out.println ("Retrieved: " + cursor.next ());
cursor.close ();
如果需要唯一索引,则可以将unique
索引选项设置为true
。 如果存在现有文档,请确保同一字段没有重复的值。
删除索引
要删除索引,请使用DBCollection.dropIndex()
函数。
以下示例将dropIndex()
与创建索引时使用的规范相同。
c.dropIndex (new BasicDBObject ("copy", new BasicDBList (1, "$int")));
注意:函数DBCollection.removeIndex()
也将删除索引。
性能功能和交易
懒惰获取
使用DBCollection.find()
方法的查询将返回一个DBCursor
对象,该对象表示迭代结果的仅前向游标。 默认情况下,查询使用一种方法,将所有选定的数据急切地提取到内存中。 要在迭代游标时获取较大结果的块,请使用惰性读取( DBCursor.lazyFetch()
)。
注意:必须先指定延迟读取,然后再打开游标。 在获取结果后关闭游标很重要; 否则可能会发生内存泄漏。
下面的示例显示如何在游标上设置延迟获取选项。
清单11.使用惰性获取来检索JSON文档
DB db = NoSQLClient.getDB (jdbcUrl, user, pass);
DBCollection c = db.getCollection ("customer");
DBCursor cur = c.find ().lazyFetch (); // specify lazy fetch
try
{
// iterate through all documents
while (cur.hasNext ())
{
// not pre-fetching, we fetch as we go
DBObject cust = cur.next ();
System.out.println (cust);
}
}
finally
{
// make sure to close the cursor to prevent leaks
cur.close ();
}
交易次数
有两个选项可以连接到DB2 JSON存储,或者通过使用提供的连接信息显式建立的单模式连接,或者通过共享连接池。
默认情况下,使用连接池,并且诸如insert()
, update()
等操作将尝试从池中获取连接,使用该连接执行操作,并在完成后将其返回到池中。
对于单模式连接,DB2 JSON API允许在处理JSON文档时控制事务行为。 因此,可以在一个事务中组合多个操作,控制自动提交行为,并在发生错误时触发回滚。
表2. DB
上控制事务行为的方法
public void startTransaction() | 如果需要,获取连接,将auto-commit设置为false。 如果正在使用连接池或数据源,则将数据库置于单连接模式,直到以后的commitTransaction()或rollbackTransaction()为止。 |
public void commitTransaction() | 提交由startTransaction()启动的事务。 |
public void rollbackTransaction() | 回滚由startTransaction()启动的事务。 |
public void setAutoCommit(boolean autoCommit) | 如果DB2使用单一连接模式,则设置自动提交。 在数据源模式下调用此方法是错误的。 |
注意:下表中描述的事务API不适用于“即发即忘”模式。
建议在使用事务API时明确获得单模式连接,以避免启动事务将连接池模式强制更改为单模式的情况。
以下示例说明了如何使用DB2 JSON API在Java程序中获取单模式连接并提交事务。 成功执行db.commitTransaction()
,客户Joe的文档和带有Joe的冰箱订单的文档将分别插入到客户和订单集合中。 如果任何文档发生错误,则不会插入任何文档。 使用这些API,可以保证将插入所有文档或不插入任何文档。
清单12.具有单模式连接的事务
// use the url, user and password to create a JDBC connection.
Connection con = DriverManager.getConnection (url, user, password);
// get a db object with this connection
DB db = NoSQLClient.getDB (con);
// get a handle to the affected collections
DBCollection dtc = db.getCollection("customer");
DBCollection dto = db.getCollection("order");
// start a transaction for this db object.
db.startTransaction ();
try{
// Create JSON object:
BasicDBObject json = new BasicDBObject ();
json.append ("name", "Joe");
json.append ("cid", 12);
dtc.insert(json);
json = new BasicDBObject ();
json.append ("product", "refrigerator");
json.append ("cid", 12);
dto.insert(json);
db.commitTransaction ();
} catch (Exception ex) {
db.rollbackTransaction();
} finally{
}
发射后忘记模式
“即发即弃”模式启用多线程异步插入,并且可以在集合上进行设置以增强插入的性能。 使用此模式的不利之处是不能保证将数据写入服务器。 此外,如果在插入过程中确实发生了错误,则应用程序将不会引发异常。 但是,对于可以忍受数据丢失的应用场景,使用此模式可以提高性能。
仅当应用程序使用连接池时,才能激活即发即弃模式。 如果应用程序启用了触发功能并且忘记了单个连接,则将忽略模式设置,并且插入将以单线程执行。
默认情况下,用于解雇的线程数为10。 可以通过在nosql.properties文件中设置asyncMaxThreadCount
来更改此值。 例如,要将线程数设置为100,请使用nosql.asyncMaxThreadCount=100
。
要启用即发即WriteConcern
模式,集合必须将WriteConcern
值设置为NONE
或NORMAL
。 其他WriteConcern
值(例如SAFE
和JOURNAL_SAFE
禁用即发即JOURNAL_SAFE
模式,因为它们可以保证写入数据库。 有关WriteConcern
更多信息,请参见Java文档。
在以下示例中,从数据库对象_db
获得了映射到名为“ firenforget”的集合的集合句柄dtc
。 当使用选项NONE
调用dtc.setWriteConcern
,将启用即发即忘模式。
DBCollection dtc = _db.getCollection("firenforget");
dtc.setWriteConcern (WriteConcern.NONE);
要开始以“插入”和“忘记”模式插入,请使用与其他插入模式相同的插入代码:
for(int i=0; i>100; i++){
DBObject obj = BasicDBObjectBuilder.start().
append("name", "Joe"+i).
add("nums", new BasicDBList(i+1, i+2, i+3)).get();
dtc.insert(obj);
}
_db.waitQueue();
上面的代码将使用多个线程插入100个文档。 该代码类似于非触发和忘记模式插入,但是,请注意以下语句:
_db.waitQueue()
该应用程序将等待,直到所有插入都已处理完毕,并且只有在插入完成后,应用程序中对该集合的后续引用才会访问该集合。 如果没有此方法,则调用搜索,例如DBCursor cursor = dtc.find(new BasicDBObject("nums", 1));
可能返回空集合,因为在执行find()
方法之后,插入可能尚未完成。
上面示例中的代码忽略了潜在的插入错误。 要检索在处理过程中可能发生的插入错误,请使用getLastError()
方法,如以下示例所示。
WriteResult wr = dtc.insert(obj);
CommandResult cr = wr.getLastError ();
有关火灾和遗忘模式的更多详细信息,请参阅DB2 JSON API的Java文档中的WriteResult
类和DBCollection
类。
批处理
批处理会累积文档,然后将多个文档一起发送到JSON存储,而不是分别发送给每个JSON存储。 DB2 JSON API提供了一种将几个JSON文档一起批处理的编程方式。 批处理的主要优点是性能更好。
要批处理文档,请应用startBatch()
标记批处理的开始,并应用endBatch()
触发对文档的操作(插入,更新,删除或保存)的执行。 请注意,如果批处理中的操作失败,则处理将继续进行批处理中的下一个操作。
DB2 JSON API支持两种类型的批处理:同质批处理和异类批处理。
- 同类批处理:这意味着所有批处理的JSON文档都是同一集合的一部分,并且对所有文档应用相同的操作。
以下示例代码使用批处理在一个集合中插入3个文档:
清单13.同类批处理
DBCollection batch = db.getCollection("batch"); BasicDBObject dbObj1 = new BasicDBObject("name", "Joe1"); dbObj1.put("_id", 1); BasicDBObject dbObj2 = new BasicDBObject("name", "Joe2"); dbObj2.put("_id", 2); BasicDBObject dbObj3 = new BasicDBObject("name", "Joe3"); dbObj3.put("_id", 3); db.startBatch(); batch.insert(dbObj1); batch.insert(dbObj2); batch.insert(dbObj3); db.endBatch();
- 异构批处理:批处理在一起的JSON文档可以是不同集合的一部分。
下面的示例代码使用批处理在集合“ batch1”中插入三个文档,在集合“ batch2”中插入两个文档。
清单14.异构批处理
DBCollection batch1 = db.getCollection("batch1"); BasicDBObject dbObj1 = new BasicDBObject("name", "Joe1"); dbObj1.put("_id", 1); BasicDBObject dbObj2 = new BasicDBObject("name", "Joe2"); dbObj2.put("_id", 2); BasicDBObject dbObj3 = new BasicDBObject("name", "Joe3"); dbObj3.put("_id", 3); DBCollection batch2 = _db.getCollection("batch2"); BasicDBObject dbObj4 = new BasicDBObject("name", "Joe4"); dbObj4.put("_id", 4); BasicDBObject dbObj5 = new BasicDBObject("name", "Joe5"); dbObj5.put("_id", 5); db.startBatch(); // inserting documents to collection batch1 batch1.insert(dbObj1); batch1.insert(dbObj2); batch1.insert(dbObj3); // inserting documents to collection batch2 batch2.insert(dbObj4); batch2.insert(dbObj5); db.endBatch();
上面的示例显示了批处理中使用的插入操作,但是您也可以批处理其他操作,例如更新,删除或删除和保存,以及将不同的操作组合在一起。
结论
本文介绍了DB2 JSON Java API的一些基本功能,并描述了控制事务和提高吞吐量的选项。 要了解有关DB2 JSON的更多信息,请参见如何使用命令行界面,或如何使用有线侦听器来接收和处理请求,请参阅本系列的其他文章。 关于DB2 JSON Java接口的详细信息也可以在DB2 JSON参考文档中找到,特别是在提供的Java文档中。
翻译自: https://www.ibm.com/developerworks/data/library/techarticle/dm-1307nosqlforjson3/index.html