Этот раздел объясняет, как использовать X DevAPI для операций Create, Read, Update и Delete (CRUD).
Основная область MySQL всегда работала с относительными таблицами. X DevAPI расширяет эту область, добавляя поддержку операций CRUD, которыми можно управлять для коллекций документов.
Операции CRUD доступны как методы, которые воздействуют на объекты схемы. Доступные объекты схемы состоят из объектов коллекции, содержащих документы или объекты таблицы, состоящие из строк и столбцов.
Следующая таблица показывает доступные операции CRUD для объектов коллекции и для объектов таблицы.
Операция |
Документ |
Таблица |
---|---|---|
Create |
||
Read |
||
Update |
||
Delete |
Рис. 3.1. Диаграмма классов
X DevAPI поддерживает много современных методов, чтобы сделать работу с операциями CRUD легче и соответствовать современным средам разработки. Эта секция объясняет, как использовать формирование цепочки метода вместо того, чтобы работать со строками SQL структур JSON.
Следующие примеры показывают, как формирование цепочки метода используется вместо последовательности SQL, работая с сессиями. Пример предполагает, что испытательная схема существует, и список сотрудников существует.
MySQL Shell JavaScript Code
// New method chaining used for executing an SQL SELECT statement // Recommended way for executing queries var employees = db.getTable('employee'); var res = employees.select(['name', 'age']). where('name like :param'). orderBy(['name']). bind('param', 'm%').execute(); // Traditional SQL execution by passing an SQL string // It should only be used when absolutely necessary var result = session.sql('SELECT name, age ' + 'FROM employee ' + 'WHERE name like ? ' + 'ORDER BY name').bind('m%').execute();
MySQL Shell Python Code
# New method chaining used for executing an SQL SELECT statement # Recommended way for executing queries employees = db.get_table('employee') res = employees.select(['name', 'age']) \ .where('name like :param') \ .order_by(['name']) \ .bind('param', 'm%').execute() # Traditional SQL execution by passing an SQL string # It should only be used when absolutely necessary result = session.sql('SELECT name, age ' + 'FROM employee ' + 'WHERE name like ? ' + 'ORDER BY name').bind('m%').execute()
Node.js JavaScript Code
// New method chaining used for executing an SQL SELECT statement // Recommended way for executing queries var employees = db.getTable('employee'); var promise = employees.select('name', 'age') .where('name like :name') .orderBy('name') .bind('m%') .execute(); // Traditional SQL execution by passing an SQL string var sqlString = 'SELECT name, age ' + 'FROM employee ' + 'WHERE name like ? ' + 'ORDER BY name'; var promise = db.executeSql(sqlString, 'm%').execute();
C# Code
// New method chaining used for executing an SQL SELECT statement // Recommended way for executing queries var employees = db.GetTable("employee"); var res = employees.Select("name", "age") .Where("name like :param") .OrderBy("name") .Bind("param", "m%").Execute(); // Traditional SQL execution by passing an SQL string // It should only be used when absolutely necessary var result = session.SQL("SELECT name, age " + "FROM employee " + "WHERE name like ? " + "ORDER BY name").Bind("m%").Execute();
Python Code
# Connector/Python # New method chaining used for executing an SQL SELECT statement # Recommended way for executing queries employees = db.get_table('employee') res = employees.select(['name', 'age']) \ .where('name like :param') \ .order_by(['name']) \ .bind('param', 'm%').execute() # Traditional SQL execution by passing an SQL string # It should only be used when absolutely necessary result = session.sql('SELECT name, age ' + 'FROM employee ' + 'WHERE name like ? ' + 'ORDER BY name').bind('m%').execute()
Java Code
// New method chaining used for executing an SQL SELECT statement // Recommended way for executing queries Table employees = db.getTable("employee"); RowResult res = employees.select("name, age") .where("name like :param") .orderBy("name") .bind("param", "m%").execute(); // Traditional SQL execution by passing an SQL string // It should only be used when absolutely necessary SqlResult result = session.sql("SELECT name, age " + "FROM employee " + "WHERE name like ? " + "ORDER BY name").bind("m%").execute();
C++ Code
// New method chaining used for executing an SQL SELECT statement // Recommended way for executing queries Table employees = db.getTable("employee"); RowResult res = employees.select("name", "age") .where("name like :param") .orderBy("name") .bind("param", "m%").execute(); // Traditional SQL execution by passing an SQL string // It should only be used when absolutely necessary RowResult result = session.sql("SELECT name, age " "FROM employee " "WHERE name like ? " "ORDER BY name").bind("m%").execute();
Традиционно многие драйверы MySQL использовали синхронный подход, выполняя SQL-операторы. Это означало, что операции, такие как открытие соединения и выполнение запросов, были заблокированы до завершения, которое могло занять много времени. Чтобы допускать параллельное выполнение, разработчик должен был написать многопоточное приложение.
Любой клиент MySQL, который поддерживает X-протокол, может обеспечить асинхронное выполнение, явно ожидая определенный результат, когда это на самом деле необходимо.
MySQL Shell не поддерживает асинхронные операции.
Использование отзывов очень распространенный способ осуществить асинхронные операции. Когда функция обратного вызова определяется, операция CRUD не блокируется, что означает, что следующий запрос немедленно вызывают даже при том, что результат из базы данных еще не был получен. Только когда результат доступен, является обратным вызовом.
Node.js JavaScript Code
var employees = db.getTable('employee'); employees.select('name', 'age') .where('name like :name') .orderBy('name') .bind('name', 'm%') .execute(function (row) { // do something with a row }) .catch(err) { // Handle error });
C# Code
var employees = db.GetTable("employee"); var select = employees.Select("name", "age") .Where("name like :name") .OrderBy("name") .Bind("name", "m%") .ExecuteAsync(); select.ContinueWith(t => { if (t.Exception != null) { // Handle error } // Do something with the resultset });
Java Code
Table employees = db.getTable("employee"); // execute the query asynchronously, obtain a future CompletableFuture<RowResult> rowsFuture = employees.select("name","age") .where("name like :name") .orderBy("name") .bind("name", "m%").executeAsync(); // dependent functions can be attached to the CompletableFuture
C++ Code
// Asynchronous execution is not yet implemented in Connector/C++
Такие языки, как C#, могут использовать шаблон async/await.
C# Code
Task<RowResult> getEmployeesTask = employees.Select("name", "age") .Where("name like :name").OrderBy("name") .Bind("name", "m%").ExecuteAsync(); // Do something else while the getEmployeesTask is executing in the background // at this point we are ready to get our results back. If it is not done, // this will block until done RowResult res = await getEmployeesTask; foreach (var row in res.FetchAll()) { // use row object }
Connector/Node.js применяет асинхронные операции через Promises для всех сетевых действий.
Java Code
Table employees = db.getTable("employee"); // execute the query asynchronously, obtain a future CompletableFuture<RowResult> rowsFuture = employees.select("name", "age") .where("name like :name") .orderBy("name") .bind("name", "m%").executeAsync(); // wait until it's ready RowResult rows = rowsFuture.get();
C++ Code
// Asynchronous execution is not yet implemented in Connector/C++
В зависимости от языка, который вы используете, X DevAPI может осуществить
такую функцию, как executeAsync()
в обмен на
execute([mysqlx.Async])
или в дополнение
execute([mysqlx.Async])
.
Например, в контексте Node.js все выполнение асинхронное.
Поэтому Connector/Node.js не должен различать
execute()
и
executeAsync()
.
Чтобы обозначить асинхронное выполнение по умолчанию, Connector/Node.js
осуществляет только execute()
, который
возвращает объекты JavaScript Promise.
Языки программирования со строгим контролем типов, такие как Ява или C#,
могут использовать в своих интересах наличие двух отчетливо названных вызовов
API синхронного и асинхронного выполнения. У двух запросов могут быть
различные типы возврата. Например, Connector/J может использовать
execute()
, чтобы вернуть
RowResult
или
DocResult
и
executeAsync()
, чтобы вернуть
CompletableFuture<T>
,
параметр типа один из типов результата.
Вместо того, чтобы использовать значения непосредственно в
последовательности выражения, хорошая практика отделить их
от последовательности выражения. Это сделано, используя параметры в
последовательности выражения и функцию bind()
,
чтобы связать их с параметрами.
Параметры могут быть определены следующими способами: анонимный и названный.
Тип параметра |
Синтаксис |
Пример |
Позволен в операциях CRUD |
Позволен в строках SQL |
---|---|---|---|---|
Анонимный | ? |
'age > ?' | Нет | Да |
Названный | :<name> |
'age > :age' | Да |
Нет |
Следующий пример показывает, как использовать функцию
bind()
перед
execute()
. Для каждого названного параметра
обеспечьте аргумент для bind()
,
который содержит название параметра и его значение.
Порядок, в котором пары значения параметра переданы
bind()
неважен. Пример предполагает, что
испытательная схема была назначена на переменную
db
, и что коллекция
my_collection
есть.
MySQL Shell и Node.js JavaScript
// Collection.find() function with fixed values var myColl = db.getCollection('my_collection'); var myRes1 = myColl.find('age = 18').execute(); // Using the .bind() function to bind parameters var myRes2 = myColl.find('name = :param1 AND age = :param2').bind('param1','Rohit'). bind('param2', 18).execute(); // Using named parameters myColl.modify('name = :param').set('age', 55). bind('param', 'Nadya').execute(); // Binding works for all CRUD statements except add() var myRes3 = myColl.find('name like :param'). bind('param', 'R%').execute();
Управляя этим с Connector/Node.js надо знать, что
execute()
вернет Promise.
Вы могли бы хотеть проверить результаты, чтобы избежать ошибок.
MySQL Shell Python Code
# Collection.find() function with hardcoded values myColl = db.get_collection('my_collection') myRes1 = myColl.find('age = 18').execute() # Using the .bind() function to bind parameters myRes2 = myColl.find('name = :param1 AND age = :param2'). bind('param1','Rohit').bind('param2', 18).execute() # Using named parameters myColl.modify('name = :param').set('age', 55).bind('param', 'Nadya').execute() # Binding works for all CRUD statements except add() myRes3 = myColl.find('name like :param').bind('param', 'R%').execute()
C# Code
// Collection.Find() function with fixed values var myColl = db.GetCollection("my_collection"); var myRes1 = myColl.Find("age = 18").Execute(); // Using the .Bind() function to bind parameters var myRes2 = myColl.Find("name = :param1 AND age = :param2"). Bind("param1", "Rohit").Bind("param2", 18).Execute(); // Using named parameters myColl.Modify("name = :param").Set("age", 55). Bind("param", "Nadya").Execute(); // Binding works for all CRUD statements except Add() var myRes3 = myColl.Find("name like :param").Bind("param", "R%").Execute();
Python Code
# Collection.find() function with hardcoded values my_coll = my_schema.get_collection('my_collection') my_res_1 = my_coll.find('age = 18').execute() # Using the .bind() function to bind parameters my_res_2 = my_coll.find('name = :param1 AND age = :param2'). bind('param1', 'Rohit').bind('param2', 18).execute() # Using named parameters my_coll.modify('name = :param').set('age', 55).bind('param', 'Nadya').execute() # Binding works for all CRUD statements except add() my_res_3 = my_coll.find('name like :param').bind('param', 'R%').execute()
Java Code
// Collection.find() function with fixed values Collection myColl = db.getCollection("my_collection"); DocResult myRes1 = myColl.find("age = 18").execute(); // Using the .bind() function to bind parameters DocResult myRes2 = myColl.find("name = :param1 AND age = :param2"). bind("param1", "Rohit").bind("param2", 18).execute(); // Using named parameters myColl.modify("name = :param").set("age", 55).bind("param", "Nadya").execute(); // Using named parameters with a Map Map<String, Object> params = new HashMap<>(); params.put("name", "Nadya"); myColl.modify("name = :name").set(".age", 55).bind(params).execute(); // Binding works for all CRUD statements except add() DocResult myRes3 = myColl.find("name like :param"). bind("param", "R%").execute();}
C++ Code
/// Collection.find() function with fixed values Collection myColl = db.getCollection("my_collection"); auto myRes1 = myColl.find("age = 18").execute(); // Using the .bind() function to bind parameters auto myRes2 = myColl.find("name = :param1 AND age = :param2"). bind("param1","Rohit").bind("param2", 18).execute(); // Using named parameters myColl.modify("name = :param").set("age", 55).bind("param", "Nadya").execute(); // Binding works for all CRUD statements except add() auto myRes3 = myColl.find("name like :param").bind("param", "R%").execute();
Анонимные заполнители не поддерживаются в X DevAPI.
Это ограничение улучшает кодовую ясность в цепях команды CRUD с
многочисленными методами, используя заполнители. Независимо от варианта
синтаксиса bind()
, всегда является ясной
ассоциацией между параметрами и заполнителями на основе названия параметра.
Все методы CRUD командуют формой цепочки в одном пространстве
имен для заполнителей. В следующем примере
find()
и fields()
связаны цепочкой. Оба метода берут выражение с заполнителями.
Заполнители относятся к одному объединенному пространству имен.
Оба метода используют один названный заполнитель
:param
. Единственный вызов
bind()
с одним параметром, передаваемым по
значению имени для :param
используется, чтобы назначить значение заполнителя на оба экземпляра
:param
в find()
и
fields().
MySQL Shell JavaScript Code
// one bind() per parameter var myColl = db.getCollection('relatives'); var juniors = myColl.find('alias = "jr"').execute().fetchAll(); for (var index in juniors) { myColl.modify('name = :param'). set('parent_name',mysqlx.expr(':param')). bind('param', juniors[index].name).execute(); }
MySQL Shell Python Code
# one bind() per parameter myColl = db.get_collection('relatives') juniors = myColl.find('alias = "jr"').execute().fetch_all() for junior in juniors: myColl.modify('name = :param'). \ set('parent_name',mysqlx.expr(':param')). \ bind('param', junior.name).execute()
Node.js JavaScript Code
// one bind() per parameter db .getCollection('relatives'); .find('alias = "jr"') .execute(function (junior) { return myColl .modify('name = :param') .set('parent_name', mysqlx.expr(':param')) .bind('param', junior.name) .execute(); });
C# Code
// one bind() per parameter myColl.Find("a = :param").Fields(":param as b") .Bind(new { param = "c"}).Execute();
Python Code
# one bind() per parameter my_coll = my_schema.get_collection('relatives') juniors = my_coll.find('alias = "jr"').execute().fetch_all() for junior in juniors: my_coll.modify('name = :param') \ .set('parent_name', mysqlx.expr(':param')) \ .bind('param', junior.name).execute()
Java Code
// one bind() per parameter myColl.find("a = :param").fields(":param as b") .bind("param", "c").execute();
C++ Code
// one bind() per parameter Collection myColl = db.getCollection("relatives"); DocResultjuniors = myColl.find("alias = 'jr'").execute(); DbDoc junior; while ((junior = juniors.fetchOne())) { myColl.modify("name = :param") .set("parent_name", expr(":param")) .bind("param", junior["name"]).execute(); }
Не разрешено для названного параметра использовать имя, которое
начинается с цифры. Например, запрещены :1one
и
:1
.
Вместо непосредственной связи и выполнения операций CRUD с
bind()
и execute()
или execute()
также возможно сохранить объект
операции CRUD в переменной для более позднего выполнения.
Преимущество такого выполнения в том, что можно
связать несколько наборов переменных к параметрам, определенным в
последовательностях выражения и поэтому получить лучшую работу, выполняя
большое количество подобных операций. Пример предполагает, что испытательная
схема была назначена на переменную db
и что коллекция есть my_collection
.
MySQL Shell JavaScript Code
var myColl = db.getCollection('my_collection'); // Only prepare a Collection.remove() operation, but do not run it yet var myRemove = myColl.remove('name = :param1 AND age = :param2'); // Binding parameters to the prepared function and .execute() myRemove.bind('param1', 'Leon').bind('param2', 39).execute(); myRemove.bind('param1', 'Johannes').bind('param2', 28).execute(); // Binding works for all CRUD statements but add() var myFind = myColl.find('name like :param1 AND age > :param2'); var myDocs = myFind.bind('param1', 'L%').bind('param2', 18).execute(); var MyOtherDocs = myFind.bind('param1', 'J%').bind('param2', 25).execute();
MySQL Shell Python Code
myColl = db.get_collection('my_collection') # Only prepare a Collection.remove() operation, but do not run it yet myRemove = myColl.remove('name = :param1 AND age = :param2') # Binding parameters to the prepared function and .execute() myRemove.bind('param1', 'Leon').bind('param2', 39).execute() myRemove.bind('param1', 'Johannes').bind('param2', 28).execute() # Binding works for all CRUD statements but add() myFind = myColl.find('name like :param1 AND age > :param2') myDocs = myFind.bind('param1', 'L%').bind('param2', 18).execute() MyOtherDocs = myFind.bind('param1', 'J%').bind('param2', 25).execute()
Node.js JavaScript Code
var myColl = db.getCollection('my_collection'); // Only prepare a Collection.remove() operation, but do not run it yet var myRemove = myColl.remove('name = :param1 AND age = :param2'); // Binding parameters to the prepared function and .execute() myRemove.bind('param1', 'Leon').bind('param2', 39).execute(); myRemove.bind('param1', 'Johannes').bind('param2', 28).execute(); // Binding works for all CRUD statements but add() var myFind = myColl.find('name like :param1 AND age > :param2'); var myDocs = myFind.bind('param1', 'L%').bind('param2', 18).execute(); var MyOtherDocs = myFind.bind('param1', 'J%').bind('param2', 25).execute();
C# Code
var myColl = db.GetCollection("my_collection"); // Only prepare a Collection.Remove() operation, but do not run it yet var myRemove = myColl.Remove("name = :param1 AND age = :param2"); // Binding parameters to the prepared function and .Execute() myRemove.Bind("param1", "Leon").Bind("param2", 39).Execute(); myRemove.Bind("param1", "Johannes").Bind("param2", 28).Execute(); // Binding works for all CRUD statements but Add() var myFind = myColl.Find("name like :param1 AND age > :param2"); var myDocs = myFind.Bind("param1", "L%").Bind("param2", 18).Execute(); var MyOtherDocs = myFind.Bind("param1", "J%").Bind("param2", 25).Execute();
Python Code
my_coll = my_schema.get_collection('my_collection') # Only prepare a Collection.remove() operation, but do not run it yet my_remove = my_coll.remove('name = :param1 AND age = :param2') # Binding parameters to the prepared function and .execute() my_remove.bind('param1', 'Leon').bind('param2', 39).execute() my_remove.bind('param1', 'Johannes').bind('param2', 28).execute() # Binding works for all CRUD statements but add() my_find = my_coll.find('name like :param1 AND age > :param2') my_docs = my_find.bind('param1', 'L%').bind('param2', 18).execute() my_other_docs = my_find.bind('param1', 'J%').bind('param2', 25).execute()
Java Code
Collection myColl = db.getCollection("my_collection"); // Create Collection.remove() operation, but do not run it yet RemoveStatement myRemove = myColl.remove("name = :param1 AND age = :param2"); // Binding parameters to the prepared function and .execute() myRemove.bind("param1", "Leon").bind("param2", 39).execute(); myRemove.bind("param1", "Johannes").bind("param2", 28).execute(); // Binding works for all CRUD statements but add() FindStatement myFind = myColl.find("name LIKE :name AND age > :age"); Map<String, Object> params = new HashMap<>(); params.put("name", "L%"); params.put("age", 18); DocResult myDocs = myFind.bind(params).execute(); params.put("name", "J%"); params.put("age", 25); DocResult myOtherDocs = myFind.bind(params).execute();
C++ Code
Collection myColl = db.getCollection("my_collection"); // Create Collection.remove() operation, but do not run it yet auto myRemove = myColl.remove("name = :param1 AND age = :param2"); // Binding parameters to the prepared function and .execute() myRemove.bind("param1", "Leon").bind("param2", 39).execute(); myRemove.bind("param1", "Johannes").bind("param2", 28).execute(); // Binding works for all CRUD statements but Add() auto myFind = myColl.find("name like :param1 AND age > :param2"); auto myDocs = myFind.bind("param1", "L%").bind("param2", 18).execute(); auto MyOtherDocs = myFind.bind("param1", "J%").bind("param2", 25).execute();
Использование X DevAPI на языке программирования, полностью определяет
синтаксис, который будет использоваться, например, выполняя SQL-операторы,
хотя сессия или любая из операций CRUD фактически выполняется только,
когда вызвана функция execute()
:
var result = mysession.sql('show databases').execute(); var city_res = db.cities.find().execute();
Вызов execute()
выше заставляет операцию быть
выполненной и вернуть объект результата. Возвращенный объект результата
назначен на переменную, и это назначение последняя выполненная операция,
который не возвращает данных. Такие операции могут также возвратить объект
результата, который используется, чтобы обработать информацию,
возвращенную из операции.
Альтернативно MySQL Shell обеспечивает следующие удобства использования, которые облегчают работу с X DevAPI в интерактивном режиме:
Автоматическое выполнение CRUD и операций SQL.
Автоматическая обработка результатов.
MySQL Shell контролирует результат последней операции каждый раз, когда вы вводите запрос. Комбинация этих особенностей делает использование интерактивного режима MySQL Shell идеальным для разработки прототипа, поскольку операции немедленно выполняются, и их результаты показаны, не требуя никакого дополнительного кодирования. Для получения дополнительной информации посмотрите MySQL Shell 8.0 (part of MySQL 8.0).
Если MySQL Shell обнаруживает, что готовая к выполнению операция CRUD,
была возвращена, это автоматически вызовет
execute()
. Повторение примеров выше в MySQL
Shell и удаление назначенной операции показывают, что
они автоматически выполняются.
mysql-js> mysession.sql('show databases');
MySQL Shell выполняет операцию SQL, и, как упомянуто выше, как только эта операция выполняется, объект результата возвращен.
Если MySQL Shell обнаруживает, что объект результата будет возвращен, это автоматически обрабатывает его, печатая данные о результате в лучшем возможном формате. Есть различные типы объектов результата и изменений формата.
mysql-js> db.countryInfo.find().limit(1) [{ "GNP": 828, "IndepYear": null, "Name": "Aruba", "_id": "ABW", "demographics": { "LifeExpectancy": 78.4000015258789, "Population": 103000 }, "geography": { "Continent": "North America", "Region": "Caribbean", "SurfaceArea": 193 }, "government": { "GovernmentForm": "Nonmetropolitan Territory of The Netherlands", "HeadOfState": "Beatrix" } }] 1 document in set (0.00 sec)