RussianLDP Рейтинг@Mail.ru
WebMoney: 
WMZ Z294115950220 
WMR R409981405661 
WME E134003968233 
Visa 
4274 3200 2453 6495 

Глава 3. Операции CRUD

Этот раздел объясняет, как использовать X DevAPI для операций Create, Read, Update и Delete (CRUD).

Основная область MySQL всегда работала с относительными таблицами. X DevAPI расширяет эту область, добавляя поддержку операций CRUD, которыми можно управлять для коллекций документов.

3.1. Обзор операций CRUD

Операции CRUD доступны как методы, которые воздействуют на объекты схемы. Доступные объекты схемы состоят из объектов коллекции, содержащих документы или объекты таблицы, состоящие из строк и столбцов.

Следующая таблица показывает доступные операции CRUD для объектов коллекции и для объектов таблицы.

Операция

Документ

Таблица

Create

Collection.add()

Table.insert()

Read

Collection.find()

Table.select()

Update

Collection.modify()

Table.update()

Delete

Collection.remove()

Table.delete()

Классы объекта базы данных

Рис. 3.1. Диаграмма классов


3.2. Формирование цепочки метода

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();

3.3. Синхронное выполнение против асинхронного

Традиционно многие драйверы 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++

Асинхронные операции с применением Awaits

Такие языки, как 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>, параметр типа один из типов результата.

3.4. Привязка параметров

Вместо того, чтобы использовать значения непосредственно в последовательности выражения, хорошая практика отделить их от последовательности выражения. Это сделано, используя параметры в последовательности выражения и функцию 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

Вместо непосредственной связи и выполнения операций 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();

3.5. Автоматическое выполнение кода MySQL Shell

Использование 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)

Поиск

 

Найди своих коллег!

Вы можете направить письмо администратору этой странички, Алексею Паутову. mailto:alexey.v.pautov@mail.ru