質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.91%

javaアプリからEC2上のmysqlのDBへ接続する

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 446

前提・実現したいこと

前提:すみません、新米SEです。javaにてHPを作っており、AWSを使って公開しようとしています。稚拙な質問かもしれませんがどうかお願いいたします。
結論:AWSのEC2上にインストールしたDB(mysql)のJDBC URLの記述方法や、EC2サーバー上でjavaからmysqlを扱う際に必要な設定・作業が知りたい。

詳細
:①アプリケーションサーバー ⇨ AWS EC2にtomcatをインストール、ローカルのeclipseで作成したWARファイルを搭載。
:②データベース      ⇨ ①と同じEC2上にmysqlをインストール。DBの作成まで完了。

①にて作成したjavaのアプリは動作するが、DBアクセスの部分ができていない。
ローカルで開発していた際は接続できており、jdbc周りが原因ではないかと考えています。

他におすすめの方法がありましたら別の方法でも大丈夫です。
※この方法に拘っていません。

以下のソースコードは、上がローカルで動作していた時のもの。
下は、EC2に移行させた後自分で考えていくつか書き換えています。
書き換えた箇所
・jdbcUrlの文字列。
localhostから、DNS名:ポート/DB名に変更。
localhostから、IPアドレス:ポート/DB名に変更。
・com.mysql.cj.jdbc.Driverをcom.mysql.jdbc.Driverへ。

発生している問題・エラーメッセージ

EC2上でWEBアプリを動作させると、DBアクセスの部分が機能しなくなる。
・DBから情報を引っ張ってこれない。
(ログイン機能を実装しており、正しいパラメータを渡してもログインできない。)

該当のソースコード

/**----------------------------------------------------------------------*
 *■■■TJMEMDaoクラス■■■
 *概要:DAO(「MEMBERS」テーブル)
 *----------------------------------------------------------------------**/
public class TJDao {

    //-------------------------------------------
    //データベースへの接続情報
    //-------------------------------------------
    //いずれはここを、AWSのDBにしたい。
    String jdbcUrl = "jdbc:mysql://localhost/takejam2020";
    String userId = "chikashi";
    String password = "takejam";

    //----------------------------------------------------------------
    //メソッド
    //----------------------------------------------------------------
    /**----------------------------------------------------------------------*
     *■doSelectメソッド
     *概要 :引数のユーザー情報に紐づくユーザーデータを「MEMBERS」テーブルから抽出する
     *引数①:ユーザーID(ユーザー入力)
     *引数②:パスワード(ユーザー入力)
     *戻り値:「MEMBERS」テーブルから抽出したユーザーデータ(UTJMEMDto型)
     *----------------------------------------------------------------------**/

    public TJDto doSelect(String inputUserName, String inputPassWord) {

        //-------------------------------------------
        //JDBCドライバのロード(不要)
        //-------------------------------------------
        try {
        Class.forName("com.mysql.cj.jdbc.Driver");
        }catch(ClassNotFoundException e) {
            e.printStackTrace();
        }

        //-------------------------------------------
        //SQL発行
        //-------------------------------------------
        Connection con = null;
        //prepared statementの準備 importが必要
        PreparedStatement ps = null;
        //result setの準備 importが必要
        ResultSet rs = null;
        //DTOの準備
        //TJMEMDto dto = null;
        TJDto dto = new TJDto();

        //-------------------------------------------
        //takejam2020 DBへ接続
        //-------------------------------------------
        try {//try with resource文


        //-------------------------------------------
        //接続の確立(Connectionオブジェクトの取得)
        //-------------------------------------------
        con = DriverManager.getConnection(jdbcUrl, userId, password);
/**----------------------------------------------------------------------*
 *■■■TJMEMDaoクラス■■■
 *概要:DAO(「MEMBERS」テーブル)
 *----------------------------------------------------------------------**/
public class TJDao {

    //-------------------------------------------
    //データベースへの接続情報
    //-------------------------------------------
    String jdbcUrl = "jdbc:mysql://ec2-35-72-4-42.ap-northeast-1.compute.amazonaws.com:3306/takejam2020";
    String userId = "chikashi";
    String password = "takejam";

    //----------------------------------------------------------------
    //メソッド
    //----------------------------------------------------------------
    /**----------------------------------------------------------------------*
     *■doSelectメソッド
     *概要 :引数のユーザー情報に紐づくユーザーデータを「MEMBERS」テーブルから抽出する
     *引数①:ユーザーID(ユーザー入力)
     *引数②:パスワード(ユーザー入力)
     *戻り値:「MEMBERS」テーブルから抽出したユーザーデータ(UTJMEMDto型)
     *----------------------------------------------------------------------**/

    public TJDto doSelect(String inputUserName, String inputPassWord) {

            //-------------------------------------------
        //JDBCドライバのロード
        //-------------------------------------------
        try {
        Class.forName("com.mysql.cj.jdbc.Driver");
        }catch(ClassNotFoundException e) {
            e.printStackTrace();
        }

        //-------------------------------------------
        //SQL発行
        //-------------------------------------------
        Connection con = null;
        //prepared statementの準備 importが必要
        PreparedStatement ps = null;
        //result setの準備 importが必要
        ResultSet rs = null;
        //DTOの準備
        //TJMEMDto dto = null;
        TJDto dto = new TJDto();

        //-------------------------------------------
        //takejam2020 DBへ接続
        //-------------------------------------------
        try {//try with resource文


        //-------------------------------------------
        //接続の確立(Connectionオブジェクトの取得)
        //-------------------------------------------
        con = DriverManager.getConnection(jdbcUrl, userId, password);

試したこと

上のソースコードは、上がローカルで動作していた時のものになります。
下は、EC2に移行させた後自分で考え、いくつか書き換えています。
●書き換えた箇所
・jdbcUrlの文字列。
localhostから、DNS名:ポート/DB名に変更。
localhostから、IPアドレス:ポート/DB名に変更。
・com.mysql.cj.jdbc.Driverをcom.mysql.jdbc.Driverへ。

●その他試したこと。

  1. 以下を参考に、EC2のポート3306を開放。
    https://medium.com/modernnerd-code/connecting-to-mysql-db-on-aws-ec2-with-jdbc-for-java-91dba3003abb
  2. サーバーの再起動。(WARを修正するたび再起動しています。)

素人考えで大変恐縮ですが、DBアクセスする部分のjavaまでは問題なく動作していますのでDAOが原因と思い、ソースを載せさせていただきました。
また、プログラミングの質問をさせていただくのは人生初でして、何かこの情報も載せて欲しいというものがあれば仰っていただきたいです。

みなさま、レベルの低い質問で大変恐縮ですが、重ねてどうかよろしくお願いいたします。

補足情報(FW/ツールのバージョンなど)

各種バージョン
・mysql  Ver 8.0.21 for Linux on x86_64 (MySQL Community Server - GPL)
・Apache Tomcat/7.0.76
・openjdk version "1.8.0_252"
・OpenJDK Runtime Environment (build 1.8.0_252-b09)
・OpenJDK 64-Bit Server VM (build 25.252-b09, mixed mode)
・開放ポート:80,443,22, 8080(tomcat用),  3306(mysql用)

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • dodox86

    2020/07/19 05:42

    同じマシン上、つまりEC2インスタンスのコンソール上でstatic void main(String[] args)なJavaプログラムでmysqlに接続できるようになったらJDBCの接続文字列とアカウント情報の設定には問題が無い、と言う切り分けになります。Javaサーブレットにしたら動かなくなったら、それはまた別の問題を持っている可能性がある、と言うことです。そうやって切り分けていきます。

    キャンセル

  • chikashi_4645

    2020/07/19 20:53

    dodox86さん
    ご丁寧に返信いただきありがとうございます。以下のようなテストプログラムを作り、実行してみました。
    (ほぼベタ書きで申し訳ありません。)

    まずEC2上でコンパイル、実行してみましたが、
    java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver
    でエラーになっています。自分のローカル環境(macのターミナル)でも同様でしたが、
    eclipse上では正常に動作し、DBの情報を抽出できています。
    JDBCドライバのパスが通っていないことを疑い、まずmacにてhttps://qiita.com/s_hino/items/a185deb4f9fc31c0f5e2
    を参考にJDBCドライバのjarファイルのパスを追加しましたが、解消しませんでした。
    いったんここまででアドバイスいただければと思います。どうかお願いいたします。

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;

    public class test {


    public static void main(String[] args) {
    //-------------------------------------------
    //データベースへの接続情報
    //-------------------------------------------

    //JDBCドライバの相対パス
    String driverName = "com.mysql.cj.jdbc.Driver";

    //接続先のデータベース
    String jdbcUrl = "jdbc:mysql://localhost/takejam2020";

    //接続するユーザー名
    String userId = "chikashi";

    //接続するユーザーのパスワード
    String userPass = "takejam";

    //-------------------------------------------
    //① JDBCドライバのロード
    //-------------------------------------------
    try {
    Class.forName(driverName); //JDBCドライバをロード&接続先として指定
    } catch (ClassNotFoundException e) {
    e.printStackTrace();
    }


    //JDBCの接続に使用するオブジェクトを宣言
    //※finallyブロックでも扱うためtryブロック内で宣言してはいけないことに注意
    Connection con = null ; // Connection(DB接続情報)格納用変数
    PreparedStatement ps = null ; // PreparedStatement(SQL発行用オブジェクト)格納用変数
    ResultSet rs = null ; // ResultSet(SQL抽出結果)格納用変数

    try {
    //-------------------------------------------
    // ②接続の確立(Connectionオブジェクトの取得)
    //-------------------------------------------
    con = DriverManager.getConnection(jdbcUrl, userId, userPass);

    //-------------------------------------------
    // ③SQL文の送信 & ④抽出結果の取得
    //-------------------------------------------

    //SQL文の生成(SELECT)
    StringBuffer buf = new StringBuffer() ;
    buf.append(" SELECT ");
    buf.append(" id , ");
    buf.append(" NickName ");
    buf.append(" FROM ");
    buf.append(" MEMBERS ");

    //PreparedStatementオブジェクトを生成&発行するSQLをセット
    ps = con.prepareStatement(buf.toString());

    //SQL文の送信&抽出結果(ResultSetオブジェクト)の取得
    rs = ps.executeQuery();

    while (rs.next()) {

    //ResultSetオブジェクトから1レコードデータを表示する
    StringBuffer rsbuf = new StringBuffer();

    //加工作成した1レコード分のデータを表示
    rsbuf.append(rs.getString("NickName"));
    System.out.println(rsbuf.toString());
    }

    キャンセル

  • dodox86

    2020/07/20 11:35

    回答として投稿しました。ご提示のテストプロソースコードは末尾が不完全でコンパイルエラーになります。今後はコードを提示するときは質問文中に追記、修正でお願いできればと思います。(他の閲覧者さんの為でもあります)

    キャンセル

回答 3

checkベストアンサー

0

ご質問の[2020/07/19 20:53]のコメントを見て:

まずEC2上でコンパイル、実行してみましたが、
java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver
でエラーになっています。
自分のローカル環境(macのターミナル)でも同様でしたが、
eclipse上では正常に動作し、DBの情報を抽出できています。
JDBCドライバのパスが通っていないことを疑い、

「JDBCのPATHを通す」とは、PATH環境変数で示されるサーチPATHに追加することではありません。*.jarCLASSPATHに追加し、Javaの実行時に当該クラスをロードできるようにする処置です。

MySQLのJDBCドライバーがインストールされていないかまたは正しくCLASSPATH上にセットされていないのではないでしょうか。static void main(String args[])なスタンドアロンのプログラムでも、Tomcat上で稼働するJavaサーブレットでも、com.mysql.cj.jdbc.Driverに合致したMySQL用のJDBCドライバーを使う必要があります。ローカルPCのEclipseをセットアップするときに、そのような手順があったと思いますが違いますでしょうか。

7.1 Connecting to MySQL Using the JDBC DriverManager Interface - MySQL

こちらで確認したところ、MySQL Community Downloadsからダウンロードした圧縮ファイルmysql-connector-java-8.0.21.tar.gzを展開して得られた「mysql-connector-java-8.0.21.jar」を利用することで、質問者さんが試したテストプログラムを一部改変した下記のもので動作させることができました。確認した環境はAmazon EC2のインスタンスではなく、別のクラウドのUbuntu18.04で、ユーザーアカウントやデータベース名も違いますが、localhostへ接続させているので状況としては同じはずです。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class Test2 {

    public static void main(String[] args) {
        //JDBCドライバの相対パス
        String driverName = "com.mysql.cj.jdbc.Driver";

        //接続先のデータベース
        String jdbcUrl = "jdbc:mysql://localhost/takejam2020";

        //接続するユーザー名
        String userId = "chikashi";

        //接続するユーザーのパスワード
        String userPass = "takejam";

        try {
            Class.forName(driverName); //JDBCドライバをロード&接続先として指定
        } catch (ClassNotFoundException e) {
            System.out.println("----1");
            e.printStackTrace();
        } catch (Exception e) {
            System.out.println("----2");
            e.printStackTrace();
        }

        Connection con = null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        try {
            con = DriverManager.getConnection(jdbcUrl, userId, userPass);

            // MySQLが既定で持つテーブルのデータを出力
            String sql = "SELECT SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME FROM INFORMATION_SCHEMA.SCHEMATA";
            ps = con.prepareStatement(sql);

            rs = ps.executeQuery();

            while (rs.next()) {
                String s1 = rs.getString("SCHEMA_NAME");
                String s2 = rs.getString("DEFAULT_CHARACTER_SET_NAME");
                System.out.println(String.format("%s, %s", s1, s2));
            }
        } catch (Exception e) {
            System.out.println("----3");
            e.printStackTrace();
        }
    }
}

実行例です。実行時には当然、CLASSPATH上にmysql-connector-java-8.0.20.jarを含める必要があります。javaコマンド実行時のコマンドラインオプションに注意して読んでみてください。

user01@DevVM1:~/work$ ls -l *.jar
-rw-r--r-- 1 user01 user01 2397321 Jun 16 15:17 mysql-connector-java-8.0.21.jar

user01@DevVM1:~/work$ javac -version
javac 1.8.0_252
user01@DevVM1:~/work$ javac Test2.java
user01@DevVM1:~/work$ java -classpath ./:./mysql-connector-java-8.0.21.jar Test2
information_schema, utf8
userdb, utf8
userdb2, utf8
mysql, latin1
performance_schema, utf8
sys, utf8


Tomcatで稼働させるJavaサーブレットでも、CLASSPATH上で参照できる必要があります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/20 19:08

    dodox86さん
    こんなに親切にご指導いただき、感動しています。心からお礼申し上げます。回答者様の親切に甘えまして、またしてもレベルの低い質問をさせていただきます。
    *.jarをCLASSPATHに追加し、とありますが具体的な操作手順はどのようになるのでしょうか。当然ながら自分なりに方法は調べたのですが、期待通りの結果は得られませんでした。

    やったこととしては、macのターミナルにてバッシュプロファイルにexport CLASSPATHと記述し、jdbcのjarのパスを記載しました。

    そもそもLinuxのパスの通し方に自信がないです…

    それからMySQLやjdkのバージョンや配置場所なども、yumコマンドにてインストールを行なっており(versionは最初の質問の末尾に記載)、本当にこのままの設定でうまく行くのかなと思いながら実行しています。(配置場所やバージョンなどはあまり関係ないでしょうか?)

    もし、その辺りもクリティカルな要素になり得るとしたら、(もちろんjdbcは、対応するMySQLのバージョンでなくてはならないですが)細かな手順も記載頂けますと非常に嬉しいです。(かなり甘ったれてますが、近くに質問できる方がおらず、大変申し訳ございません)

    このままDBに接続できないWEBサイトでは我慢できなく、お力添えいただきたいです。本当に重ね重ねありがとうございます。

    キャンセル

  • 2020/07/20 23:45

    最終的には $CATALINA_HOME/lib か WEB-INF/lib に入ってなかっただとおもうけどどう解決したんだろうね。

    キャンセル

0

  1. ローカルとリモート の ${CATALINA_HOME}/lib に過不足がないか確認する。
  2. ローカルとリモート の ${CATALINA_HOME}/Catalina/localhost に過不足がないか確認する。
  3. ローカルとリモート の ${CATALINA_HOME}/server.xml で設定が違わないか確認する
  4. ローカルとリモート の ${CATALINA_HOME}/context.xml で設定が違わないか確認する
  5. ローカルとリモート の ${CATALINA_HOME}/web.xml で設定が違わないか確認する

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/19 11:15

    そうですね。意外とJDBC"jdbc:mysql://localhost/takejam2020"ではDBに接続可能な状態になっていて、asahina1979さんの回答でのご指摘のように、tomcat/サーブレットの設定自体の問題の可能性もあります。(それを見極める為の必要最小限なコード、と言うのもありますが)

    キャンセル

  • 2020/07/19 11:31

    @dodobox86

    環境依存の処理を書かない+Pure Java
    でかけば、「Write once, run anywhere」なんで

    今回の件だと JDBC URL が ベタがきなんで lib 以外は不要ではあるが ・・

    キャンセル

0

みなさま、大変お世話になりました。linuxの環境変数の定義を一から学び直し、linux周りを業務で扱っている方がわざわざ声をかけていただき解決しました。

環境変数の定義の方法がやはり間違えており、PATHとCLASSPATHの違いをはっきり理解した後で接続を試みたところ正常に動作しました。

今回学んだことは、eclipseは非常に便利なツールであるが、本質を理解する上では足枷になる可能性もあるということです。
基本的な理解がないままコードがかけ、プログラムが動作するというのは便利な一方、こうした情けない事態を招いてしまうことがよくわかりました。

回答いただきましたお二方、見ず知らずの若輩者にここまで丁寧にアドバイスいただきまして心から感謝しています。これを皮切りにしっかりとまた一段と精進していきたいと思います。人の温かみに触れ、素晴らしい経験をさせていただきました。
繰り返しになりますが、ご親切にコーディングのイロハまでも学ばせていただき感謝しています。ありがとうございました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/21 01:14

    しばらく離れていて追記しようかと思い、PCに向きあったところこちらの報を読みました。解決できてよかったです。環境変数PATH, CLASSPATHについては意味合いも違えば設定の仕方もWindows, macOS、Linux、それぞれで少しずつ違っていたりして特に初心者の方には理解もしづらかったと思います。ひき続きがんばってください。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.91%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る