实验 1 搭建 JSON 实例应用开发环境
通过 Java SDK 进行数据库连接
// Create a database link.
Sequoiadb db = new Sequoiadb("sdbserver1", 11810,
"sdbadmin", "sdbadmin");
try {
// Get the information from data set.
DBCursor rgs = db.listReplicaGroups();
System.out.println("The data group information queried after connecting to the database is:");
// Formatted print the information of data set.
JsonUtil.formatPrint(rgs);
// Close the cursor result set.
rgs.close();
} finally {
// Close the database link.
db.close();
}
实验 2 数据类型
插入记录:此代码样例将会向集合中添加一条人员记录。人员记录的详细信息为: {“姓名”:“乔治”,“年龄”:”22“,”职位“:{“职位名称”:”工程师“,”级别“:”P3“,”工资“:9000}}。可以看到,“职位信息”是以嵌套对象的形式存在于这条数据中的:
// Create a record for the personnel.
BasicBSONObject record = new BasicBSONObject();
// Add attributes for the personnel.
record.put("ename", "Georgi");
record.put("age", 22);
// Add the nested object property position for the personnel.
// The position information includes: {position_name:engineer, level:P3,pay:9000}.
BasicBSONObject position = new BasicBSONObject();
position.put("position_name", "engineer");
position.put("level", "P3");
position.put("pay", 9000);
// Insert the position object into the property of the personnel record.
record.put("position", position);
// Insert this record into the employee collection.
cl.insert(record);
数组的使用:此代码样例将会向集合中添加一条人员记录。人员记录的详细信息为: {“姓名”:“乔治”,“年龄”:”22“,”爱好“:[”足球“,”篮球“]}。可以看到,“爱好”是以数组对象的形式嵌套在这条数据中的
BasicBSONObject record = new BasicBSONObject();
// Add attributes for the personnel.
record.put("ename", "Georgi");
record.put("age", 22);
// Add an array type attribute for the personnel favorite.
// favorite:[basketball,football]
BasicBSONList favorite = new BasicBSONList();
favorite.add("football");
favorite.add("basketball");
// Insert the favorite array into the properties of the personnel record.
record.put("favorite", favorite);
// Insert this record into the employee collection.
cl.insert(record);
此代码样例将会通过 ObjectId 进行数据的精准查询:
//Query with _id as the query condition.
ObjectId id = new ObjectId(idStr);
queryOne = cl.query(new BasicBSONObject("_id", id), null,
null, null);
日期的使用:此代码样例将会向集合中插入一条包含日期的数据。日期日期为字符串格式,通过 SimpleDateFormat 格式化后,返回一个 Date 对象,再将 Date 对象添加到这条记录中去,最后向集合插入这条记录:
BSONObject record = new BasicBSONObject();
// Add attributes for the personnel.
record.put("ename", "Georgi");
// Add the date of joining attribute for the personnel, and the object type is Date.
String str = "2020-3-25";
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
java.util.Date date = format.parse(str);
record.put("date", date);
// Insert this record into the employee collection.
cl.insert(record);
时间戳的使用:
此代码样例将会向集合中插入一条包含时间戳对象类型的数据。
首先拟定这条数据的时间属性为 2020-01-01 12:30:30.124232,代码样例中,会分为三步进行操作。
第一步,将数据以小数点前后进行差分,截取 2020-01-01 12:30:30 部分并将其转换成 Date 对象,然后通过 Date 对象的 getTime 方法获取这一部分的时间戳。最后,再将小数点后面的部分转换成时间戳。
第二步,构造一个 BSONTimestamp 对象,并将两部分时间戳作为构造参数传入。
第三步,将 BSONTimestamp 放入记录中进行插入。
// Create a personnel record.
BasicBSONObject record = new BasicBSONObject();
// Add attributes for the personnel.
record.put("ename", "Georgi");
String mydate = "2020-01-01 12:30:30.124232";
String dateStr = mydate.substring(0, mydate.lastIndexOf('.'));
String incStr = mydate.substring(mydate.lastIndexOf('.') + 1);
// Create a date and time string formatting object.
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// Convert date and time strings to Date objects.
Date date = format.parse(dateStr);
// Convert date time to time stamp (accurate to second).
int seconds = (int) (date.getTime() / 1000);
// Convert the part after the decimal point to a timestamp.
int inc = Integer.parseInt(incStr);
// Create timestamp object.
BSONTimestamp ts = new BSONTimestamp(seconds, inc);
record.put("timestamp", ts);
cl.insert(record);
二进制数据的使用
此代码样例将会向集合中插入一条包含二进制流的数据。
这条数据中事先添加了一个名为 binary 的字段,为其添加了二进制类型的值,并采用简单的字符串 getBytes 方法获取来获取二进制流的数据。用户也可以通过其他方式,例如读取图片、文档流的方式获取。
// Create a record for the personnel.
BasicBSONObject record = new BasicBSONObject();
// Add attributes for the personnel.
record.put("ename", "Georgi");
// Prepare a string for converting to binary data.
String str = "This is the binary data";
// Get the binary streams of the object.
byte[] arr = str.getBytes();
// Create a binary object.
org.bson.types.Binary binary = new org.bson.types.Binary(arr);
record.put("binary", binary);
cl.insert(record);
正则表达式的使用
此代码样例将会通过正则表达式更新数据。这段代码中,先指定要匹配的字段为 ename 字段,再指定正则表达式规则为 ^Anne (匹配以 Anne 开头的值),这里就准备好了 update 方法需要的第一个参数,用于匹配的条件。之后,再构造一个修改结果,{”age“:55}。通过这两部分,就可以成功将集合中姓名以 Anne 开头的数据,修改其年龄为 55 了。
这里的代码样例,使用的是前置模糊匹配。需要注意的是,前置模糊查询,是无法匹配索引的,但是后置模糊查询可以。
// Set the regular expression in matcher.
BSONObject matcher = new BasicBSONObject();
// Set the regular expression rule: match the string beginning with Ann
Pattern obj = Pattern.compile("^Anne", Pattern.CASE_INSENSITIVE);
matcher.put("ename", obj);
// Set the value to be modified in the modifier, and modify age to 55.
BSONObject modifier = new BasicBSONObject("$set", new BasicBSONObject("age", 55));
// Execute update operation.
cl.update(matcher, modifier, null);
高精度数的使用
此代码样例将会向集合中插入一条数据,此数据包含两个字段,两个字段都是高精度数,不同的是一个字段指定了 decimal 的长度为(100,30),另一个未指定长度,结果显示两种方式都可以正常插入高精度数据。
// Create a record for the personnel.
BasicBSONObject record = new BasicBSONObject();
//Java BSON constructs Decimal type without precision requirement.
// {a:{"$decimal":"12345.067891234567890123456789"}}
String str = "12345.067891234567890123456789";
BSONDecimal decimal = new BSONDecimal(str);
record.put("unfixed length data", decimal);
// Java BSON constructs a Decimal type with up to 100 significant digits, of which the decimal part has up to 30 digits.
// {b:{"$decimal":"12345.067891234567890123456789", "$precision":[100, 30]}}
BSONDecimal decimal2 = new BSONDecimal(str, 100, 30);
record.put("fixed length data", decimal2);
cl.insert(record);
LOB 对象的使用
此代码样例将会向数据库中插入一条 LOB 记录,准备插入的 LOB 数据内容来源于字符串的二进制流。这里演示如何向集合中插入 LOB 数据,以及如何通过 OID 获取这条 LOB 数据。在 Java 开发中,会使用 com.sequoiadb.base.DBLob 来构造 LOB 对象。
需要注意的是,LOB 的存取是以流的形式,所以操作完毕要执行 close 方法。
BSONObject record = new BasicBSONObject();
// Create a file stream with text content.
String word = "Hello there! This is the specific content of the Text file.";
// Create the Lob.
DBLob lob = cl.createLob();
// Add the file stream to Lob.
lob.write(word.getBytes());
// Get the unique ID after successful lob creation.
ObjectId id = lob.getID();
// Print ID.
String s = id.toString();
System.out.println("The ID generated after creating the lob object is:" + s);
// Close the file stream.
lob.close();
// Get the inserted lob object.
DBLob lobCopy = cl.openLob(id);
byte[] bytes = new byte[word.length()];
// Read the file stream of the lob object into memory.
lobCopy.read(bytes);
String get = new String(bytes);
System.out.println("The content of the obtained lob object file stream is:" + get);
lob.close();
实验 3 数据操作
单条插入 JSON 格式字符串
此代码样例将会向集合内插入1条数据,数据为 JSON 格式,数据中包含的信息为编号、姓名和年龄字段对应的值。
// Insert 1 piece of data into the collection, and the data is in JSON format.
cl.insert("{ \"empno\": 10001, \"ename\": \"Georgi\", \"age\": 48}}");
单条插入BsonObject 对象
此代码样例将会向集合内插入1条数据,数据为 BsonObject 对象。用户构造 BsonObject 对象时,通过 put 方法将值写入,key 和 value 也是数据中较为常见的对应方式。 构造 BsonObject 对象,调用集合的 insert 方法,就可以将 BsonObject 内的数据成功写入数据库了。
// Insert a piece of data into the collection, and the data is a BsonObject object.
BSONObject record = new BasicBSONObject();
record.put("empno", 10002);
record.put("ename", "Bezalel");
record.put("age", 31);
cl.insert(record);
批量插入 BsonObject 对象
此代码样例将会向集合内插入多条数据。其中 records 是一个 List 集合容器,r1 和 r2 分别对应了一条数据,最后通过 insert 方法将 records 整体插入数据库,达到批量插入的效果。
// Insert multiple pieces of data into a collection.
List<BSONObject> records = new ArrayList<>();
BasicBSONObject r1 = new BasicBSONObject();
r1.put("empno", 10003);
r1.put("ename", "Parto");
r1.put("age", 33);
records.add(r1);
BasicBSONObject r2 = new BasicBSONObject();
r2.put("empno", 10004);
r2.put("ename", "Chirstian");
r2.put("age", 18);
records.add(r2);
cl.insert(records);
查询指定集合下的所有数据
此代码样例将会查询 cl 集合下的所有数据。
cursor = cl.query(); //select
查询指定集合下符合条件的数据
此代码样例将会通过条件过滤进行查询,这里以查询年龄等于 19 的数据为例。在拼接查询条件的过程中,可以使用各种匹配符,如这里使用的 $et 代表的”值等于“。
//select where
BSONObject matcher = new BasicBSONObject();
// $ et means equal.
BSONObject et = new BasicBSONObject();
et.put("$et", 19);
// Age equals to 19.
matcher.put("age", et);
cursor = cl.query(matcher, null, null, null);
更新指定数据
此代码样例将会更新指定数据的年龄,将 age = 19 的数据改为 age = 20。这里 matcher 是一个匹配条件对象,modifier 是期望修改后的值。最后调用集合的 update 方法,执行修改操作。
构造 matcher 用到了匹配符,构造 modifier 用到了更新符。
//update
// Set the matching rule, and $et equals to the value.
BSONObject matcher = new BasicBSONObject();
BSONObject et = new BasicBSONObject();
et.put("$et", 19);
matcher.put("age", et);
// Set the modified value.
BSONObject modifier = new BasicBSONObject();
BSONObject value = new BasicBSONObject();
value.put("age", 20);
modifier.put("$set", value);
// Execute update operation.
cl.update(matcher, modifier, null);
删除数据
此代码样例将会删除 age = 19 的数据。先通过 BSONObject 构造一个匹配条件对象,然后再调用集合的 delete 方法,最后成功删除数据。
//delete
// Set the matching rule, and $et equals to the value.
BSONObject matcher = new BasicBSONObject();
BSONObject et = new BasicBSONObject();
et.put("$et", 19);
matcher.put("age", et);
// Execute delete operation.
cl.delete(matcher);
实验 4 索引
普通索引
此代码样例将会为 empno 字段创建索引。代码段中 column 为一个指定需要创建索引字段的 BsonObject 对象,然后通过 DBCollection 对象的 createIndex 方法就可以为这个集合的指定字段创建索引了。
// Index contains fields
column.put("empno", 1);
// Create an ordinary index.
cl.createIndex("idx_empno", column, false, false);
唯一索引
此代码样例将会为集合的 empno 字段创建一条唯一索引
BasicBSONObject column = new BasicBSONObject();
// Index contains fields
column.put("empno", 1);
// Create a unique index.
cl.createIndex("idx_empno", column, true, false);
联合索引
此代码样例将会为 empno 和 deptno 字段创建一条联合索引。创建方式依旧为调用 createIndex 接口,通过不同的参数控制,实现创建不同的索引类型。
BasicBSONObject column = new BasicBSONObject();
// Index contains fields
column.put("empno", 1);
column.put("deptno", 1);
// Create a joint index.
cl.createIndex("idx_empno", column, false, false);
实验 5 事务
为插入操作添加事务
此代码样例将会通过 beginTransaction 方法声明事务,分别插入了两次数据。第一次插入后,执行 rollback 方法回滚,期望数据不会插入到数据库中;第二次插入后,执行commit 方法,提交事务,期望数据插入成功。
db.beginTransaction();
// Insert 2 pieces of data into the collection, and the data is in Json format.
cl.insert("{ \"empno\": 10007, \"ename\": \"Trancer\", \"age\": " +
"11}}");
// Transaction rollbacks.
db.rollback();
db.beginTransaction();
cl.insert("{ \"empno\": 10008, \"ename\": \"Actioner\", \"age\": " +
"12}}");
db.commit();
同一个事务内多个集合的操作
在此代码样例中,将会假设公司新成立了一个部门,并为此部门招收了一名员工,因此需要向”员工集合“和”部门集合“同时插入数据。插入完毕后,执行回滚操作,并查看执行效果,期望数据插入失败,部门信息和员工信息都未有新增项。
// Start the transaction.
db.beginTransaction();
// Create a new department.
departmentCl.insert("{ \"deptno\": 10008, \"deptname\": " +
"\"service\", \"note\": \"service department\"}}");
// Create a new employee information and associate it with the department.
employeeCl.insert("{ \"empno\": 10001, \"deptno\": 10008, " +
"\"ename\": \"Trancer\", \"age\": 11}}");
// Transaction rollbacks.
db.rollback();
实验 6 连接池
此代码样例将会初始化一个巨杉数据库连接池对象。连接池中只添加了一个连接地址 sdbserver1:11810,如果存在多个地址,可一并添加到地址的 List 集合中去。
ArrayList<String> addrs = new ArrayList<>();
ConfigOptions nwOpt = new ConfigOptions();
DatasourceOptions dsOpt = new DatasourceOptions();
// Provide the coord node addresses, and multiple can be added.
addrs.add("sdbserver1" + ":" + 11810);
// Set the network parameters.
nwOpt.setConnectTimeout(500); // The connection establishment timeout period is 500ms
nwOpt.setMaxAutoConnectRetryTime(0); // The retry time after connection establishment fails is 0ms
// Set the connection pool parameters.
dsOpt.setMaxCount(500); // The connection pool can provide up to 500 connections.
dsOpt.setDeltaIncCount(20); // Add 20 connections at a time.
dsOpt.setMaxIdleCount(20); // When the connection pool is idle, 20 connections are reserved.
dsOpt.setKeepAliveTimeout(0); // The survival time of idle connections in the pool. Unit: ms.
// 0 means that it is indifferent to how long the connection has not been sent or received.
dsOpt.setCheckInterval(60 * 1000);
// Close the idle connections in the connection pool that are more than MaxIdleCount limit every 60 seconds.
// Close the connection with a long survival time (the connection has stopped sending and receiving beyond the keepAliveTimeout time).
// Synchronize the period of the coord address to the catalog. Unit: milliseconds.
// 0 means out of sync.
dsOpt.setSyncCoordInterval(0);
// When the connection is out of the pool, the availability of the connection is checked. The default is non-detection.
dsOpt.setValidateConnection(false);
// Use coord address load balancing strategy to obtain connection by default.
dsOpt.setConnectStrategy(ConnectStrategy.BALANCE);
// Establish a connection pool.
ds = new SequoiadbDatasource(addrs, "sdbadmin", "sdbadmin",
nwOpt, dsOpt);
实验 7 警告与错误的处理
异常处理
此代码样例将会手动制造异常信息,然后通过 try catch 进行抓取。程序抓取异常后,再进行错误码比对,符合期望错误的情况下,将异常信息打印出来;不符合的情况下,直接抛出异常信息到更外层。这里制造异常信息的方式为重复调用 createCollectionSpace 创建同名集合空间,由于第一次创建成功,第二次创建时会抛出异常,提示集合空间已存在。
try {
db.createCollectionSpace("company");
// Repeat create operation.
db.createCollectionSpace("company");
} catch (BaseException e) {
// Indentify that the error code is -33, and the collection space already exists.
if (e.getErrorCode() == -33) {
System.out.println("The error is :" + e.getMessage());
} else {
throw e;
}
} finally {
db.close();
}
实验 8 表分区规则
水平分区
此代码样例将会创建一个水平分区集合,将集合中的 age 字段作为分区键。
将对应的参数设置在一个 BsonObject 对象中,然后在执行 createCollection 方法时,将想要创建的集合名和这个 BsonObject 传入,就可以成功创建一个水平分区集合了。
// Create an employee collection.
BSONObject options = new BasicBSONObject();
BasicBSONObject shardingKey = new BasicBSONObject();
// Use the age field as the partition key.
shardingKey.put("age", 1);
options.put("ShardingKey", shardingKey);
// Set the consistency of the collection.
options.put("ReplSize", 1);
// Set partition type.
options.put("ShardingType", "hash");
// The number of partitions. It is only filled in when the hash partition is selected, and represents the number of hash partitions.
// Its value must be a power of 2, and the range is [2 ^ 3, 2 ^ 20]. The default is 4096.
options.put("Partition", 4096);
// Indicate whether the new collection is enabled for automatic segmentation, and the default is false.
options.put("AutoSplit", true);
// Indicates whether the new collection is enabled for data compression, and the default is true.
options.put("Compressed", true);
// Type of compression algorithm. The default is the lzw algorithm. The selectable values are as follows:
// "snappy": Use the snappy algorithm to compress.
// "lzw": Use the lzw algorithm for compression.
options.put("CompressionType", "lzw");
cs.createCollection("employee", options);
垂直分区(主子表)
在此代码样例中,先创建了一个 employee 集合,此集合为主集合;然后再创建一个子集合 employee201,子集合为水平分区集合;然后将子集合通过 attachCatollection 方法添加到主集合中去。
需要注意的是,主集合的分区类型为 range。子集合挂载主集合的时候,需要指定范围边界。在边界范围以内的数据,会落到对应的子集合中去。
// Create a collection of employee (main table).
BSONObject optionmain = new BasicBSONObject();
BasicBSONObject shardingkeymain = new BasicBSONObject();
// Set the department number as partition key.
shardingkeymain.put("deptno", 1);
optionmain.put("ShardingKey", shardingkeymain);
// The partition type is range partition.
optionmain.put("ShardingType", "range");
// Mark it as main table.
optionmain.put("IsMainCL", true);
DBCollection employee = cs.createCollection("employee", optionmain);
// Create an employee201 (child table with department number 201 as the partition range).
// Note: In some table designs, we can also use the month or year as the partition range.
BSONObject options201 = new BasicBSONObject();
// Set subtable properties. The child table can also be a partitioned table.
BasicBSONObject shardingKey201 = new BasicBSONObject();
shardingKey201.put("age", 1);
options201.put("ShardingKey", shardingKey201);
options201.put("ReplSize", 1);
options201.put("ShardingType", "hash");
options201.put("Partition", 4096);
options201.put("AutoSplit", true);
options201.put("Compressed", true);
options201.put("CompressionType", "lzw");
cs.createCollection("employee201", options201);
// Add the child table to the main table.
BSONObject bound = (BSONObject) org.bson.util.JSON.parse("{'LowBound':{'deptno':201}}");
// Specifies the boundary value of the range to which the subtable to be added belongs.
// bound: Each partition interval is left-closed and right-open rule, ie [201, 202).
bound.putAll((BSONObject) org.bson.util.JSON.parse("{'UpBound':{'deptno':202}}"));
// Add the subtable.
employee.attachCollection("company.employee201", bound);
employee.insert("{ \"empno\": 10002, \"deptno\": 201, \"ename\": " +
"\"Bezalel\", \"age\": 21 }");
实验 9 嵌套数据模型
设计实例
此代码样例将会创建一个集合空间,名为 school ,然后创建 student 集合,并为 student 集合的 id + class 字段添加联合唯一索引。
// Create the collection space.
CollectionSpace cs = db.createCollectionSpace("school");
// Create the collection.
cl = cs.createCollection("student");
// Design the index.
BasicBSONObject column = new BasicBSONObject();
// Index contains fields
// Student ID
column.put("id", 1);
// Class number
column.put("class", 1);
// Create a joint index.
cl.createIndex("idx_oid", column, true, false);