Skip to content

Commit

Permalink
docs(mysql): use async (#1711)
Browse files Browse the repository at this point in the history
  • Loading branch information
atian25 authored and popomore committed Nov 29, 2017
1 parent 1ec1705 commit cb9c9a4
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 101 deletions.
103 changes: 51 additions & 52 deletions docs/source/en/tutorials/mysql.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
title: MySQL
---

MySQL is one of the most common and best RDBMS in terms of web applications. It is used in many large-scale websites such as Google and Facebook. The document provides a tutorial to access MySQL using Egg framework and plugins.
MySQL is one of the most common and best RDBMS in terms of web applications. It is used in many large-scale websites such as Google and Facebook.

## egg-mysql

egg-mysql is provided to access both the MySQL databases and MySQL-based online database service.
egg-mysql is provided to access both the MySQL databases and MySQL-based online database service.

### Installation and Configuration

Expand Down Expand Up @@ -32,7 +33,7 @@ Configuration to accesss single MySQL instance as shown below:
```js
// config/config.${env}.js
exports.mysql = {
// database configuration
// database configuration
client: {
host: 'mysql.com',
port: '3306',
Expand All @@ -47,10 +48,10 @@ exports.mysql = {
};
```

Use:
Use:

```js
yield app.mysql.query(sql, values); // single instance can be accessed through app.mysql
await app.mysql.query(sql, values); // single instance can be accessed through app.mysql
```

#### Multiple Data Sources
Expand Down Expand Up @@ -93,10 +94,10 @@ Use:

```js
const client1 = app.mysql.get('db1');
yield client1.query(sql, values);
await client1.query(sql, values);

const client2 = app.mysql.get('db2');
yield client2.query(sql, values);
await client2.query(sql, values);
```

#### Dynamic Creation
Expand All @@ -105,53 +106,50 @@ Pre-declaration of configuration might not needed in the configuration file. Obt

```js
// {app_root}/app.js
module.exports = function(app) {
app.beforeStart(function* () {
module.exports = app => {
app.beforeStart(async () => {
// obtain the MySQL configuration from the configuration center
// { host: 'mysql.com', port: '3306', user: 'test_user', password: 'test_password', database: 'test' }
const mysqlConfig = yield app.configCenter.fetch('mysql');
const mysqlConfig = await app.configCenter.fetch('mysql');
app.database = app.mysql.createInstance(mysqlConfig);
});
};
```

## service layer
## Service layer

Connecting to MySQL is a data processing layer in the Web layer. So it is strongly recommended that keeping the code in the service layer.
Connecting to MySQL is a data processing layer in the Web layer. So it is strongly recommended that keeping the code in the Service layer.

An example of connecting to MySQL as follows.

Details of service layer, refer to [service](../basics/service.md)
Details of Service layer, refer to [service](../basics/service.md)

```js
// app/service/user.js
module.exports = app => {
return class User extends app.Service {
* find(uid) {
// assume we have the user id then trying to get the user details from database
const user = yield app.mysql.get('users', {
id: 11,
});
return {
user,
};
}
class UserService extends Service {
async find(uid) {
// assume we have the user id then trying to get the user details from database
const user = await this.app.mysql.get('users', { id: 11 });
return { user };
}
};
}
```

After that, obtaining the data from service layer using the controller

```js
// app/controller/user.js
exports.info = function* (ctx) {
const userId = ctx.params.id;
const user = yield ctx.service.user.find(userId);
ctx.body = user;
};
class UserController extends Controller {
async info() {
const ctx = this.ctx;
const userId = ctx.params.id;
const user = await ctx.service.user.find(userId);
ctx.body = user;
}
}
```

## Writing CRUD
## Writing CRUD

Following statments default under `app/service` if not specifed

Expand All @@ -161,7 +159,7 @@ INSERT method to perform the INSERT INTO query

```js
// INSERT
const result = yield this.app.mysql.insert('posts', { title: 'Hello World' }); //insert a record title 'Hello World' to 'posts' table
const result = await this.app.mysql.insert('posts', { title: 'Hello World' }); //insert a record title 'Hello World' to 'posts' table

=> INSERT INTO `posts`(`title`) VALUES('Hello World');

Expand Down Expand Up @@ -189,23 +187,23 @@ Use `get` or `select` to select one or multiple records. `select` method support
- get one record

```js
const post = yield this.app.mysql.get('posts', { id: 12 });
const post = await this.app.mysql.get('posts', { id: 12 });

=> SELECT * FROM `posts` WHERE `id` = 12 LIMIT 0, 1;
```

- query all from the table

```js
const results = yield this.app.mysql.select('posts');
const results = await this.app.mysql.select('posts');

=> SELECT * FROM `posts`;
```

- query criteria and result customization

```js
const results = yield this.app.mysql.select('posts', { // search posts table
const results = await this.app.mysql.select('posts', { // search posts table
where: { status: 'draft', author: ['author1', 'author2'] }, // WHERE criteria
columns: ['author', 'title'], // get the value of certain columns
orders: [['created_at','desc'], ['id','desc']], // sort order
Expand All @@ -231,7 +229,7 @@ const row = {
otherField: 'other field value', // any other fields u want to update
modifiedAt: this.app.mysql.literals.now, // `now()` on db server
};
const result = yield this.app.mysql.update('posts', row); // update records in 'posts'
const result = await this.app.mysql.update('posts', row); // update records in 'posts'

=> UPDATE `posts` SET `name` = 'fengmk2', `modifiedAt` = NOW() WHERE id = 123 ;

Expand All @@ -244,7 +242,7 @@ const updateSuccess = result.affectedRows === 1;
DELETE operation to delete the records of databases

```js
const result = yield this.app.mysql.delete('posts', {
const result = await this.app.mysql.delete('posts', {
author: 'fengmk2',
});

Expand All @@ -263,17 +261,18 @@ Refer to [preventing-sql-injection-in-node-js](http://stackoverflow.com/question

```js
const postId = 1;
const results = yield this.app.mysql.query('update posts set hits = (hits + ?) where id = ?', [1, postId]);
const results = await this.app.mysql.query('update posts set hits = (hits + ?) where id = ?', [1, postId]);

=> update posts set hits = (hits + 1) where id = 1;
```

## Transaction

Transaction is mainly used to deal with large data of high complexity. For example, in a personnel management system, deleting a person which need to delete the basic information of the staff, but also need to delete the related information of staff, such as mailboxes, articles and so on. It is easier to use transaction to run a set of operations.
A transaction is a set of continuous database operations which performed as a single unit of work. Each individual operation within the group is successful and the transaction succeeds. If one part of the transaction fails, then the entire transaction fails.
In gerenal, transaction must be atomic, consistent, isolated and durable.
- Atomicity requires that each transaction be "all or nothing": if one part of the transaction fails, then the entire transaction fails, and the database state is left unchanged.
- The consistency property ensures that any transaction will bring the database from one valid state to another.
- Atomicity requires that each transaction be "all or nothing": if one part of the transaction fails, then the entire transaction fails, and the database state is left unchanged.
- The consistency property ensures that any transaction will bring the database from one valid state to another.
- The isolation property ensures that the concurrent execution of transactions results in a system state that would be obtained if transactions were executed sequentially
- The durability property ensures that once a transaction has been committed, it will remain so.

Expand All @@ -283,35 +282,35 @@ egg-mysql proviodes two types of transactions

### Manual Control

- adventage: ```beginTransaction```, ```commit``` or ```rollback``` can be completely under control by developer
- adventage: `beginTransaction`, `commit` or `rollback` can be completely under control by developer
- disadventage: more handwritten code, Forgot catching error or cleanup will lead to serious bug.

```js
const conn = yield app.mysql.beginTransaction(); // initialize the transaction
const conn = await app.mysql.beginTransaction(); // initialize the transaction

try {
yield conn.insert(table, row1); // first step
yield conn.update(table, row2); // second step
yield conn.commit(); // commit the transaction
await conn.insert(table, row1); // first step
await conn.update(table, row2); // second step
await conn.commit(); // commit the transaction
} catch (err) {
// error, rollback
yield conn.rollback(); // rollback after catching the exception!!
await conn.rollback(); // rollback after catching the exception!!
throw err;
}
```

### Automatic control: Transaction with scope

- API:`*beginTransactionScope(scope, ctx)`
- API:`beginTransactionScope(scope, ctx)`
- `scope`: A generatorFunction which will execute all sqls of this transaction.
- `ctx`: The context object of current request, it will ensures that even in the case of a nested transaction, there is only one active transaction in a request at the same time.
- adventage: easy to use, as if there is no transaction in your code.
- disadvantage: all transation will be successful or failed, cannot control precisely
```js
const result = yield app.mysql.beginTransactionScope(function* (conn) {
const result = await app.mysql.beginTransactionScope(async conn => {
// don't commit or rollback by yourself
yield conn.insert(table, row1);
yield conn.update(table, row2);
await conn.insert(table, row1);
await conn.update(table, row2);
return { success: true };
}, ctx); // ctx is the context of current request, accessed by `this.ctx` within in service file.
// if error throw on scope, will auto rollback
Expand All @@ -326,7 +325,7 @@ const result = yield app.mysql.beginTransactionScope(function* (conn) {
- `NOW()`:The database system time, obtained by `app.mysql.literals.now`

```js
yield this.app.mysql.insert(table, {
await this.app.mysql.insert(table, {
create_time: this.app.mysql.literals.now,
});

Expand All @@ -341,7 +340,7 @@ The following demo showe how to call `CONCAT(s1, ...sn)` funtion in mysql to do
const Literal = this.app.mysql.literals.Literal;
const first = 'James';
const last = 'Bond';
yield this.app.mysql.insert(table, {
await this.app.mysql.insert(table, {
id: 123,
fullname: new Literal(`CONCAT("${first}", "${last}"`),
});
Expand Down
Loading

0 comments on commit cb9c9a4

Please sign in to comment.