์๋ ์์ ์์๋ ํจ์ ๋ฐฐ์ด์ ์ง๋ ฌ๋ก ์คํํ๋ ค๊ณ ํฉ๋๋ค. ๊ทธ๋ฌ๋ ์์ฒญ์ LoggedIn ์ํ์์๋ง ๋ง๋ค ์ ์์ผ๋ฏ๋ก connection.state !== connection.STATE.LOGGED_IN
๋ฅผ ํ์ธํด์ผ ํ์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ์๋์ ์ฝ๊ธฐ ๊ธฐ๋ฅ์์ ๋ณผ ์ ์๋ฏ์ด ์ค๋ฅ๋ฅผ ์ ๊ฑฐํ๊ธฐ ์ํด ์์ฒญ์ ๋ค์ ๋๊ธฐ์ด์ ๋ฃ์ด์ผ ํ์ต๋๋ค.
{ [RequestError: Requests can only be made in the LoggedIn state, not the SentClientRequest state]
message: 'Requests can only be made in the LoggedIn state, not the SentClientRequest state',
code: 'EINVALIDSTATE' }
์ด๊ฒ์ ๋ฌ์ฑํ๋ ๋ ์ข์ ๋ฐฉ๋ฒ์ด ์์ต๋๊น? ๋น์ทํ ๋ฌธ์ ๊ฐ #19 ๋ฐ #355 ์ด์ ์ ์ ๊ธฐ๋์์์ ์ ์ ์์ต๋๋ค. ์ฐ๊ฒฐ์์ ์ฌ๋ฌ ์์ฒญ์ ์คํํ๋ ๊ถ์ฅ ๋ฐฉ๋ฒ์ด ์์ต๋๊น?
์ํธ:
var Connection = require('tedious').Connection;
var Request = require('tedious').Request;
var TYPES = require('tedious').TYPES;
var async = require('async');
// Create connection to database
var config = {
userName: 'mylogin',
password: 'mypassword',
server: 'localhost',
options: {
// encrypt: true, /*If you are connecting to a Microsoft Azure SQL database, you will need this*/
database: 'testdb'
}
}
var connection = new Connection(config);
// Attempt to connect and execute queries if connection goes through
connection.on('connect', function(err) {
if (err) {
console.log(err);
}
else {
console.log("Connected");
// Execute all functions in the array serially
async.waterfall([
function Start(callback){
console.log("Starting...");
callback(null, 'Jake', 'United States');
},
function Insert(name, location, callback){
console.log("Inserting into Table...");
request = new Request("INSERT dbo.employees (name, location) OUTPUT INSERTED.id VALUES (<strong i="14">@Name</strong>, @Location);", function(err){
if (err) {
console.log(err);
}
}
);
request.addParameter('Name', TYPES.NVarChar, name);
request.addParameter('Location', TYPES.NVarChar, location);
request.on('row', function(columns) {
columns.forEach(function(column) {
if (column.value === null) {
console.log('NULL');
} else {
console.log("Employee id inserted is " + column.value);
}
});
});
// Check how many rows were inserted
request.on('doneInProc', function(rowCount, more) {
console.log(rowCount + ' row(s) inserted');
callback(null, 'Jared');
});
connection.execSql(request);
},
function Read(callback){
// Requests can only be made in the LoggedIn state, so check for that
if (connection.state !== connection.STATE.LOGGED_IN) {
// Put the request back on the dispatcher if connection is not in LoggedIn state
setTimeout(Read, 0, callback);
return;
}
console.log("Reading rows from the Table...");
// Create the request to read from table
request = new Request("SELECT * FROM dbo.employees;", function(err) {
if (err) {
console.log(err);
}
});
// Output the number of rows read
request.on('doneInProc', function (rowCount, more, rows) {
console.log(rowCount + ' row(s) returned');
callback(null);
});
connection.execSql(request);
}],
function Complete(err, result) {
if(err) {
console.log("Error:", err);
}
else {
console.log("Done!");
}
}
)
}
});
์์ฒญ์ ์ค์ ํ ์ ์๋ '์ฝ๋ฐฑ' ์์ฑ์ด ์๊ณ ์์ฒญ์ 'requestCompleted' ์ด๋ฒคํธ๊ฐ ์์ผ๋ฉฐ ๋ ๋ค ์๋ํ๋ ๊ฒ ๊ฐ์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ด๊ฒ์ ์ฐ๋ฆฌ๊ฐ ์๋ํ์ง ์์ ๋ ๊ฐ์ง์ ๋๋ค :)
์ด์ ๋ํ ์ ๋ฆฌ ๋ฐ ๋ฌธ์ํ๊ฐ ํ์ํ ์ ์์ต๋๋ค.
์ด๊ฒ์ ์๋ํ๊ณ ์๋ํ๋์ง ํ์ธํ์ญ์์ค.
'์ฝ๋ฐฑ' ์ฌ์ฉ:
request.callback = function (err, rowCount, rows) {
// rows is not being set but rowCount is. May be a bug.
if (err) {
// Error handling.
} else {
// Next SQL statement.
}
};
'์์ฒญ ์๋ฃ' ์ฌ์ฉ:
request.on('requestCompleted', function () {
// Next SQL statement.
});
์ค์ ๋ก ์ด ๋ ธํธ๋ฅผ https://github.com/tediousjs/tedious/issues/61 ์ ๋ฃ๊ณ ๋์ผํ ๋ฌธ์ ์ด๋ฏ๋ก ์ด ๋ ธํธ๋ฅผ ๋ซ์ต๋๋ค.
๋ฌธ์ ๋ฅผ ๋ค์ ์ฝ๋๋ค. https://github.com/tediousjs/tedious/issues/61 ์ ์ ํ ๊ด๋ จ์ด ์์ต๋๋ค. @SaloniSonpal ์ด ์ธ๊ธํ ๋ฌธ์ ๋ ์ค์ ๋ก ์ข ๋ฃ๋์์ต๋๋ค. ๊ทธ๋์ ์ถ์ ์ ์ํด ์ด๊ฒ์ ๋ค์ ์ฝ๋๋ค.
์ด๊ฒ์ ์ฝ๊ฐ์ ์ ๋ฆฌ์ ๋ฌธ์๊ฐ ํ์ํฉ๋๋ค.
@tvrprasad ๊ฐ์ฌํฉ๋๋ค. ๋ ๋ค ํจ๊ณผ๊ฐ ์์๊ณ ํจ์ฌ ๋ ๊นจ๋ํฉ๋๋ค. callback
์ ๊ทผ ๋ฐฉ์์ ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ๋ ์ด์ ์ ์ ๊ณตํฉ๋๋ค. Event: 'requestCompleted'
๋ ๋ฐ๋์ ๋ฌธ์ํํด์ผ ํฉ๋๋ค.
(ํธ๋ํฐ์ผ๋ก ๋ณด๋ด๋ ๋ง์ด ๊ธธ์ด์ง๋ ์ ์ํด ๋ถํ๋๋ฆฝ๋๋ค.)
callback ์์ฑ์ ์ค์ ํ๋ฉด ์ ๋ฌํ ์ฝ๋ฐฑ์ ๋ฎ์ด์๋๋ค.
์์ฒญ ์์ฑ์์. ๋์ ๋ค์์์ ์ฝ๋ฐฑ์ ํธ์ถํด์ผ ํฉ๋๋ค.
Request ์์ฑ์์ ์ ๋ฌ๋ ์ฝ๋ฐฑ ๋ด๋ถ์ async. ์ด๋ ๊ฒ ๋น์ ์
์ค๋ฅ๋ฅผ ๋น๋๊ธฐ๋ก ์ฌ๋ฐ๋ฅด๊ฒ ์ ๋ฌํ ์๋ ์์ต๋๋ค.
์, ๊ทธ ์ฝ๋ฐฑ์ด ์ ๋ฌ๋ ์ฝ๋ฐฑ์ผ๋ก ์ค์ ๋์ด ์๋ค๋ ๊ฒ์ ๋์ณค์ต๋๋ค. ์ฌ๋ฐ๋ฅธ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
request = new Request(sqlQuery, function (err, rowCount, rows) {
if (err) {
// Error handling.
} else {
// Next SQL statement.
}
});
@arthurschreiber 'requestCompleted' ์ด๋ฒคํธ์ ๋ํ ์ด์ ๊ฐ ์์ต๋๊น? ์ค๋ณต๋ ๊ฒ ๊ฐ์ต๋๋ค. ๋ด๊ฐ ์์์ฐจ๋ฆฐ ๋ ๋ค๋ฅธ ์ฌ์ค์ ์ฝ๋ฐฑ์ ์ ๋ฌ๋ ํ ๋งค๊ฐ๋ณ์๊ฐ ํญ์ ๋น์ด ์๋ค๋ ๊ฒ์ ๋๋ค. ์ ํจํ ๋ฐ์ดํฐ๊ฐ ์๋ ์๋๋ฆฌ์ค๊ฐ ์์ต๋๊น? ๋ฌธ์๋ฅผ ์ ๋ฐ์ดํธํ๊ฒ ์ต๋๋ค.
๋ด๊ฐ ์์์ฐจ๋ฆฐ ๋ ๋ค๋ฅธ ์ฌ์ค์ ์ฝ๋ฐฑ์ ์ ๋ฌ๋ ํ ๋งค๊ฐ๋ณ์๊ฐ ํญ์ ๋น์ด ์๋ค๋ ๊ฒ์ ๋๋ค. ์ ํจํ ๋ฐ์ดํฐ๊ฐ ์๋ ์๋๋ฆฌ์ค๊ฐ ์์ต๋๊น? ๋ฌธ์๋ฅผ ์ ๋ฐ์ดํธํ๊ฒ ์ต๋๋ค.
์ฐ๊ฒฐํ ๋ ์ง์ ํ ์ ์๋ rowCollectionOnRequestCompletion
์ต์
์ด ์์ต๋๋ค. ์ ์ญ ์ต์
์ผ๋ก ์ฌ์ฉํ๋ ๊ฒ์ ์ฝ๊ฐ ์ด์ํฉ๋๋ค. ์์ฒญ๋ณ๋ก ์ด๊ฒ์ ๊ฐ๋ ๊ฒ์ด ๋ ํฉ๋ฆฌ์ ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค.
์ด ์ด๋ฉด์ ์ฃผ์ ์์ด๋์ด๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. rowCollectionOnRequestCompletion
์ต์
์ด ํ์ฑํ๋ ๊ฒฝ์ฐ ํ์ ํด๋น Request
๊ฐ ์๋ฃ๋ ๋๊น์ง ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅ๋ฉ๋๋ค(ํ์ฌ๋ก์๋ Request
๋ gc'๋ฅผ ์ป์ต๋๋ค). ์์ ๊ฒฐ๊ณผ ์งํฉ์ ๊ฒฝ์ฐ ์ผ๋ฐ์ ์ผ๋ก ๋ฌธ์ ๊ฐ ๋์ง ์์ง๋ง ํฐ ๊ฒฐ๊ณผ ์งํฉ์ ๊ฒฝ์ฐ ์ฑ๋ฅ ์ ๋ง์ ๋ถ์ ์ ์ธ ์ํฅ์ ๋ฏธ์น ์ ์์ต๋๋ค. ์ ํธ๋๋ ์ ๊ทผ ๋ฐฉ์์ rows
์ฝ๋ฐฑ์ ์ฌ์ฉํ๋ ๊ฒ์ด๋ฉฐ ๋ชจ๋ ํ์ ๋ฐฐ์ด๋ก ์์งํด์ผ ํ๋ ๊ฒฝ์ฐ ์ง์ ์์งํ ์ ์์ต๋๋ค.
๋๋ ์ด๊ฒ์ด ์ต์ ์ด๋ผ๊ณ ์๊ฐํ์ง ์์ต๋๋ค. ์ฐ๊ฒฐ๋น ๋์ ์์ฒญ๋ณ๋ก ๊ตฌ์ฑํ๋ ๊ฒ์ด ๋ ๋์ ๊ฒ์
๋๋ค. ๊ทธ๋ฌ๋ Request
์์ฑ์๋ ์์ง ์ต์
์ ์ทจํ์ง ์์ผ๋ฏ๋ก ๋ฉ์๋ ์๋ช
์ ๋ค์๊ณผ ๊ฐ์์ผ ํฉ๋๋ค. ๋ณ๊ฒฝ๋์์ต๋๋ค.
'requestCompleted' ์ด๋ฒคํธ์ ๋ํ ์ด์ ๊ฐ ์์ต๋๊น?
ํ์คํ์ง ์์ต๋๋ค. ์ด๊ฒ์ ์ง๋ฃจํ ์์ ์ ์์ํ๊ธฐ ์ ์ ์ถ๊ฐ๋์์ต๋๋ค.
rowCollectionOnRequestCompletion ๋ฌธ์ ๋ฅผ ์ถ์ ํ๊ธฐ ์ํด #459๋ฅผ ์ด์์ต๋๋ค. ๋๋ ์ฐ๋ฆฌ๊ฐ ๊ทธ๊ฒ์ ์ถ๊ฐํ๊ณ ์ฒ๋ฆฌํ ์ ์๋ค๊ณ ํ์ ํ๋ค
์ด์ ๋ฒ์ ๊ณผ ํธํ๋๋ ๋ฐฉ์์ผ๋ก.
callback ์์ฑ์ ์ค์ ํ๋ฉด ์ ๋ฌํ ์ฝ๋ฐฑ์ ๋ฎ์ด์๋๋ค.
์์ฒญ ์์ฑ์์. ๋์ ๋ค์์์ ์ฝ๋ฐฑ์ ํธ์ถํด์ผ ํฉ๋๋ค.
Request ์์ฑ์์ ์ ๋ฌ๋ ์ฝ๋ฐฑ ๋ด๋ถ์ async. ์ด๋ ๊ฒ ๋น์ ์
์ค๋ฅ๋ฅผ ๋น๋๊ธฐ๋ก ์ฌ๋ฐ๋ฅด๊ฒ ์ ๋ฌํ ์๋ ์์ต๋๋ค.
@arthurschreiber ๋ง์ต๋๋ค. ๊ทธ๊ฒ์ด ๊ฒฐ๊ณผ/์ค๋ฅ๋ฅผ ๋ฌด์ํ์ง ์๋ ์ฌ๋ฐ๋ฅธ ๋ฐฉ๋ฒ์ ๋๋ค. ๋งค๋ ฅ์ฒ๋ผ ์๋ํฉ๋๋ค :-)
Event: 'requestCompleted'
์ ๋ํ ๋ฌธ์๋ฅผ ๊ฐ์ ํ๊ธฐ ์ํด #464๋ฅผ ๋ง๋ค์์ต๋๋ค.
Google์์ ์ฌ๊ธฐ๋ก ์ค๋ ์ฌ๋๋ค(์ ์ฒ๋ผ): tedious-connection-pool ์ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ ์ข์ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. pool.acquire((err, connection) => ...)
๋ฐ connection.release()
๋ฅผ ์ฌ์ฉํ๋ฉด ๋์์ฑ ๋ฌธ์ ๋ฅผ ๋ฐฉ์งํ ์ ์์ต๋๋ค. ๋ค์ค ์ฐ๊ฒฐ์ ์ํ์ง ์์ผ๋ฉด {min: 1, max: 1}
๋ก ํ์ ๊ตฌ์ฑํ์ฌ ์ฟผ๋ฆฌ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ์ง๋ ฌํํฉ๋๋ค.
๋๊ตฌ๋ ์ง ์ ์ํ์ญ์์ค. Windows ์ธ์ฆ ๋ชจ๋๋ nodejs2Sql ์ฐ๊ฒฐ์ ๋ํด ์๋ํ์ง ์์ต๋๋ค.
@wafaabbass tedious
๋ ์์ง Windows ํตํฉ ์ธ์ฆ์ ์ง์ํ์ง ์์ต๋๋ค. ํ์ฌ ์์
์ค์ด๋ฉฐ #415์์ ์ถ์ ํ ์ ์์ต๋๋ค.
์ฌ๋ฌ๋ถ, ์ ๋ ๊ฐ์ ๋ฌธ์ ๊ฐ ์์ต๋๋ค.
๋๋ฒ๊ทธ:
์์ฒญ์ SentClientRequest ์ํ๊ฐ ์๋ LoggedIn ์ํ์์๋ง ์ด๋ฃจ์ด์ง ์ ์์ต๋๋ค.
(node:5180) UnhandledPromiseRejectionWarning: Unhandled Promise Rejection (rejection id: 1): RequestError: SentClientRequest ์ํ๊ฐ ์๋ LoggedIn ์ํ์์๋ง ์์ฒญ ๊ฐ๋ฅ
(node:5180) [DEP0018] DeprecationWarning: ์ฒ๋ฆฌ๋์ง ์์ ์ฝ์ ๊ฑฐ๋ถ๋ ๋ ์ด์ ์ฌ์ฉ๋์ง ์์ต๋๋ค. ์์ผ๋ก ์ฒ๋ฆฌ๋์ง ์์ ์ฝ์ ๊ฑฐ๋ถ๋ 0์ด ์๋ ์ข ๋ฃ ์ฝ๋๋ก Node.js ํ๋ก์ธ์ค๋ฅผ ์ข ๋ฃํฉ๋๋ค.
์์ง ํด๊ฒฐ๋์๋์? ์ด๊ฒ์ ๋ด ์ฝ๋์ ๋๋ค.
function createAsPromiseWithTransaction(callback, data, connection) {
const transactionReady = (err) => {
if (err) {
return callback(err)
}
return callback(null)
}
const transactionFailed = (originalErr) =>
(err) => {
if (err) {
return callback(err)
}
return callback(originalErr)
}
const willIGetArea = new Promise(
(resolve, reject) => {
const create = function(data, connection) {
let areaIdInserted = null
const request = new Request(CONSTANTS.SPNames.Area,
(err, rowCount, rows) => err ? reject(err) : resolve(areaIdInserted))
request.addParameter('IUser', TYPES.UniqueIdentifier, data.iUser)
request.addParameter('ParentArea', TYPES.Int, data.parentArea)
request.addParameter('Name', TYPES.VarChar, data.nameArea)
request.addParameter('ShortName', TYPES.VarChar, data.shortNameArea)
request.addParameter('Description', TYPES.VarChar, data.descriptionArea)
request.addParameter('Gender', TYPES.Bit, data.gender)
request.addParameter('Colour', TYPES.VarChar, data.colour)
request.addParameter('X', TYPES.Int, data.x)
request.addParameter('Y', TYPES.Int, data.y)
request.addParameter('Active', TYPES.Int, data.active)
request.on('row', function(columns) {
areaIdInserted = columns[1].value
});
connection.callProcedure(request)
}
const transactionStarted = function(err) {
if (err) return callback(err)
create(data, connection)
}
connection.beginTransaction(transactionStarted)
})
const willIGetSymptom = function(areaId) {
return new Promise(function(resolve, reject) {
const create = function(data, connection, areaId) {
let symptomIdInserted = null
const request = new Request(CONSTANTS.SPNames.Symptom,
(err, rowCount, rows) => err ? reject(err) : resolve(symptomIdInserted))
request.addParameter('IUser', TYPES.UniqueIdentifier, data.iUser)
request.addParameter('AreaId', TYPES.BigInt, areaId)
request.addParameter('Code', TYPES.VarChar, data.code)
request.addParameter('Name', TYPES.VarChar, data.nameSymptom)
request.addParameter('ShortName', TYPES.VarChar, data.shortNameSymptom)
request.addParameter('Description', TYPES.VarChar, data.descriptionSymptom)
request.addParameter('Gender', TYPES.Bit, data.gender)
request.addParameter('Active', TYPES.Bit, data.active)
request.on('row', function(columns) {
symptomIdInserted = columns[1].value
});
connection.callProcedure(request)
}
create(data, connection, areaId)
})
}
const willIGetModifier = new Promise(function(resolve, reject) {
const request = new Request(
CONSTANTS.SPNames.Modifier,
function(err, rowCount, rows) {
if (err) {
reject(err)
} else {
resolve(rowCount,rows)
}
})
request.addParameter('IUser', TYPES.UniqueIdentifier, data.iUser)
request.addParameter('Name', TYPES.VarChar, data.nameModifier)
request.addParameter('Order', TYPES.SmallInt, data.order)
request.addParameter('Active', TYPES.Bit, data.active)
connection.callProcedure(request)
})
const runPromise = () =>
willIGetArea
.then( (areaId) =>
willIGetSymptom(areaId)
.then( (symptomId) =>
willIGetModifier
.then((rowCount,rows) => connection.commitTransaction(transactionReady))
.catch((err) => connection.rollbackTransaction(transactionFailed(err)))
)
.catch((err) => connection.rollbackTransaction(transactionFailed(err)))
)it
.catch((err) => connection.rollbackTransaction(transactionFailed(err)))
runPromise()
}
willIGetArea ๋ฐ willIGetSymptom์ ํธ์ถํ๋ฉด ์ด ๋ชจ๋ ๊ฒ์ด ์๋ํ์ง๋ง willGetModifier๋ก ํธ์ถํ๋ฉด ๋์ผํ ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค. ์ ๋ง ๊ฐ์ฌํฉ๋๋ค.
Google์ด ์ด ์ค๋ฅ ๋ฉ์์ง์ ๋ํด ์ด ํ์ด์ง๋ฅผ ๋จผ์ ๋ฐํํ๊ธฐ ๋๋ฌธ์ ๋๊ตฐ๊ฐ ์ ์ฉํ๋ค๊ณ ์๊ฐํ๋ ๊ฒฝ์ฐ๋ฅผ ๋๋นํ์ฌ.
๋จ์ผ ์ฐ๊ฒฐ ๊ธฐ๋ฐ ์๋น์ค์์ ์ฐ๊ฒฐ์ ์ํ Promise ๊ธฐ๋ฐ ๋ํผ๋ฅผ ๋ง๋๋ ๋ฐ ํจ๊ณผ๊ฐ ์์์ต๋๋ค. ๊ฒฝํ ๋ง์ js ๊ฐ๋ฐ์๊ฐ ์๋๊ธฐ ๋๋ฌธ์ ์ผ๋ฐ์ ์ผ๋ก ์ข์ ์๋ฃจ์
์ธ์ง ํ์คํ์ง ์์ต๋๋ค.
class PromisedConnection {
constructor(config) {
// this.connection always points to a promise resolving after the last assigned request
// initial setting is either resolved once a new connection is established or rejected if an error occurs
this.connection = new Promise((resolve, reject) => {
const dbConnection = new Connection(config);
dbConnection.on("connect", function (err) {
if (err) {
reject(err);
}
else {
resolve(dbConnection);
}
});
});
}
execute(request) {
const nextConnection = new Promise((resolve, reject) => {
// after scheduling new request this.connection should be reassigned to be the last in promise queue
this.connection
.catch( (reason) => {
reject(reason);
} )
.then( (dbConnection) => { // a new request can be executed only within the connection is free again (resolved after the last request)
request.on("requestCompleted", () => { // add an additional event listener in order to release connection after the request is done
resolve(dbConnection);
});
dbConnection.execSql(request);
});
} );
this.connection = nextConnection;
}
}
๊ทธ๋ฆฌ๊ณ ์ฟผ๋ฆฌ ์์ฒด๋ ๋ค์๊ณผ ๊ฐ์ด ์คํํ ์ ์์ต๋๋ค.
const dbConnection = new PromisedConnection(config);
function getObjList(query, parameters = []) {
return new Promise((resolve, reject) => {
const objList = [];
let request = new Request(
query,
function (err, rowCount, rows) {
if (err) {
reject(err);
} else if (rowCount < 1) {
reject(new Error("0 rows returned from DB"));
}
}
);
for (const {name, type, value} of parameters) {
request.addParameter(name, type, value);
};
request.on("row", (columns) => {
objList.push(Obj.fromColumns(columns)); // here I just make a specific object from each row
});
request.on("requestCompleted", () => {
resolve(objList);
});
dbConnection.execute(request);
});
}
๋ฐ๋ผ์ getObjList ๋ ์ด์ ์ฐ๊ฒฐ ์ํ๋ฅผ ํ์ธํ์ง ์๊ณ ์ธ์ ๋ ์ง ์คํํ ์ ์์ต๋๋ค.
์ฌ๊ธฐ์ ๋ํ ์ฐ๋ ค๋ ์ข์ต๋๋ค. ๋ด ์ฝ๋์์๋ ์ฐ๊ฒฐ ์์ฒญ, SQL ์์ฒญ, ์ฝ์
์์ฒญ์ ์ํํฉ๋๋ค. SQL ์์ฒญ ํ requestCompleted
๋ฅผ ๊ธฐ๋ค๋ฆฐ ํ์๋ SQL๊ณผ ์ฝ์
์์ฒญ ์ฌ์ด์ ๋ค๋ฅธ ์ฐ๊ฒฐ ์์ฒญ์ ํ์ง ์์ผ๋ฉด ์ฝ์
์์ฒญ์์ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
์ด ์ค๋ฅ์ ์ผ๋ฐ์ ์ธ ์ด์ ๋ _ํ ๋ฒ์ ํ๋์ ์ฐ๊ฒฐ์์ ํ๋์ ์ฟผ๋ฆฌ๋ง ์คํํ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค. ๋ค๋ฅธ ์์ฒญ์ ํ๊ธฐ ์ ์ ์ค๋ฅ๋ ๊ฒฐ๊ณผ์ ํจ๊ป ์์ฒญ ์ฝ๋ฐฑ์ด ์คํ๋ ๋๊น์ง ๊ธฐ๋ค๋ ค์ผ ํฉ๋๋ค. ์ฌ๊ธฐ์์ FAQ ํ์ด์ง๋ฅผ ๋ฐฉ๋ฌธํ์ญ์์ค.
์ด ํฌ๋ผ์๋ ๋ค์ํ ๋ฌธ์ ๊ฐ ๋๋ฌด ๋ง์ ๊ฒ ๊ฐ์ต๋๋ค. Requests can only be made in the LoggedIn state, not the SentClientRequest state
์ค๋ฅ๋ ๋ค์ํ ์ด์ ๋ก ์ธํด ๋ฐ์ํ ์ ์์ต๋๋ค. ์ด ์ค๋ฅ๊ฐ ๋ฐ์ํ๊ณ FAQ ํ์ด์ง๊ฐ ๋์์ด ๋์ง ์์๋ค๋ฉด ๋ค์ ์ ๋ณด๋ก ๋ฌธ์ ๋ฅผ ์ ๊ธฐํ์ฌ ๋ฌธ์ ๋ฅผ ๋ณด๋ค ์ ํํ๊ฒ ํด๊ฒฐํ ์ ์๋๋ก ํ์ญ์์ค.
๊ฐ์ฌ ํด์! ๐
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์๊ณ ๋ฌธ์ ๋ ๋ด ํธ์ด์์ผ๋ฉฐ ๊ฐ ์์ฒญ์ ๋ํด ๋ณ๋์ ์ฐ๊ฒฐ์ด ํ์ํ๋ค๋ ๊ฒ์ ๊นจ๋ซ์ง ๋ชปํ์ต๋๋ค.
@mgarf ๋น์ ์ ์๋ฃจ์ ์ ๋ฌด์์ด์์ต๋๊น? ๋ํ ๊ฐ ์์ฒญ์ ๋ํด ๋ณ๋์ ์ฐ๊ฒฐ์ด ํ์ํ๋ค๋ ๊ฒ์ ๋ชฐ๋์ต๋๋ค. ์ด ํ ๋ก ์์ ๋ค๋ฅธ ์ฌ๋๋ค๊ณผ ๊ฐ์ ๋์์ฑ ๋ฌธ์ ๊ฐ ์์ต๋๋ค.
@mikebutak ๊ฐ ์์ฒญ์ ๋ํด ๋ณ๋์ ์ฐ๊ฒฐ์ด ๋ฐ๋์ ํ์ํ ๊ฒ์ ์๋๋๋ค. ํ ๋ฒ์ ํ๋์ ์์ฒญ์ ์ฒ๋ฆฌํ๋ ํ๋์ ์ฐ๊ฒฐ๋ง ์์ผ๋ฉด ๋ฉ๋๋ค. ํ๋์ ์ฐ๊ฒฐ์์ ์ฌ๋ฌ ์์ฒญ์ ์ฒ๋ฆฌํ๋ ค๋ฉด ์๋ฃ๋ ํ ์ด์ ์์ฒญ์ ์ฝ๋ฐฑ์์ ์ ์์ฒญ์ ์คํํด์ผ ํฉ๋๋ค. ์๋ฅผ ๋ค์ด,
function executeStatement() {
request = new Request("select 42, 'hello world'", function(err, rowCount) {
if (err) {
console.log(err);
} else {
console.log(rowCount + ' rows');
}
connection.execSql(new Request("select 42, 'hello world'", function(err, rowCount) {
if (err) {
console.log(err);
} else {
console.log(rowCount + ' rows');
}
connection.close();
}))
});
connection.execSql(request);
์ด ๋ฌธ์ ์ ๋ํ ์ฝ๋ฐฑ์ ์ฌ์ฉํ์ฌ ์ ์ฒด ์๋ฃจ์ ์ ๊ฒ์ํ๊ณ ์์ต๋๋ค. ๋๋ ๊ฐ์ ๋ฌธ์ ๊ฐ ์์๊ณ Google์ ๋ณผ ๋ ์ฌ๊ธฐ์์ ๋๋ฌ์ต๋๋ค. ๋งค์ด 1 http ํธ์ถ์ ์คํํ๊ณ ๋ฌธ์ ์์ด 0.5์ด๋ฅผ ์คํํ๋ ์คํฌ๋ฆฝํธ๋ก ์ด ์ฝ๋๋ฅผ ๋ก๋ ํ ์คํธํ์ต๋๋ค.
const {Connection, Request} = require("tedious");
const executeSQL = (sql, callback) => {
let connection = new Connection({
"authentication": {
"options": {
"userName": "USERNAME",
"password": "PASSWORD"
},
"type": "default"
},
"server": "SERVER",
"options": {
"validateBulkLoadParameters": false,
"rowCollectionOnRequestCompletion": true,
"database": "DATABASE",
"encrypt": true
}
});
connection.connect((err) => {
if (err)
return callback(err, null);
const request = new Request(sql, (err, rowCount, rows) => {
connection.close();
if (err)
return callback(err, null);
callback(null, {rowCount, rows});
});
connection.execSql(request);
});
};
executeSQL("SELECT * FROM users", (err, data) => {
if (err)
console.error(err);
console.log(data.rowCount);
});
//or
executeSQL("SELECT * FROM users", (err, {rowCount, rows}) => {
if (err)
console.error(err);
console.log(rowCount);
});
์ด ๋ฌธ์ ์ ๋ํ ์ฝ๋ฐฑ์ ์ฌ์ฉํ์ฌ ์ ์ฒด ์๋ฃจ์ ์ ๊ฒ์ํ๊ณ ์์ต๋๋ค. ๋๋ ๊ฐ์ ๋ฌธ์ ๊ฐ ์์๊ณ Google์ ๋ณผ ๋ ์ฌ๊ธฐ์์ ๋๋ฌ์ต๋๋ค. ๋งค์ด 1 http ํธ์ถ์ ์คํํ๊ณ ๋ฌธ์ ์์ด 0.5์ด๋ฅผ ์คํํ๋ ์คํฌ๋ฆฝํธ๋ก ์ด ์ฝ๋๋ฅผ ๋ก๋ ํ ์คํธํ์ต๋๋ค.
const {Connection, Request} = require("tedious"); const executeSQL = (sql, callback) => { let connection = new Connection({ "authentication": { "options": { "userName": "USERNAME", "password": "PASSWORD" }, "type": "default" }, "server": "SERVER", "options": { "validateBulkLoadParameters": false, "rowCollectionOnRequestCompletion": true, "database": "DATABASE", "encrypt": true } }); connection.connect((err) => { if (err) return callback(err, null); const request = new Request(sql, (err, rowCount, rows) => { connection.close(); if (err) return callback(err, null); callback(null, {rowCount, rows}); }); connection.execSql(request); }); }; executeSQL("SELECT * FROM users", (err, data) => { if (err) console.error(err); console.log(data.rowCount); }); //or executeSQL("SELECT * FROM users", (err, {rowCount, rows}) => { if (err) console.error(err); console.log(rowCount); });
์ด ์๋ฃจ์ ์ ์๋ํ์ง๋ง ์ ํจํ ๊ตฌํ์ ๋๊น? ์์ญ๋ง ๊ฐ์ ์ฝ์ /์ ํ์ด ์๊ณ ๊ฐ๊ฐ์ ๋ํ ์ฐ๊ฒฐ์ ์์ฑํ ์ ์๋ค๋ ์ ์ ๊ณ ๋ คํ ๋ ๊ทธ๊ฒ์ด ์ผ๋ง๋ ์คํ ๊ฐ๋ฅํฉ๋๊น? ์๋ฃจ์ btw์ ๊ฐ์ฌ๋๋ฆฝ๋๋ค. ์คํ ๊ฐ๋ฅํ ์๋ฃจ์ ์ธ์ง ์ดํดํ๋ ค๊ณ ํฉ๋๋ค. ํนํ Azure Function์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ?
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
Google์์ ์ฌ๊ธฐ๋ก ์ค๋ ์ฌ๋๋ค(์ ์ฒ๋ผ): tedious-connection-pool ์ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ ์ข์ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค.
pool.acquire((err, connection) => ...)
๋ฐconnection.release()
๋ฅผ ์ฌ์ฉํ๋ฉด ๋์์ฑ ๋ฌธ์ ๋ฅผ ๋ฐฉ์งํ ์ ์์ต๋๋ค. ๋ค์ค ์ฐ๊ฒฐ์ ์ํ์ง ์์ผ๋ฉด{min: 1, max: 1}
๋ก ํ์ ๊ตฌ์ฑํ์ฌ ์ฟผ๋ฆฌ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ์ง๋ ฌํํฉ๋๋ค.