Skip to content

Commit 9e54839

Browse files
committed
Merge remote-tracking branch 'upstream/master'
2 parents 05d8458 + e1fc958 commit 9e54839

24 files changed

+867
-165
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ node_js:
33
- 0.4
44
- 0.6
55
- 0.8
6+
- 0.10

Changes.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@ This file is a manually maintained list of changes for each release. Feel free
44
to add your changes here when sending pull requests. Also send corrections if
55
you spot any mistakes.
66

7+
## v2.0.0-alpha9 (2013-08-27)
8+
9+
* Add query to pool to execute queries directly using the pool
10+
* Pool option to set queue limit
11+
* Pool sends 'connection' event when it opens a new connection
12+
* Added stringifyObjects option to treat input as strings rather than objects (#501)
13+
* Support for poolClusters
14+
* Datetime improvements
15+
* Bug fixes
16+
717
## v2.0.0-alpha8 (2013-04-30)
818

919
* Switch to old mode for Streams 2 (Node.js v 0.10.x)

Readme.md

Lines changed: 149 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
## Install
66

77
```bash
8-
npm install [email protected]alpha8
8+
npm install [email protected]alpha9
99
```
1010

1111
Despite the alpha tag, this is the recommended version for new applications.
@@ -208,7 +208,7 @@ var mysql = require('mysql');
208208
var pool = mysql.createPool({
209209
host : 'example.org',
210210
user : 'bob',
211-
password : 'secret'
211+
password : 'secret',
212212
});
213213

214214
pool.getConnection(function(err, connection) {
@@ -220,12 +220,12 @@ If you need to set session variables on the connection before it gets used,
220220
you can listen to the `connection` event.
221221

222222
```js
223-
pool.on('connection', function(err, connection) {
223+
pool.on('connection', function(connection) {
224224
connection.query('SET SESSION auto_increment_increment=1')
225-
})
225+
});
226226
```
227227

228-
When you are done with a connection, just call `connection.end()` and the
228+
When you are done with a connection, just call `connection.release()` and the
229229
connection will return to the pool, ready to be used again by someone else.
230230

231231
```js
@@ -236,7 +236,7 @@ pool.getConnection(function(err, connection) {
236236
// Use the connection
237237
connection.query( 'SELECT something FROM sometable', function(err, rows) {
238238
// And done with the connection.
239-
connection.end();
239+
connection.release();
240240

241241
// Don't use the connection here, it has been returned to the pool.
242242
});
@@ -270,6 +270,62 @@ addition to those options pools accept a few extras:
270270
before returning an error from `getConnection`. If set to `0`, there is no
271271
limit to the number of queued connection requests. (Default: `0`)
272272

273+
## PoolCluster
274+
275+
PoolCluster provides multiple hosts connection. (group & retry & selector)
276+
277+
```js
278+
// create
279+
var poolCluster = mysql.createPoolCluster();
280+
281+
poolCluster.add(config); // anonymous group
282+
poolCluster.add('MASTER', masterConfig);
283+
poolCluster.add('SLAVE1', slave1Config);
284+
poolCluster.add('SLAVE2', slave2Config);
285+
286+
// Target Group : ALL(anonymous, MASTER, SLAVE1-2), Selector : round-robin(default)
287+
poolCluster.getConnection(function (err, connection) {});
288+
289+
// Target Group : MASTER, Selector : round-robin
290+
poolCluster.getConnection('MASTER', function (err, connection) {});
291+
292+
// Target Group : SLAVE1-2, Selector : order
293+
// If can't connect to SLAVE1, return SLAVE2. (remove SLAVE1 in the cluster)
294+
poolCluster.on('remove', function (nodeId) {
295+
console.log('REMOVED NODE : ' + nodeId); // nodeId = SLAVE1
296+
});
297+
298+
poolCluster.getConnection('SLAVE*', 'ORDER', function (err, connection) {});
299+
300+
// of namespace : of(pattern, selector)
301+
poolCluster.of('*').getConnection(function (err, connection) {});
302+
303+
var pool = poolCluster.of('SLAVE*', 'RANDOM');
304+
pool.getConnection(function (err, connection) {});
305+
pool.getConnection(function (err, connection) {});
306+
307+
// destroy
308+
poolCluster.end();
309+
```
310+
311+
## PoolCluster Option
312+
* `canRetry`: If `true`, `PoolCluster` will attempt to reconnect when connection fails. (Default: `true`)
313+
* `removeNodeErrorCount`: If connection fails, node's `errorCount` increases.
314+
When `errorCount` is greater than `removeNodeErrorCount`, remove a node in the `PoolCluster`. (Default: `5`)
315+
* `defaultSelector`: The default selector. (Default: `RR`)
316+
* `RR`: Select one alternately. (Round-Robin)
317+
* `RANDOM`: Select the node by random function.
318+
* `ORDER`: Select the first node available unconditionally.
319+
320+
```js
321+
var clusterConfig = {
322+
removeNodeErrorCount: 1, // Remove the node immediately when connection fails.
323+
defaultSelector: 'ORDER',
324+
};
325+
326+
var poolCluster = mysql.createPoolCluster(clusterConfig);
327+
```
328+
273329
## Switching users / altering connection state
274330

275331
MySQL offers a changeUser command that allows you to alter the current user and
@@ -297,33 +353,45 @@ by this module.
297353
## Server disconnects
298354

299355
You may lose the connection to a MySQL server due to network problems, the
300-
server timing you out, or the server crashing. All of these events are
301-
considered fatal errors, and will have the `err.code =
356+
server timing you out, the server being restarted, or crashing. All of these
357+
events are considered fatal errors, and will have the `err.code =
302358
'PROTOCOL_CONNECTION_LOST'`. See the [Error Handling](#error-handling) section
303359
for more information.
304360

305-
The best way to handle such unexpected disconnects is shown below:
361+
A good way to handle such unexpected disconnects is shown below:
306362

307363
```js
308-
function handleDisconnect(connection) {
309-
connection.on('error', function(err) {
310-
if (!err.fatal) {
311-
return;
312-
}
364+
var db_config = {
365+
host: 'localhost',
366+
user: 'root',
367+
password: '',
368+
database: 'example'
369+
};
313370

314-
if (err.code !== 'PROTOCOL_CONNECTION_LOST') {
315-
throw err;
316-
}
371+
var connection;
317372

318-
console.log('Re-connecting lost connection: ' + err.stack);
373+
function handleDisconnect() {
374+
connection = mysql.createConnection(db_config); // Recreate the connection, since
375+
// the old one cannot be reused.
319376

320-
connection = mysql.createConnection(connection.config);
321-
handleDisconnect(connection);
322-
connection.connect();
377+
connection.connect(function(err) { // The server is either down
378+
if(err) { // or restarting (takes a while sometimes).
379+
console.log('error when connecting to db:', err);
380+
setTimeout(handleDisconnect, 2000); // We introduce a delay before attempting to reconnect,
381+
} // to avoid a hot loop, and to allow our node script to
382+
}); // process asynchronous requests in the meantime.
383+
// If you're also serving http, display a 503 error.
384+
connection.on('error', function(err) {
385+
console.log('db error', err);
386+
if(err.code === 'PROTOCOL_CONNECTION_LOST') { // Connection to the MySQL server is usually
387+
handleDisconnect(); // lost due to either server restart, or a
388+
} else { // connnection idle timeout (the wait_timeout
389+
throw err; // server variable configures this)
390+
}
323391
});
324392
}
325393

326-
handleDisconnect(connection);
394+
handleDisconnect();
327395
```
328396

329397
As you can see in the example above, re-connecting a connection is done by
@@ -337,7 +405,7 @@ space for a new connection to be created on the next getConnection call.
337405

338406
In order to avoid SQL Injection attacks, you should always escape any user
339407
provided data before using it inside a SQL query. You can do so using the
340-
`connection.escape()` method:
408+
`connection.escape()` or `pool.escape()` methods:
341409

342410
```js
343411
var userId = 'some user provided value';
@@ -627,12 +695,51 @@ connection.query(options, function(err, results) {
627695
table1_fieldA: '...',
628696
table1_fieldB: '...',
629697
table2_fieldA: '...',
630-
table2_fieldB: '...'
698+
table2_fieldB: '...',
631699
}, ...]
632700
*/
633701
});
634702
```
635703

704+
## Transactions
705+
706+
Simple transaction support is available at the connection level:
707+
708+
```js
709+
connection.beginTransaction(function(err) {
710+
if (err) { throw err; }
711+
connection.query('INSERT INTO posts SET title=?', title, function(err, result) {
712+
if (err) {
713+
connection.rollback(function() {
714+
throw err;
715+
});
716+
}
717+
718+
var log = 'Post ' + result.insertId + ' added';
719+
720+
connection.query('INSERT INTO log SET data=?', log, function(err, result) {
721+
if (err) {
722+
connection.rollback(function() {
723+
throw err;
724+
});
725+
}
726+
connection.commit(function(err) {
727+
if (err) {
728+
connection.rollback(function() {
729+
throw err;
730+
});
731+
}
732+
console.log('success!');
733+
});
734+
});
735+
});
736+
});
737+
```
738+
Please note that beginTransaction(), commit() and rollback() are simply convenience
739+
functions that execute the START TRANSACTION, COMMIT, and ROLLBACK commands respectively.
740+
It is important to understand that many commands in MySQL can cause an implicit commit,
741+
as described [in the MySQL documentation](http://dev.mysql.com/doc/refman/5.5/en/implicit-commit.html)
742+
636743
## Error handling
637744

638745
This module comes with a consistent approach to error handling that you should
@@ -775,7 +882,7 @@ Or on the query level:
775882
var options = {sql: '...', typeCast: false};
776883
var query = connection.query(options, function(err, results) {
777884

778-
}):
885+
});
779886
```
780887

781888
You can also pass a function and handle type casting yourself. You're given some
@@ -792,11 +899,23 @@ connection.query({
792899
}
793900
return next();
794901
}
795-
})
902+
});
903+
```
904+
__WARNING: YOU MUST INVOKE the parser using one of these three field functions in your custom typeCast callback. They can only be called once.( see #539 for discussion)__
905+
906+
```
907+
field.string()
908+
field.buffer()
909+
field.geometry()
910+
```
911+
are aliases for
912+
```
913+
parser.parseLengthCodedString()
914+
parser.parseLengthCodedBuffer()
915+
parser.parseGeometryValue()
796916
```
917+
__You can find which field function you need to use by looking at: [RowDataPacket.prototype._typeCast](https://github.com/felixge/node-mysql/blob/master/lib/protocol/packets/RowDataPacket.js#L41)__
797918

798-
If you need a buffer there's also a `.buffer()` function and also a `.geometry()` one
799-
both used by the default type cast that you can use.
800919

801920
## Connection Flags
802921

@@ -813,7 +932,7 @@ prepend the flag with a minus sign. To add a flag that is not in the default lis
813932
The next example blacklists FOUND_ROWS flag from default connection flags.
814933

815934
```js
816-
var connection = mysql.createConnection("mysql://localhost/test?flags=-FOUND_ROWS")
935+
var connection = mysql.createConnection("mysql://localhost/test?flags=-FOUND_ROWS");
817936
```
818937

819938
### Default Flags
@@ -886,11 +1005,10 @@ For example, if you have an installation of mysql running on localhost:3306 and
8861005
* Make sure the database (e.g. 'test') you want to use exists and the user you entered has the proper rights to use the test database. (E.g. do not forget to execute the SQL-command ```FLUSH PRIVILEGES``` after you have created the user.)
8871006
* In a DOS-box (or CMD-shell) in the folder of your application run ```npm install mysql --dev``` or in the mysql folder (```node_modules\mysql```), run ```npm install --dev```. (This will install additional developer-dependencies for node-mysql.)
8881007
* Run ```npm test mysql``` in your applications folder or ```npm test``` in the mysql subfolder.
889-
* If you want to log the output into a file use ```npm test mysql > test.log``` or ```npm test > test.log```.
1008+
* If you want to log the output into a file use ```npm test mysql > test.log``` or ```npm test > test.log```.
8901009

8911010
## Todo
8921011

8931012
* Prepared statements
8941013
* setTimeout() for Connection / Query
8951014
* Support for encodings other than UTF-8 / ASCII
896-
* API support for transactions, similar to [php](http://www.php.net/manual/en/mysqli.quickstart.transactions.php)

index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ var Types = require('./lib/protocol/constants/types');
44
var SqlString = require('./lib/protocol/SqlString');
55
var Pool = require('./lib/Pool');
66
var PoolConfig = require('./lib/PoolConfig');
7+
var PoolCluster = require('./lib/PoolCluster');
78

89
exports.createConnection = function(config) {
910
return new Connection({config: new ConnectionConfig(config)});
@@ -13,6 +14,10 @@ exports.createPool = function(config) {
1314
return new Pool({config: new PoolConfig(config)});
1415
};
1516

17+
exports.createPoolCluster = function(config) {
18+
return new PoolCluster(config);
19+
};
20+
1621
exports.createQuery = Connection.createQuery;
1722

1823
exports.Types = Types;

lib/Connection.js

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
var Net = require('net');
22
var ConnectionConfig = require('./ConnectionConfig');
3-
var Pool = require('./Pool');
43
var Protocol = require('./protocol/Protocol');
54
var SqlString = require('./protocol/SqlString');
65
var Query = require('./protocol/sequences/Query');
@@ -74,6 +73,8 @@ Connection.prototype.connect = function(cb) {
7473
};
7574

7675
Connection.prototype.changeUser = function(options, cb){
76+
cb = cb || function() {};
77+
7778
this._implyConnect();
7879

7980
if (typeof options === 'function') {
@@ -85,6 +86,8 @@ Connection.prototype.changeUser = function(options, cb){
8586
? Config.getCharsetNumber(options.charset)
8687
: this.config.charsetNumber;
8788

89+
var self = this;
90+
8891
return this._protocol.changeUser({
8992
user : options.user || this.config.user,
9093
password : options.password || this.config.password,
@@ -94,6 +97,33 @@ Connection.prototype.changeUser = function(options, cb){
9497
}, cb);
9598
};
9699

100+
Connection.prototype.beginTransaction = function(cb) {
101+
this._implyConnect();
102+
103+
var query = Connection.createQuery('START TRANSACTION', cb);
104+
query._connection = this;
105+
106+
return this._protocol._enqueue(query);
107+
};
108+
109+
Connection.prototype.commit = function(cb) {
110+
this._implyConnect();
111+
112+
var query = Connection.createQuery('COMMIT', cb);
113+
query._connection = this;
114+
115+
return this._protocol._enqueue(query);
116+
};
117+
118+
Connection.prototype.rollback = function(cb) {
119+
this._implyConnect();
120+
121+
var query = Connection.createQuery('ROLLBACK', cb);
122+
query._connection = this;
123+
124+
return this._protocol._enqueue(query);
125+
};
126+
97127
Connection.prototype.query = function(sql, values, cb) {
98128
this._implyConnect();
99129

0 commit comments

Comments
 (0)