how to use the powerpoint template - oracle cloud · – ^javascript object notation –well...
TRANSCRIPT
Copyright © 2017, Oracle and/or its affiliates. All rights reserved.
利用MySQL数据库新特性开发一个Node.js订票网站Oracle Code
Ivan Ma ([email protected])Principal Sales ConsultantMay, 2017
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
免责声明
以下内容旨在概述产品的总体发展方向。该内容仅供参考,不可纳入任何合同。本
演示不承诺提供任何材料、代码或功能,也不应将其作为购买决策的依据。此处所
述有关 Oracle 产品的任何特性或功能的开发、发布和时间安排均由 Oracle 自行决定。
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
The world's most popular open source database
8.0
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
议程
从 MySQL 看 NoSQL
MySQL Workbench 实践 DB 模型
以NodeJS / ExpressJS 创建预定应用
新开发的 XDevAPI - Up and Running with Connector/Node.js
1
2
3
4
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
从 MySQL 看 NoSQL
• 混合型数据库“关系数据库和文档数据库之间的X-Over”
• 多语言通用的API– C++, Java, .Net, Node.js, Python and PHP
–MySQL Shell - 新开发的客户端
–方便对关系表和文档数据库使用CRUD操作
• 基于MySQL的基础– InnoDB
– Replication
– ....
Confidential – Oracle Internal 6
MySQL Document-store
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
The MySQL Approach
• Documents in the Docstore are represented as JSON
– “JavaScript Object Notation”
–Well supported by MySQL
• Multiple documents are stored inside a Collection– Technically, an InnoDB table
–One regular column of type JSON
–Multiple virtual columns on top for indexes
Confidential – Oracle Internal 7
Documents and Collections
Collection / Table_id, doc JSON_id, doc JSON_id, doc JSON_id, doc JSON
…..
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
搭建预定网站
• MySQL Workbench来搭建数据模型–设计核心模型• 包括以JSON 数据类型
• 部署和测试– JSON 格式
– GENERATED/虚拟列
• 以NodeJS编写应用程序
9
MySQL 8.0.11nodejs
expressJSmysql
MySQL Workbench
MySQLShell
JSONJSON
JSONJSON
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Designing Model with MySQL WorkbenchFlexible Schema
Confidential – Oracle Internal/Restricted/Highly Restricted 10
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Schema or schema-less?
• Schema – 已有规范的场景。
• 但是,对座位编号:–有建筑物号码
–有段号,也不一定有指定座位号
–需要弹性 – Schema-less
12
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
JSON 数据类型 - 技术规格
• utf8mb4 字符
• 优化读取密集型工作负载
• 仅在插入时解析和验证
• 通过索引快速查询数组单元
14
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
JSON VS TEXT/VARCHAR - 的好处
1. 提供JSON文档验证:
2. 高效的二进制格式-更快,更方便 - 对 JSON数组单元查询
SELECT doc->”$.id” from seats;
SELECT doc->”$.location” from seats;
15
INSERT INTO employees VALUES ('some random text');
ERROR 3130 (22032): Invalid JSON text: "Expect a value here."
at position 0 in value (or column) 'some random text'.
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
查询 JSON - Seats
mysql> SELECT id, venue_id, doc->”$.section” FROM seats;
+----+------------+------------+
| id | venue_id | section |
+----+------------+------------+
| 1 | 1 | 1 |
| 2 | 1 | 0 |
| 3 | 1 | 9 |
+----+------------+------------+
3 row in set (0.00 sec)
新语法 : 查询JSON文档中的值
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
创建JSON 索引
1. + GENERATED 列:
2. 对 GENERATED/虚拟列加索引
mysql> ALTER TABLE seats ADD section AS (doc->”$.section”) VIRTUAL;
mysql> ALTER TABLE seats ADD INDEX (section);
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
JSON 函数
19
JSON_ARRAY_APPEND()
JSON_ARRAY_INSERT()
JSON_ARRAY()
JSON_CONTAINS_PATH()
JSON_CONTAINS()
JSON_DEPTH()
JSON_EXTRACT()
JSON_INSERT()
JSON_KEYS()
JSON_LENGTH()
JSON_MERGE()
JSON_OBJECT()
JSON_QUOTE()
JSON_REMOVE()
JSON_REPLACE()
JSON_SEARCH()
JSON_SET()
JSON_TYPE()
JSON_UNQUOTE()
JSON_VALID()
JSON_ARRAYAGG()
JSON_OBJECTAGG()
JSON_PRETTY()
JSON_STORAGE_FREE()
JSON_STORAGE_SIZE()
JSON_TABLE()
JSON_MERGE_PATCH()
JSON_MERGE_PRESERVE()
https://dev.mysql.com/doc/refman/5.7/en/json-functions.htmlhttps://dev.mysql.com/doc/refman/8.0/en/json-function-reference.html
MySQL 8.0 新加函数
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
预定事务流程
1. 选出一个活动
2. 有没有空票 – 座位
3. 锁定和保留票
4. 生成订单Order
5. 添加门票到订单
20
Events Orders Tickets
一张order可以订多张
座位票(tickets)
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Node.JS + MySQL 编写 MyBooking 应用
Confidential – Oracle Internal/Restricted/Highly Restricted 21
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
编写 MyBooking 应用
• Javascript End-to-End
• Node.js + ExpressJS Framework
• 准备• 安装• Nodejs
• expressJS
– sudo npm install express-generator –g
– sudo npm install express –g
• MySQL and NodeJS Connector
• Schema & Data
22
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
安装
• express myapp
• cd myapp
• npm install
• npm start
Confidential – Oracle Internal/Restricted/Highly Restricted 23
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Confidential – Oracle Internal/Restricted/Highly Restricted 24
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Writing the Front End
• Pure HTML/CSS/Javascript
• Speaks to the backend via restful API
25
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Up and Running with Connector/Node.jsTapping into MySQL 8.0
Confidential – Oracle Internal 28
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Using Connector/Node.jsInstallation and setup
Confidential – Oracle Internal 29
$ npm install --save --save-exact @mysql/xdevapi
'use strict';
const mysqlx = require('@mysql/xdevapi');
(async function () {
try {
const session = await mysqlx.getSession({ user: 'root' });
console.log(session.inspect()); // { auth: 'PLAIN', ssl: true, dbUser: 'root', host: 'localhost', port: 33060, socket: undefined }
process.exit();
} catch (err) {
console.error(err.message);
process.exit(1);
}
})();
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Using Connector/Node.jsCreating a database/schema
Confidential – Oracle Internal 30
'use strict';
const mysqlx = require('@mysql/xdevapi');
(async function () {
try {
const session = await mysqlx.getSession({ user: 'root' });
const schema = await session.createSchema('products');
console.log(schema); // { name: 'products' }
const schemas = await session.getSchemas();
console.log(schemas); // [{ name: 'products' }]
session.close();
process.exit();
} catch (err) {
console.error(err.message);
process.exit(1);
}
})();
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Using Connector/Node.jsCreating or re-using a collection
Confidential – Oracle Internal 31
'use strict';
const mysqlx = require('@mysql/xdevapi');
(async function () {
try {
const session = await mysqlx.getSession({ user: 'root' });
const schema = session.getSchema('products')
const collection = await schema.createCollection('servers', { ReuseExistingObject: true });
console.log(collection); // { schema: 'products', collection: 'servers' }
const collections = await schema.getCollections();
console.log(collections); // [{ schema: 'products', collection: 'servers' }]
session.close();
process.exit();
} catch (err) {
console.error(err.message);
process.exit(1);
}
})();
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Using Connector/Node.jsAdding documents to the collection
Confidential – Oracle Internal 32
'use strict';
const mysqlx = require('@mysql/xdevapi');
(async function () {
try {
const session = await mysqlx.getSession({ user: 'root' });
const collection = session.getSchema('products').getCollection('servers');
await collection.add({ name: 'Sakila', version: 5.7, revision: 21, public: true }).execute();
const batchA = collection
.add({ name: 'Sakila', version: 8.0, revision: 1, public: true })
.add({ name: 'Sakila', version: 8.0, revision: 3, public: true });
const batchB = collection
.add([{ name: 'Sakila', version: 8.0, revision: 4, public: true }, { name: 'Sakila', version: 8.0, revision: 11, public: false }])
await Promise.all([batchA.execute(), batchB.execute()]);
session.close();
process.exit();
} catch (err) {
console.error(err.message);
process.exit(1);
}
})();
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Using Connector/Node.jsRetrieving documents from the collection
Confidential – Oracle Internal 33
'use strict';
const mysqlx = require('@mysql/xdevapi');
(async function () {
try {
const session = await mysqlx.getSession({ user: 'root' });
await session
.getSchema('products')
.getCollection('servers')
.find('version = :version AND revision > :revision AND public = :public')
.bind({ version: 8.0, revision: 2, public: true })
.fields('_id', 'revision')
.sort('revision ASC')
.limit(2, 1)
.execute(console.log); // { _id: '00005ac380a30000000000000005', revision: 4 }
session.close();
process.exit();
} catch (err) {
console.error(err.stack);
process.exit(1);
}
})();
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Using Connector/Node.jsModifying documents in a collection
Confidential – Oracle Internal 34
'use strict';
const mysqlx = require('@mysql/xdevapi');
(async function () {
try {
const session = await mysqlx.getSession({ user: 'root' });
const collection = session.getSchema('products').getCollection('servers');
await collection.modify('revision = 11').set('release', 'GA').execute();
await collection.modify('revision = 11').patch({ public: true, features: ['doc-store'] }).execute();
await collection.modify('revision = 11').arrayAppend('features', 'caching_sha2_password').execute();
await collection.find('"doc-store" IN features').fields(['features', 'public', 'release']).execute(console.log);
// { public: true, features: ['doc-store', 'caching_sha2_password'], release: 'GA' }
session.close();
process.exit();
} catch (err) {
console.error(err.message);
process.exit(1);
}
})();
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Using Connector/Node.jsRemoving documents from a collection
Confidential – Oracle Internal 35
'use strict';
const mysqlx = require('@mysql/xdevapi');
(async function () {
try {
const session = await mysqlx.getSession({ user: 'root' });
const collection = session.getSchema('products').getCollection('servers');
await collection.remove('version != :version OR revision != :revision').bind({ version: 8.0, revision: 11 }).execute();
await collection.find().fields(['version', 'revision']).execute(console.log); // { version: 8, revision: 11 }
session.close();
process.exit();
} catch (err) {
console.error(err.message);
process.exit(1);
}
})();
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Using Connector/Node.jsUsing transactions for cross-collection atomic updates
Confidential – Oracle Internal 36
'use strict';
const mysqlx = require('@mysql/xdevapi');
(async function () {
let session, release;
try {
session = await mysqlx.getSession({ user: 'root' });
const db = session.getSchema('products');
await db.createCollection('clients', { ReuseExistingObject: true });
await session.startTransaction();
await db.getCollection('servers').find('version = 8.0 AND revision = 11').lockExclusive(mysqlx.LockContention.DEFAULT)
.execute(doc => { release = doc.release; });
await db.getCollection('clients').add({ name: 'c-nodejs' }).execute();
await db.getCollection('clients').modify('true').set('serverType', release).execute();
await session.commit();
session.close();
process.exit();
} catch (err) {
if (session) { await session.rollback(); }
console.error(err.message);
process.exit(1);
}
})();
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Using Connector/Node.jsCreating secondary indexes
Confidential – Oracle Internal 37
'use strict';
const mysqlx = require('@mysql/xdevapi');
(async function () {
try {
const session = await mysqlx.getSession({ user: 'root' });
const collection = session.getSchema('products').getCollection('clients');
await collection.createIndex('server', { fields: [{ field: '$.serverType', type: 'TEXT(3)' }] });
await session
.sql(`SELECT INDEX_NAME FROM information_schema.STATISTICS WHERE TABLE_NAME = '${collection.getName()}'`)
.execute(console.log);
// ['PRIMARY']
// ['server']
session.close();
process.exit();
} catch (err) {
console.error(err.message);
process.exit(1);
}
})();
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Using Connector/Node.jsExecuting raw SQL statements
Confidential – Oracle Internal 38
'use strict';
const mysqlx = require('@mysql/xdevapi');
(async function () {
let session, release;
try {
session = await mysqlx.getSession({ user: 'root' });
// list clients and the corresponding supported server versions
await session
.sql('SELECT t2.doc->>"$.name", t1.doc->>"$.revision"'
+ ' FROM `products`.`servers` t1 JOIN `products`.`clients` t2'
+ ' ON t1.doc->>"$.release" = t2.doc->>"$.serverType"')
.execute(console.log);
session.close();
process.exit();
} catch (err) {
if (session) { await session.rollback(); }
console.error(err.message);
process.exit(1);
}
})();
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. |
Using Connector/Node.jsCleaning up
Confidential – Oracle Internal 39
'use strict';
const mysqlx = require('@mysql/xdevapi');
(async function () {
try {
const session = await mysqlx.getSession({ user: 'root' });
const schema = session.getSchema('products');
await schema.dropCollection('servers');
await schema.dropCollection('clients');
await session.dropSchema('products');
session.close();
process.exit();
} catch (err) {
console.error(err.message);
process.exit(1);
}
})();
Copyright © 2017, Oracle and/or its affiliates. All rights reserved. | Confidential – Oracle Internal/Restricted/Highly Restricted 40