node-mssql使用介绍文档百度翻译

百度翻译node-mssql

介绍

本文是由【百度翻译】翻译的,本人不保证意思准确无误,有问题请看原文,如果本文中存在问题欢迎大家指出!
Microsoft SQL Server client for Node.js

NPM版本NPM下载Travis CI Appveyor CI加入聊天室https://gitter.im/patriksimek/node-mssql

支持的TDS驱动程序:(纯JavaScript-Windows/macOS/Linux,默认)
节点的Microsoft/Contributors节点V8驱动程序。js for SQL Server(v2本机-仅限Windows或Linux/macOS 64位)

安装

npm install mssql

使用

连接字符串

const sql = require('mssql')

async () => {
    try {
        // 确保连接字符串中的所有项目都正确地进行了URL编码
        await sql.connect('Server=localhost,1433;Database=database;User Id=username;Password=password;Encrypt=true')
        const result = await sql.query`select * from mytable where id = ${value}`
        console.dir(result)
    } catch (err) {
        // ... 错误处理
    }
}

如果您使用的是Windows Azure,请添加?encrypt=您的连接字符串为true。请参阅文档以了解更多信息。连接URI的一部分应该正确地进行URL编码,以便可以正确地解析URI。更详细的示例:通过配置对象连接假设您设置了适当的环境变量,您可以按照如下方式构造配置对象:

const sql = require('mssql')
const sqlConfig = {
  user: process.env.DB_USER,
  password: process.env.DB_PWD,
  database: process.env.DB_NAME,
  server: 'localhost',
  pool: {
    max: 10,
    min: 0,
    idleTimeoutMillis: 30000
  },
  options: {
    encrypt: true, // for azure
    trustServerCertificate: false // 本地开发人员/自签名证书更改为true
  }
}

async () => {
 try {
  // 确保连接字符串中的所有项目都正确地进行了URL编码
  await sql.connect(sqlConfig)
  const result = await sql.query`select * from mytable where id = ${value}`
  console.dir(result)
 } catch (err) {
  // ... 错误处理
 }
}

例子

配置(Config)

const config = {
    user: '...',
    password: '...',
    server: 'localhost', // 您可以使用“localhost\\instance”连接到命名实例
    database: '...',
}

异步/等待(Async/Await)

const sql = require('mssql')

(async function () {
    try {
        let pool = await sql.connect(config)
        let result1 = await pool.request()
            .input('input_parameter', sql.Int, value)
            .query('select * from mytable where id = @input_parameter')
            
        console.dir(result1)
    
        // 存储过程
        
        let result2 = await pool.request()
            .input('input_parameter', sql.Int, value)
            .output('output_parameter', sql.VarChar(50))
            .execute('procedure_name')
        
        console.dir(result2)
    } catch (err) {
        // ... 错误检查
    }
})()

sql.on('error', err => {
    // ... 错误处理
})

Promises

查询(Queries)

const sql = require('mssql')

sql.on('error', err => {
    // ... 错误处理
})

sql.connect(config).then(pool => {
    // 查询
    
    return pool.request()
        .input('input_parameter', sql.Int, value)
        .query('select * from mytable where id = @input_parameter')
}).then(result => {
    console.dir(result)
}).catch(err => {
  // ... 错误处理
});

存储过程 (Stored procedures)

const sql = require('mssql')

sql.on('error', err => {
    // ... 错误处理
})

sql.connect(config).then(pool => {
    
    // 存储过程
    
    return pool.request()
        .input('input_parameter', sql.Int, value)
        .output('output_parameter', sql.VarChar(50))
        .execute('procedure_name')
}).then(result => {
    console.dir(result)
}).catch(err => {
    // ... 错误处理
})

默认情况下使用本机承诺。您可以使用sql轻松地更改这一点。sql.Promise=require(‘myownpromisepackage’)

ES6 标记的模板文本

const sql = require('mssql')

sql.connect(config).then(() => {
    return sql.query`select * from mytable where id = ${value}`
}).then(result => {
    console.dir(result)
}).catch(err => {
    // ... 错误处理
})

sql.on('error', err => {
    // ... 错误处理
})

所有值都会针对sql注入进行自动清理。这是因为它被呈现为prepared语句,因此MSSQL中对参数施加的所有限制都适用。e.g.不能在使用变量的语句中传递/设置列名。

回调(Callbacks)

const sql = require('mssql')

sql.connect(config, err => {
    // ... 错误处理程序

    // 查询

    new sql.Request().query('select 1 as number', (err, result) => {
        // ... 错误处理

        console.dir(result)
    })

    // 存储过程

    new sql.Request()
    .input('input_parameter', sql.Int, value)
    .output('output_parameter', sql.VarChar(50))
    .execute('procedure_name', (err, result) => {
        // ... 错误处理

        console.dir(result)
    })

    // 使用模板文字

    const request = new sql.Request()
    request.query(request.template`select * from mytable where id = ${value}`, (err, result) => {
        // ... 错误处理
        console.dir(result)
    })
})

sql.on('error', err => {
    // ... 错误处理
})

流(Streaming)

如果计划处理大量行,则应始终使用流式处理。启用此功能后,必须侦听事件以接收数据。

const sql = require('mssql')

sql.connect(config, err => {
    // ... 检查错误

    const request = new sql.Request()
    request.stream = true // 您可以为每个请求设置不同的流
    request.query('select * from verylargetable') // 或request.execute(procedure)

    request.on('recordset', columns => {
        // 为查询中的每个记录集发出一次
    })

    request.on('row', row => {
        // 为记录集中的每一行发出
    })

    request.on('rowsaffected', rowCount => {
        // 为每个'INSERT'、'UPDATE'或'DELETE'语句发出
        // 要求关闭NOCOUNT(默认)
    })

    request.on('error', err => {
        // 可能会发射多次
    })

    request.on('done', result => {
        // 始终作为最后一个发射
    })
})

sql.on('error', err => {
    // ... 错误处理
})

当流式传输大数据集时,您希望回退或分块正在处理的数据量,以防止内存耗尽问题;您可以使用请求函数来执行此操作。以下是一个以15行为一批管理的示例:

let rowsToProcess = [];
request.on('row', row => {
  rowsToProcess.push(row);
  if (rowsToProcess.length >= 15) {
    request.pause();
    processRows();
  }
});
request.on('done', () => {
    processRows();
});

function processRows() {
  // 处理行
  rowsToProcess = [];
  request.resume();
}

连接池管理(Pool Management)

使用此库时需要了解的一个重要概念是连接池,因为此库广泛使用连接池。

由于一个节点JS进程能够一次处理多个请求,我们可以利用这个长时间运行的进程来创建一个数据库连接池以供重用;这节省了为每个请求连接到数据库的开销(就像PHP中的情况一样,一个进程处理一个请求)。

池的优点带来了一些额外的复杂性,但这些大多只是概念性的,一旦您了解池是如何工作的,就很容易高效地使用它。

全局连接池(The Global Connection)

为了帮助应用程序中的池管理,可以使用global connect()函数。从该库的v6开始,开发人员可以重复调用该函数以获得全局连接池。这意味着您不需要跟踪应用程序中的池(以前是这样)。如果全局池已连接,它将解析为已连接的池。例如:

const sql = require('mssql')

// 对全局连接池运行查询
function runQuery(query) {
  // sql.connect() (如果存在)将返回现有的全局池,或者(如果不存在)创建一个新的全局池
  return sql.connect().then((pool) => {
    return pool.query(query)
  })
}

在这里,我们通过运行sql.connect()获得全局连接池,然后对池运行查询。我们也不会在执行查询后关闭池,这是因为可能需要对该池运行其他查询,而关闭该池将增加运行查询的开销。我们应该在应用程序完成后才关闭池。例如,如果我们正在运行某种CLI工具或CRON作业:

const sql = require('mssql')

(() => {
  sql.connect().then(pool => {
    return pool.query('SELECT 1')
  }).then(result => {
    // do something with result
  }).then(() => {
    return sql.close()
  })
})()

在这里,一旦查询和其他应用程序逻辑完成,连接将关闭,节点进程将退出。当应用程序退出时,或者您知道应用程序将永远不会进行另一个SQL查询时,您应该只在应用程序中关闭池一次。

高级池管理(Advanced Pool Management)

在某些情况下,您可能不想使用连接池,您可能有多个数据库要连接,或者您可能有一个池用于只读操作,另一个池用于读写。在这种情况下,您需要实现自己的池管理。

可能看起来像这样:

const { ConnectionPool } = require('mssql')
const POOLS = {}

function createPool(config, name) {
  if (getPool(name)) {
    return Promise.reject(new Error('Pool with this name already exists'))
  }
  return (new ConnectionPool(config)).connect().then((pool) => {
    return POOLS[name] = pool
  })
}

function closePool(name) {
  const pool = getPool(name)
  if (pool) {
    delete POOLS[name]
    return pool.close()
  }
  return Promise.resolve()
}

function getPool(name) {
  if (Object.prototype.hasOwnProperty.apply(POOLS, name)) {
    return POOLS[name]
  }
}

module.exports = {
  closePool,
  createPool,
  getPool
}

然后,可以在应用程序中使用此帮助文件来创建、获取和关闭池。与全局池一样,您应该只在知道应用程序不再需要某个池时才关闭该池;通常,这将在应用程序关闭时发生。

连接池 (Connection Pools)

建议对应用程序/服务使用单个连接池。使用回调实例化池,或立即调用。connect是异步的,以确保在返回之前可以建立连接。从那时起,您就可以像平常一样获得连接:

const sql = require('mssql')

// async/await style:
const pool1 = new sql.ConnectionPool(config);
const pool1Connect = pool1.connect();

pool1.on('error', err => {
    // ... 错误处理
})

async function messageHandler() {
    await pool1Connect; // 确保已创建池
    try {
        const request = pool1.request(); // 或: new sql.Request(pool1)
        const result = await request.query('select 1 as number')
        console.dir(result)
        return result;
    } catch (err) {
        console.error('SQL error', err);
    }
}

// promise方式:
const pool2 = new sql.ConnectionPool(config)
const pool2Connect = pool2.connect()

pool2.on('error', err => {
    // ... 错误处理
})

function runStoredProcedure() {
    return pool2Connect.then((pool) => {
        pool.request() // 或: new sql.Request(pool2)
        .input('input_parameter', sql.Int, 10)
        .output('output_parameter', sql.VarChar(50))
        .execute('procedure_name', (err, result) => {
            // ... 错误检查
            console.dir(result)
        })
    }).catch(err => {
        // ... 错误处理
    })
}

因此,创建池是确保池始终处于就绪状态的安全方法,而不需要知道首先需要它的位置。实际上,一旦创建了池,下一个操作就不会有延迟。

从v6.1.0开始您可以重复调用ConnectionPool.connect()和ConnectonPool.close()不会抛出错误,从而可以安全使用mssql.connect().then(…)在整个代码中,以及在应用程序关闭时多次调用关闭。

重复调用connect()的功能旨在简化池管理,但是仍然建议遵循上面的示例,其中connect()只调用一次,并使用原始解析的连接承诺。在运行查询时重复调用connect(),在池上调用close()时可能会遇到问题。

ES6标记的模板文本

new sql.ConnectionPool(config).connect().then(pool => {
    return pool.query`select * from mytable where id = ${value}`
}).then(result => {
    console.dir(result)
}).catch(err => {
    // ... 错误检查
})

所有值都会针对sql注入进行自动清理。

管理连接池(Managing connection pools)

大多数应用程序只需要一个可以在整个代码中共享的连接池。为了帮助共享单个池,此库公开了一组函数以访问单个全局连接。如:

// 作为应用程序启动过程的一部分

const sql = require('mssql')
const poolPromise = sql.connect()

// 在应用程序运行时

poolPromise.then(() => {
  return sql.query('SELECT 1')
}).then(result => {
  console.dir(result)
})

// 当应用程序退出时
poolPromise.then(() => {
  return sql.close()
})

如果每个应用程序需要多个池(可能需要连接多个DBs,或者需要一个只读池),则需要自己管理池。最好的方法是创建一个共享库文件,它可以为您保存对池的引用。例如:

const sql = require('mssql')

const pools = {}

// 按名称管理一组池(创建池需要配置)
// 池关闭时将被删除
async function getPool(name, config) {
  if (!Object.prototype.hasOwnProperty.call(pools, name)) {
    const pool = new sql.ConnectionPool(config)
    const close = pool.close.bind(pool)
    pool.close = (...args) => {
      delete pools[name]
      return close(...args)
    }
    await pool.connect()
    pools[name] = pool
  }
  return pools[name]
}

// 关闭所有池
function closeAll() {
  return Promise.all(Object.values(pools).map((pool) => {
    return pool.close()
  }))
}

module.exports = {
  closeAll,
  getPool
}

然后,您可以在代码中使用此库文件在需要时获取连接池:

const { getPool } = require('./path/to/file')

// run a query
async function runQuery(query, config) {
  // pool will always be connected when the promise has resolved - may reject if the connection config is invalid
  const pool = await getPool('default', config)
  const result = await pool.request().query(query)
  return result
}

配置(Configuration)

const config = {
    user: '...',
    password: '...',
    server: 'localhost',
    database: '...',
    pool: {
        max: 10,
        min: 0,
        idleTimeoutMillis: 30000
    }
}
General (same for all drivers)
  • user - 用于身份验证的用户名。
  • password - 用于身份验证的密码。
  • server - 要连接到的服务器。您可以使用“localhost\instance”连接到命名实例。
  • port - 要连接到的端口(默认值:1433)。连接到命名实例时不进行设置。
  • domain - 设置域后,驱动程序将使用域登录连接到SQL Server。
  • database - 要连接到的数据库(默认值:取决于服务器配置)。
  • connectionTimeout - 以毫秒为单位的连接超时(默认值:15000)。
  • requestTimeout - 请求超时(以毫秒为单位)(默认值:15000)。注意:msnodesqlv8驱动程序不支持超时时间小于1秒。当通过连接字符串传递时,密钥必须是RequestTimeout
  • stream - 流化记录集/行,而不是将它们作为回调参数一次性返回(默认值:false)。您还可以独立地为每个请求启用流(request.stream=true)。如果计划处理大量行,请始终设置为true。
  • parseJSON - 将JSON记录集解析为JS对象(默认值:false)。有关更多信息,请参阅JSON支持部分。
  • pool.max - 池中可以存在的最大连接数(默认值:10)。
  • pool.min - 池中可以存在的最小连接数(默认值:0)。
  • pool.idleTimeoutMillis - 关闭未使用的连接之前的毫秒数(默认值:30000)。
  • arrayRowMode - 将行结果作为数组而不是键控对象返回。还添加了列数组。

请参见处理重复列名:

可在此处找到池选项的完整列表。

格式

除了配置对象之外,还有一个选项可以将配置作为连接字符串传递。支持连接字符串。

经典连接字符串

Server=localhost,1433;Database=database;User Id=username;Password=password;Encrypt=true
Driver=msnodesqlv8;Server=(local)\INSTANCE;Database=database;UID=DOMAIN\username;PWD=password;Encrypt=true

驱动程序(Drivers)

Tedious

默认驱动程序,主动维护并准备好生产。独立于平台,在每个节点上运行。js运行。微软官方支持。

其他选择:

  • beforeConnect(conn) - 该函数在打开连接之前调用。参数conn是配置的单调乏味的参数 联系它可以用于像下面这样附加事件处理程序例子:
require('mssql').connect({...config, beforeConnect: conn => {   
    conn.once('connect', err => { err ? console.error(err) : console.log('mssql connected')})
    conn.once('end', err => { err ? console.error(err) : console.log('mssql disconnected')})
}}) 
  • options.instanceName - 要连接到的实例名称。SQL Server Browser服务必须在数据库服务器上运行,并且必须可以访问数据库服务器上的UDP端口1434。
  • options.useUTC - 一个布尔值,用于确定是否对没有时区偏移的值使用UTC时间(默认值:true)。
  • options.encrypt - 一个布尔值,用于确定连接是否将被加密(默认值:true)。
  • options.tdsVersion - 要使用的TDS版本(默认值:7_4,可用值:7_1、7_2、7_3_A、7_3_B、7_4)。
  • options.appName - 用于SQL server日志记录的应用程序名称。

options.abortTransactionOnError - 一个布尔值,用于确定在给定事务执行期间遇到任何错误时是否自动回滚事务。这将在连接的初始SQL阶段设置XACT_ABORT的值。

认证:

除了这些额外选项之外,还可以将身份验证属性添加到池配置选项中

  • authentication - 根据冗长的文档,具有身份验证设置的对象。传递此对象将覆盖用户、密码和域设置。
  • authentication.type - 身份验证方法的类型,有效类型为默认值、ntlm、azure active directory密码、azure active directory访问令牌、azure active directory msi
    vm或azure active directory msi应用程序服务
  • authentication.options - 冗长的驱动程序所需的身份验证选项取决于身份验证。类型有关更多详细信息,请查看繁琐的身份验证接口

有关繁琐的特定选项的更多信息:http://tediousjs.github.io/tedious/api-connection.html

节点的Microsoft/Contributors节点V8驱动程序。js或sqlserver需要node.js V10+或更新版本。仅限Windows 32-64位或Linux/macOS 64位。 此驱动程序不是默认软件包的一部分,必须由npm install msnodesqlv8@^2单独安装。要使用此驱动程序,请使用此require语法:

const sql = require(‘mssql/msnodesqlv8’).

笔记: 如果使用import-into-lib来准备请求(const{VarChar}=require(‘mssql’)),则还需要将所有类型的import升级到代码(const{VarChar}=require(‘mssql/msnodesqlv8’))或连接中。on不是将抛出的函数错误。

其他选择:
  • beforeConnect(conn)-函数,在打开连接之前调用该函数。参数conn是连接配置,可以修改它以向驱动程序的open()方法传递额外的参数。
  • connectionString - 连接字符串(默认值:见下文)。
  • options.instanceName - 要连接到的实例名称。SQL Server Browser服务必须在数据库服务器上运行,并且必须可以访问数据库服务器上的UDP端口1444。选项。trustedConnection-使用Windows身份验证(默认值:false)。
  • options.useUTC - 一个布尔值,用于确定是否对没有时区偏移的值使用UTC时间(默认值:true)。

连接到端口时的默认连接字符串:

Driver={SQL Server Native Client 11.0};Server={#{server},#{port}};Database={#{database}};Uid={#{user}};Pwd={#{password}};Trusted_Connection={#{trusted}};

连接到命名实例时的默认连接字符串:

Driver={SQL Server Native Client 11.0};Server={#{server}\\#{instance}};Database={#{database}};Uid={#{user}};Pwd={#{password}};Trusted_Connection={#{trusted}};

请注意,此驱动程序的连接字符串与冗长的连接字符串不同,请使用yes/no而不是true/false。您可以在ODBC文档中看到更多信息。

连接(Connections)

在内部,每个ConnectionPool实例都是一个单独的TDS连接池。创建新的请求/事务/准备语句后,将从池中获取一个新的TDS连接,并为所需的操作保留该连接。操作完成后,将释放回池的连接。连接健康检查是内置的,因此一旦发现死连接,就会立即用新连接替换。

重要提示:始终将错误侦听器附加到创建的连接。每当连接出现问题时,它都会发出错误,如果没有侦听器,它会以未捕获的错误使应用程序崩溃。

const pool = new sql.ConnectionPool({ /* config */ })

事件(Events)

  • error(err) - 在连接错误时发送。

connect ([callback])

创建一个新的连接池。创建初始探测连接以确定配置是否有效。

论据(Arguments)
  • callback(err) - 在建立初始探测连接或发生错误后调用的回调。可选择的如果省略,则返回承诺。
实例(Example)
const pool = new sql.ConnectionPool({
    user: '...',
    password: '...',
    server: 'localhost',
    database: '...'
})

pool.connect(err => {
    // ...
})
错误
  • ELOGIN (ConnectionError) - 登录失败。
  • ETIMEOUT (ConnectionError) - 连接超时。
  • EALREADYCONNECTED (ConnectionError) - 数据库已连接!
  • EALREADYCONNECTING (ConnectionError) - 已连接到数据库!
  • EINSTLOOKUP (ConnectionError) - 实例查找失败。
  • ESOCKET (ConnectionError) - 套接字错误。

close()

关闭池中的所有活动连接。

实例(Example)
pool.close()

请求(Request)

const request = new sql.Request(/* [pool or transaction] */)

如果省略pool/transaction参数,则使用全局池。

事件(Events)

  • recordset(columns) - 在解析新记录集的元数据时调度。
  • row(row) - 在分析新行时调度。
  • done(returnValue) - 请求完成时发送。
  • error(err) - 错误时发送。
  • info(message) - 根据信息性消息发送。

execute (procedure, [callback])

调用存储过程。

参数(Arguments)
  • procedure - 要执行的存储过程的名称。
  • callback(err, recordsets, returnValue) - 在执行完成或发生错误后调用的回调。returnValue也可以作为记录集的属性访问。可选择的如果省略,则返回承诺。
实例(Example)
const request = new sql.Request()
request.input('input_parameter', sql.Int, value)
request.output('output_parameter', sql.Int)
request.execute('procedure_name', (err, result) => {
    // ... 错误检查

    console.log(result.recordsets.length) // 过程返回的记录集计数
    console.log(result.recordsets[0].length) // 第一个记录集中包含的行数
    console.log(result.recordset) // 结果的第一个记录集。输出数据集
    console.log(result.returnValue) // 过程返回值
    console.log(result.output) // 输出值的键/值集合
    console.log(result.rowsAffected) // 数字数组,每个数字表示受已执行状态影响的行数

    // ...
})
错误
  • EREQUEST (RequestError) - 来自SQL Server的消息
  • ECANCEL (RequestError) - 取消。
  • ETIMEOUT (RequestError) - 请求超时。
  • ENOCONN (RequestError) - 没有为该请求指定连接。
  • ENOTOPEN (ConnectionError) - 连接尚未打开。
  • ECONNCLOSED (ConnectionError) - 连接已关闭。
  • ENOTBEGUN (TransactionError) - 交易尚未开始。
  • EABORT (TransactionError) - 事务已中止(由用户或由于错误)。

input (name, [type], value)

向请求添加输入参数。

参数(Arguments)
  • name - 不带@char的输入参数的名称。
  • type - 输入参数的SQL数据类型。若您省略了类型,模块会根据JS数据类型自动决定应该使用哪种SQL数据类型。
  • value - 输入参数值。未定义值和NaN值将自动转换为null。
实例(Example)
request.input('input_parameter', value)
request.input('input_parameter', sql.Int, value)

JS数据类型对应SQL数据类型:

  • String -> sql.NVarChar
  • Number -> sql.Int
  • Boolean -> sql.Bit
  • Date -> sql.DateTime
  • Buffer -> sql.VarBinary
  • sql.Table -> sql.TVP

未知对象的默认数据类型为sql.NVarChar

您可以定义自己的类型映射。

sql.map.register(MyClass, sql.Text)

您还可以覆盖默认类型映射。

sql.map.register(Number, sql.BigInt)
错误(同步)
  • EARGS (RequestError) - 参数数无效。
  • EINJECT (RequestError) - SQL注入警告。

注意: 不要使用@p{n}参数,因为这些参数由内部驱动程序使用,会导致冲突。

output (name, type, [value])

向请求添加输出参数。

参数(Arguments)
  • name - 不带@char的输出参数的名称。
  • type - 输出参数的SQL数据类型。
  • value - 输出参数值初始值。未定义值和NaN值将自动转换为空值。可选择的
实例(Example)
request.output('output_parameter', sql.Int)
request.output('output_parameter', sql.VarChar(50), 'abc')
错误 (同步)
  • EARGS (RequestError) - 参数数无效。
  • EINJECT (RequestError) - SQL注入警告。

toReadableStream

将请求转换为node.js可读流

实例(Example)
const { pipeline } = require('stream')
const request = new sql.Request()
const readableStream = request.toReadableStream()
pipeline(readableStream, transformStream, writableStream)
request.query('select * from mytable')

或者,如果您想增加读取流的highWaterMark以在内存中缓冲更多行

const { pipeline } = require('stream')
const request = new sql.Request()
const readableStream = request.toReadableStream({ highWaterMark: 100 })
pipeline(readableStream, transformStream, writableStream)
request.query('select * from mytable')

pipe (stream)

将请求设置为流模式,并将所有记录集中的所有行拉入给定流。

参数(Arguments)
  • stream - 对象模式下的可写流。
实例(Example)
const request = new sql.Request()
request.pipe(stream)
request.query('select * from mytable')
stream.on('error', err => {
    // ...
})
stream.on('finish', () => {
    // ...
})

query (command, [callback])

执行SQL命令。若要执行诸如create procedure之类的命令,或者如果您计划使用本地临时表,请改用batch。

参数(Arguments)
  • command - 要执行的T-SQL命令。
  • callback(err, recordset) - 在执行完成或发生错误后调用的回调。可选择的如果省略,则返回承诺。
实例(Example)
const request = new sql.Request()
request.query('select 1 as number', (err, result) => {
    // ... 检查错误

    console.log(result.recordset[0].number) // return 1

    // ...
})
错误
  • ETIMEOUT (RequestError) - 请求超时。
  • EREQUEST (RequestError) - 来自SQL Server的消息
  • ECANCEL (RequestError) - 取消。
  • ENOCONN (RequestError) - 没有为该请求指定连接。
  • ENOTOPEN (ConnectionError) - 连接尚未打开。
  • ECONNCLOSED (ConnectionError) - 连接已关闭。
  • ENOTBEGUN (TransactionError) - 交易尚未开始。
  • EABORT (TransactionError) - 事务已中止(由用户或由于错误)。
const request = new sql.Request()
request.query('select 1 as number; select 2 as number', (err, result) => {
    // ... 错误处理

    console.log(result.recordset[0].number) // return 1
    console.log(result.recordsets[0][0].number) // return 1
    console.log(result.recordsets[1][0].number) // return 2
})

注意: 要获取受语句影响的行数,请参阅“受影响的行”部分。

batch (batch, [callback])

执行SQL命令。与查询不同,它不使用sp_executesql,因此SQL Server不太可能重用它为SQL生成的执行计划。仅在特殊情况下使用此选项,例如,当您需要执行诸如create procedure之类的命令,而这些命令无法通过查询执行时,或者在SQL Server 2000上执行的语句长度超过4000个字符时。如果您计划使用本地临时表(此处有更多信息),也应该使用此选项。

注意: 批处理中不支持表值参数(TVP)。

参数(Arguments)
  • batch - 要执行的T-SQL命令。
  • callback(err, recordset) - 在执行完成或发生错误后调用的回调。可选择的如果省略,则返回承诺。
实例(Example)
const request = new sql.Request()
request.batch('create procedure #temporary as select * from table', (err, result) => {
    // ... 错误检查
})
错误
  • ETIMEOUT (RequestError) -请求超时。
  • EREQUEST (RequestError) - 来自SQL Server的消息
  • ECANCEL (RequestError) - 取消。
  • ENOCONN (RequestError) -没有为该请求指定连接。
  • ENOTOPEN (ConnectionError) - 连接尚未打开。
  • ECONNCLOSED (ConnectionError) - 连接已关闭。
  • ENOTBEGUN (TransactionError) - 交易尚未开始。
  • EABORT (TransactionError) - 事务已中止(由用户或由于错误)。

您可以在带有请求的查询中启用多个记录集request.multiple = true命令。

bulk (table, [options,] [callback])

执行批量插入。

参数(Arguments)
  • table - sql.Table实例.
  • options - 要传递给驱动程序的选项对象(目前仅为乏味的)。可选择的如果参数是一个函数,它将被视为回调函数。
  • callback(err, rowCount) -在大容量插入完成或发生错误后调用的回调。可选择的如果省略,则返回Promise。
实例(Example)
const table = new sql.Table('table_name') // or temporary table, e.g. #temptable
table.create = true
table.columns.add('a', sql.Int, {nullable: true, primary: true})
table.columns.add('b', sql.VarChar(50), {nullable: false})
table.rows.add(777, 'test')

const request = new sql.Request()
request.bulk(table, (err, result) => {
    // ... 错误检查
})

重要的: 始终指示列是否可为空!

提示:

  1. 若table.create为true时,模块将在开始发送数据之前检查表是否存在。如果没有,它将自动创建它。通过将primary:true设置为列的选项,可以指定主键列。支持多列上的主键约束
  2. 您还可以使用记录集从任何记录集创建表变量Table()。您可以选择在第一个参数中指定表类型名称。
错误
  • ENAME (RequestError) - 必须为大容量插入指定表名。
  • ETIMEOUT (RequestError) - 请求超时。
  • EREQUEST (RequestError) -来自SQL Server的消息
  • ECANCEL (RequestError) - 取消。
  • ENOCONN (RequestError) - 没有为该请求指定连接。
  • ENOTOPEN (ConnectionError) - 连接尚未打开。
  • ECONNCLOSED (ConnectionError) - 连接已关闭
  • ENOTBEGUN (TransactionError) - 交易尚未开始。
  • EABORT (TransactionError) - 事务已中止(由用户或由于错误)。

cancel()

取消当前正在执行的请求。如果成功发送取消数据包,则返回true。

实例(Example)
const request = new sql.Request()
request.query('waitfor delay \'00:00:05\'; select 1 as number', (err, result) => {
    console.log(err instanceof sql.RequestError)  // true
    console.log(err.message)                      // Cancelled.
    console.log(err.code)                         // ECANCEL

    // ...
})
request.cancel()

事务(Transaction)

重要的: 始终使用事务类来创建事务-它确保所有请求都在一个连接上执行。调用begin后,将从连接池中获取单个连接,并且所有后续请求(使用事务对象初始化)都将在此连接上以独占方式执行。在调用commit或rollback之后,连接被释放回连接池。

const transaction = new sql.Transaction(/* [pool] */)

如果省略连接参数,则使用全局连接。

实例(Example)
const transaction = new sql.Transaction(/* [pool] */)
transaction.begin(err => {
    // ... 检查错误

    const request = new sql.Request(transaction)
    request.query('insert into mytable (mycolumn) values (12345)', (err, result) => {
        // ... 检查错误

        transaction.commit(err => {
            // ... 检查错误

            console.log("Transaction committed.")
        })
    })
})

事务也可以由创建const transaction = pool.transaction()。 请求也可以由创建 const request = transaction.request()

终止事务(Aborted transactions)

此示例显示了在启用AbortTransactionError(XACT_ABORT)时应如何正确处理事务错误。在2.0中添加。

const transaction = new sql.Transaction(/* [pool] */)
transaction.begin(err => {
    // ... 检查错误

    let rolledBack = false

    transaction.on('rollback', aborted => {
        // emited with aborted === true

        rolledBack = true
    })

    new sql.Request(transaction)
    .query('insert into mytable (bitcolumn) values (2)', (err, result) => {
        // 由于值无效,插入应失败

        if (err) {
            if (!rolledBack) {
                transaction.rollback(err => {
                    // ... 检查错误
                })
            }
        } else {
            transaction.commit(err => {
                // ... 检查错误
            })
        }
    })
})

事件(Events)

  • begin - 事务开始时已调度。
  • commit - 在成功提交时发送。
  • rollback(aborted) - 在成功回滚时调度,参数确定事务是否中止(由用户中止或由于错误)。

begin ([isolationLevel], [callback])

开始事务。

参数(Arguments)
  • isolationLevel - 控制连接发出的TSQL语句的锁定和行版本控制行为。可选择的默认情况下读取提交的。有关可能的值,请参见sql.ISOLATION_LEVEL。
  • callback(err) - 在事务开始或发生错误后调用的回调。可选择的如果省略,则返回Promise。
实例(Example)
const transaction = new sql.Transaction()
transaction.begin(err => {
    // ... 检查错误
})
错误
  • ENOTOPEN (ConnectionError) - 连接尚未打开。
  • EALREADYBEGUN (TransactionError) - 事务已经开始。

commit ([callback])

提交事务。

参数(Arguments)
  • callback(err) -在事务已提交或发生错误后调用的回调。可选择的如果省略,则返回Promise。
实例(Example)
const transaction = new sql.Transaction()
transaction.begin(err => {
    // ... 检查错误

    transaction.commit(err => {
        // ... 检查错误
    })
})
错误
  • ENOTBEGUN (TransactionError) -事务尚未开始。
  • EREQINPROG (TransactionError) - 无法提交事务。有一个请求正在进行中。

rollback ([callback])

回滚事务。如果队列不是空的,所有排队的请求都将被取消,事务将被标记为中止。

参数(Arguments)
  • callback(err) - 在事务回滚或发生错误后调用的回调。可选择的如果省略,则返回Promise。
实例(Example)
const transaction = new sql.Transaction()
transaction.begin(err => {
    // ... 检查错误

    transaction.rollback(err => {
        // ... 检查错误
    })
})
错误
  • ENOTBEGUN (TransactionError) - 事务尚未开始。
  • EREQINPROG (TransactionError) - 无法回滚事务。有一个请求正在进行中。

准备声明(Prepared Statement)

重要的: 始终使用PreparedStatement类来创建准备好的语句-它确保在一个连接上执行所有准备好的语句。调用prepare后,将从连接池中获取一个连接,并且所有后续执行都将在此连接上独占执行。调用unprepare后,连接将被释放回连接池。

const ps = new sql.PreparedStatement(/* [pool] */)

如果省略connection参数,则使用全局连接。

实例(Example)
const ps = new sql.PreparedStatement(/* [pool] */)
ps.input('param', sql.Int)
ps.prepare('select @param as value', err => {
    // ... 检查错误

    ps.execute({param: 12345}, (err, result) => {
        // ... 检查错误

        // release the connection after queries are executed
        ps.unprepare(err => {
            // ... 检查错误

        })
    })
})

重要的: 请记住,每个准备好的语句都意味着池中的一个保留连接。当您完成查询时,不要忘记取消准备一个准备好的语句!

您可以对同一个已准备好的语句执行多个查询,但必须在使用完该语句后取消该语句的准备,否则将导致连接池的可用连接耗尽。

提示: 您还可以在事务中创建准备好的语句(new sql.PreparedStatement(transaction)),但请记住,在调用unprepare之前,您不能在事务中执行其他请求。

input (name, type)

将输入参数添加到准备好的语句中。

参数(Arguments)
  • name - 不带@char的输入参数的名称。
  • type - 输入参数的SQL数据类型。
实例(Example)
ps.input('input_parameter', sql.Int)
ps.input('input_parameter', sql.VarChar(50))
错误(同步)
  • EARGS (PreparedStatementError) - 参数数无效。
  • EINJECT (PreparedStatementError) - SQL注入警告。

output (name, type)

将输出参数添加到准备好的语句中。

参数(Arguments)
  • name - 不带@char的输出参数的名称。
  • type - 输出参数的SQL数据类型。
实例(Example)
ps.output('output_parameter', sql.Int)
ps.output('output_parameter', sql.VarChar(50))
错误(同步)
  • EARGS (PreparedStatementError) - 参数数无效。
  • EINJECT (PreparedStatementError) - SQL注入警告。

prepare (statement, [callback])

准备一份声明。

参数(Arguments)
  • statement - 要准备的T-SQL语句。
  • callback(err) -准备完成或发生错误后调用的回调。可选择的如果省略,则返回Promise。
实例(Example)
const ps = new sql.PreparedStatement()
ps.prepare('select @param as value', err => {
    // ... 检查错误
})
错误
  • ENOTOPEN (ConnectionError) - 连接尚未打开。
  • EALREADYPREPARED (PreparedStatementError) - 声明已经准备好了。
  • ENOTBEGUN (TransactionError) - 事务尚未开始。

execute (values, [callback])

执行准备好的语句。

参数(Arguments)
  • values - 一个对象,其名称与准备语句之前添加到准备语句中的参数名称相对应。
  • callback(err) - 在执行完成或发生错误后调用的回调。可选择,如省略,则返回Promise。
实例(Example)
const ps = new sql.PreparedStatement()
ps.input('param', sql.Int)
ps.prepare('select @param as value', err => {
    // ... 检查错误

    ps.execute({param: 12345}, (err, result) => {
        // ... 检查错误

        console.log(result.recordset[0].value) // return 12345
        console.log(result.rowsAffected) // 返回INSERT、UPDATE或DELETE语句中受影响的行数。
        
        ps.unprepare(err => {
            // ... 检查错误
        })
    })
})

您还可以流式处理执行的请求。

const ps = new sql.PreparedStatement()
ps.input('param', sql.Int)
ps.prepare('select @param as value', err => {
    // ... 检查错误

    ps.stream = true
    const request = ps.execute({param: 12345})

    request.on('recordset', columns => {
        // 为查询中的每个记录集发出一次
    })

    request.on('row', row => {
        // 为记录集中的每一行发出
    })

    request.on('error', err => {
        // 可能会发射多次
    })

    request.on('done', result => {
        // 始终作为最后一个发射
        
        console.log(result.rowsAffected) // 返回INSERT、UPDATE或DELETE语句中受影响的行数。
        
        ps.unprepare(err => {
            // ... 检查错误
        })
    })
})

提示: 要了解更多有关受影响行数的工作原理,请参阅“受影响行”一节。

错误
  • ENOTPREPARED (PreparedStatementError) -声明没有准备好。
  • ETIMEOUT (RequestError) - 请求超时。
  • EREQUEST (RequestError) - 来自SQL Server的消息
  • ECANCEL (RequestError) - 取消。

unprepare ([callback])

不准备一份事先准备好的声明。

参数(Arguments)
  • callback(err) - 在取消准备完成或发生错误后调用的回调。可选择的如果省略,则返回Promise。
实例(Example)
const ps = new sql.PreparedStatement()
ps.input('param', sql.Int)
ps.prepare('select @param as value', err => {
    // ... 检查错误

    ps.unprepare(err => {
        // ... 检查错误

    })
})
错误
  • ENOTPREPARED (PreparedStatementError) - 声明没有准备好。

CLI

在开始使用CLI之前,必须使用npm install mssql-g全局安装mssql。一旦这样做,您将能够执行mssql命令。

设置(Setup)

设置创建一个.mssql.json配置文件(任意位置)。文件的结构与标准配置对象相同。

{
    "user": "...",
    "password": "...",
    "server": "localhost",
    "database": "..."
}
实例(Example)
echo "select * from mytable" | mssql /path/to/config

结果:

[[{"username":"patriksimek","password":"tooeasy"}]]

您还可以查询多个记录集。

echo "select * from mytable; select * from myothertable" | mssql

结果:

[[{"username":"patriksimek","password":"tooeasy"}],[{"id":15,"name":"Product name"}]]

若省略配置路径参数,mssql将尝试从当前工作目录加载它。

地理与几何(Geography and Geometry)

node-mssql 具有用于地理和几何CLR数据类型的内置反序列化器。

地理(Geography)

地理类型可以通过几种不同的方式构造。仔细参考文件以验证坐标顺序;ST方法倾向于将参数排序为经度(x)然后是纬度(y),而自定义CLR方法倾向于将参数排序为纬度(y)然后是经度(x)。

查询:

select geography::STGeomFromText(N'POLYGON((1 1, 3 1, 3 1, 1 1))',4326)

结果:

{
  srid: 4326,
  version: 2,
  points: [
    Point { lat: 1, lng: 1, z: null, m: null },
    Point { lat: 1, lng: 3, z: null, m: null },
    Point { lat: 1, lng: 3, z: null, m: null },
    Point { lat: 1, lng: 1, z: null, m: null }
  ],
  figures: [ { attribute: 1, pointOffset: 0 } ],
  shapes: [ { parentOffset: -1, figureOffset: 0, type: 3 } ],
  segments: []
}

注意: 您还将在解析的地理点中看到x和y坐标,不建议使用它们。因此,在本示例中省略了它们。为了兼容性,它们保持翻转(x,水平偏移,用于纬度,垂直),因此有误导您的风险。更倾向于使用lat和lng特性。

几何(Geometry)

几何图形类型也可以通过多种方式构造。与地理位置不同,它们始终在y之前放置x。节点mssql解码此查询的结果:

select geometry::STGeomFromText(N'POLYGON((1 1, 3 1, 3 7, 1 1))',4326)

进入JavaScript对象:

{
  srid: 4326,
  version: 1,
  points: [
    Point { x: 1, y: 1, z: null, m: null },
    Point { x: 1, y: 3, z: null, m: null },
    Point { x: 7, y: 3, z: null, m: null },
    Point { x: 1, y: 1, z: null, m: null }
  ],
  figures: [ { attribute: 2, pointOffset: 0 } ],
  shapes: [ { parentOffset: -1, figureOffset: 0, type: 3 } ],
  segments: []
}

表值参数TVP(Table-Valued Parameter (TVP))

在SQL Server 2008及更高版本上受支持。可以将数据表作为参数传递给存储过程。首先,我们必须在数据库中创建自定义类型。

CREATE TYPE TestType AS TABLE ( a VARCHAR(50), b INT );

接下来我们需要一个存储过程。

CREATE PROCEDURE MyCustomStoredProcedure (@tvp TestType readonly) AS SELECT * FROM @tvp
Now let's go back to our Node.js app.

const tvp = new sql.Table() // 您可以选择在第一个参数中指定表类型名称。

// 列必须与我们在数据库中创建的类型对应。
tvp.columns.add('a', sql.VarChar(50))
tvp.columns.add('b', sql.Int)

// Add rows
tvp.rows.add('hello tvp', 777) // 值的顺序与列的顺序相同。

您可以将表作为参数发送到存储过程。

const request = new sql.Request()
request.input('tvp', tvp)
request.execute('MyCustomStoredProcedure', (err, result) => {
    // ... 检查错误

    console.dir(result.recordsets[0][0]) // {a: 'hello tvp', b: 777}
})

提示: 您还可以使用记录集从任何记录集创建表变量Table()。您可以选择在第一个参数中指定表类型名称。

响应(Response Schema)

从成功的基本查询返回的对象如下所示。

{
	recordsets: [
		[
			{
				COL1: "some content",
				COL2: "some more content"
			}
		]
	],
	recordset: [
		{
			COL1: "some content",
			COL2: "some more content"
		}
	],
	output: {},
	rowsAffected: [1]
}

受影响的行(Affected Rows)

如果在查询中执行INSERT、UPDATE或DELETE,则可以读取受影响的行数。rowsAffected变量是一个数字数组。每个数字表示单个语句所影响的行数。

使用Promises的示例
const request = new sql.Request()
request.query('update myAwesomeTable set awesomness = 100').then(result => {
    console.log(result.rowsAffected)
})
使用回调的示例
const request = new sql.Request()
request.query('update myAwesomeTable set awesomness = 100', (err, result) => {
    console.log(result.rowsAffected)
})
使用流媒体的示例

除了done事件上的rowsAffected属性外,每个语句在完成时都将发出受影响行的数量。

const request = new sql.Request()
request.stream = true
request.query('update myAwesomeTable set awesomness = 100')
request.on('rowsaffected', rowCount => {
    console.log(rowCount)
})
request.on('done', result => {
    console.log(result.rowsAffected)
})

支持JSON(JSON support)

SQL Server 2016引入了内置JSON序列化。默认情况下,JSON在名为JSON_F52E2B61-18A1-11d1-B105-00805F49916B的特殊列中以纯文本形式返回。

实例
SELECT
    1 AS 'a.b.c',
    2 AS 'a.b.d',
    3 AS 'a.x',
    4 AS 'a.y'
FOR JSON PATH
结果:
recordset = [ { 'JSON_F52E2B61-18A1-11d1-B105-00805F49916B': '{"a":{"b":{"c":1,"d":2},"x":3,"y":4}}' } ]

您可以使用config启用内置JSON解析器。parseJSON=true。启用此功能后,记录集将包含已解析的JS对象行。给出相同的示例,结果如下所示:

recordset = [ { a: { b: { c: 1, d: 2 }, x: 3, y: 4 } } ]

重要的:为了使其工作,记录集中必须正好有一列名为JSON_F52E2B61-18A1-11d1-B105-00805F49916B。

关于JSON支持的更多信息可以在官方文档中找到。

处理重复的列名(Handling Duplicate Column Names)

如果查询包含具有相同名称的输出列,mssql的默认行为将仅返回具有该名称的最后一列的列元数据。您也不能总是重新组合所请求的输出列的顺序。

违约行为:

const request = new sql.Request()
request
    .query("select 'asdf' as name, 'qwerty' as other_name, 'jkl' as name")
    .then(result => {
        console.log(result)
    });

结果:

{
  recordsets: [
    [ { name: [ 'asdf', 'jkl' ], other_name: 'qwerty' } ]
  ],
  recordset: [ { name: [ 'asdf', 'jkl' ], other_name: 'qwerty' } ],
  output: {},
  rowsAffected: [ 1 ]
}

您可以使用arrayRowMode配置参数将行值作为数组返回,并添加单独的列值数组。arrayRowMode可以在初始连接期间全局设置,也可以按请求设置。

const request = new sql.Request()
request.arrayRowMode = true
request
    .query("select 'asdf' as name, 'qwerty' as other_name, 'jkl' as name")
    .then(result => {
        console.log(result)
    });

结果:

{
  recordsets: [ [ [ 'asdf', 'qwerty', 'jkl' ] ] ],
  recordset: [ [ 'asdf', 'qwerty', 'jkl' ] ],
  output: {},
  rowsAffected: [ 1 ],
  columns: [
    [
      {
        index: 0,
        name: 'name',
        length: 4,
        type: [sql.VarChar],
        scale: undefined,
        precision: undefined,
        nullable: false,
        caseSensitive: false,
        identity: false,
        readOnly: true
      },
      {
        index: 1,
        name: 'other_name',
        length: 6,
        type: [sql.VarChar],
        scale: undefined,
        precision: undefined,
        nullable: false,
        caseSensitive: false,
        identity: false,
        readOnly: true
      },
      {
        index: 2,
        name: 'name',
        length: 3,
        type: [sql.VarChar],
        scale: undefined,
        precision: undefined,
        nullable: false,
        caseSensitive: false,
        identity: false,
        readOnly: true
      }
    ]
  ]
}

流式处理重复列名

在启用流的情况下使用arrayRowMode时,记录集事件的输出(如流中所述)将作为列元数据数组返回,而不是作为键控对象返回。当启用arrayRowMode时,recordset事件提供的列元数据的顺序将与行值的顺序匹配。

默认行为(不带arrayRowMode):

const request = new sql.Request()
request.stream = true
request.query("select 'asdf' as name, 'qwerty' as other_name, 'jkl' as name")
request.on('recordset', recordset => console.log(recordset))

结果:

{
  name: {
    index: 2,
    name: 'name',
    length: 3,
    type: [sql.VarChar],
    scale: undefined,
    precision: undefined,
    nullable: false,
    caseSensitive: false,
    identity: false,
    readOnly: true
  },
  other_name: {
    index: 1,
    name: 'other_name',
    length: 6,
    type: [sql.VarChar],
    scale: undefined,
    precision: undefined,
    nullable: false,
    caseSensitive: false,
    identity: false,
    readOnly: true
  }
}

和arrayRowMode:

const request = new sql.Request()
request.stream = true
request.arrayRowMode = true
request.query("select 'asdf' as name, 'qwerty' as other_name, 'jkl' as name")

request.on('recordset', recordset => console.log(recordset))

结果:

[
  {
    index: 0,
    name: 'name',
    length: 4,
    type: [sql.VarChar],
    scale: undefined,
    precision: undefined,
    nullable: false,
    caseSensitive: false,
    identity: false,
    readOnly: true
  },
  {
    index: 1,
    name: 'other_name',
    length: 6,
    type: [sql.VarChar],
    scale: undefined,
    precision: undefined,
    nullable: false,
    caseSensitive: false,
    identity: false,
    readOnly: true
  },
  {
    index: 2,
    name: 'name',
    length: 3,
    type: [sql.VarChar],
    scale: undefined,
    precision: undefined,
    nullable: false,
    caseSensitive: false,
    identity: false,
    readOnly: true
  }
]

错误

您可以处理4种类型的错误:

ConnectionError - 与连接和连接池相关的错误。
TransactionError - 与创建、提交和回滚事务相关的错误。
RequestError - 与查询和存储过程执行相关的错误。
PreparedStatementError - 与准备的报表相关的错误。
这些错误在节点mssql模块中初始化,其原始堆栈可能会被裁剪。您始终可以使用err访问原始错误。err.precedingErrors。

SQL Server可能会为一个请求生成多个错误,因此您可以使用err访问前面的错误。先入为主的错误。

错误代码

每个已知错误都有名称、代码和消息属性。

名称编码消息属性
ConnectionErrorELOGINLogin failed.
ConnectionErrorETIMEOUTConnection timeout.
ConnectionErrorEDRIVERUnknown driver.
ConnectionErrorEALREADYCONNECTEDDatabase is already connected!
ConnectionErrorEALREADYCONNECTINGAlready connecting to database!
ConnectionErrorENOTOPENConnection not yet open.
ConnectionErrorEINSTLOOKUPInstance lookup failed.
ConnectionErrorESOCKETSocket error.
ConnectionErrorECONNCLOSEDConnection is closed.
TransactionErrorENOTBEGUNTransaction has not begun.
TransactionErrorEALREADYBEGUNTransaction has already begun.
TransactionErrorEREQINPROGCan’t commit/rollback transaction. There is a request in progress.
TransactionErrorEABORTTransaction has been aborted.
RequestErrorEREQUESTMessage from SQL Server. Error object contains additional details.
RequestErrorECANCELCancelled.
RequestErrorETIMEOUTRequest timeout.
RequestErrorEARGSInvalid number of arguments.
RequestErrorEINJECTSQL injection warning.
RequestErrorENOCONNNo connection is specified for that request.
PreparedStatementErrorEARGSInvalid number of arguments.
PreparedStatementErrorEINJECTSQL injection warning.
PreparedStatementErrorEALREADYPREPAREDStatement is already prepared.
PreparedStatementErrorENOTPREPAREDStatement is not prepared.
详细的SQL错误

SQL错误(err.code等于EREQUEST的RequestError)包含其他详细信息。

err.number - 错误号。
err.state - 错误状态,用作数字的修饰符。
err.class - 错误的类别(严重性)。小于10的类表示信息性消息。详细的解释可以在这里找到。
err.lineNumber - 导致错误的SQL批处理或存储过程中的行号。行号从1开始;因此,如果行号不适用于消息,则LineNumber的值将为0。
err.serverName - 服务器名称。
err.procName - 存储过程名称。

数据信息(Informational messages)

要接收由PRINT或RAISERROR命令生成的信息性消息,请使用:

const request = new sql.Request()
request.on('info', info => {
    console.dir(info)
})
request.query('print \'Hello world.\';', (err, result) => {
    // ...
})
数据信息的结构:

info.message - 信息。
info.number - 消息号码
info.state - 消息状态,用作数字的修饰符。
info.class - 消息的类别(严重性)。等于或小于10。详细的解释可以在这里找到。
info.lineNumber - 生成消息的SQL批处理或存储过程中的行号。行号从1开始;因此,如果行号不适用于消息,则LineNumber的值将为0。
info.serverName - 服务器名称。
info.procName - 存储过程名称。

元数据(Metadata)

可通过记录集访问记录集元数据。columns属性。

const request = new sql.Request()
request.query('select convert(decimal(18, 4), 1) as first, \'asdf\' as second', (err, result) => {
    console.dir(result.recordset.columns)

    console.log(result.recordset.columns.first.type === sql.Decimal) // true
    console.log(result.recordset.columns.second.type === sql.VarChar) // true
})

列结构,例如上面的示例:

{
    first: {
        index: 0,
        name: 'first',
        length: 17,
        type: [sql.Decimal],
        scale: 4,
        precision: 18,
        nullable: true,
        caseSensitive: false
        identity: false
        readOnly: true
    },
    second: {
        index: 1,
        name: 'second',
        length: 4,
        type: [sql.VarChar],
        nullable: false,
        caseSensitive: false
        identity: false
        readOnly: true
    }
}

Data Types

你可以使用length/precision/scale:

request.input("name", sql.VarChar, "abc")               // varchar(3)
request.input("name", sql.VarChar(50), "abc")           // varchar(50)
request.input("name", sql.VarChar(sql.MAX), "abc")      // varchar(MAX)
request.output("name", sql.VarChar)                     // varchar(8000)
request.output("name", sql.VarChar, "abc")              // varchar(3)

request.input("name", sql.Decimal, 155.33)              // decimal(18, 0)
request.input("name", sql.Decimal(10), 155.33)          // decimal(10, 0)
request.input("name", sql.Decimal(10, 2), 155.33)       // decimal(10, 2)

request.input("name", sql.DateTime2, new Date())        // datetime2(7)
request.input("name", sql.DateTime2(5), new Date())     // datetime2(5)

支持的数据类型列表:

sql.Bit
sql.BigInt
sql.Decimal ([precision], [scale])
sql.Float
sql.Int
sql.Money
sql.Numeric ([precision], [scale])
sql.SmallInt
sql.SmallMoney
sql.Real
sql.TinyInt

sql.Char ([length])
sql.NChar ([length])
sql.Text
sql.NText
sql.VarChar ([length])
sql.NVarChar ([length])
sql.Xml

sql.Time ([scale])
sql.Date
sql.DateTime
sql.DateTime2 ([scale])
sql.DateTimeOffset ([scale])
sql.SmallDateTime

sql.UniqueIdentifier

sql.Variant

sql.Binary
sql.VarBinary ([length])
sql.Image

sql.UDT
sql.Geography
sql.Geometry

要设置VarChar、NVarChar和VarBinary的最大长度,请使用sql.MAX。输入sql.XML和sql.Variant 变量不支持作为输入参数。

SQL 注入

此模块具有内置的SQL注入保护。始终使用参数或标记的模板文字将经过清理的值传递给查询。

const request = new sql.Request()
request.input('myval', sql.VarChar, '-- commented')
request.query('select @myval as myval', (err, result) => {
    console.dir(result)
})

已知问题

Tedious

  • 如果在连接SQL Server 2000时遇到问题,请尝试使用config将默认TDS版本设置为7.1。选项。tdsVersion=‘7_1’ (问题)
  • 如果在SQL Server 2000上执行的语句长度超过4000个字符,请始终使用批处理而不是查询(问题)

6.x to 7.x changes

  • Upgraded tedious version to v11
  • Upgraded msnodesqlv8 version support to v2
  • Upgraded tarn.js version to v3
  • Requests in stream mode that pipe into other streams no longer pass
    errors up the stream chain
  • Request.pipe now pipes a true node stream for better support of
    backpressure
  • tedious config option trustServerCertificate defaults to false if not
  • supplied Dropped support for Node < 10

5.x to 6.x changes

  • Upgraded tarn.js so _poolDestroy can take advantage of being a
    promise
  • ConnectionPool.close() now returns a promise / callbacks will be
    executed once closing of the pool is complete; you must make sure
    that connections are properly released back to the pool otherwise the
    pool may fail to close.
  • It is safe to pass read-only config objects to the library; config
    objects are now cloned
  • options.encrypt is now true by default
  • TYPES.Null has now been removed
  • Upgraded tedious driver to v6 and upgraded support for msnodesqlv8]
  • You can now close the global connection by reference and this will
    clean up the global connection, eg: const conn = sql.connect();
    conn.close() will be the same as sql.close()
  • Bulk table inserts will attempt to coerce dates from non-Date objects
    if the column type is expecting a date
  • Repeat calls to the global connect function (sql.connect()) will
    return the current global connection if it exists (rather than
    throwing an error)
  • Attempting to add a parameter to queries / stored procedures will now
    throw an error; use replaceInput and replaceOutput instead
  • Invalid isolation levels passed to Transactions will now throw an
    error
  • ConnectionPool now reports if it is healthy or not
    (ConnectionPool.healthy) which can be used to determine if the pool
    is able to create new connections or not
  • Pause/Resume support for streamed results has been added to the
    msnodesqlv8 driver

4.x to 5.x changes

  • Moved pool library from node-pool to tarn.js
  • ConnectionPool.pool.size deprecated, use ConnectionPool.size instead
  • ConnectionPool.pool.available deprecated, use
    ConnectionPool.available instead
  • ConnectionPool.pool.pending deprecated, use ConnectionPool.pending
    instead
  • ConnectionPool.pool.borrowed deprecated, use ConnectionPool.borrowed
    instead

3.x to 4.x changes

  • Library & tests are rewritten to ES6.
  • Connection was renamed to ConnectionPool.
  • Drivers are no longer loaded dynamically so the library is now
    compatible with Webpack. To use msnodesqlv8 driver, use const sql =
    require(‘mssql/msnodesqlv8’) syntax.
  • Every callback/resolve now returns result object only. This object
    contains recordsets (array of recordsets), recordset (first recordset
    from array of recordsets), rowsAffected (array of numbers representig
    number of affected rows by each insert/update/delete statement) and
    output (key/value collection of output parameters’ values).
  • Affected rows are now returned as an array. A separate number for
    each SQL statement. Directive multiple: true was removed.
  • Transaction and PreparedStatement internal queues was removed.
    ConnectionPool no longer emits connect and close events. Removed
    verbose and debug mode.
  • Removed support for tds and msnodesql drivers.
  • Removed support for Node versions lower than 4.
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值