【Scala】Scala ~ JDBC / DB接続 ~

■ はじめに

SparkからSnowflakeへの接続について考える
https://dk521123.hatenablog.com/entry/2023/03/19/013833

で、JDBCでもSnowflakeにアクセスすることに触れたが
今回は、ScalaでJDBCドライバからDBにアクセスすることについて触れる

目次

【1】JDBCドライバ取得
 1)PostgreSQL
 2)Snowflake
【2】JDBC ドライバー
 1)JDBC ドライバークラス
 2)JDBC ドライバー接続文字列
【3】API
 1)PostgreSQL
 2)Snowflake
【4】サンプル
 1)PostgreSQL

【1】JDBCドライバ取得

1)PostgreSQL

libraryDependencies ++= Seq(
  "org.postgresql" % "postgresql" % "42.6.0",

https://mvnrepository.com/artifact/org.postgresql/postgresql

2)Snowflake

libraryDependencies ++= Seq(
  "net.snowflake" % "snowflake-jdbc" % "3.13.28",

https://mvnrepository.com/artifact/net.snowflake/snowflake-jdbc
https://docs.snowflake.com/ja/user-guide/jdbc-download#integrating-the-driver-into-a-maven-project

【2】JDBC ドライバー

1)JDBC ドライバークラス

[1] PostgreSQL

Class.forName("org.postgresql.Driver")

[2] Snowflake

Class.forName("net.snowflake.client.jdbc.SnowflakeDriver")

https://docs.snowflake.com/ja/user-guide/jdbc-configure#jdbc-driver-class
https://docs.snowflake.com/ja/user-guide/jdbc-api#object-driver

2)JDBC ドライバー接続文字列

[1] PostgreSQL

// jdbc:postgresql://<host>:<port>/<db_name>?<connection_params>
val connectionURL ="jdbc:postgresql://localhost:5432/sample_db"

[2] Snowflake

// Syntax
// jdbc:snowflake://<account_identifier>.snowflakecomputing.com/?<connection_params>
val connectionURL = "jdbc:snowflake://myorganization-myaccount.snowflakecomputing.com/?query_tag='folder%3Dfolder1%20folder2%26'

https://docs.snowflake.com/ja/user-guide/jdbc-configure#jdbc-driver-connection-string

【3】API

1)PostgreSQL

https://www.postgresql.jp/document/7.4/html/jdbc.html

2)Snowflake

* メソッドの中には、Snowflake独自の動きをするメソッドも
 ちらほらあるので使う前に確認しておいた方がよさそう

オブジェクト: Statement
https://docs.snowflake.com/ja/user-guide/jdbc-api#object-statement
オブジェクト: PreparedStatement
https://docs.snowflake.com/ja/user-guide/jdbc-api#object-preparedstatement

【4】サンプル

1)PostgreSQL

例1:SELECT文

import java.sql.DriverManager
import java.sql.Connection

object  Hello {
  def main(args: Array[String]) {
    val dbUrl = "jdbc:postgresql://localhost:5432/sample_db"
    val dbUser = "postgres"
    val dbPassword = "password"

    var dbConnector: Connection = null
    Class.forName("org.postgresql.Driver")
    try {
      dbConnector = DriverManager.getConnection(dbUrl, dbUser, dbPassword)
      val sql = "SELECT user_id, user_name, created_at FROM users LIMIT ?"
      val limit = 5
      val sqlStatement = dbConnector.prepareStatement(sql)
      sqlStatement.setInt(1, limit)
      val resultSet = sqlStatement.executeQuery()
      var index = 0
      while (resultSet.next()) {
        println(s"*[${index}]******************")
        println("user_id: " + resultSet.getInt(1))
        println("user_name: " + resultSet.getString("user_name"))
        println("created_at: " + resultSet.getTimestamp("created_at"))
        println("*******************")
        index = index + 1
      }
      resultSet.close()
      sqlStatement.close()
    } finally {
      if (dbConnector != null) {
        dbConnector.close()
      }
    }
    println("Done...")
  }
}

サンプルデータ

CREATE TABLE IF NOT EXISTS "users" (
    "user_id" INTEGER NOT NULL,
    "user_name" VARCHAR(50) NOT NULL,
    "created_at" TIMESTAMP NULL DEFAULT 'CURRENT_TIMESTAMP',
    PRIMARY KEY ("user_id")
);

INSERT INTO "users" ("user_id", "user_name", "created_at") VALUES
    (1, 'Mike', '2019-12-19 21:50:21.3885'),
    (2, 'Tom', '2019-12-19 21:50:21.3885'),
    (3, 'Sam', '2019-12-19 21:50:21.3885'),
    (4, 'Kevin', '2019-12-19 21:50:27.483248'),
    (5, 'Smith', '2019-12-19 21:50:27.484514'),
    (6, 'Ken', '2019-12-19 21:50:27.484514'),
    (10, 'Sam', '2020-08-26 22:39:55.175736'),
    (12, 'Naomi', '2020-08-26 22:39:55.175736'),
    (20, 'Tim', '2021-08-02 16:39:55.175736'),
    (30, 'kevin', '2021-08-02 16:40:55.175736');

例2:複数SQL文実行 / addBatch

import java.sql.DriverManager
import java.sql.Connection

object  Hello {
  def main(args: Array[String]) {
    val dbUrl = "jdbc:postgresql://localhost:5432/sample_db"
    val dbUser = "postgres"
    val dbPassword = "password"

    var dbConnector: Connection = null
    Class.forName("org.postgresql.Driver")
    try {
      dbConnector = DriverManager.getConnection(dbUrl, dbUser, dbPassword)
      val statement = dbConnector.createStatement()
      statement.addBatch("/*ex1*/ DROP TABLE IF EXISTS test;")
      statement.addBatch("/*ex2*/ CREATE TABLE test(id integer, name varchar);")
      statement.addBatch("/*ex3*/ INSERT INTO test VALUES(1, 'Mike');")
      statement.addBatch("/*ex4*/ INSERT INTO test VALUES(2, 'Smith');")
      val results = statement.executeBatch()
      println(s"Result ${results.length}")
      statement.close()
    } finally {
      if (dbConnector != null) {
        dbConnector.close()
      }
    }
    println("Done...")
  }
}

例3:複数SQL文実行 / execute

import java.sql.DriverManager
import java.sql.Connection

object  Hello {
  def main(args: Array[String]) {
    val dbUrl = "jdbc:postgresql://localhost:5432/sample_db"
    val dbUser = "postgres"
    val dbPassword = "password"

    var dbConnector: Connection = null
    Class.forName("org.postgresql.Driver")
    try {
      dbConnector = DriverManager.getConnection(dbUrl, dbUser, dbPassword)
      val statement = dbConnector.createStatement()
      val param11 = 1
      val param12 = "Mike"
      val param21 = 2
      val param22 = "Kevin"
      val sql = s"""
      -- ex1
      DROP TABLE IF EXISTS test2;
      -- ex2
      CREATE TABLE test2 (
        id integer,
        name varchar
      );
      -- ex3
      INSERT INTO test2 VALUES(${param11}, '${param12}');
      INSERT INTO test2 VALUES(${param21}, '${param22}');
      INSERT INTO test2 VALUES(3, 'Tommy');
      """
      val isOk = statement.execute(sql)
      println(s"Result ${isOk}")
      statement.close()
    } finally {
      if (dbConnector != null) {
        dbConnector.close()
      }
    }
    println("Done...")
  }
}

関連記事

Scala ~ 環境構築編 ~
https://dk521123.hatenablog.com/entry/2023/03/10/193805
Scala ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2023/03/12/184331
Scala ~ 基本編 / 繰り返し ~
https://dk521123.hatenablog.com/entry/2023/01/24/000000
Scala ~ 基本編 / Option型 ~
https://dk521123.hatenablog.com/entry/2023/03/09/000000
Scala ~ 基本編 / メソッド ~
https://dk521123.hatenablog.com/entry/2023/03/03/000000
Scala ~ 基本編 / クラス ~
https://dk521123.hatenablog.com/entry/2023/03/14/000857
Scala ~ 基本編 / コレクション ~
https://dk521123.hatenablog.com/entry/2023/03/13/000345
Scala ~ 基本編 / 日付・日時 ~
https://dk521123.hatenablog.com/entry/2023/03/08/000000
Scala ~ 基本編 / 正規表現
https://dk521123.hatenablog.com/entry/2023/03/18/034704
Scala ~ 基本編 / ジェネリック
https://dk521123.hatenablog.com/entry/2023/03/21/003817
ScalaEnum
https://dk521123.hatenablog.com/entry/2023/01/05/000000
Scala ~ ファイル名・パスの扱い ~
https://dk521123.hatenablog.com/entry/2023/03/11/000000
Scala ~ ファイルハンドリング ~
https://dk521123.hatenablog.com/entry/2023/01/03/000000
ScalaYAML
https://dk521123.hatenablog.com/entry/2023/03/16/012034
ScalaAWS SDK
https://dk521123.hatenablog.com/entry/2023/03/24/211033
SBT ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2023/03/22/000000
SBT ~ 基本編 / build.sbt ~
https://dk521123.hatenablog.com/entry/2023/01/27/000000
SBT ~ 基本編 / sbtコマンド ~
https://dk521123.hatenablog.com/entry/2023/01/26/000000
SBT ~ sbtプラグイン
https://dk521123.hatenablog.com/entry/2023/01/25/000000
JavaでEmail ~ JavaMail / Text ~
https://dk521123.hatenablog.com/entry/2016/07/16/222422
JavaでEmail ~ JavaMail / 添付ファイル ~
https://dk521123.hatenablog.com/entry/2016/07/17/023459
JavaでEmail ~ SMTP認証 ~
https://dk521123.hatenablog.com/entry/2016/11/07/215251
JavaでEmail ~ SMTP認証 / DIGEST-MD5
https://dk521123.hatenablog.com/entry/2016/12/07/222229
JavaでEmail ~ JavaMail / TLS
https://dk521123.hatenablog.com/entry/2017/05/03/163219
JavaでEmail ~ JavaMail / Return-Path・Errors-To ~
https://dk521123.hatenablog.com/entry/2017/05/07/000344
Amazon SES ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2017/04/28/234103
Amazon S3 ~ Boto3編 ~
https://dk521123.hatenablog.com/entry/2019/10/21/230004
Amazon S3 ~ Boto3でファイル存在チェック ~
https://dk521123.hatenablog.com/entry/2022/02/26/182526
AWS Glue ~ Scalaでの実装 ~
https://dk521123.hatenablog.com/entry/2023/03/17/000000
AWS Glue ~ ローカル環境を作成する / Glue v3.0版 ~
https://dk521123.hatenablog.com/entry/2022/01/31/165650
LocalStack ~ ローカルで疑似AWSを作成する ~
https://dk521123.hatenablog.com/entry/2019/12/14/010524
LocalStack ~ ローカルで疑似Lambda/S3/DynamoDBを作成する ~
https://dk521123.hatenablog.com/entry/2019/12/16/231149
SparkからSnowflakeへの接続について考える
https://dk521123.hatenablog.com/entry/2023/03/19/013833