分享方式:


適用於 Go 的 Databricks SQL 驅動程式

適用於 Go 的 Databricks SQL 驅動程式是一個 Go 程式庫,可讓您使用 Go 程式碼,在 Azure Databricks 計算資源上執行 SQL 命令。 本文補充適用於 Go 的 Databricks SQL 驅動程式讀我檔案API 參考範例

需求

開始使用適用於 Go 的 Databricks SQL 驅動程式

  1. 在已安裝 Go 1.20 或更新版本的開發機器上,以及已建立現有的 Go 程式碼專案上,執行 go mod init 命令來建立 go.mod 檔案,以追蹤您的 Go 程式碼相依性,例如:

    go mod init sample
    
  2. 透過執行 go mod edit -require 命令以相依於適用於 Go 的 Databricks SQL 驅動程式套件,並將 v1.5.2 取代為最新版本的適用於 Go 的 Databricks SQL 驅動程式套件,如版本中所列:

    go mod edit -require github.com/databricks/databricks-sql-go@v1.5.2
    

    您的 go.mod 檔案看起來應該如下所示:

    module sample
    
    go 1.20
    
    require github.com/databricks/databricks-sql-go v1.5.2
    
  3. 在您的專案中,建立可匯入適用於 Go 的 Databricks SQL 驅動程式的 Go 程式碼檔案。 下列範例在名為 main.go 且具有下列內容的檔案中,列出 Azure Databricks 工作區中的所有叢集:

    package main
    
    import (
      "database/sql"
      "os"
      _ "github.com/databricks/databricks-sql-go"
    )
    
    func main() {
      dsn := os.Getenv("DATABRICKS_DSN")
    
      if dsn == "" {
        panic("No connection string found. " +
         "Set the DATABRICKS_DSN environment variable, and try again.")
      }
    
      db, err := sql.Open("databricks", dsn)
      if err != nil {
        panic(err)
      }
      defer db.Close()
    
      if err := db.Ping(); err != nil {
        panic(err)
      }
    }
    
  4. 執行 go mod tidy 命令以新增任何遺漏的模組相依性:

    go mod tidy
    

    注意

    如果您收到錯誤 go: warning: "all" matched no packages,表示您忘記了新增可匯入適用於 Go 的 Databricks SQL 驅動程式的 Go 程式碼檔案。

  5. 執行 go mod vendor 命令,在 main 模組中建立支援建置和測試套件所需的所有套件複本:

    go mod vendor
    
  6. 視需要修改您的程式碼,以設定 Azure Databricks 驗證DATABRICKS_DSN 環境變數。 另請參閱使用 DSN 連接字串進行連線

  7. 透過執行 go run 命令,來執行 Go 程式碼檔案,假定檔案名為 main.go

    go run main.go
    
  8. 如果未傳回任何錯誤,表示您已成功使用 Azure Databricks 工作區驗證適用於 Go 的 Databricks SQL 驅動程式,並連線到該工作區中執行中的 Azure Databricks 叢集或 SQL 倉儲。

使用 DSN 連接字串來連線

若要存取叢集和 SQL 倉儲,請使用 sql.Open() 透過資料來源名稱 (DSN) 連接字串建立資料庫控制代碼。 此程式碼範例會從名為 DATABRICKS_DSN 的環境變數中,擷取 DSN 連接字串:

package main

import (
  "database/sql"
  "os"
  _ "github.com/databricks/databricks-sql-go"
)

func main() {
  dsn := os.Getenv("DATABRICKS_DSN")

  if dsn == "" {
    panic("No connection string found. " +
          "Set the DATABRICKS_DSN environment variable, and try again.")
  }

  db, err := sql.Open("databricks", dsn)
  if err != nil {
    panic(err)
  }
  defer db.Close()

  if err := db.Ping(); err != nil {
    panic(err)
  }
}

若要以正確的格式指定 DSN 連接字串,請參閱驗證中的 DSN 連接字串範例。 例如,針對 Azure Databricks 個人存取權杖驗證,請使用下列語法,其中:

  • <personal-access-token> 是來自需求的 Azure Databricks 個人存取權杖。
  • <server-hostname> 是來自需求的 [伺服器主機名稱] 值。
  • <port-number>是來自需求的 [連接埠] 值,通常是 443
  • <http-path> 是來自需求的 [HTTP 路徑] 值。
  • <paramX=valueX> 是本文稍後所列的一或多個選擇性參數
token:<personal-access-token>@<server-hostname>:<port-number>/<http-path>?<param1=value1>&<param2=value2>

例如,針對叢集:

token:dapi12345678901234567890123456789012@adb-1234567890123456.7.azuredatabricks.net:443/sql/protocolv1/o/1234567890123456/1234-567890-abcdefgh

例如,針對 SQL 倉儲:

token:dapi12345678901234567890123456789012@adb-1234567890123456.7.azuredatabricks.net:443/sql/1.0/endpoints/a1b234c5678901d2

注意

作為安全性最佳做法,您不應該將此 DSN 連接字串硬式編碼到您的 Go 程式碼中。 相反地,您應從安全的位置擷取這些 DSN 連接字串。 例如,本文稍早的程式碼範例使用環境變數。

選擇性參數

  • 支援的選擇性連線參數可以在 <param=value> 中指定。 一些較常用項目包括:
    • catalog:在工作階段中設定初始目錄名稱。
    • schema:在工作階段中設定初始結構描述名稱。
    • maxRows:設定每個要求擷取的資料列數目上限。 預設值為 10000
    • timeout:新增伺服器查詢執行的逾時 (以秒為單位)。 預設值沒有時間限制。
    • userAgentEntry:用於識別合作夥伴。 如需詳細資訊,請參閱您的合作夥伴的文件。
  • 支援的選擇性工作階段參數可以在 param=value 中指定。 一些較常用項目包括:
    • ansi_mode:布林值字串。 true 表示符合 ANSI SQL 規格所指定規則的工作階段陳述式。 系統預設值為 false。
    • timezone:字串,例如 America/Los_Angeles。 設定工作階段時區。 系統預設值為 UTC。

例如,針對 SQL 倉儲:

token:dapi12345678901234567890123456789012@adb-1234567890123456.7.azuredatabricks.net:443/sql/1.0/endpoints/a1b234c5678901d2?catalog=hive_metastore&schema=example&maxRows=100&timeout=60&timezone=America/Sao_Paulo&ansi_mode=true

連接 NewConnector 函式

或者,使用 sql.OpenDB(),透過使用 dbsql.NewConnector() 建立的新連接器物件,以建立 資料庫控制代碼 (使用新的連接器物件連線到 Azure Databricks 叢集和 SQL 倉儲需要,適用於 Go 的 Databricks SQL 驅動程式的 v1.0.0 或更高版本)。 例如:

package main

import (
  "database/sql"
  "os"
  dbsql "github.com/databricks/databricks-sql-go"
)

func main() {
  connector, err := dbsql.NewConnector(
    dbsql.WithAccessToken(os.Getenv("DATABRICKS_ACCESS_TOKEN")),
    dbsql.WithServerHostname(os.Getenv("DATABRICKS_HOST")),
    dbsql.WithPort(443),
    dbsql.WithHTTPPath(os.Getenv("DATABRICKS_HTTP_PATH")),
  )
  if err != nil {
    panic(err)
  }

  db := sql.OpenDB(connector)
  defer db.Close()

  if err := db.Ping(); err != nil {
    panic(err)
  }
}

若要指定正確的 NewConnector 設定集,請參閱驗證中的範例。

注意

作為安全性最佳做法,您不應該將設定 NewConnector 硬式編碼到 Go 程式碼中。 相反地,您應從安全的位置擷取這些值。 例如,上述程式碼會使用環境變數。

一些較為常用的功能選項包括:

  • WithAccessToken(<access-token>):來自需求的 Azure Databricks 個人存取權杖。 必要的 string
  • WithServerHostname(<server-hostname>):來自需求的 [伺服器主機名稱] 值。 必要的 string
  • WithPort(<port>):伺服器的連接埠號碼,通常是 443。 必要的 int
  • WithHTTPPath(<http-path>):來自需求的 [HTTP 路徑] 值。 必要的 string
  • WithInitialNamespace(<catalog>, <schema>):工作階段中的目錄和結構描述名稱。 選擇性 string, string
  • WithMaxRows(<max-rows>):每個要求擷取的資料列數目上限。 預設值為 10000. 選擇性 int
  • WithSessionParams(<params-map>):工作階段參數,包括「timezone」和「ansi_mode」。 選擇性 map[string]string
  • WithTimeout(<timeout>). 伺服器查詢執行逾時 (以 time.Duration 為單位)。 預設值沒有時間限制。 選擇性。
  • WithUserAgentEntry(<isv-name-plus-product-name>). 用於識別合作夥伴。 如需詳細資訊,請參閱您的合作夥伴的文件。 選擇性 string

例如:

connector, err := dbsql.NewConnector(
  dbsql.WithAccessToken(os.Getenv("DATABRICKS_ACCESS_TOKEN")),
  dbsql.WithServerHostname(os.Getenv("DATABRICKS_HOST")),
  dbsql.WithPort(443),
  dbsql.WithHTTPPath(os.Getenv("DATABRICKS_HTTP_PATH")),
  dbsql.WithInitialNamespace("samples", "nyctaxi"),
  dbsql.WithMaxRows(100),
  dbsql.SessionParams(map[string]string{"timezone": "America/Sao_Paulo", "ansi_mode": "true"}),
  dbsql.WithTimeout(time.Minute),
  dbsql.WithUserAgentEntry("example-user"),
)

驗證

適用於 Go 的 Databricks SQL 驅動程式支援下列 Azure Databricks 驗證類型:

適用於 Go 的 Databricks SQL 驅動程式尚不支援下列 Azure Databricks 驗證類型:

Databricks 個人存取權杖驗證

若要搭配 Azure Databricks 個人存取權杖驗證使用適用於 Go 的 Databricks SQL 驅動程式,您必須首先建立 Azure Databricks 個人存取權杖,如下所示:

  1. 在 Azure Databricks 工作區中,按一下頂端列中的 Azure Databricks 使用者名稱,然後從下拉式清單中選取 [設定]
  2. 按一下 [開發人員]
  3. 在 [存取權杖] 旁,按一下 [管理]
  4. 按一下 產生新權杖
  5. (選擇性) 輸入可協助您之後識別此權杖的註解,並變更權杖的預設存留期 90 天。 若要建立沒有存留期的權杖 (不建議),請將 [存留期 (天)] 方塊留空 (空白)。
  6. 按一下 產生
  7. 將顯示的權杖複製到安全位置,然後選取 [完成]

注意

請務必將複製的權杖儲存在安全位置。 請勿與其他人共用複製的權杖。 如果您遺失複製的權杖,就無法重新產生完全相同的權杖。 相反地,您必須重複此程序來建立新的權杖。 如果您遺失複製的權杖,或您認為權杖已遭入侵,Databricks 強烈建議您按一下 [存取權杖] 頁面上權杖旁邊的垃圾桶 (撤銷) 圖示,立即從工作區中刪除該權杖。

注意:如果您無法在工作區中建立或使用 PAT,這可能是因為您的工作區系統管理員已停用權杖,或未授與您建立或使用權杖的權限。 請諮詢您的工作區系統管理員或參閱下列主題:

若要使用 DSN 連接字串來驗證適用於 Go 的 Databricks SQL 驅動程式,以及使用 DSN 連接字串連線中的程式碼範例,請使用下列 DSN 連接字串語法,其中:

  • <personal-access-token> 是來自需求的 Azure Databricks 個人存取權杖。
  • <server-hostname> 是來自需求的 [伺服器主機名稱] 值。
  • <port-number>是來自需求的 [連接埠] 值,通常是 443
  • <http-path> 是來自需求的 [HTTP 路徑] 值。

您也可以附加本文先前所列的一或多個選擇性參數

token:<personal-access-token>@<server-hostname>:<port-number>/<http-path>

若要使用 NewConnector 函式驗證適用於 Go 的 Databricks SQL 驅動程式,請使用下列程式碼片段和使用 NewConnector 函式連接中的程式碼範例,假設您已設定下列環境變數:

  • DATABRICKS_SERVER_HOSTNAME 設定為叢集或 SQL 倉儲的 [伺服器主機名稱] 值。
  • DATABRICKS_HTTP_PATH,設定為叢集或 SQL 倉儲的 HTTP 路徑 值。
  • DATABRICKS_TOKEN,設定為 Azure Databricks 個人存取權杖。

若要設定環境變數,請參閱您的作業系統文件。

connector, err := dbsql.NewConnector(
  dbsql.WithServerHostname(os.Getenv("DATABRICKS_SERVER_HOSTNAME")),
  dbsql.WithHTTPPath(os.Getenv("DATABRICKS_HTTP_PATH")),
  dbsql.WithPort(443),
  dbsql.WithAccessToken(os.Getenv("DATABRICKS_TOKEN")),
)

Microsoft Entra ID 權杖驗證

適用於 Go 的 Databricks SQL 驅動程式支援 Azure Databricks 使用者或 Microsoft Entra ID 服務主體的 Microsoft Entra ID 權杖。

若要建立 Microsoft Entra ID 存取權杖,請按照下列步驟操作:

  • 針對 Azure Databricks 使用者,您可使用 Azure CLI。 請參閱使用 Azure CLI 取得使用者的 Microsoft Entra ID 權杖

    Microsoft Entra ID 權杖的預設存留期約為 1 小時。 若要建立新的 Microsoft Entra ID 權杖,請重複此程序。

    若要使用 DSN 連接字串來驗證適用於 Go 的 Databricks SQL 驅動程式,以及使用 DSN 連接字串連線中的程式碼範例,請使用下列 DSN 連接字串語法,其中:

    • <microsoft-entra-id-token> 是您的 Microsoft Entra ID 權杖。
    • <server-hostname> 是來自需求的 [伺服器主機名稱] 值。
    • <port-number>是來自需求的 [連接埠] 值,通常是 443
    • <http-path> 是來自需求的 [HTTP 路徑] 值。

    您也可以附加本文先前所列的一或多個選擇性參數

    token:<microsoft-entra-id-token>@<server-hostname>:<port-number>/<http-path>
    

    若要使用 NewConnector 函式驗證適用於 Go 的 Databricks SQL 驅動程式,請使用下列程式碼片段和使用 NewConnector 函式連接中的程式碼範例,假設您已設定下列環境變數:

    • DATABRICKS_SERVER_HOSTNAME 設定為叢集或 SQL 倉儲的 [伺服器主機名稱] 值。
    • DATABRICKS_HTTP_PATH,設定為叢集或 SQL 倉儲的 HTTP 路徑 值。
    • DATABRICKS_TOKEN,設定為 Microsoft Entra ID 權杖。

    若要設定環境變數,請參閱您的作業系統文件。

    connector, err := dbsql.NewConnector(
      dbsql.WithServerHostname(os.Getenv("DATABRICKS_SERVER_HOSTNAME")),
      dbsql.WithHTTPPath(os.Getenv("DATABRICKS_HTTP_PATH")),
      dbsql.WithPort(443),
      dbsql.WithAccessToken(os.Getenv("DATABRICKS_TOKEN")),
    )
    

OAuth 使用者對機器 (U2M) 驗證

適用於 Go 的 Databricks SQL 驅動程式 1.5.0 版和更新版本支援 OAuth 使用者對機器 (U2M) 驗證

若要藉助 DSN 連接字串來使用適用於 Go 的 Databricks SQL 驅動程式,以及使用 DSN 連接字串連線中的程式碼範例,請使用下列 DSN 連接字串語法,其中:

  • <server-hostname> 是來自需求的 [伺服器主機名稱] 值。
  • <port-number>是來自需求的 [連接埠] 值,通常是 443
  • <http-path> 是來自需求的 [HTTP 路徑] 值。

您也可以附加本文先前所列的一或多個選擇性參數

<server-hostname>:<port-number>/<http-path>?authType=OauthU2M

若要使用 NewConnector 函式驗證適用於 Go 的 Databricks SQL 驅動程式,必須先將下列內容新增至 import 宣告:

"github.com/databricks/databricks-sql-go/auth/oauth/u2m"

然後使用下列程式碼片段和使用 NewConnector 函式連接中的程式碼範例,假設您已設定下列環境變數:

  • DATABRICKS_SERVER_HOSTNAME 設定為叢集或 SQL 倉儲的 [伺服器主機名稱] 值。
  • DATABRICKS_HTTP_PATH,設定為叢集或 SQL 倉儲的 HTTP 路徑 值。

若要設定環境變數,請參閱您的作業系統文件。

authenticator, err := u2m.NewAuthenticator(os.Getenv("DATABRICKS_SERVER_HOSTNAME"), 1*time.Minute)
if err != nil {
  panic(err)
}

connector, err := dbsql.NewConnector(
  dbsql.WithServerHostname(os.Getenv("DATABRICKS_SERVER_HOSTNAME")),
  dbsql.WithHTTPPath(os.Getenv("DATABRICKS_HTTP_PATH")),
  dbsql.WithPort(443),
  dbsql.WithAuthenticator(authenticator),
)

OAuth 機器對機器 (M2M) 驗證

適用於 Go 的 Databricks SQL 驅動程式 1.5.2 版和更新版本支援 OAuth 機器對機器 (M2M) 驗證

若要使用 OAuth M2M 驗證來驗證適用於 Go 的 Databricks SQL 驅動程式,您必須執行下列動作:

  1. 在 Azure Databricks 工作區中建立 Azure Databricks 服務主體,並為該服務主體建立 OAuth 祕密。

    若要建立服務主體及其 OAuth 祕密,請參閱使用 OAuth (OAuth M2M) 透過服務主體對 Azure Databricks 的存取進行驗證。 記下服務主體的 [UUID] 或 [應用程式 ID] 值,以及服務主體 OAuth 祕密的 [祕密]值。

  2. 為服務主體提供叢集或倉儲的存取權。

    若要授與服務主體對叢集或倉儲的存取權,請參閱計算權限管理 SQL 倉儲

若要使用 DSN 連接字串來驗證適用於 Go 的 Databricks SQL 驅動程式,以及使用 DSN 連接字串連線中的程式碼範例,請使用下列 DSN 連接字串語法,其中:

  • <server-hostname> 是來自需求的 [伺服器主機名稱] 值。
  • <port-number>是來自需求的 [連接埠] 值,通常是 443
  • <http-path> 是來自需求的 [HTTP 路徑] 值。
  • <client-id> 為服務主體的 [UUID] 或 [應用程式 ID] 值。
  • <client-secret> 為 Azure Databricks 服務主體的 OAuth [祕密] 值。

您也可以附加本文先前所列的一或多個選擇性參數

<server-hostname>:<port-number>/<http-path>?authType=OAuthM2M&clientID=<client-id>&clientSecret=<client-secret>

若要使用 NewConnector 函式驗證適用於 Go 的 Databricks SQL 驅動程式,必須先將下列內容新增至 import 宣告:

"github.com/databricks/databricks-sql-go/auth/oauth/m2m"

然後使用下列程式碼片段和使用 NewConnector 函式連接中的程式碼範例,假設您已設定下列環境變數:

  • DATABRICKS_SERVER_HOSTNAME 設定為叢集或 SQL 倉儲的 [伺服器主機名稱] 值。
  • DATABRICKS_HTTP_PATH,設定為叢集或 SQL 倉儲的 HTTP 路徑 值。
  • DATABRICKS_CLIENT_ID,設定為服務主體的 [UUID] 或 [應用程式 ID] 值。
  • DATABRICKS_CLIENT_SECRET,設定為 Azure Databricks 服務主體的 OAuth [祕密] 值。

若要設定環境變數,請參閱您的作業系統文件。

authenticator := m2m.NewAuthenticator(
  os.Getenv("DATABRICKS_CLIENT_ID"),
  os.Getenv("DATABRICKS_CLIENT_SECRET"),
  os.Getenv("DATABRICKS_SERVER_HOSTNAME"),
)

connector, err := dbsql.NewConnector(
  dbsql.WithServerHostname(os.Getenv("DATABRICKS_SERVER_HOSTNAME")),
  dbsql.WithHTTPPath(os.Getenv("DATABRICKS_HTTP_PATH")),
  dbsql.WithPort(443),
  dbsql.WithAuthenticator(authenticator),
)

查詢資料

下列程式碼範例示範如何呼叫適用於 Go 的 Databricks SQL 驅動程式,在 Azure Databricks 計算資源上執行基本 SQL 查詢。 此命令會從 samples 目錄的 nyctaxi 結構描述中的 trips 資料表傳回前兩個資料列。

此程式碼範例會從名為 DATABRICKS_DSN 的環境變數中,擷取 DSN 連接字串

package main

import (
  "database/sql"
  "fmt"
  "os"
  "time"

  _ "github.com/databricks/databricks-sql-go"
)

func main() {
  dsn := os.Getenv("DATABRICKS_DSN")

  if dsn == "" {
    panic("No connection string found." +
          "Set the DATABRICKS_DSN environment variable, and try again.")
  }

  db, err := sql.Open("databricks", dsn)
  if err != nil {
    panic(err)
  }

  defer db.Close()

  var (
    tpep_pickup_datetime  time.Time
    tpep_dropoff_datetime time.Time
    trip_distance         float64
    fare_amount           float64
    pickup_zip            int
    dropoff_zip           int
  )

  rows, err := db.Query("SELECT * FROM samples.nyctaxi.trips LIMIT 2")
  if err != nil {
    panic(err)
  }

  defer rows.Close()

  fmt.Print("tpep_pickup_datetime,",
    "tpep_dropoff_datetime,",
    "trip_distance,",
    "fare_amount,",
    "pickup_zip,",
    "dropoff_zip\n")

  for rows.Next() {
    err := rows.Scan(&tpep_pickup_datetime,
      &tpep_dropoff_datetime,
      &trip_distance,
      &fare_amount,
      &pickup_zip,
      &dropoff_zip)
    if err != nil {
      panic(err)
    }

    fmt.Print(tpep_pickup_datetime, ",",
      tpep_dropoff_datetime, ",",
      trip_distance, ",",
      fare_amount, ",",
      pickup_zip, ",",
      dropoff_zip, "\n")
  }

  err = rows.Err()
  if err != nil {
    panic(err)
  }
}

管理 Unity 目錄磁碟區中的檔案

Databricks SQL 驅動程式可讓您將本機檔案寫入 Unity 目錄磁碟區、從磁碟區下載檔案,以及從磁碟區刪除檔案,如下列範例所示:

package main

import (
  "context"
  "database/sql"
  "os"

  _ "github.com/databricks/databricks-sql-go"
  "github.com/databricks/databricks-sql-go/driverctx"
)

func main() {
  dsn := os.Getenv("DATABRICKS_DSN")

  if dsn == "" {
    panic("No connection string found." +
      "Set the DATABRICKS_DSN environment variable, and try again.")
  }

  db, err := sql.Open("databricks", dsn)
  if err != nil {
    panic(err)
  }
  defer db.Close()

  // For writing local files to volumes and downloading files from volumes,
  // you must first specify the path to the local folder that contains the
  // files to be written or downloaded.
  // For multiple folders, add their paths to the following string array.
  // For deleting files in volumes, this string array is ignored but must
  // still be provided, so in that case its value can be set for example
  // to an empty string.
  ctx := driverctx.NewContextWithStagingInfo(
    context.Background(),
    []string{"/tmp/"},
  )

  // Write a local file to the path in the specified volume.
  // Specify OVERWRITE to overwrite any existing file in that path.
  db.ExecContext(ctx, "PUT '/tmp/my-data.csv' INTO '/Volumes/main/default/my-volume/my-data.csv' OVERWRITE")

  // Download a file from the path in the specified volume.
  db.ExecContext(ctx, "GET '/Volumes/main/default/my-volume/my-data.csv' TO '/tmp/my-downloaded-data.csv'")

  // Delete a file from the path in the specified volume.
  db.ExecContext(ctx, "REMOVE '/Volumes/main/default/my-volume/my-data.csv'")

  db.Close()
}

記錄

使用 github.com/databricks/databricks-sql-go/logger 來記錄適用於 Go 的 Databricks SQL 驅動程式發出的訊息。 下列程式碼範例會使用 sql.Open() 透過 DSN 連接字串建立資料庫控制代碼。 此程式碼範例會從名為 DATABRICKS_DSN 的環境變數中,擷取 DSN 連接字串。 在 debug 層級及以下發出的所有記錄訊息都會寫入 results.log 檔案。

package main

import (
  "database/sql"
  "io"
  "log"
  "os"

  _ "github.com/databricks/databricks-sql-go"
  dbsqllog "github.com/databricks/databricks-sql-go/logger"
)

func main() {
  dsn := os.Getenv("DATABRICKS_DSN")

  // Use the specified file for logging messages to.
  file, err := os.Create("results.log")
  if err != nil {
    log.Fatal(err)
  }
  defer file.Close()

  writer := io.Writer(file)

  // Log messages at the debug level and below.
  if err := dbsqllog.SetLogLevel("debug"); err != nil {
    log.Fatal(err)
  }

  // Log messages to the file.
  dbsqllog.SetLogOutput(writer)

  if dsn == "" {
    panic("Error: Cannot connect. No connection string found. " +
      "Set the DATABRICKS_DSN environment variable, and try again.")
  }

  db, err := sql.Open("databricks", dsn)
  if err != nil {
    panic(err)
  }
  defer db.Close()

  if err := db.Ping(); err != nil {
    panic(err)
  }
}

測試

若要測試程式碼,請使用 Go 測試架構,例如測試標準程式庫。 若要在不呼叫 Azure Databricks REST API 端點或變更 Azure Databricks 帳戶或工作區的狀態的情況下,在模擬條件下測試程式碼,可以使用 Go 模擬程式庫,例如 testfify

例如,假設下列名為 helpers.go 的檔案,其中包含一個 GetDBWithDSNPAT 函式,該函式傳回 Azure Databricks 工作區連線,一個 GetNYCTaxiTrips 函式,該函式使用從 trips 目錄 samples 結構描述中的 nyctaxi 資料表傳回資料,以及列印傳回資料的 PrintNYCTaxiTrips

package main

import (
  "database/sql"
  "fmt"
  "strconv"
  "time"
)

func GetDBWithDSNPAT(dsn string) (*sql.DB, error) {
  db, err := sql.Open("databricks", dsn)
  if err != nil {
    return nil, err
  }
  return db, nil
}

func GetNYCTaxiTrips(db *sql.DB, numRows int) (*sql.Rows, error) {
  rows, err := db.Query("SELECT * FROM samples.nyctaxi.trips LIMIT " + strconv.Itoa(numRows))
  if err != nil {
    return nil, err
  }
  return rows, nil
}

func PrintNYCTaxiTrips(rows *sql.Rows) {
  var (
    tpep_pickup_datetime  time.Time
    tpep_dropoff_datetime time.Time
    trip_distance         float64
    fare_amount           float64
    pickup_zip            int
    dropoff_zip           int
  )

  fmt.Print(
    "tpep_pickup_datetime,",
    "tpep_dropoff_datetime,",
    "trip_distance,",
    "fare_amount,",
    "pickup_zip,",
    "dropoff_zip\n",
  )

  for rows.Next() {
    err := rows.Scan(
      &tpep_pickup_datetime,
      &tpep_dropoff_datetime,
      &trip_distance,
      &fare_amount,
      &pickup_zip,
      &dropoff_zip,
    )
    if err != nil {
      panic(err)
    }

    fmt.Print(
      tpep_pickup_datetime, ",",
      tpep_dropoff_datetime, ",",
      trip_distance, ",",
      fare_amount, ",",
      pickup_zip, ",",
      dropoff_zip, "\n",
    )
  }

  err := rows.Err()
  if err != nil {
    panic(err)
  }
}

並指定下列名為 main.go 的檔案,該檔案會呼叫這些函式:

package main

import (
  "os"
)

func main() {
  db, err := GetDBWithDSNPAT(os.Getenv("DATABRICKS_DSN"))
  if err != nil {
    panic(err)
  }

  rows, err := GetNYCTaxiTrips(db, 2)
  if err != nil {
    panic(err)
  }

  PrintNYCTaxiTrips(rows)
}

下列名為 helpers_test.go 的檔案會測試函 GetNYCTaxiTrips 式是否傳回預期的回應。 此測試會模擬 sql.DB 物件,而不是建立與目標工作區的實際連線。 測試也會模擬一些符合實際資料中結構描述和值的資料。 測試會透過模擬連線傳回模擬的資料,然後檢查其中一個模擬資料列的值是否符合預期的值。

package main

import (
  "database/sql"
  "testing"

  "github.com/stretchr/testify/assert"
  "github.com/stretchr/testify/mock"
)

// Define an interface that contains a method with the same signature
// as the real GetNYCTaxiTrips function that you want to test.
type MockGetNYCTaxiTrips interface {
  GetNYCTaxiTrips(db *sql.DB, numRows int) (*sql.Rows, error)
}

// Define a struct that represents the receiver of the interface's method
// that you want to test.
type MockGetNYCTaxiTripsObj struct {
  mock.Mock
}

// Define the behavior of the interface's method that you want to test.
func (m *MockGetNYCTaxiTripsObj) GetNYCTaxiTrips(db *sql.DB, numRows int) (*sql.Rows, error) {
  args := m.Called(db, numRows)
  return args.Get(0).(*sql.Rows), args.Error(1)
}

func TestGetNYCTaxiTrips(t *testing.T) {
  // Instantiate the receiver.
  mockGetNYCTaxiTripsObj := new(MockGetNYCTaxiTripsObj)

  // Define how the mock function should be called and what it should return.
  // We're not concerned with whether the actual database is connected to--just
  // what is returned.
  mockGetNYCTaxiTripsObj.On("GetNYCTaxiTrips", mock.Anything, mock.AnythingOfType("int")).Return(&sql.Rows{}, nil)

  // Call the mock function that you want to test.
  rows, err := mockGetNYCTaxiTripsObj.GetNYCTaxiTrips(nil, 2)

  // Assert that the mock function was called as expected.
  mockGetNYCTaxiTripsObj.AssertExpectations(t)

  // Assert that the mock function returned what you expected.
  assert.NotNil(t, rows)
  assert.Nil(t, err)
}

因為 GetNYCTaxiTrips 函式包含 SELECT 陳述式,因此不會變更 trips 資料表的狀態,所以在此範例中絕對不需要模擬。 不過,模擬可讓您快速執行測試,而無需等待與工作區建立實際連線。 此外,模擬可讓您針對可能會變更資料表狀態的函式執行模擬測試多次,例如 INSERT INTOUPDATEDELETE FROM

其他資源