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

Глава 8. Выполнение запросов

Этот раздел объясняет выполнение запроса с информацией о том, как обращаться с транзакциями и ошибками.

8.1. Операционная обработка

Транзакции можно использовать в групповых операциях атомно. Или все операции имеют успех, когда они передаются, или ни одна. Возможно отменить транзакцию, пока это не было передано.

Транзакции могут быть начаты в сессии, используя метод startTransaction(), переданы через commitTransaction() и отменены через rollbackTransaction(). Это иллюстрировано в следующем примере. Пример предполагает, что испытательная схема существует и что коллекция my_collection не существует.

MySQL Shell JavaScript Code

var mysqlx = require('mysqlx');
// Connect to server
var session = mysqlx.getSession( {
  host: 'localhost', port: 33060,
  user: 'user', password: 'password' } );

// Get the Schema test
var db = session.getSchema('test');
// Create a new collection
var myColl = db.createCollection('my_collection');

// Start a transaction
session.startTransaction();
try {
  myColl.add({name: 'Rohit', age: 18, height: 1.76}).execute();
  myColl.add({name: 'Misaki', age: 24, height: 1.65}).execute();
  myColl.add({name: 'Leon', age: 39, height: 1.9}).execute();
  // Commit the transaction if everything went well
  session.commit();
  print('Data inserted successfully.');
}
catch (err) {
  // Rollback the transaction in case of an error
  session.rollback();
  // Printing the error message
  print('Data could not be inserted: ' + err.message);
}

MySQL Shell Python Code

from mysqlsh import mysqlx
# Connect to server
session = mysqlx.get_session( {
  'host': 'localhost', 'port': 33060,
  'user': 'user', 'password': 'password' } )

# Get the Schema test
db = session.get_schema('test')
# Create a new collection
myColl = db.create_collection('my_collection')
# Start a transaction
session.start_transaction()
try:
  myColl.add({'name': 'Rohit', 'age': 18, 'height': 1.76}).execute()
  myColl.add({'name': 'Misaki', 'age': 24, 'height': 1.65}).execute()
  myColl.add({'name': 'Leon', 'age': 39, 'height': 1.9}).execute()

# Commit the transaction if everything went well
session.commit()
print('Data inserted successfully.')
except Exception as err:
# Rollback the transaction in case of an error
session.rollback()

# Printing the error message
print('Data could not be inserted: %s' % str(err))

C# Code

// Connect to server
var session = MySQLX.GetSession("server=localhost;port=33060;user=user;password=password;");

// Get the Schema test
var db = session.GetSchema("test");
// Create a new collection
var myColl = db.CreateCollection("my_collection");

// Start a transaction
session.StartTransaction();
try
{
  myColl.Add(new { name = "Rohit", age = 18, height = 1.76}).Execute();
  myColl.Add(new { name = "Misaki", age = 24, height = 1.65}).Execute();
  myColl.Add(new { name = "Leon", age = 39, height = 1.9}).Execute();
  // Commit the transaction if everything went well
  session.Commit();
  Console.WriteLine("Data inserted successfully.");
}
catch(Exception err)
{
  // Rollback the transaction in case of an error
  session.Rollback();
  // Printing the error message
  Console.WriteLine("Data could not be inserted: " + err.Message);
}

Python Code

import mysqlx

# Connect to server
my_session = mysqlx.get_session({
  'host': 'localhost', 'port': 33060,
  'user': 'user', 'password': 'password'
})

# Get the Schema test
my_schema = my_session.get_schema('test')
# Create a new collection
my_coll = my_schema.create_collection('my_collection')

# Start a transaction
session.start_transaction()
try:
my_coll.add({'name': 'Rohit', 'age': 18, 'height': 1.76}).execute()
my_coll.add({'name': 'Misaki', 'age': 24, 'height': 1.65}).execute()
my_coll.add({'name': 'Leon', 'age': 39, 'height': 1.9}).execute()

# Commit the transaction if everything went well
my_session.commit()
print('Data inserted successfully.')
except Exception as err:
# Rollback the transaction in case of an error
my_session.rollback()
# Printing the error message
print('Data could not be inserted: {0}'.format(str(err)))

Java Code

import com.mysql.cj.xdevapi.*;

// Connect to server
Session mySession = new SessionFactory().getSession("mysqlx://localhost:33060/test?user=user&password=password");
Schema db = mySession.getSchema("test");

// Create a new collection
Collection myColl = db.createCollection("my_collection");
// Start a transaction
mySession.startTransaction();
try {
  myColl.add("{\"name\":\"Rohit\", \"age\":18}", "{\"name\":\"Misaki\", \"age\":24}", "{\"name\":\"Leon\", \"age\":39}");
  mySession.commit();
  System.out.println("Data inserted successfully.");
} catch (Exception err) {
  // Rollback the transaction in case of an error
  mySession.rollback();
  // Printing the error message
  System.out.println("Data could not be inserted: " + err.getMessage());
}

C++ Code

// Connect to server
Session session(SessionOption::HOST, "localhost",
SessionOption::PORT, 33060,
SessionOption::USER, "user",
SessionOption::PWD, "password");

// Get the Schema test
Schema db = session.getSchema("test");
// Create a new collection
Collection myColl = db.createCollection("my_collection");

// Start a transaction
session.startTransaction();
try {
  myColl.add(R"({"name": "Rohit", "age": 18, "height": 1.76})").execute();
  myColl.add(R"({"name": "Misaki", "age": 24, "height": 1.65})").execute();
  myColl.add(R"({"name": "Leon", "age": 39, "height": 1.9})").execute();
  // Commit the transaction if everything went well
  session.commit();
  cout << "Data inserted successfully." << endl;
}
catch (const Error &err) {
  // Rollback the transaction in case of an error
  session.rollback();
  // Printing the error message
  cout << "Data could not be inserted: " << err << endl;
}

8.1.1. Обработка предупреждений

Подобно выполнению отдельных операторов или отмене транзакции можно также получить предупреждения. Чтобы быть в состоянии обработать эти предупреждения, должен быть проверен объект результата Session.commit(); или Session.rollback();.

Это показывают в следующем примере. Пример предполагает, что испытательная схема существует и что коллекция my_collection не существует.

MySQL Shell JavaScript Code

var mysqlx = require('mysqlx');
// Connect to server
var mySession = mysqlx.getSession( {
  host: 'localhost', port: 33060,
  user: 'user', password: 'password' } );

// Get the Schema test
var myDb = mySession.getSchema('test');
// Create a new collection
var myColl = myDb.createCollection('my_collection');

// Start a transaction
mySession.startTransaction();
try
{
  myColl.add({'name': 'Rohit', 'age': 18, 'height': 1.76}).execute();
  myColl.add({'name': 'Misaki', 'age': 24, 'height': 1.65}).execute();
  myColl.add({'name': 'Leon', 'age': 39, 'height': 1.9}).execute();
  // Commit the transaction if everything went well
  var reply = mySession.commit();
  // handle warnings
  if (reply.warningCount)
  {
     var warnings = reply.getWarnings();
     for (index in warnings)
     {
       var warning = warnings[index];
       print ('Type ['+ warning.level + '] (Code ' + warning.code +
              '): ' + warning.message + '\n');
     }
  }
  print ('Data inserted successfully.');
}
catch(err)
{
  // Rollback the transaction in case of an error
  reply = mySession.rollback();
  // handle warnings
  if (reply.warningCount)
  {
     var warnings = reply.getWarnings();
     for (index in warnings)
     {
       var warning = warnings[index];
       print ('Type ['+ warning.level + '] (Code ' + warning.code + '): ' +
              warning.message + '\n');
     }
  }
  // Printing the error message
  print ('Data could not be inserted: ' + err.message);
}

MySQL Shell Python Code

from mysqlsh import mysqlx

# Connect to server
mySession = mysqlx.get_session( {
  'host': 'localhost', 'port': 33060,
  'user': 'user', 'password': 'password' } )

# Get the Schema test
myDb = mySession.get_schema('test')
# Create a new collection
myColl = myDb.create_collection('my_collection')

# Start a transaction
mySession.start_transaction()
try:
myColl.add({'name': 'Rohit', 'age': 18, 'height': 1.76}).execute()
myColl.add({'name': 'Misaki', 'age': 24, 'height': 1.65}).execute()
myColl.add({'name': 'Leon', 'age': 39, 'height': 1.9}).execute()

# Commit the transaction if everything went well
reply = mySession.commit()

# handle warnings
if reply.warning_count:
for warning in result.get_warnings():
print('Type [%s] (Code %s): %s\n' % (warning.level, warning.code, warning.message))

print('Data inserted successfully.')
except Exception as err:
# Rollback the transaction in case of an error
reply = mySession.rollback()

# handle warnings
if reply.warning_count:
for warning in result.get_warnings():
print('Type [%s] (Code %s): %s\n' % (warning.level, warning.code, warning.message))
# Printing the error message
print('Data could not be inserted: %s' % str(err))

C# Code

// Connect to server
var session = MySQLX.GetSession("server=localhost;port=33060;user=user;password=password;");

// Get the Schema test
var db = session.GetSchema("test");
// Create a new collection
var myColl = db.CreateCollection("my_collection");

// Start a transaction
session.StartTransaction();
int warningCount = 0;
try
{
  var result = myColl.Add(new { name = "Rohit", age = 18,
                                height = 1.76}).Execute();
  warningCount += result.Warnings.Count;
  result = myColl.Add(new { name = "Misaki", age = 24,
                            height = 1.65}).Execute();
  warningCount += result.Warnings.Count;
  result = myColl.Add(new { name = "Leon", age = 39,
                            height = 1.9}).Execute();
  warningCount += result.Warnings.Count;
  // Commit the transaction if everything went well
  session.Commit();
  if (warningCount > 0)
  {
     // handle warnings
  }
  Console.WriteLine("Data inserted successfully.");
} catch (Exception err) {
  // Rollback the transaction in case of an error
  session.Rollback();
  if (warningCount > 0)
  {
     // handle warnings
  }
  // Printing the error message
  Console.WriteLine("Data could not be inserted: " + err.Message);
}

Python Code

import mysqlx
# Connect to server
my_session = mysqlx.get_session({
  'host': 'localhost', 'port': 33060,
  'user': 'user', 'password': 'password'
})

# Get the Schema test
my_schema = my_session.get_schema('test')
# Create a new collection
my_coll = my_schema.create_collection('my_collection')

# Start a transaction
my_session.start_transaction()
try:
my_coll.add({'name': 'Rohit', 'age': 18, 'height': 1.76}).execute()
my_coll.add({'name': 'Misaki', 'age': 24, 'height': 1.65}).execute()
my_coll.add({'name': 'Leon', 'age': 39, 'height': 1.9}).execute()

# Commit the transaction if everything went well
result = my_session.commit()
# handle warnings
if result.get_warnings_count() > 0:
for warning in result.get_warnings():
print('Type [{0}] (Code {1}): {2}'.format(warning['level'], warning['code'], warning['msg']))

print('Data inserted successfully.')
except Exception as err:
# Rollback the transaction in case of an error
result = my_session.rollback()

# handle warnings
if result.get_warnings_count() > 0:
for warning in result.get_warnings():
print('Type [{0}] (Code {1}): {2}'.format(warning['level'], warning['code'], warning['msg']))

# Printing the error message
print('Data could not be inserted: {0}'.format(err))

Java Code

// c.f. "standard transaction handling"

C++ Code

/*
Connector/C++ does not yet provide access to transaction warnings
-- Session methods commit() and rollback() do not return a result object.
*/

По умолчанию все предупреждения посылают с сервера клиенту. Если операция производит много предупреждений, и предупреждения не представляют ценности, их отправку можно выключить. Это помогает экономить пропускную способность. session.setFetchWarnings() управляет тем, отказываются ли от предупреждений в сервере или посылают их клиенту. session.getFetchWarnings() используется, чтобы узнать текущие настройки.

MySQL Shell JavaScript Code

var mysqlx = require('mysqlx');

function process_warnings(result)
{
  if (result.getWarningCount())
  {
     var warnings = result.getWarnings();
     for (index in warnings)
     {
       var warning = warnings[index];
       print ('Type ['+ warning.level + '] (Code ' + warning.code + '): ' +
              warning.message + '\n');
     }
  } else {
    print ("No warnings were returned.\n");
  }
}

// Connect to server
var mySession = mysqlx.getSession( {
  host: 'localhost', port: 33060,
  user: 'user', password: 'password' } );

// Disables warning generation
mySession.setFetchWarnings(false);
var result = mySession.sql('drop schema if exists unexisting').execute();
process_warnings(result);

// Enables warning generation
mySession.setFetchWarnings(true);
var result = mySession.sql('drop schema if exists unexisting').execute();
process_warnings(result);

MySQL Shell Python Code

from mysqlsh import mysqlx
def process_warnings(result):
if result.get_warnings_count():
for warning in result.get_warnings():
print('Type [%s] (Code %s): %s\n' % (warning.level, warning.code, warning.message))
else:
print("No warnings were returned.\n")

# Connect to server
mySession = mysqlx.get_session( {
  'host': 'localhost', 'port': 33060,
  'user': 'user', 'password': 'password' } );

# Disables warning generation
mySession.set_fetch_warnings(False)
result = mySession.sql('drop schema if exists unexisting').execute()
process_warnings(result)

# Enables warning generation
mySession.set_fetch_warnings(True)
result = mySession.sql('drop schema if exists unexisting').execute()
process_warnings(result)

Java Code

// Connect to server
Session mySession = new SessionFactory().getSession("mysqlx://localhost:33060/test?user=user&password=password");
Schema db = mySession.getSchema("test");
// Create a new collection
Collection myColl = db.createCollection("my_collection");
// Start a transaction
mySession.startTransaction();
try {
  Result res = myColl.add("{\"name\":\"Rohit\", \"age\":18}",
                          "{\"name\":\"Misaki\", \"age\":24}",
                          "{\"name\":\"Leon\", \"age\":39}").execute();
  System.out.println(res.getWarningsCount());
  Iterator<Warning> warnings = res.getWarnings();
  while (warnings.hasNext()) {
    Warning warn = warnings.next();
    System.out.println(warn.getCode() + ", " + warn.getLevel() + ", " +
                       warn.getMessage());
  }
  mySession.commit();
  System.out.println("Data inserted successfully.");
} catch (Exception err) {
  // Rollback the transaction in case of an error
  mySession.rollback();
  // Printing the error message
  System.out.println("Data could not be inserted: " + err.getMessage());
}

8.1.2. Обработка ошибок

Разрабатывая скрипты для MySQL Shell, можно часто просто полагаться на обработку исключений, сделанную MySQL Shell. Для всех других языков надлежащая обработка исключений требуется, чтобы фиксировать ошибки, или традиционный образец обработки ошибок должен использоваться, если язык не поддерживает исключения.

Обработка ошибок по умолчанию может быть изменена, создав SessionContext и передав его функции mysqlx.getSession(). Это позволяет переключиться с исключений на проверку на ошибки.

Следующие примеры показывают, как выполнить надлежащую обработку ошибок для различных языков. Пример предполагает, что испытательная схема существует и что коллекция my_collection тоже существует.

MySQL Shell JavaScript Code

var mysqlx = require('mysqlx');
var mySession;
try {
  // Connect to server on localhost
  mySession = mysqlx.getSession( {
    host: 'localhost', port: 33060,
    user: 'user', password: 'password' } );
} catch (err) {
  print('The database session could not be opened: ' + err.message);
}
try {
  var myDb = mySession.getSchema('test');
  // Use the collection 'my_collection'
  var myColl = myDb.getCollection('my_collection');
  // Find a document
  var myDoc = myColl.find('name like :param').limit(1)
      .bind('param','L%').execute();
  // Print document
  print(myDoc.first());
} catch (err) {
  print('The following error occurred: ' + err.message);
}
finally {
  // Close the session in any case
  mySession.close();
}

MySQL Shell Python Code

from mysqlsh import mysqlx
mySession
try:
# Connect to server on localhost
mySession = mysqlx.get_session( {
  'host': 'localhost', 'port': 33060,
  'user': 'user', 'password': 'password' } )

except Exception as err:
print('The database session could not be opened: %s' % str(err))
try:
  myDb = mySession.get_schema('test')

# Use the collection 'my_collection'
myColl = myDb.get_collection('my_collection')
# Find a document
myDoc = myColl.find('name like :param').limit(1).bind('param','L%').execute()
# Print document
print(myDoc.first())
except Exception as err:
print('The following error occurred: %s' % str(err))
finally:
# Close the session in any case
mySession.close()

Node.js JavaScript Code

var mysqlx = require('@mysql/xdevapi');
// Connect to server on localhost
mysqlx
.getSession({
  host: 'localhost',
  port: 33060,
  user: 'user',
  password: 'password'
})
.then(function (mySession) {
  // This can't throw an error as we check existence at a later operation only
  var myDb = mySession.getSchema('test');
  // Use the collection 'my_collection'
  // This can't throw an error as we check existence at a later operation only
  var myColl = myDb.getCollection('my_collection');
  // Find a document
  return myColl
  .find('name like :param')
  .limit(1)
  .bind('param','L%')
  .execute(function (row) {
    console.log(row);
  })
  .then(function () {
    return session.close();
  })
  .catch(function (err) {
    console.log('The following error occurred: ' + err.message);
  });
})
.catch (err) {
  console.log('The database session could not be opened: ' + err.message);
});

C# Code

Session mySession = null;
try
{
  // Connect to server on localhost
  mySession = MySQLX.GetSession("mysqlx://user:password@localhost:33060");
  try
  {
    Schema myDb = mySession.GetSchema("test");
    // Use the collection 'my_collection'
    Collection myColl = myDb.GetCollection("my_collection");
    // Find a document
    DocResult myDoc = myColl.Find("name like :param").Limit(1).
                             Bind("param", "L%").Execute();
    // Print document
    Console.WriteLine(myDoc.FetchOne());
  } catch (Exception err) {
    Console.WriteLine("The following error occurred: " + err.Message);
  } finally {
    // Close the session in any case
    mySession.Close();
  }
} catch (Exception err) {
  Console.WriteLine("The database session could not be opened: "+err.Message);
}

Python Code

import mysqlx

# Connect to server
my_session = mysqlx.get_session({
  'host': 'localhost', 'port': 33060,
  'user': 'user', 'password': 'password'
})

# Get the Schema test
my_schema = my_session.get_schema('test')
# Create a new collection
my_coll = my_schema.create_collection('my_collection')

# Start a transaction
my_session.start_transaction()
try:
my_coll.add({'name': 'Rohit', 'age': 18, 'height': 1.76}).execute()
my_coll.add({'name': 'Misaki', 'age': 24, 'height': 1.65}).execute()
my_coll.add({'name': 'Leon', 'age': 39, 'height': 1.9}).execute()

# Commit the transaction if everything went well
result = my_session.commit()
# handle warnings
if result.get_warnings_count() > 0:
for warning in result.get_warnings():
print('Type [{0}] (Code {1}): {2}'.format(warning['level'], warning['code'], warning['msg']))

print('Data inserted successfully.')
except Exception as err:
# Rollback the transaction in case of an error
my_session.rollback()

# handle warnings
if reply.get_warnings_count() > 0:
for warning in result.get_warnings():
print('Type [{0}] (Code {1}): {2}'.format(warning['level'], warning['code'], warning['msg']))

# Printing the error message
print('Data could not be inserted: {0}'.format(err))

Java Code

import com.mysql.cj.xdevapi.*;

Session mySession;
try {
// Connect to server on localhost
mySession = new SessionFactory().getSession("mysqlx://localhost:33060/test?user=user&password=password");

try {
Schema myDb = mySession.getSchema("test");
// Use the collection 'my_collection'
Collection myColl = myDb.getCollection("my_collection");
// Find a document
DocResult myDoc = myColl.find("name like :param").limit(1).bind("param", "L%").execute();
// Print document
System.out.println(myDoc.fetchOne());
} catch (XDevAPIError err) { // special exception class for server errors
System.err.println("The following error occurred: " + err.getMessage());
} finally {
  // Close the session in any case
  mySession.close();
}} catch (Exception err) {
System.err.println("The database session could not be opened: " + err.getMessage());
}

C++ Code

#include <mysqlx/xdevapi.h>
try
{
  // Connect to server on localhost
  Session session(33060, "user", "password");
  try
  {
    Schema db = session.getSchema("test");
    // Use the collection 'my_collection'
    Collection myColl = db.getCollection("my_collection");
    // Find a document
    auto myDoc = myColl.find("name like :param").limit(1).
                        bind("param", "L%").execute();
    // Print document
    cout << myDoc.fetchOne() << endl;
    // Exit with success code
    exit(0);
  } catch (const Error &err) {
    cout << "The following error occurred: " << err << endl;
    exit(1);
  }
  // Note: session is closed automatically when session
  // object is destructed.
} catch (const Error &err) {
  cout << "The database session could not be opened: " << err << endl;
  // Exit with error code
  exit(1);
}

8.2. Работа с точками сохранения

X DevAPI поддерживает точки сохранения, которые позволяют вам установить названный пункт в транзакции, к которому можно вернуться. Устанавливая точки сохранения в транзакции, можно позже использовать функциональность отката, чтобы отменить любые запросы, сделанные после создания точки сохранения. Точки сохранения могут быть рсвобождены, если вы больше в них не нуждаетесь. Этот раздел покажет, как работать с точками сохранения в X DevAPI. См. SAVEPOINT.

Установка точки сохранения

Точки сохранения определяются именем строки. Последовательность может содержать любой символ, разрешенный для идентификатора. Чтобы создать точку сохранения, используйте session.setSavepoint(), которая отобраается на SQL-запрос SAVEPOINT name;. Если вы не определяете name, оно автоматически произведено. Например:

session.setSavepoint()

Операционная точка сохранения создается с автоматически произведенным именем, и последовательность возвращена с названием точки сохранения. Это имя может использоваться с session.rollbackTo() или session.releaseSavepoint(). Операция session.setSavepoint() может быть вызвана многократно в сессии, каждый раз уникальное название точки сохранения произведено.

Также возможно вручную определить название точки сохранения, передавая строку name так:

session.setSavepoint('name')

Результат: операционная точка сохранения с указанным name, которое возвращено операцией как последовательность. session.setSavepoint(' name') можно вызвать многократно таким образом, и если name уже использовалось для точки сохранения, предыдущая точка сохранения удалена и установлена новая.

Откат назад к точке сохранения

Когда у сессии есть операционные точки сохранения, можно отменить любые последующие транзакции, используя session.rollbackTo(), что отображается на ROLLBACK TO name:

session.rollbackTo('name')

откатывает назад к операционной точке сохранения name. Эта операция имеет успех, пока данная точка сохранения не была освобождена. Откат назад к точке сохранения, которая была создана до других результатов точек сохранения в последующих или освобождаемых точках сохранения или удалена:

session.startTransaction()
(some data modifications occur...)
session.setSavepoint('point1') <---- succeeds
(some data modifications occur...)
session.setSavepoint('point2') <---- succeeds
(some data modifications occur...)
session.rollbackTo('point1') <---- succeeds
session.rollbackTo('point1') <---- still succeeds, but position stays the same
session.rollbackTo('point2') <---- generates an error because lines above already cleared point2
session.rollbackTo('point1') <---- still succeeds

Отмена точки сохранения

Отменить точку сохранения, например, когда она более не требуется, можно через releaseSavepoint() с передачей имени точки сохранения:

session.releaseSavepoint('name')

освобождает точку сохранения name .

Точки сохранения и поведение неявной транзакции

Точное поведение точек сохранения определяется сервером, и определено как autocommit, см. autocommit, Commit, and Rollback.

Например, рассмотрите следующие запросы без явного BEGIN, session.startTransaction() или подобных запросов:

session.setSavepoint('testsavepoint');
session.releaseSavepoint('testsavepoint');

Если включен autocommit на сервере, эти запросы вернут ошибку потому, что нет точки сохранения testsavepoint. Это потому, что session.setSavepoint() создает транзакцию, точку сохранения и непосредственно передает ее. Результат состоит в том, что точки сохранения не существует к моменту вызова releaseSavepoint(), который находится вместо этого в своей собственной транзакции. В этом случае, чтобы точка сохранения работала нормально, надо начать блок явной транзакции сначала.

8.3. Работа с блокировками

X DevAPI понимает блокировки MySQL через методы lockShared() и lockExclusive() для Collection.find() и Table.select(). Это позволяет вам управлять блокировкой строки, чтобы гарантировать безопасные обновления транзакционного документа на коллекциях и избежать проблем параллелизма, например используя методы lockShared() и lockExclusive(). Для большего количества справочной информации о блокировках см. Locking Reads.

Методы lockShared() и lockExclusive() имеют следующие свойства, используются ли они с коллекцией или таблицей.

  • Множественные вызовы методов блокировки разрешены. Если запрос выполняется, в то время как иная транзакция держит ту же самую блокировку, запрос ждет, пока другая транзакция не освободит блокировку. Если множественные вызовы методов сделаны, последний вызванный метод имеет приоритет. Другими словами, find().lockShared().lockExclusive() эквивалент find().lockExclusive().

  • lockShared() имеет ту же самую семантику, как SELECT ... LOCK IN SHARE MODE. Устанавливает коллективную блокировку на любых строках, которые прочитаны. Другие сессии могут прочитать строки, но не могут изменить их, пока ваша транзакция не передается. Если какая-либо из этих строк была изменена другой транзакцией, которая еще не передана, ваш запрос ждет до конца той транзакции и затем использует последние значения.

  • lockExclusive() имеет ту же самую семантику, как SELECT ... FOR UPDATE. Поскольку любой индекс делает запись ограничений поиска, он захватывает строки любые связанные элементы индекса, таким же образом как будто вы применили UPDATE для тех строк. Другие транзакции заблокированы на обновление тех строк при работе SELECT ... LOCK IN SHARE MODE или от чтения данных на определенных уровнях изоляции транзакции. Последовательное чтение игнорирует любой набор блокировок на записях, которые существуют в прочитанном представлении. Старые версии записей не могут быть блокированы, они восстановлены применинем журнала отмены к копии записи в памяти.

  • Блокировки проводятся столько, сколько транзакции, в которых они были приобретены, существуют. Они немедленно освобождены после того, как запрос завершен, если транзакция не открыта или autocommit выключен.

Оба метода поддерживают режимы NOWAIT и SKIP LOCKED для InnoDB, см. Locking Read Concurrency with NOWAIT and SKIP LOCKED. Чтобы использовать эти способы с методами блокировки, используйте:

  • NOWAIT, если функция сталкивается с блокировкой строки, она прерывается и производит ошибку ER_LOCK_NOWAIT.

  • SKIP_LOCKED, если функция сталкивается с блокировкой строки, она пропускает строку и продолжается.

  • DEFAULT, если функция сталкивается с блокировкой строки, она ждет снятия блокировки. Эквивалент запроса метода блокировки без указания способа.

Советы по блокировкам

Прпи работе с режимом блокировки, учитывайте, что:

  • autocommit означает, что всегда есть открытая транзакция, которая передается автоматически, когда SQL-оператор выполняется.

  • По умолчанию сессии находятся в режиме autocommit.

  • Вы отключаете autocommit неявно, когда вызываете startTransaction().

  • В режиме autocommit, если блокировка получена, она снята после того, как запрос заканчивается. Это может принудить вас приходить к заключению, что блокировки не были приобретены, но дело не в этом.

  • Точно так же, при попытке приобрести блокировку, которая уже принадлежит кому-то еще, запрос ждет, пока другая блокировка не будет снята.

8.4. Работа с подготовленными запросами

Сделано в MySQL 8.0.16 и выше: X DevAPI улучшает работу для каждого запроса CRUD, который неоднократно выполняется при помощи подготовленного запроса серверной стороны для его второго и последующего выполнения. Это происходит внутренне: приложения не должны делать ничего дополнительного, чтобы использовать эту особенность, пока тот же самый объект операции снова используется.

Когда запрос выполняется второй раз с изменениями только в значениях данных или в значениях, которые уточняют результаты выполнения (например, отличающийся offset() или limit()), сервер готовит запрос к последующему выполнению, так, чтобы не было никакой потребности повторно разобрать его, когда этим управляют снова. Новым значениям для повторных выполнений подготовленного запроса предоставляют привязку параметров. Когда запрос изменяется, привязывая к нему метод, который уточняет результат (например, sort(), skip() , limit() или offset()), запрос повторно подготовлен. Следующий псевдокод и комментарии к нему демонстрируют эту особенность:

var f = coll.find("field = :field");
f.bind("field", 1).execute(); // Normal execution
f.bind("field", 2).execute(); // Same statement executed with a different parameter value triggers statement preparation
f.bind("field", 3).execute(); // Prepared statement executed with a new value
f.bind("field", 3).limit(10).execute(); // Statement reprepared as it is modified with limit()
f.bind("field", 4).limit(20).execute(); // Reprepared statement executed with new parameters 

Заметьте, что, чтобы использовать в своих интересах эту особенность, тот же самый объект операции должен быть снова использован в повторениях запроса. Посмотрите на этот пример:

for (i=0; i<100; ++i)
{
  collection.find().execute();
}

Цикл не может использовать особенность подготовленного запроса потому, что объект операции collection.find() воссоздается при каждом повторении цикла for. Теперь посмотрите на этот пример:

for (i=0; i<100; ++i)
{
  var op = collection.find()
  op.execute();
}

Повторный запрос подготовлен однажды и затем снова использован потому, что тот же самый объект операции collection.find() повторно выполняется при каждом повторении цикла for.

Подготовленные запросы это часть Session. Когда Client перезапускает Session (например, через Mysqlx.Session.Reset), подготовленные запросы удалены.

Поиск

 

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

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