ASP ADO

Connection / Recordset / Command 三个核心对象,查询、参数化、事务。

Advanced
Key PointsADO 是经典 ASP 访问数据库的标准方式:Connection 建连接,Recordset 拿结果,Command 带参数执行。

三个核心对象

ObjectRole
ADODB.Connection建立与数据库的连接,执行 SQL,管事务
ADODB.Recordset承载查询结果,可遍历、可更新
ADODB.Command带参数的 SQL,防注入

连接与查询

ASP
<%
    Dim conn, rs, connStr
    connStr = "Provider=SQLOLEDB;Data Source=localhost;Initial Catalog=app;" & _
              "User ID=appuser;Password=secret;"

    Set conn = Server.CreateObject("ADODB.Connection")
    conn.Open connStr

    Set rs = conn.Execute("SELECT id, name, email FROM users ORDER BY id")
    Do While Not rs.EOF
        Response.Write rs("id") & " — " & _
                       Server.HTMLEncode(rs("name")) & " — " & _
                       Server.HTMLEncode(rs("email")) & "<br>"
        rs.MoveNext
    Loop

    rs.Close
    Set rs = Nothing
    conn.Close
    Set conn = Nothing
%>
Output
1 — Ada — ada@example.com
2 — Bob — bob@example.com
3 — Cy — cy@example.com

conn.Execute returns a Recordset directly, fine for simple queries. Parameterisation requires a Command, the only reliable defence against injection.

参数化查询

ASP
<%
    Dim cmd, prm
    Set cmd = Server.CreateObject("ADODB.Command")
    Set cmd.ActiveConnection = conn
    cmd.CommandText = "SELECT id, name FROM users WHERE name = ? AND status = ?"
    cmd.CommandType = 1                                  ' 1 = adCmdText

    cmd.Parameters.Append cmd.CreateParameter("name", 200, 1, 100, Request.Form("name"))
    cmd.Parameters.Append cmd.CreateParameter("status", 3, 1, , 1)

    Set rs = cmd.Execute
%>
ParamMeaning
name参数名
200adVarWChar(宽字符串)
1adParamInput 输入
100最大字符数
值实际传的值

With parameters the input is always a value, never SQL. Passing ' OR '1'='1 simply matches a user with that literal name and returns nothing.

ASP
<%-- 危险:拼接 --%>
sql = "SELECT * FROM users WHERE name = '" & Request.Form("name") & "'"
<%-- 输入 ' OR '1'='1 后变成:WHERE name = '' OR '1'='1'  → 返回全表 --%>

事务

ASP
<%
    conn.BeginTrans
    On Error Resume Next

    conn.Execute "UPDATE accounts SET balance = balance - 100 WHERE id = 1"
    If Err.Number = 0 Then
        conn.Execute "UPDATE accounts SET balance = balance + 100 WHERE id = 2"
    End If

    If Err.Number <> 0 Then
        conn.RollbackTrans
        Response.Write "转账失败:" & Err.Description
        Err.Clear
    Else
        conn.CommitTrans
        Response.Write "转账成功"
    End If

    On Error GoTo 0
%>
Output
转账成功

BeginTrans / CommitTrans / RollbackTrans guarantee all-or-nothing. Without a transaction, a successful debit plus a failed credit makes money vanish.

连接字符串

ASP
<%
    ' SQL Server(推荐用新版驱动)
    "Provider=MSOLEDBSQL;Server=localhost;Database=app;UID=app;PWD=secret;"

    ' Access(.mdb / .accdb)
    "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Server.MapPath("/data/app.mdb")
    "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & Server.MapPath("/data/app.accdb")

    ' MySQL(需装 ODBC 驱动)
    "Driver={MySQL ODBC 8.0 Driver};Server=localhost;Database=app;User=app;Password=secret;"
%>

An Access file inside the web root can be downloaded by anyone — the whole database leaks. Keep it outside the root or block the extension in IIS request filtering.

Connection strings contain passwords and must never live in a downloadable or includable file. Keep conn.asp outside the web root, or initialise it into Application from Global.asa.

Recordset 的常用操作

ASP
<%
    Response.Write "字段数:" & rs.Fields.Count & "<br>"
    Response.Write "记录数:" & rs.RecordCount & "<br>"       ' 需游标支持,否则为 -1

    Dim fld
    For Each fld In rs.Fields
        Response.Write fld.Name & " (" & fld.Type & ")<br>"
    Next

    rs.MoveFirst
    rs.MoveLast
    rs.Move 2
%>

RecordCount returns -1 with the default forward-only cursor. To get a real count, open with CursorType = 3 (static) or issue a separate SELECT COUNT(*).

分页

ASP
<%
    Dim page, size, offset, sql
    page = CLng(Request("page") & "")
    If page < 1 Then page = 1
    size = 20
    offset = (page - 1) * size

    ' SQL Server 2012+ 的写法
    sql = "SELECT id, name FROM users ORDER BY id " & _
          "OFFSET " & offset & " ROWS FETCH NEXT " & size & " ROWS ONLY"
%>

OFFSET ... FETCH requires SQL Server 2012+. Older versions need a ROW_NUMBER() subquery. Even numeric paging parameters must be cast with CLng and range-checked, or they can carry injection.

Friends & Partners