【Azure Functions】Java APIからDB(SQL Server)接続 (Win10)

事前準備

docker-composeを使ってSQL Serverをローカルで起動します。

Docker Desktop for Windows セットアップ

※すでにインストール済みであればこの手順はスキップしてください。

インストール

cinst docker-desktop -y

確認

$ docker -v
Docker version 19.03.5, build 633a0ea

$ docker-compose -v
docker-compose version 1.24.1, build 4667896b

Hyper-Vの設定

Docker for Windows を使用する場合、Hyper-Vの有効化が必要です。以下手順で有効化します。

  1. 「Win + i」で設定画面を開く
  2. アプリ > アプリと機能 > プログラムと機能 を開く
  3. Windowsの機能の有効化または無効化 を開く
  4. Hiper-V にチェックが入っていなければ、チェックして再起動する

データベース準備

前回の記事 で c:\TEST 以下にapiを作成したので、ここに docker-compose.yml を作成します。

c:\TEST\docker-compose.yml

version: '3'
services:
  db:
    image: mcr.microsoft.com/mssql/server:latest
    ports:
      - "1433:1433"
    environment:
      ACCEPT_EULA: Y
      SA_PASSWORD: test1234@password

起動

$ cd c:\TEST

$ docker-compose up -d
Starting test_db_1 ... done

$ docker ps -a
CONTAINER ID  IMAGE                                  COMMAND                  CREATED         STATUS         PORTS                   NAMES
8a32a712e45d  mcr.microsoft.com/mssql/server:latest  "/opt/mssql/bin/perm…"  44 minutes ago  Up 12 seconds  0.0.0.0:1433->1433/tcp  test_db_1

データベースとテーブル作成

起動したSQL Serverにデータベースを準備します。

# test_db_1コンテナに入る
$ docker exec -i -t test_db_1 bash

# SQL Server へ接続
mssql@8a32a712e45d:/$ /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P test1234@password

# データベース作成
1> CREATE DATABASE mydb COLLATE Japanese_Bushu_Kakusu_140_CS_AS_KS_WS;
2> go

1> use mydb
2> go
Changed database context to 'mydb'.

# membersテーブル作成
1> create table members(
2>   id int identity(1,1) primary key,
3>   name nvarchar(32),
4>   created_at datetime
5> );
6> go

1> insert into members values
2>   ('太郎', current_timestamp),
3>   ('次郎', current_timestamp),
4>   ('三郎', current_timestamp);
5> go
(3 rows affected)

# データ確認
1> select * from members;
2> go
id          name                             created_at
----------- -------------------------------- -----------------------
          1 太郎                               2021-04-28 23:52:21.427
          2 次郎                               2021-04-28 23:52:21.427
          3 三郎                               2021-04-28 23:52:21.427
(3 rows affected)

長くなりましたがこれで事前準備が完了です。次に作ったテーブルをAzure Functionから利用する処理の実装です。

実装

ライブラリの準備

まずは基本中の基本である、JDBCを使ってデータベースへのアクセスを行います。JDBCはほとんどすべてのリレーショナルDBへアクセスできる標準Java APIです。

pom.xml

<dependency>
    <groupId>com.microsoft.sqlserver</groupId>
    <artifactId>mssql-jdbc</artifactId>
    <version>9.2.1.jre8</version>
</dependency>

Function側の処理

Function.java

前回の記事 で作成したFunctionの処理を次のように修正します。

// Parse query parameter
final String query = request.getQueryParameters().get("id");
int id = 0;

Map<String, String> response = new HashMap<>();
int status = 200;
String message = null;

// 入力パラメータのチェック
try {
  if (request.getBody().orElse(query) != null) {
    id = Integer.parseInt(request.getBody().orElse(query));
  }
} catch (NumberFormatException nfex) {
  status = 400;
  message = "Invalid parameter";
}

if (status == 200) {
  try {
    // データベース接続
    Driver driver = (Driver) Class.forName(
      "com.microsoft.sqlserver.jdbc.SQLServerDriver").newInstance();
    String connectionUrl = 
      "jdbc:sqlserver://localhost;database=mydb;"
        + "integratedSecurity=false;user=sa;password=test1234@password";
    Connection connection = driver.connect(connectionUrl, new Properties());

    // SQL実行
    String sql = "select * from members where id = " + id + ";";
    Statement statement = connection.createStatement();
    ResultSet result = statement.executeQuery(sql);

    // 結果を取得            
    if (result.next()) {
      message = "Hello, " + result.getString("name");
    } else {
      status = 404;
      message = "What's your name?";
    }

    result.close();
    statement.close();
  } catch (Exception e) {
    // エラー処理
    status = 500;
    message = e.getMessage();
    e.printStackTrace();
  }
}

// レスポンスを作成
response.put("message", message);
HttpResponseMessage.Builder builder = request
    .createResponseBuilder(HttpStatus.valueOf(status))
    .header("Content-Type", "application/json");
builder.body(response);
return builder.build();

入力パラメータをString型のnameからint型のidとして受け取っているので数値チェックを行い、パラメータ不正はステータス400を返すようにします。

パラメータチェックが問題なければ、データベース接続 > SQL実行 > 結果処理を行います。また、検索結果が0件の場合は404を返却し、予期しないエラーが発生した場合は500を返すようにしました。

動作確認

※テストコードスキップでAPIを起動します。

mvn clean package azure-functions:run -Dmaven.test.skip=true
$ curl -i -X GET \
>  'http://localhost:7071/api/HttpExample?id=2'
HTTP/1.1 200 OK
Date: Thu, 29 Apr 2021 14:03:19 GMT
Content-Type: application/json; charset=utf-8
Server: Kestrel
Transfer-Encoding: chunked
{
  "message": "Hello, 次郎"
}

今回は単純な例のためFunction.javaにすべて処理を書きましたが、生産性を上げるための様々なライブラリが用意されているので次回以降でこの辺を見ていこうと思います。

コメント

このブログの人気の投稿

docker-compose up で proxyconnect tcp: dial tcp: lookup proxy.example.com: no such host

docker-compose で起動したweb、MySQLに接続できない事象

【PHP】PHP_CodeSnifferを使う(コーディングルールのカスタマイズ)