tag:crieit.net,2005:https://crieit.net/tags/Oracle/feed 「Oracle」の記事 - Crieit Crieitでタグ「Oracle」に投稿された最近の記事 2022-12-19T13:23:20+09:00 https://crieit.net/tags/Oracle/feed tag:crieit.net,2005:PublicArticle/18341 2022-12-19T13:23:20+09:00 2022-12-19T13:23:20+09:00 https://crieit.net/posts/c1d391c26b9ce512e85d9960b9f6376d 全テーブルの中から対象データが含まれているテーブルと項目を取得 <pre><code>--//出力表示 SET SERVEROUT ON; DECLARE --//変数定義 type cursor_type is ref cursor; cur_search cursor_type; vCount INTEGER; ERR_CODE NUMBER; ERR_MSG VARCHAR2(255); TYPE objName IS VARRAY(260) OF VARCHAR2(30); --//対象データを指定 tDATE objName := objName('') BEGIN --//テーブルを指定する(全テーブルの中から特定の文字列が含まれるテーブルを指定) FOR vRec (SELECT table_name,column_name FROM user_tab_cols WHERE table_name LIKE '' OR table_name = '') LOOP BEGIN --//指定したテーブルの中から対象データを検索 FOR i IN tDATA.first..tDATA.last LOOP OPEN cur_search FOR 'SELECT COUNT(*) AS cnt FROM ' || vRec.column_name || 'LIKE ''%' || tDATA(i) || '%'''; FETCH cur_search INTO vCount; IF vCount > 0 THEN --//対象データがあった場合、そのテーブルと項目名、件数を出力する DBMS_OUTPUT.PUT_LINE( tDATA(i) || ':' || vRec.table_name || '.' || vRec.column_name || ' ' || vCount || '件あり' ); END IF; CLOSE cur_search; END LOOP; EXCEPTION --//例外処理 WHEN OTHERS THEN ERR_CODE := SQLCODE; ERR_MSG := SUBSTEB(SQLERRM,1,255); DBMS_OUTPUT.PUT_LINE('error:' || ERR_CODE || ' ' || ERR_MSG || ' ' || vRec.table_name || '.' || vRec.column_name ); END; END LOOP; END; / </code></pre> speasmen88 tag:crieit.net,2005:PublicArticle/15858 2020-04-21T13:51:26+09:00 2020-04-21T14:04:20+09:00 https://crieit.net/posts/AWS-Lambda-cx-Oracle-OracleDB AWS Lambdaでcx_Oracleを使ってOracleDBへ接続する <h1 id="前書き"><a href="#%E5%89%8D%E6%9B%B8%E3%81%8D">前書き</a></h1> <p>Pythonで書かれた Lambdaファンクションから、OracleDBへ接続する方法を記載します。</p> <p>LambdaファンクションからMySQLへの接続はたくさん記事があるんだけど、OracleDBへの接続はあまり記事がなく、実現まで結構時間がかかったので、自分用の備忘録に。</p> <h1 id="結論"><a href="#%E7%B5%90%E8%AB%96">結論</a></h1> <ul> <li>LambdaファンクションからOracleDBに接続する時には、cx_Oracleのモジュールだけではなく、Oracle Instant Clientのモジュールも、デプロイパッケージに入れてあげる必要がある。</li> <li>すべてのモジュールを一つのデプロイパッケージに入れると、大きすぎてAWS Lambdaのインラインエディタで編集できなくなる。なので、cx_OracleとOracle Instant Clientのモジュールはレイヤに分けると良い。</li> </ul> <h1 id="手順"><a href="#%E6%89%8B%E9%A0%86">手順</a></h1> <h2 id="前提"><a href="#%E5%89%8D%E6%8F%90">前提</a></h2> <p>2020年4月時点で、使用した環境は下記の通りです。<br /> python3のインストールまで完了している状態で、後続の作業を開始します。</p> <ul> <li>Amazon Linux 2(AWS EC2上で作業)</li> <li>python3.7</li> <li>cx_Oracle7.3</li> <li>Oracle Instant Client 19.6</li> </ul> <h2 id="手順の流れ"><a href="#%E6%89%8B%E9%A0%86%E3%81%AE%E6%B5%81%E3%82%8C">手順の流れ</a></h2> <ol> <li>必要なモジュールをインストールする</li> <li>デプロイパッケージを作る</li> <li>Lambdaファンクションを作成する</li> <li>レイヤ用のデプロイパッケージを作成する</li> <li>Lambdaファンクションにレイヤを適用する</li> </ol> <h2 id="1. 必要なモジュールをインストールする"><a href="#1.+%E5%BF%85%E8%A6%81%E3%81%AA%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B">1. 必要なモジュールをインストールする</a></h2> <h3 id="Oracle Instant Client"><a href="#Oracle+Instant+Client">Oracle Instant Client</a></h3> <p>まずは、Oracle Instant Client から。<br /> 最新版のOracle Instant Clientを公式サイトからダウンロードします。作業環境が Amazon Linux 2 なので、Linux用の64ビット版を使います。<br /> * <a target="_blank" rel="nofollow noopener" href="https://www.oracle.com/technetwork/jp/database/database-technologies/instant-client/overview/index.html">Oracle Instant Client</a><br /> * <a target="_blank" rel="nofollow noopener" href="https://www.oracle.com/database/technologies/instant-client/linux-x86-64-downloads.html">Instant Client Downloads for Linux x86-64 (64-bit)</a></p> <p>インストールしたのは、とりあえずbasicとsqlplusのふたつだけ。LambdaファンクションからのDB接続だけを考えるなら、sqlplusは不要かも。</p> <pre><code>$ sudo yum -y localinstall ./oracle-instantclient19.6-basic-19.6.0.0.0-1.x86_64.rpm $ sudo yum -y localinstall ./oracle-instantclient19.6-sqlplus-19.6.0.0.0-1.x86_64.rpm </code></pre> <p>インストール完了後、SQL*PLUSでDBに接続できることを確認しておきます。<br /> なお、Oracle Instant Clientを使用する分には、ORACLE_HOMEなどの設定は不要らしいです。</p> <pre><code>$ sqlplus <user>/<pass>@<hostname>:<port>/<sid> SQL*Plus: Release 19.0.0.0.0 - Production on xxx xxx xx xx:xx:xx xxxx Version 19.6.0.0.0 Copyright (c) 1982, 2019, Oracle. All rights reserved. Last Successful login time: xxx xxx xx xxxx xx:xx:xx +09:00 Connected to: Oracle Database 12c Standard Edition Release 12.1.0.2.0 - 64bit Production SQL> select TNAME from tab; TNAME -------------------------------------------------------------------------------- SAMPLE_EMP SQL> select * from SAMPLE_EMP; EMPNO EMPNAME GENDER_F ---------- -------------------------------------------------- ---------- 0000000001 EMP_A 1 0000000002 EMP_B 2 0000000003 EMP_C 1 SQL> quit Disconnected from Oracle Database 12c Standard Edition Release 12.1.0.2.0 - 64bit Production </code></pre> <p>サンプルで作っておいたテーブルの中身が見えており、Oracle Instant Clientのインストールは完了です。</p> <h3 id="cx_Oracle"><a href="#cx_Oracle">cx_Oracle</a></h3> <p>PythonでOracleDBに接続するために、cx_Oracleもインストールしておきます。</p> <pre><code>$ sudo pip3 install cx_oracle </code></pre> <h3 id="EC2からcx_Oracleを使ってOracleDBへ接続する"><a href="#EC2%E3%81%8B%E3%82%89cx_Oracle%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6OracleDB%E3%81%B8%E6%8E%A5%E7%B6%9A%E3%81%99%E3%82%8B">EC2からcx_Oracleを使ってOracleDBへ接続する</a></h3> <p>ここまで完了したら、pythonでOracleDBへ接続できるようになっているはずなので、簡単なサンプルでOracleDBに接続できるか確認します。例えば下記のような感じ。ファイル名は<code>dbconnect_oracle.py</code>とします。</p> <pre><code>import json import cx_Oracle def lambda_handler(event, context): # TODO implement # cx_oracleバージョン確認 verOraCli = cx_Oracle.clientversion() print( verOraCli ) # oracle接続 print( "DB connect" ) connection = cx_Oracle.connect("<user>", "<pass>", "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=<hostname>) (PORT=<port>))(CONNECT_DATA=(SID=<sid>)))") # select実行 print( "select execute" ) try: cursor = connection.cursor() sql = "select * from sample_emp" cursor.execute( sql ) result = cursor.fetchall() print( result ) finally: cursor.close() connection.close() return { 'statusCode': 200, 'body': json.dumps( 'cx_oracle clientversion = ' + str(verOraCli) ) } </code></pre> <p>本来はハンドラの中でDB接続処理を行わない方が良いけど、まあとりあえずということでひとつ。早速実行してみます。</p> <pre><code>$ python3 -c "import dbconnect_oracle; dbconnect_oracle.lambda_handler(0,0)" (19, 6, 0, 0, 0) DB connect select execute [('0000000001', 'EMP_A', 1), ('0000000002', 'EMP_B', 2), ('0000000003', 'EMP_C', 1)] </code></pre> <p>Oracle Instant Client 19.6 を使用してOracleDBでselectを実行できていることが確認できました。</p> <h2 id="2. デプロイパッケージを作る"><a href="#2.+%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%82%92%E4%BD%9C%E3%82%8B">2. デプロイパッケージを作る</a></h2> <p>EC2上での動作は確認できたので、AWS Lambdaの関数として定義するためにデプロイパッケージを作成します。</p> <h3 id="デプロイパッケージ構成"><a href="#%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E6%A7%8B%E6%88%90">デプロイパッケージ構成</a></h3> <p>Lambdaファンクションで外部ライブラリのimportを行う場合、外部ライブラリを含んだデプロイパッケージを作る必要があります。今回はさらに、cx_OracleがOracle Instant Clientを利用するので、Oracle Instant Clinentもデプロイパッケージに含める必要があります。</p> <p>というわけで、目指すべき構成は下記の形。作業ディレクトリは<code>/tmp/dbconnect_oracle_pack</code>とします。</p> <pre><code>/tmp/dbconnect_oracle_pack ├ dbconnect_oracle.py ├ cx_Oracle.cpython-37m-x86_64-linux-gnu.so ├ cx_Oracle-7.3.0.dist-info │ ├ INSTALLER │ ├ METADATA │ ├ RECORD │ ├ WHEEL │ └ top_level.txt └ lib ├ libaio.so -> ./libaio.so.1 ├ libaio.so.1 ├ libclntsh.so -> ./libclntsh.so.19.1 ├ libclntsh.so.19.1 ├ libclntshcore.so -> ./libclntshcore.so.19.1 ├ libclntshcore.so.19.1 ├ libipc1.so ├ libmql1.so ├ libnnz19.so ├ libocci.so -> ./libocci.so.19.1 ├ libocci.so.19.1 └ libociei.so </code></pre> <h3 id="デプロイパッケージ作成"><a href="#%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E4%BD%9C%E6%88%90">デプロイパッケージ作成</a></h3> <p>デプロイパッケージにcx_Oracleを含めるため、作業ディレクトリへcx_Oracleを持ってきます。作業ディレクトリへのインストールなので、今回は<code>sudo</code>は不要です。</p> <pre><code>$ pip3 install cx_Oracle -t /tmp/dbconnect_oracle_pack </code></pre> <p>Oracle Instant Clientのモジュールは、インストール先からコピーします。<code>libaio.so.1</code>だけは、<code>/usr/lib64/</code>から持ってきます。</p> <p>なお、記事を書く際に再度確認したら、<code>libaio.so.1</code>はシンボリックリンクで、実体は<code>libaio.so.1.0.1</code>でした。<br /> 下記の通りでも動作はしますが、気になる方は、<code>libaio.so.1.0.1</code>をコピーしてそこからシンボリックリンクを作成する方が良いかもしれません。</p> <pre><code>$ mkdir /tmp/dbconnect_oracle_pack $ cp /usr/lib/oracle/19.6/client64/lib/libclntsh.so.19.1 /tmp/dbconnect_oracle_pack/lib $ cp /usr/lib/oracle/19.6/client64/lib/libclntshcore.so.19.1 /tmp/dbconnect_oracle_pack/lib $ cp /usr/lib/oracle/19.6/client64/lib/libipc1.so /tmp/dbconnect_oracle_pack/lib $ cp /usr/lib/oracle/19.6/client64/lib/libmql1.so /tmp/dbconnect_oracle_pack/lib $ cp /usr/lib/oracle/19.6/client64/lib/libnnz19.so /tmp/dbconnect_oracle_pack/lib $ cp /usr/lib/oracle/19.6/client64/lib/libocci.so.19.1 /tmp/dbconnect_oracle_pack/lib $ cp /usr/lib/oracle/19.6/client64/lib/libociei.so /tmp/dbconnect_oracle_pack/lib $ cp /usr/lib64/libaio.so.1 /tmp/dbconnect_oracle_pack/lib </code></pre> <p>最初に挙げたデプロイパッケージ構成に不足している部分を、シンボリックリンクで作成します。<br /> デプロイパッケージのサイズ上限は250MBのため、絞れるところは絞りましょう。</p> <pre><code>$ cd /tmp/dbconnect_oracle_pack $ ln -s ./libaio.so.1 libaio.so $ ln -s ./libclntsh.so.19.1 libclntsh.so $ ln -s ./libclntshcore.so.19.1 libclntshcore.so $ ln -s ./libocci.so.19.1 libocci.so </code></pre> <p>ここまで完了すると、デプロイパッケージ構成通りの状態となっているはずです。zip圧縮して、デプロイパッケージを作成します。圧縮後のファイルは70MB弱くらいになると思います。<br /> シンボリックリンクを含んでいるので、<code>--symlinks</code>オプションを忘れないように。また、圧縮対象は<code>/tmp/dbconnect_oracle_pack</code>ディレクトリではなく、その配下であることに注意してください。</p> <pre><code>$ cd /tmp/dbconnect_oracle_pack $ zip -r --symlinks dbconnect_oracle_sample.zip ./dbconnect_oracle.py ./cx_Oracle.cpython-37m-x86_64-linux-gnu.so ./cx_Oracle-7.3.0.dist-info ./lib </code></pre> <h2 id="3. Lambdaファンクションを作成する"><a href="#3.+Lambda%E3%83%95%E3%82%A1%E3%83%B3%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B">3. Lambdaファンクションを作成する</a></h2> <p>完成したデプロイパッケージ元にLambdaファンクションを作成します。</p> <p>ですが、作成したデプロイパッケージが50MBを超えているため、Lambdaファンクションとして直接アップロードを行う事ができません。一旦S3上にアップロードした後、LambdaファンクションにS3からアップロードする形になります。なお、Lambdaファンクションのサイズ上限は諸々含めて250MB。cx_OracleとOracle Instant Client だけで200MBを超えていて、結構カツカツです。</p> <p>Lambdaファンクションとしてのアップロードが完了すると、インラインエディタで確認ができる…のが通常なのですが、サイズが大きすぎてインラインエディタでは編集できない旨の警告が表示されます。実行はできるようなので、良しとしておきます。</p> <p><a href="https://crieit.now.sh/upload_images/97382e5555931319dd5fd600612effab5e9e5b7d04327.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/97382e5555931319dd5fd600612effab5e9e5b7d04327.png?mw=700" alt="デプロイパッケージが大きすぎてインラインコード編集を有効にできません" /></a></p> <p>OracleDBに限らず、DBに接続するLambdaファンクションにはIPアドレスの付与が必要です。VPC設定を行い、VPC設定、サブネット、セキュリティグループを指定します。</p> <p>また、初回実行に限り、そこそこの時間がかかります。デフォルトのタイムアウト値は3秒となっていますが、10秒程度に増やしておいたほうがよいでしょう。</p> <p>上記の設定を完了したら、テスト実行を行います。サンプルは引数不要のイベントハンドラなので、空のテストイベントを作成してテストを行いましょう。</p> <p><a href="https://crieit.now.sh/upload_images/1874ff95cb0fe728e14c95e0dc913dae5e9e5d40e3989.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/1874ff95cb0fe728e14c95e0dc913dae5e9e5d40e3989.png?mw=700" alt="実行結果:成功" /></a></p> <p>ヨシ! ちゃんと、Oracle Instant Client 19.6が使われているようです。<br /> 初回は時間がかかりましたが、2回目からは1秒かからずに実行されます。時間がかかるのは、IP付与によるものかしら。</p> <h2 id="4. レイヤ用のデプロイパッケージを作成する"><a href="#4.+%E3%83%AC%E3%82%A4%E3%83%A4%E7%94%A8%E3%81%AE%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B">4. レイヤ用のデプロイパッケージを作成する</a></h2> <p>当初の目的である、cx_Oracleを使ってOracleDBへ接続するLambdaファンクションの作成は、ここまでで実現できました。</p> <p>ただ、インラインエディタでの編集ができないのはちょっといただけません。サイズが大きい原因はcx_OracleとOracle Instant Clientなので、この部分をcx_Oracleレイヤとして切り出せば良いのではないか?</p> <h3 id="cx_Oracleレイヤ用のデプロイパッケージ構成"><a href="#cx_Oracle%E3%83%AC%E3%82%A4%E3%83%A4%E7%94%A8%E3%81%AE%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E6%A7%8B%E6%88%90">cx_Oracleレイヤ用のデプロイパッケージ構成</a></h3> <p><a target="_blank" rel="nofollow noopener" href="https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/configuration-layers.html">AWS Lambda レイヤー</a></p> <blockquote> <p>関数コードからランタイム依存関係を移動するには、それらをレイヤーに配置します。Lambda ランタイムには、関数コードを使用して、レイヤーに含まれるライブラリにアクセスできることを確認する、<code>/opt</code>ディレクトリのパスが含まれます。</p> <p>ライブラリをレイヤーに含めるには、ランタイムでサポートされているいずれかのフォルダにそれらを配置します。<br /> * <strong>Python</strong> – <code>python</code>、<code>python/lib/python3.8/site-packages</code>(サイトディレクトリ)</p> </blockquote> <p>レイヤ用のデプロイパッケージを作る場合、pyhon関連のライブラリは<code>python</code>配下に、配置します。なので、cx_Oracle関連のモジュールはこちらに置きます。</p> <p><a target="_blank" rel="nofollow noopener" href="https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/configuration-envvars.html">AWS Lambda 環境変数の使用</a></p> <blockquote> <p>予約されていない環境変数<br /> (略)<br /> <code>LD_LIBRARY_PATH</code> – システムライブラリのパス<br /> (<code>/lib64:/usr/lib64:$LAMBDA_RUNTIME_DIR:$LAMBDA_RUNTIME_DIR/lib:$LAMBDA_TASK_ROOT:$LAMBDA_TASK_ROOT/lib:/opt/lib</code>)。</p> </blockquote> <p>Oracle Instant Clientのモジュールについては、<code>LD_LIBRARY_PATH</code>で指定されたパスに配置する必要があります。Lambdaファンクションの設定で編集しても良いのですが、デフォルトで指定されたパス<code>/opt/lib</code>があるので、そちらを使いましょう。レイヤに含まれるライブラリは<code>/opt</code>配下に配置されるとのことなので、<code>lib</code>配下です。</p> <p>というわけで、レイヤ用デプロイパッケージの構成は下記の通りになります。作業ディレクトリは<code>/tmp/dbconnect_oracle_pack/layer</code>とします。</p> <pre><code>/tmp/dbconnect_oracle_pack/layer ├ python │ ├ cx_Oracle.cpython-37m-x86_64-linux-gnu.so │ └ cx_Oracle-7.3.0.dist-info │ ├ INSTALLER │ ├ METADATA │ ├ RECORD │ ├ WHEEL │ └ top_level.txt └ lib ├ libaio.so -> ./libaio.so.1 ├ libaio.so.1 ├ libclntsh.so -> ./libclntsh.so.19.1 ├ libclntsh.so.19.1 ├ libclntshcore.so -> ./libclntshcore.so.19.1 ├ libclntshcore.so.19.1 ├ libipc1.so ├ libmql1.so ├ libnnz19.so ├ libocci.so -> ./libocci.so.19.1 ├ libocci.so.19.1 └ libociei.so </code></pre> <h3 id="レイヤ用デプロイパッケージ作成"><a href="#%E3%83%AC%E3%82%A4%E3%83%A4%E7%94%A8%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E4%BD%9C%E6%88%90">レイヤ用デプロイパッケージ作成</a></h3> <p>配置ができたらzip圧縮し、レイヤ用デプロイパッケージを作成します。ファイル名は何でも良いですが、<code>oraclelib.zip</code>としてみました。</p> <pre><code>$ cd /tmp/dbconnect_oracle_pack/layer $ zip -r --symlinks oraclelib.zip ./python ./lib </code></pre> <h2 id="5. Lambdaファンクションにレイヤを適用する"><a href="#5.+Lambda%E3%83%95%E3%82%A1%E3%83%B3%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AB%E3%83%AC%E3%82%A4%E3%83%A4%E3%82%92%E9%81%A9%E7%94%A8%E3%81%99%E3%82%8B">5. Lambdaファンクションにレイヤを適用する</a></h2> <p>レイヤを作るため、AWS Lambdaの左側メニューから「レイヤー」を選択し、レイヤの作成を行います。</p> <p>先程と同様に、S3経由でアップロードする形になります。また、「互換性のあるランタイム」には、作業環境であるAmazon Linux 2にインストールしたのと同じ Python3.7 を指定します。</p> <p><a href="https://crieit.now.sh/upload_images/731c2c355d8a949923189d7ba3ba8e7b5e9e7566a330b.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/731c2c355d8a949923189d7ba3ba8e7b5e9e7566a330b.png?mw=700" alt="レイヤー作成設定" /></a></p> <p>レイヤの作成が完了したら、Lambdaファンクションにレイヤを適用します。</p> <p>作成したLambdaファンクションの画面から「レイヤーの追加」を行う事ができます。<br /> Lambdaファンクションのランタイムを「Python3.7」にした上で、「レイヤーの追加」を行ってください。</p> <p>選択できるレイヤーは、Lambdaファンクションで設定しているランタイムを「互換性のあるランタイム」で指定したレイヤーだけです。<br /> <a href="https://crieit.now.sh/upload_images/505ac0668a3516271d2a73ce9c2b569a5e9e765c9c085.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/505ac0668a3516271d2a73ce9c2b569a5e9e765c9c085.png?mw=700" alt="関数にレイヤーを追加" /></a></p> <p>こうしておくと、Lambdaファンクションそのものは、今回のサンプルの<code>dbconnect_oracle.py</code>だけにしても大丈夫です。インラインコード編集も可能となります。</p> <p><a href="https://crieit.now.sh/upload_images/7d20015f8e9283b81e552707518b66645e9e77bc2ef5e.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/7d20015f8e9283b81e552707518b66645e9e77bc2ef5e.png?mw=700" alt="OK" /></a></p> <p>動作も問題ありません。</p> <h1 id="後書き"><a href="#%E5%BE%8C%E6%9B%B8%E3%81%8D">後書き</a></h1> <p>一番わからなかったのは、Oracle Instant Client 19 だとどのlibをデプロイパッケージに含めればよいのか、ということです。今回記事に残そうとしたのも、それが要因です。</p> <p>それにしても、Oracle Instant Client だけで200MBオーバーなんだけど、そのうちOracle Instant ClientだけでLambdaのサイズ制限を超えてしまうのではないだろうか。</p> <h1 id="参考サイト"><a href="#%E5%8F%82%E8%80%83%E3%82%B5%E3%82%A4%E3%83%88">参考サイト</a></h1> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/aidy91614/items/92987d547c318e0483f5">Lambda から RDS にアクセスする方法 (python)</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/ikeisuke/items/45ba4d88b887d793c444">AWS Lambda (Node.js-v4.3.2)からOracleに接続する(ORA-21561への対応)</a></li> <li><p><a target="_blank" rel="nofollow noopener" href="http://wiki.nikhil.io/Lambda,_Python,_and_Oracle/raw">Lambda, Python, and Oracle</a></p> <p>その他、検索に引っかかったフォーラムの記事とか色々参考にしました。</p></li> </ul> tag:crieit.net,2005:PublicArticle/15698 2020-01-27T10:01:36+09:00 2020-01-27T10:01:36+09:00 https://crieit.net/posts/JavaFX-Oracle-TableView 【JavaFX】Oracle に接続して取得したデータをTableView に表示する <p>引き続き、JavaFXで Oracle から取得したデータを TableView に表示したいと思います。</p> <p>プログラムは前回のものを流用します。</p> <p><a target="_blank" rel="nofollow noopener" href="https://www.doraxdora.com/blog/2017/09/30/post-2626/" target="_blank" rel="noopener">【JavaFX】Oracleに接続して取得したデータをコンボボックスに設定する</a></p> <h2 id="クラスの作成"><a href="#%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%AE%E4%BD%9C%E6%88%90">クラスの作成</a></h2> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/09/JavaFxTblView000.jpg" alt="クラスの作成" /></p> <p>パッケージ・エクスプローラーから「dto」パッケージを右クリックし「新規」>「クラス」を選択します。</p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/09/JavaFxTblView001.jpg" alt="名前を入力" /></p> <p>クラス名に「TblCat」を入力し、「完了」ボタンをクリックします。</p> <p>作成したクラスの実装は次のようにします。</p> <p>TblCat.java</p> <pre><code>/** * */ package jp.co.doraxdora.dto; import java.io.Serializable; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; /** * TBL猫DTOクラス. * * @author doraxdora * */ public class TblCat implements Serializable { /** No */ private StringProperty no; /** 名前 */ private StringProperty name; /** 性別 */ private StringProperty sex; /** 年齢 */ private StringProperty age; /** 種別 */ private StringProperty kindCd; /** 好物 */ private StringProperty favorite; /** * @return no */ public StringProperty noProperty() { return no; } /** * @param no * セットする no */ public void setNo(String no) { this.no = new SimpleStringProperty(no); } /** * @return name */ public StringProperty nameProperty() { return name; } /** * @param name * セットする name */ public void setName(String name) { this.name = new SimpleStringProperty(name); } /** * @return sex */ public StringProperty sexProperty() { return sex; } /** * @param sex * セットする sex */ public void setSex(String sex) { this.sex = new SimpleStringProperty(sex); } /** * @return age */ public StringProperty ageProperty() { return age; } /** * @param age * セットする age */ public void setAge(String age) { this.age = new SimpleStringProperty(age); } /** * @return kind */ public StringProperty kindCdProperty() { return kindCd; } /** * @param kind * セットする kind */ public void setKindCd(String kindCd) { this.kindCd = new SimpleStringProperty(kindCd); } /** * @return favorite */ public StringProperty favoriteProperty() { return favorite; } /** * @param favorite * セットする favorite */ public void setFavorite(String favorite) { this.favorite = new SimpleStringProperty(favorite); } } </code></pre> <p> </p> <p><span style="color: #000000;">TblViewの仕組み上</span><br /> <span style="color: #000000;">通常のアクセサとは異なり、getter のメソッド名は [メンバ名]Property とします。<br /> こうしておかないと一覧にデータが表示されずにあたふたしますよ。</span></p> <h2 id="プログラム修正"><a href="#%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E4%BF%AE%E6%AD%A3">プログラム修正</a></h2> <h3 id="画面の修正"><a href="#%E7%94%BB%E9%9D%A2%E3%81%AE%E4%BF%AE%E6%AD%A3">画面の修正</a></h3> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/09/JavaFxTblView002.jpg" alt="" /> メソッドの追加</p> <p>SceneBuilder からであれば、右側のメニューから「On Action」にメソッド名を設定しますが、<br /> fxmlを直接修正しても問題ありません。</p> <p>Smaple.fxml</p> <pre><code><?xml version="1.0" encoding="UTF-8"?> <import javafx.scene.control.Button> <import javafx.scene.control.ComboBox> <import javafx.scene.control.Label> <import javafx.scene.control.TableColumn> <import javafx.scene.control.TableView> <import javafx.scene.control.TextField> <import javafx.scene.layout.AnchorPane> <import javafx.scene.control.cell.PropertyValueFactory> <AnchorPane fx:id="mainPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="350.0" prefWidth="530.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.SampleController"> <children> <Label fx:id="lbName" layoutX="14.0" layoutY="33.0" text="名前:" /> <TextField fx:id="txName" layoutX="58.0" layoutY="29.0" /> <Label fx:id="lbKind" layoutX="221.0" layoutY="33.0" text="種別:" /> <ComboBox fx:id="cbKind" layoutX="264.0" layoutY="29.0" prefWidth="150.0" /> <Button fx:id="btSearch" layoutX="456.0" layoutY="29.0" mnemonicParsing="false" onAction="#btSearchButtonActionHandle" text="検索" /> <TableView fx:id="tvCat" layoutX="14.0" layoutY="63.0" prefHeight="273.0" prefWidth="500.0"> <columns> <TableColumn maxWidth="50.0" minWidth="50.0" prefWidth="50.0" resizable="false" text="No"> <cellValueFactory><PropertyValueFactory property="no"/></cellValueFactory> </TableColumn> <TableColumn maxWidth="100.0" minWidth="100.0" prefWidth="100.0" text="名前" > <cellValueFactory><PropertyValueFactory property="name"/></cellValueFactory> </TableColumn> <TableColumn maxWidth="40.0" minWidth="40.0" prefWidth="40.0" text="性別" > <cellValueFactory><PropertyValueFactory property="sex"/></cellValueFactory> </TableColumn> <TableColumn maxWidth="40.0" minWidth="40.0" prefWidth="40.0" text="年齢" > <cellValueFactory><PropertyValueFactory property="age"/></cellValueFactory> </TableColumn> <TableColumn minWidth="120.0" prefWidth="120.0" text="種別" > <cellValueFactory><PropertyValueFactory property="kindCd"/></cellValueFactory> </TableColumn> <TableColumn minWidth="145.0" prefWidth="147.0" text="好物" > <cellValueFactory><PropertyValueFactory property="favorite"/></cellValueFactory> </TableColumn> </columns> <columnResizePolicy> <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" /> </columnResizePolicy> </TableView> </children> </AnchorPane> </code></pre> <h3 id="CSSの修正"><a href="#CSS%E3%81%AE%E4%BF%AE%E6%AD%A3">CSSの修正</a></h3> <p><span class=" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z9z84zrpz78zez89zz80zz74zz70ziz73z2qz76zgqnz66z0uyz82zz89zz78zz83zhjez73zj">application.css<br /> </span></p> <pre><code> /* JavaFX CSS - Leave this comment until you have at least create one rule which uses -fx-Property */ .root { -fx-font-family: "Meiryo"; } </code></pre> <h3 id="TableViewの型を変更"><a href="#TableView%E3%81%AE%E5%9E%8B%E3%82%92%E5%A4%89%E6%9B%B4">TableViewの型を変更</a></h3> <p>SampleController.java</p> <p>クラスに定義されているメンバーの型を新規作成した TblCat に変更します。</p> <pre><code> /** テーブルビュー:一覧 */ @FXML private TableView<TblCat> tvCat; </code></pre> <h3 id="検索ボタンクリック時のメソッドを追加"><a href="#%E6%A4%9C%E7%B4%A2%E3%83%9C%E3%82%BF%E3%83%B3%E3%82%AF%E3%83%AA%E3%83%83%E3%82%AF%E6%99%82%E3%81%AE%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%82%92%E8%BF%BD%E5%8A%A0">検索ボタンクリック時のメソッドを追加</a></h3> <p>SampleController.java(メソッドのみ抜粋)</p> <pre><code> /** * 検索ボタンアクションハンドラー. * * @param ev */ @FXML public void btSearchButtonActionHandle(ActionEvent ev) { try { DBAccess dba = new DBAccess(); ResultSet rs = dba.executeQuery("SELECT * FROM TBLCAT ORDER BY NO"); // 取得したデータを追加 ObservableList<TblCat> list = FXCollections.observableArrayList(); while (rs != null &amp;&amp; rs.next()) { TblCat cat = new TblCat(); cat.setNo(rs.getString("NO")); cat.setName(rs.getString("NAME")); cat.setSex(rs.getString("SEX")); cat.setAge(rs.getString("AGE")); cat.setKindCd(rs.getString("KIND_CD")); cat.setFavorite(rs.getString("FAVORITE")); list.add(cat); } tvCat.setItems(list); } catch (SQLException e) { // TODO 自動生成された catch ブロック e.printStackTrace(); } catch (Exception e) { // TODO 自動生成された catch ブロック e.printStackTrace(); } } </code></pre> <p> </p> <h2 id="起動してみる"><a href="#%E8%B5%B7%E5%8B%95%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B">起動してみる</a></h2> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/09/JavaFxTblView003.jpg" alt="検索" /></p> <p>起動後、検索ボタンをクリックします。</p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/09/JavaFxTblView004.jpg" alt="データが表示される" /></p> <p>無事にデータが表示されました。</p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>とりあえず検索の条件などは無視してデータを表示してみました。</p> <p>次回は、検索条件の設定などをやっていきたいと思います。</p> <p>ではでは。</p> doraxdora tag:crieit.net,2005:PublicArticle/15694 2020-01-24T09:43:29+09:00 2020-01-24T09:43:29+09:00 https://crieit.net/posts/JavaFX-Oracle 【JavaFX】Oracleに接続して取得したデータをコンボボックスに設定する <p>前回に引き続き、JavaFXです。<br /> 今回は Oracle からデータを取得してコンボボックスに設定します。</p> <p>利用するテーブルや Oracle のインストールなどは次の記事を参照してください。</p> <p><a target="_blank" rel="nofollow noopener" href="https://www.doraxdora.com/blog/2017/08/31/post-2304/" target="_blank" rel="noopener noreferrer">Oracle Database Express Edition 11g Release 2 のインストールからテーブル作成まで</a></p> <p>Swing でやったのとほぼほぼ同じです。</p> <p>プログラムは前回のものを流用します。</p> <p><a target="_blank" rel="nofollow noopener" href="https://www.doraxdora.com/blog/2017/09/28/post-2615/" target="_blank" rel="noopener noreferrer">【JavaFX】コンボボックスに項目を設定する</a></p> <h2 id="ライブラリの追加"><a href="#%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%81%AE%E8%BF%BD%E5%8A%A0">ライブラリの追加</a></h2> <p>Oracle からデータを取得するために、ライブラリを追加します。<br /> パッケージ・エクスプローラーからプロジェクトを右クリックし、「プロパティ」を開きます。</p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/09/JavaFxOrclCmb000.jpg" alt="外部 JARの追加" /></p> <p>「Javaのビルドパス」メニューを選択し、「ライブラリー」タブを表示、<br /> 「外部 JAR の追加」ボタンをクリックします。</p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/09/JavaFxOrclCmb001.jpg" alt="外部ファイルの選択" /></p> <p>ファイル選択ダイアログが表示されるので、<br /> Oracle のインストールディレクトリから対象のファイルが格納されているフォルダを開きます。</p> <p>デフォルト(Oracle 11g XE)の場合は次の場所に格納されています。</p> <pre><code>C:\oraclexe\app\oracle\product\11.2.0\server\jdbc\lib </code></pre> <p>ライブラリフォルダーに格納されている「ojdbc6.jar」を開きます。</p> <h2 id="パッケージの作成"><a href="#%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%81%AE%E4%BD%9C%E6%88%90">パッケージの作成</a></h2> <p>次の2つのパッケージを作成します。</p> <pre><code>jp.co.doraxdora.common jp.co.doraxdora.dto </code></pre> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/09/JavaFxOrclCmb002.jpg" alt="パッケージの作成" /></p> <p>パッケージ・エクスプローラーで「src」を右クリック>「新規」>「パッケージ」を選択します。</p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/09/JavaFxOrclCmb003.jpg" alt="パッケージ名の入力" /></p> <p>名前に「jp.co.doraxdora.common」を入力して「完了」ボタンをクリックします。<br /> 同様に「jp.co.doraxdora.dto」も作成します。</p> <p> </p> <h2 id="クラスの作成"><a href="#%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%AE%E4%BD%9C%E6%88%90">クラスの作成</a></h2> <p>次の2つのクラスをそれぞれのパッケージに作成します。</p> <pre><code>jp.co.doraxdora.common.DBAccess.java jp.co.doraxdora.dto.MstKind.java </code></pre> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/09/JavaFxOrclCmb004.jpg" alt="クラスの作成" /></p> <p>パッケージ・エクスプローラーでパッケージを右クリック>「新規」>「クラス」を選択します。</p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/09/JavaFxOrclCmb005.jpg" alt="クラス名の入力" /></p> <p>名前に「DBAccess」を入力して「完了」ボタンをクリックします。<br /> 同様に「MstKind」も作成します。</p> <h3 id="実装"><a href="#%E5%AE%9F%E8%A3%85">実装</a></h3> <p>DBAccess.java</p> <pre><code> package jp.co.doraxdora.common; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.List; import oracle.jdbc.pool.OracleDataSource; /** * @author doraxdora * */ public class DBAccess { private static String DB_URL = "jdbc:oracle:thin:USER01/USER01@localhost:1521:XE"; private static Connection con = null; /** * コンストラクタ. * * @throws Exception */ public DBAccess() throws Exception{ super(); // ドライバのロード OracleDataSource ds = new OracleDataSource(); ds.setURL(DB_URL); // DB接続 con = ds.getConnection(); } /** * SQLを実行して結果を取得します. * @param sql * @return */ public ResultSet executeQuery(String sql) throws Exception { PreparedStatement stmt = con.prepareStatement(sql); return stmt.executeQuery(); } /** * パラメータを指定してSQLを実行し、結果を取得します. * * @param sql * @param param * @return * @throws Exception */ public ResultSet executeQuery(String sql, List<Object> param) throws Exception { PreparedStatement stmt = con.prepareStatement(sql); for (int i = 0; i < param.size(); i++) { if (param.get(i) instanceof String) { stmt.setString(i, (String) param.get(i)); } else if (param.get(i) instanceof Integer) { stmt.setInt(i, (int) param.get(i)); } } return stmt.executeQuery(); } } </code></pre> <p>MstKind.java</p> <pre><code>/** * */ package jp.co.doraxdora.dto; import java.io.Serializable; /** * MST種別クラス. * * @author doraxdora * */ public class MstKind implements Serializable { /** 種別コード */ private String kindCd; /** 種別名 */ private String kindName; /** * @return kindCd */ public String getKindCd() { return kindCd; } /** * @param kindCd セットする kindCd */ public void setKindCd(String kindCd) { this.kindCd = kindCd; } /** * @return kindName */ public String getKindName() { return kindName; } /** * @param kindName セットする kindName */ public void setKindName(String kindName) { this.kindName = kindName; } /* (非 Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return kindName; } } </code></pre> <p>JavaFX の ComboBox の実装が、<br /> toString()メソッドを利用して表示文字列を取得しているため、<br /> toString()メソッドをオーバーライドし、表示するメンバーの値を返すようにする必要があります。</p> <h2 id="コントローラーの修正"><a href="#%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%A9%E3%83%BC%E3%81%AE%E4%BF%AE%E6%AD%A3">コントローラーの修正</a></h2> <h3 id="インポート文の追加およびメンバー型の変更"><a href="#%E3%82%A4%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%88%E6%96%87%E3%81%AE%E8%BF%BD%E5%8A%A0%E3%81%8A%E3%82%88%E3%81%B3%E3%83%A1%E3%83%B3%E3%83%90%E3%83%BC%E5%9E%8B%E3%81%AE%E5%A4%89%E6%9B%B4">インポート文の追加およびメンバー型の変更</a></h3> <p>SampleController.java(変更箇所のみ抜粋)</p> <pre><code>// インポート文追加 import jp.co.doraxdora.common.DBAccess; import jp.co.doraxdora.dto.MstKind; public class SampleController implements Initializable{ /** コンボボックス:名前 */ // String から MstKind のリストに変更 // アクセサも修正が必要 @FXML //private ComboBox<String> cbKind; private ComboBox<MstKind> cbKind; /** * @return cbKind */ public ComboBox<MstKind> getCbKind() { return cbKind; } /** * @param cbKind セットする cbKind */ public void setCbKind(ComboBox<MstKind> cbKind) { this.cbKind = cbKind; } ) </code></pre> <h3 id="初期化処理の修正"><a href="#%E5%88%9D%E6%9C%9F%E5%8C%96%E5%87%A6%E7%90%86%E3%81%AE%E4%BF%AE%E6%AD%A3">初期化処理の修正</a></h3> <p>SampleController.java(メソッドのみ抜粋)</p> <pre><code> /* * (非 Javadoc) * @see javafx.fxml.Initializable#initialize(java.net.URL, java.util.ResourceBundle) */ @Override public void initialize(URL location, ResourceBundle resources) { try { DBAccess dba = new DBAccess(); ResultSet rs = dba.executeQuery("SELECT * FROM MSTKIND ORDER BY KIND_CD"); // 指定なしを追加 MstKind empty = new MstKind(); empty.setKindCd("-1"); empty.setKindName("指定なし"); cbKind.getItems().add(empty); // 取得したデータを追加 while (rs != null &amp;&amp; rs.next()) { MstKind kind = new MstKind(); kind.setKindCd(rs.getString("KIND_CD")); kind.setKindName(rs.getString("KIND_NAME")); cbKind.getItems().add(kind); } // 初期選択状態を設定 cbKind.getSelectionModel().select(0); } catch (SQLException e) { // TODO 自動生成された catch ブロック e.printStackTrace(); } catch (Exception e) { // TODO 自動生成された catch ブロック e.printStackTrace(); } } </code></pre> <h2 id="起動してみる"><a href="#%E8%B5%B7%E5%8B%95%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B">起動してみる</a></h2> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/09/JavaFxOrclCmb006.jpg" alt="起動した画面" /></p> <p>内容は前回のものと変わりませんが、<br /> 無事に表示することができました。</p> <p>次回は一覧にデータ表示するところまでやってみたいと思います。</p> <p>ではでは。</p> doraxdora tag:crieit.net,2005:PublicArticle/15669 2020-01-09T09:39:32+09:00 2020-01-09T09:39:32+09:00 https://crieit.net/posts/Swing-Oracle-JTable 【Swing】Oracleに接続して取得したデータをJTable に表示してみる <p>前回に引き続き、Swingを弄ってみます。<br /> 今回はWPFの時と同様、猫の一覧を表示しました。</p> <p>プログラムは前回のものを流用します。<br /> <a target="_blank" rel="nofollow noopener" href="https://www.doraxdora.com/blog/2017/09/09/2400/" target="_blank" rel="noopener noreferrer" data-blogcard="1">【Swing】Oracleに接続して取得したデータをコンボボックスに設定する</a></p> <h2 id="画面の変更"><a href="#%E7%94%BB%E9%9D%A2%E3%81%AE%E5%A4%89%E6%9B%B4">画面の変更</a></h2> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/09/SwingJTable000.jpg" alt="JTableの配置" /></p> <p>JScrollPane、JTableを配置します。<br /> こうすることにより、JTableにヘッダー、スクロールバーが表示されるようになります。</p> <h2 id="プログラムの修正"><a href="#%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%81%AE%E4%BF%AE%E6%AD%A3">プログラムの修正</a></h2> <h3 id="新規クラス(インナー)の追加"><a href="#%E6%96%B0%E8%A6%8F%E3%82%AF%E3%83%A9%E3%82%B9%EF%BC%88%E3%82%A4%E3%83%B3%E3%83%8A%E3%83%BC%EF%BC%89%E3%81%AE%E8%BF%BD%E5%8A%A0">新規クラス(インナー)の追加</a></h3> <p>検索ボタン押下時の処理を追加します。<br /> イベントは、「ActionListener」を実装したクラスで行います。</p> <p>MainForm.java</p> <pre><code> /** * 検索ボタンアクションリスナークラス * * @author doraxdora * */ public class SearchActionListener implements ActionListener { /** * イベントハンドラ. * */ @Override public void actionPerformed(ActionEvent event) { if (event.getSource().equals(btnSearch)) { try { // SQL文の組み立て // 画面で指定された条件を組み込む String sql = "SELECT C.NO" + ", C.NAME" + ", C.SEX" + ", C.AGE" + ", K.KIND_NAME" + ", C.FAVORITE" + " FROM TBLCAT C" + " LEFT OUTER JOIN MSTKIND K ON (" + " C.KIND_CD = K.KIND_CD" + " )"; String where = ""; String searchName = txSearchName.getText(); if (searchName != null &amp;&amp; !searchName.equals("")) { where = " WHERE C.NAME LIKE '" + searchName + "%'"; } String searchKind = (String)cbSearchKind.getSelectedItem(); if (searchKind != null &amp;&amp; !searchKind.equals("指定なし")) { if (where != "") { where += " AND"; } else { where += " WHERE"; } where += " K.KIND_NAME = '" + searchKind + "'"; } sql += where; sql += " ORDER BY C.NO"; // データを取得し、JTableにセットする TableModel の形に編集 DBAccess dba = new DBAccess(); ResultSet rs = dba.executeQuery(sql); List<String[]> list = new ArrayList<String[]>(); while (rs != null &amp;&amp; rs.next()) { String[] items = new String[6]; items[0] = rs.getString("NO"); items[1] = rs.getString("NAME"); items[2] = rs.getString("SEX"); items[3] = rs.getString("AGE"); items[4] = rs.getString("KIND_NAME"); items[5] = rs.getString("FAVORITE"); list.add(items); } // JTable にセット String[] columnHeader = {"No","名前","性別","年齢","種別","好物"}; DefaultTableModel tm = new DefaultTableModel((String[][])list.toArray(new String[0][0]), columnHeader); tblCatData.setModel(tm); } catch (Exception e) { System.out.println(e.getMessage()); } } } } </code></pre> <p> </p> <h3 id="初期化処理の修正"><a href="#%E5%88%9D%E6%9C%9F%E5%8C%96%E5%87%A6%E7%90%86%E3%81%AE%E4%BF%AE%E6%AD%A3">初期化処理の修正</a></h3> <p>少し整理しました。<br /> あとは検索ボタン押下時の処理に、作成したクラスをセットします。</p> <p>MainForm.java</p> <pre><code> /** * 画面生成処理. * */ public MainForm() { // メインパネル setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 480, 304); mainPanel = new JPanel(); mainPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); setContentPane(mainPanel); mainPanel.setLayout(new BorderLayout(0, 0)); JPanel panel = new JPanel(); FlowLayout flowLayout = (FlowLayout) panel.getLayout(); flowLayout.setHgap(10); flowLayout.setAlignment(FlowLayout.LEFT); mainPanel.add(panel, BorderLayout.NORTH); // 名前ラベル JLabel label = new JLabel("名前:"); panel.add(label); // 名前テキストボックス txSearchName = new JTextField(); panel.add(txSearchName); txSearchName.setColumns(10); // 種別ラベル JLabel label_1 = new JLabel("種別:"); panel.add(label_1); // 種別コンボボックス cbSearchKind = new JComboBox<String>(); cbSearchKind.setMinimumSize(new Dimension(100, 19)); cbSearchKind.setBounds(195, 7, 119, 19); panel.add(cbSearchKind); // 検索ボタン btnSearch = new JButton("検索"); // 検索ボタン押下時の処理としてインナークラスをセット btnSearch.addActionListener(new SearchActionListener()); panel.add(btnSearch); // スクロールパネル // JTableは基本スクロールパネルとセットで使用する // 縦横のスクロールおよび、ヘッダが表示されるようになります。 scrollPane = new JScrollPane(); mainPanel.add(scrollPane, BorderLayout.CENTER); // 猫一覧テーブル tblCatData = new JTable(); tblCatData.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); scrollPane.setViewportView(tblCatData); } </code></pre> <p> </p> <h2 id="起動してみる"><a href="#%E8%B5%B7%E5%8B%95%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B">起動してみる</a></h2> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/09/SwingJTable001.jpg" alt="起動後画面" /></p> <p>起動後の画面です。</p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/09/SwingJTable002.jpg" alt="検索結果1" /></p> <p>検索条件を指定しないで検索した結果。</p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/09/SwingJTable003.jpg" alt="検索結果2" /></p> <p>名前を指定して検索した結果。</p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/09/SwingJTable004.jpg" alt="検索結果3" /></p> <p>種別を指定して検索した結果。</p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>Swingはひとまずここまでにするかもしれません。<br /> 次回は Java FX なんかもやってみようかなーとか思っています。</p> <p>ではでは。</p> doraxdora tag:crieit.net,2005:PublicArticle/15668 2020-01-09T09:37:13+09:00 2020-01-09T09:37:13+09:00 https://crieit.net/posts/Swing-Oracle 【Swing】Oracleに接続して取得したデータをコンボボックスに設定する <p>今回は、Oracleからデータを取得してコンボボックスに設定してみたいと思います。</p> <p>プロジェクトは前回のものを流用します。</p> <p><a target="_blank" rel="nofollow noopener" href="https://www.doraxdora.com/blog/2017/08/26/post-2203/" target="_blank" rel="noopener noreferrer">【Swing】eclipse に Swingプラグインをインストールして Hello Wolrd してみる</a></p> <h2 id="新規クラスの追加"><a href="#%E6%96%B0%E8%A6%8F%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%AE%E8%BF%BD%E5%8A%A0">新規クラスの追加</a></h2> <h3 id="パッケージの作成"><a href="#%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%81%AE%E4%BD%9C%E6%88%90">パッケージの作成</a></h3> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/09/SwingCombo000.jpg" alt="" /><br /> パッケージ・エクスプローラーから「src」を右クリックし、「新規」>「パッケージ」を選択します。</p> <div class="mceTemp"></div> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/09/SwingCombo001.jpg" alt="パッケージ作成" /></p> <p>パッケージ名を入力し、「完了」ボタンをクリックします。<br /> 今回は「jp.co.doraxdora.common」としました。</p> <h3 id="クラスの作成"><a href="#%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%AE%E4%BD%9C%E6%88%90">クラスの作成</a></h3> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/09/SwingCombo002.jpg" alt="クラス作成" /></p> <p>パッケージ・エクスプローラーから作成したパッケージを右クリックし、<br /> 「新規」>「クラス」を選択します。</p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/09/SwingCombo003.jpg" alt="クラス作成" /></p> <p>クラス名を入力し、「完了」ボタンをクリックします。<br /> 今回は「DBAccess」としました。</p> <p>DBAccess.java</p> <pre><code> /** * */ package jp.co.doraxdora.common; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.List; import oracle.jdbc.pool.OracleDataSource; /** * @author doraxdora * */ public class DBAccess { private static String DB_URL = "jdbc:oracle:thin:USER01/USER01@localhost:1521:XE"; private static Connection con = null; /** * コンストラクタ. * * @throws Exception */ public DBAccess() throws Exception{ super(); // ドライバのロード OracleDataSource ds = new OracleDataSource(); ds.setURL(DB_URL); // DB接続 con = ds.getConnection(); } /** * SQLを実行して結果を取得します. * @param sql * @return */ public ResultSet executeQuery(String sql) throws Exception { PreparedStatement stmt = con.prepareStatement(sql); return stmt.executeQuery(); } /** * パラメータを指定してSQLを実行し、結果を取得します. * * @param sql * @param param * @return * @throws Exception */ public ResultSet executeQuery(String sql, List<Object> param) throws Exception { PreparedStatement stmt = con.prepareStatement(sql); for (int i = 0; i < param.size(); i++) { if (param.get(i) instanceof String) { stmt.setString(i, (String) param.get(i)); } else if (param.get(i) instanceof Integer) { stmt.setInt(i, (int) param.get(i)); } } return stmt.executeQuery(); } } </code></pre> <p> </p> <h3 id="ライブラリの追加"><a href="#%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%81%AE%E8%BF%BD%E5%8A%A0">ライブラリの追加</a></h3> <p>Oracle からデータを取得するために、ライブラリを追加します。<br /> パッケージ・エクスプローラーからプロジェクトを右クリックし、「プロパティ」を開きます。</p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/09/SwingCombo004.jpg" alt="Javaのビルドパス" /></p> <p>「Javaのビルドパス」メニューを選択し、「ライブラリー」タブを表示、<br /> 「外部 JAR の追加」ボタンをクリックします。</p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/09/SwingCombo005.jpg" alt="ファイル選択" /></p> <p>ファイル選択ダイアログが表示されるので、<br /> Oracle のインストールディレクトリから対象のファイルが格納されているフォルダを開きます。</p> <p>デフォルト(Oracle 11g XE)の場合は次の場所に格納されています。</p> <p>C:\oraclexe\app\oracle\product\11.2.0\server\jdbc\lib</p> <p>ライブラリフォルダーに格納されている「ojdbc6.jar」を開きます。</p> <p> </p> <h3 id="画面の修正"><a href="#%E7%94%BB%E9%9D%A2%E3%81%AE%E4%BF%AE%E6%AD%A3">画面の修正</a></h3> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/09/SwingCombo006.jpg" alt="コンポーネントの配置" /></p> <p>WPFの時と同様に、名前ラベル・テキスト、種別ラベル・コンボボックス、ボタンを配置します。</p> <h3 id="プログラムの修正"><a href="#%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%81%AE%E4%BF%AE%E6%AD%A3">プログラムの修正</a></h3> <p>初期表示時に、<br /> Oracle からデータを取得してコンボボックスに設定するように修正します。</p> <p>MainForm.java</p> <pre><code> package jp.co.doraxdora.form; import java.awt.EventQueue; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.border.EmptyBorder; import jp.co.doraxdora.common.DBAccess; public class MainForm extends JFrame { private JPanel contentPane; private JTextField textField; private JComboBox<String> comboBox; /** * Launch the application. */ public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { MainForm frame = new MainForm(); // コンポーネント初期化 frame.initializeComponent(); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); } /** * Create the frame. */ public MainForm() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 462, 304); contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); setContentPane(contentPane); contentPane.setLayout(null); JLabel label = new JLabel("名前:"); label.setBounds(12, 10, 46, 13); contentPane.add(label); textField = new JTextField(); textField.setBounds(47, 7, 96, 19); contentPane.add(textField); textField.setColumns(10); JLabel label_1 = new JLabel("種別:"); label_1.setBounds(159, 10, 56, 13); contentPane.add(label_1); comboBox = new JComboBox(); comboBox.setBounds(195, 7, 119, 19); contentPane.add(comboBox); JButton btnNewButton = new JButton("検索"); btnNewButton.setBounds(345, 6, 91, 21); contentPane.add(btnNewButton); } /** * コンポーネントの初期化処理. * */ private void initializeComponent() throws Exception { DBAccess dba = new DBAccess(); ResultSet rs = dba.executeQuery("SELECT * FROM MSTKIND ORDER BY KIND_CD"); List<String> list = new ArrayList<String>(); while (rs != null &amp;&amp; rs.next()) { list.add((rs.getString("KIND_NAME"))); } DefaultComboBoxModel<String> model = new DefaultComboBoxModel<String>((String[])list.toArray(new String[0])); comboBox.setModel(model); } } </code></pre> <p> </p> <h2 id="起動してみる"><a href="#%E8%B5%B7%E5%8B%95%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B">起動してみる</a></h2> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/09/SwingCombo007.jpg" alt="画面" /></p> <p>無事にデータを設定することができました。</p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>ひとまずデータの取得まではできたので、<br /> 次回はデータテーブルを設置して、検索したデータを表示するところをやろうかと思います。</p> <p>ではでは。</p> <p> </p> doraxdora tag:crieit.net,2005:PublicArticle/15538 2019-11-11T10:57:24+09:00 2019-11-11T10:57:24+09:00 https://crieit.net/posts/Oracle-Django-Nginx-uWSGI Oracle無料ティアでDjango+Nginx+uWSGIでサーバを立ててみる <p>Oracle Cloudで常時無料サービスが開始されたので使ってみた。<br /> 構成は、Django+nginx+uWSGI+Oracle Database+Oracle Linux</p> <p>以下の3つの環境を作ってみたので、その時の備忘録。</p> <ul> <li>ローカルの開発環境</li> <li>ローカルでDockerを使った開発環境</li> <li>コンピュート・インスタンスでの本番環境</li> </ul> <p>とりあえず、Djangoの雛形アプリにアクセスできるまでの簡易なので、<br /> SSL対応などは省いてます。</p> <h3 id="Oracle Cloudの常時無料サービス(無料ティア)について"><a href="#Oracle+Cloud%E3%81%AE%E5%B8%B8%E6%99%82%E7%84%A1%E6%96%99%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%28%E7%84%A1%E6%96%99%E3%83%86%E3%82%A3%E3%82%A2%29%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6">Oracle Cloudの常時無料サービス(無料ティア)について</a></h3> <p>新しく常時無料で利用できるようになったサービスたち。<br /> ・<a target="_blank" rel="nofollow noopener" href="https://www.oracle.com/jp/cloud/free/">Oracle Cloud無償ティア | オラクル | Oracle 日本</a></p> <p>利用できるのは、以下のようなもの。</p> <ul> <li>データベース ... 20GBを2つまで</li> <li>コンピュート ... 仮想マシン。1/8 OCPU・1GBを2つまで</li> <li>ストレージ ... 合計100GBの2つのブロック・ボリューム。10GBのオブジェクト・ストレージ</li> </ul> <p>ほかにもロードバランサや監視・通知などある。</p> <p>仮想マシンもデータベースも1アカウントにつき2つまでなので、<br /> 1サービスであれば、ステージング環境と本番環境を用意できそう。</p> <hr /> <h3 id="とりあえずDBを作ってみる"><a href="#%E3%81%A8%E3%82%8A%E3%81%82%E3%81%88%E3%81%9ADB%E3%82%92%E4%BD%9C%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B">とりあえずDBを作ってみる</a></h3> <p>トップ画面から。</p> <p><img width="1367" alt="oracle_1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/dde42040-2f99-5a2a-4824-5894bd4ce59d.png"></p> <p>名前とAdminのパスワードを設定する。<br /> Always FreeもONにしておく。</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/ce050658-f517-7338-ef93-cd0d07893e16.png" alt="oracle_2.png" /></p> <p>「Autonomous Databaseの作成」をクリックすると、プロビジョンがはじまる。<br /> プロビジョンが終わるとこんな感じに。</p> <p><img width="1436" alt="スクリーンショット 2019-11-10 15.59.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/0df9b110-5004-76cd-f942-10780d1c1e39.png"></p> <h5 id="WebブラウザでDBにアクセスしてみる"><a href="#Web%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%81%A7DB%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B">WebブラウザでDBにアクセスしてみる</a></h5> <p>SQL Developer Webからアクセスできる。</p> <p>「DB接続」>「アプリケーション接続」>「SQL Developer Web」にある。<br /> 「アクセスURL」をコピーして、ブラウザに貼り付け。</p> <p><img width="742" alt="oracle_3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/8795616a-9ab4-87a2-cc78-460e9680f30d.png"></p> <p>ログイン画面が表示されるので、DBを作ったときのパスワードを入力。<br /> アカウントは「admin」</p> <p><img width="490" alt="スクリーンショット 2019-11-10 16.00.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/003a489d-23f3-3f50-4cff-a49f674fe002.png"></p> <p>ログインできるとこんな感じ</p> <p><img width="843" alt="スクリーンショット 2019-11-10 16.01.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/485c6462-de41-ad35-6829-33292cce2129.png"></p> <hr /> <h3 id="ローカルの開発環境を作ってみる"><a href="#%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%81%AE%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83%E3%82%92%E4%BD%9C%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B">ローカルの開発環境を作ってみる</a></h3> <p>とりあえず、開発用にローカル環境で<code>python manage.py runserver</code>できるようにする。<br /> ローカルの環境はmacOS Mojave(10.14.6)</p> <h4 id="まずは、Djangoの雛形を作成する"><a href="#%E3%81%BE%E3%81%9A%E3%81%AF%E3%80%81Django%E3%81%AE%E9%9B%9B%E5%BD%A2%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B">まずは、Djangoの雛形を作成する</a></h4> <pre><code class="shell"># pythonのバージョンは3.7.3 $ python3 -V Python 3.7.3 # ディレクトリの作成 $ mkdir sample $ cd sample/ # 仮想環境の作成 $ python3 -m venv venv $ source venv/bin/activate # djangoのインストール $ pip install --upgrade pip $ pip install django # djangoプロジェクトの作成 $ django-admin startproject myproject $ cd myproject $ python manage.py migrate # 起動 $ python manage.py runserver </code></pre> <p>これでとりあえず、デフォルトのデータベース(SQLite)で立ち上がるとこまで完成。</p> <p><img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/e2a487cd-a318-d09c-e9f3-899f598eee09.png" /></p> <h4 id="ローカルでOracleDBを使えるようにする"><a href="#%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%81%A7OracleDB%E3%82%92%E4%BD%BF%E3%81%88%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%81%99%E3%82%8B">ローカルでOracleDBを使えるようにする</a></h4> <h5 id="Oracle Instant Clientのインストール"><a href="#Oracle+Instant+Client%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">Oracle Instant Clientのインストール</a></h5> <p>OracleDBを使うためには、Oracle Instant Clientが必要なので、<br /> 以下からダウンロードしてインストールする。<br /> ・<a target="_blank" rel="nofollow noopener" href="https://www.oracle.com/database/technologies/instant-client/downloads.html">Oracle Instant Client Downloads</a></p> <p>Macだったので、「<a target="_blank" rel="nofollow noopener" href="https://www.oracle.com/database/technologies/instant-client/macos-intel-x86-downloads.html">Instant Client for macOS (Intel x86)</a>」の「Basic Light Package」を選択</p> <pre><code class="sh">## インストールするディレクトリを作成 $ sudo mkdir -p /opt/oracle ## インストールしたファイルを展開 $ sudo unzip ~/Downloads/instantclient-basiclite-macos.x64-19.3.0.0.0dbru.zip -d /opt/oracle ## ライブラリを参照できるように${HOME}/libにリンクを追加 $ mkdir ~/lib $ ls -s /opt/oracle/instantclient_19_3/libclntsh.dylib ~/lib/ $ cp /opt/oracle/instantclient_19_3/lib* ~/lib/ </code></pre> <h5 id="環境変数にインストールした場所を設定"><a href="#%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0%E3%81%AB%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%97%E3%81%9F%E5%A0%B4%E6%89%80%E3%82%92%E8%A8%AD%E5%AE%9A">環境変数にインストールした場所を設定</a></h5> <pre><code class="shell">echo "export ORACLE_HOME=/opt/oracle/instantclient_19_3" >> ~/.bashrc source ~/.bashrc </code></pre> <h5 id="認証情報の配置"><a href="#%E8%AA%8D%E8%A8%BC%E6%83%85%E5%A0%B1%E3%81%AE%E9%85%8D%E7%BD%AE">認証情報の配置</a></h5> <p>Oracle Cloudの「Autonomous Database」>「Autonomous Databaseの詳細」にある<br /> 「DB接続」からウォレットをダウンロードしてくる。</p> <p><img width="753" alt="oracle_4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/6b23b62d-623d-2fad-ea3b-a95c11d4d605.png"></p> <p>ファイル名は「<code>Wallet_<データベース名>.zip</code>」。<br /> 今回はデータベース名が<code>sample</code>なので、<code>Wallet_sample.zip</code>となる。</p> <pre><code class="shell">## 認証ファイルを配置するディレクトリを作成 $ mkdir -p /opt/oracle/instantclient_19_3/network/admin ## ダウンロードしたウォレットを展開して配置 $ sudo unzip ~/Downloads/Wallet_sample.zip -d ${ORACLE_HOME}/network/admin Archive: ~/Downloads/Wallet_sample.zip inflating: /opt/oracle/instantclient_19_3/network/admin/cwallet.sso inflating: /opt/oracle/instantclient_19_3/network/admin/tnsnames.ora inflating: /opt/oracle/instantclient_19_3/network/admin/truststore.jks inflating: /opt/oracle/instantclient_19_3/network/admin/ojdbc.properties inflating: /opt/oracle/instantclient_19_3/network/admin/sqlnet.ora inflating: /opt/oracle/instantclient_19_3/network/admin/ewallet.p12 inflating: /opt/oracle/instantclient_19_3/network/admin/keystore.jks </code></pre> <h5 id="cx_Oracle(pythonライブラリ)のインストール"><a href="#cx_Oracle%28python%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%29%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">cx_Oracle(pythonライブラリ)のインストール</a></h5> <p>Oracle Databaseのpythonライブラリをインストールする</p> <pre><code>$ pip install cx_Oracle </code></pre> <h5 id="settings.pyの設定"><a href="#settings.py%E3%81%AE%E8%A8%AD%E5%AE%9A">settings.pyの設定</a></h5> <p>settings.pyをOracleように変更。<br /> <code>NAME</code>には、TNS名のどれかを指定する。</p> <p><img width="753" alt="oracle_4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/6b23b62d-623d-2fad-ea3b-a95c11d4d605.png"></p> <p>今回は一番上の<code>sample_HIGH</code>を選択。</p> <pre><code class="python">DATABASES = { 'default': { 'ENGINE': 'django.db.backends.oracle', 'NAME': 'sample_HIGH', 'USER': 'admin', 'PASSWORD': '<DB作成時に入力したパスワード>', } } </code></pre> <p>マイグレーションをもう一度実行してみて、接続できるか確認。</p> <pre><code class="shell">$ python manage.py migrate </code></pre> <p>マイグレーションが成功すると、Webブラウザ上のSQL Developerでも確認できる。</p> <p><img width="926" alt="スクリーンショット 2019-11-10 16.35.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/53393a83-0772-2f8e-9814-6d2ddbe203bd.png"></p> <p>これで、とりあえず、開発できるようになった(<em>´ω`</em>)</p> <hr /> <h3 id="ローカルでDockerを使った開発環境を作ってみる"><a href="#%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%81%A7Docker%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83%E3%82%92%E4%BD%9C%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B">ローカルでDockerを使った開発環境を作ってみる</a></h3> <p>実際にデプロイする際は、NginxとuWSGIを利用するので、<br /> それを試せる環境をDockerで構築する。</p> <h4 id="Django側の変更"><a href="#Django%E5%81%B4%E3%81%AE%E5%A4%89%E6%9B%B4">Django側の変更</a></h4> <p>nginx+uWSGIで動かすために、いくつか変更。</p> <h5 id="1. STATIC_ROOTとALLOWED_HOSTS設定"><a href="#1.+STATIC_ROOT%E3%81%A8ALLOWED_HOSTS%E8%A8%AD%E5%AE%9A">1. STATIC_ROOTとALLOWED_HOSTS設定</a></h5> <p>settings.pyを以下の感じに変更。<br /> ログファイルも出るように変更。</p> <pre><code class="diff">-ALLOWED_HOSTS = [] +ALLOWED_HOSTS = ["127.0.0.1"] ... STATIC_URL = '/static/' +STATIC_ROOT = os.path.join(BASE_DIR, "static/") +# for logging +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + + 'formatters': { + 'standard': { + 'format': "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s", + 'datefmt': "%d/%b/%Y %H:%M:%S" + }, + }, + 'handlers': { + 'file': { + 'level': 'INFO', + 'class': 'logging.handlers.RotatingFileHandler', + 'filename': 'django.log', + 'maxBytes': 50000, + 'backupCount': 2, + 'formatter': 'standard', + }, + }, + 'loggers': { + 'django': { + 'handlers': ['file'], + 'level': 'DEBUG', + 'propagate': True, + }, + }, +} </code></pre> <h5 id="2. staticディレクトリを作成&amp;配置"><a href="#2.+static%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA%E3%82%92%E4%BD%9C%E6%88%90%26amp%3B%E9%85%8D%E7%BD%AE">2. staticディレクトリを作成&配置</a></h5> <p>manage.pyと同じ場所に作成し、<br /> django-adminのcssとかを配置</p> <pre><code class="shell">$ mkdir static $ python manage.py collectstatic </code></pre> <h4 id="Docker用の資材を配置"><a href="#Docker%E7%94%A8%E3%81%AE%E8%B3%87%E6%9D%90%E3%82%92%E9%85%8D%E7%BD%AE">Docker用の資材を配置</a></h4> <pre><code class="shell"># Docker用の資材の配置場所を作成 $ mkdir docker # 資格情報の配置 $ mkdir docker/wallet $ unzip ~/Downloads/Wallet_sample.zip -d docker/wallet/ Archive: ~/Downloads/Wallet_sample.zip inflating: wallet/cwallet.sso inflating: wallet/tnsnames.ora inflating: wallet/truststore.jks inflating: wallet/ojdbc.properties inflating: wallet/sqlnet.ora inflating: wallet/ewallet.p12 inflating: wallet/keystore.jks # NginxやuWSGIの設定ファイルは以下に配置 $ mkdir docker/conf $ touch docker/conf/requirements.txt $ touch docker/conf/myproject_nginx.conf $ touch docker/conf/myproject_uwsgi.ini $ touch docker/conf/uwsgi.service # Dockerfireとdocker-compose.ymlを配置 $ touch docker/Dockerfile $ touch docker-compose.yml </code></pre> <p>ディレクトリ的にはこんな感じ。</p> <pre><code>. ├── docker/ │   ├── conf/ │   │   ├── myproject_nginx.conf │   │   ├── myproject_uwsgi.ini │   │   └── uwsgi.service │   ├── wallet │   │   ├── ... │   │   └── tnsnames.ora │   ├── Dockerfile │   └── requirements.txt ├── myproject/ │   ├── myproject/ │   │   ├── settings.py │   │   └── wsgi.py │   ├── static/ │   └── manage.py ├── venv/ └── docker-compose.yml </code></pre> <p>各ファイルの中身は以下の感じ。</p> <h5 id="docker-compose.yml"><a href="#docker-compose.yml">docker-compose.yml</a></h5> <pre><code class="yml">version: '2' services: web: build: "./docker" volumes: # djangoアプリを/var/www配下にマウント - ./myproject:/var/www/myproject ports: # 80および8000ポートを開けておく - "80:80" - "8000:8000" # systemctlを使うので特権を有効にしておく privileged: true command: /sbin/init </code></pre> <h5 id="docker/Dockerfile"><a href="#docker%2FDockerfile">docker/Dockerfile</a></h5> <pre><code class="dockerfile"># Oracle Cloud Infrastructureでも # OracleLinuxを使うのでoraclelinuxのイメージを使う FROM oraclelinux:7 ### ENV ENV ORACLE_HOME "/usr/lib/oracle/18.3" ### INSTALL ORACLE DATABASE # oracle-instantclientを利用するために、2つリポジトリを有効化 RUN yum install -y oracle-release-el7 oracle-softwarecollection-release-el7 RUN yum install -y oracle-instantclient18.3-basiclite RUN echo /usr/lib/oracle/18.3/client64/lib > /etc/ld.so.conf.d/oracle-instantclient.conf RUN mkdir -p ${ORACLE_HOME}/network/admin COPY wallet/* ${ORACLE_HOME}/network/admin/ ### INSTALL PYTHON # python3-develを利用するために、ol7_optional_latestを有効化 RUN yum-config-manager --enable ol7_optional_latest RUN yum install -y python3 python3-devel gcc ### CREATE VIRTUAL ENV RUN mkdir /var/www/ RUN mkdir /var/www/myproject WORKDIR /var/www/ RUN python3 -m venv venv # 作成した仮想環境(venv)にactivateする ENV PATH="/var/www/venv/bin:$PATH" COPY requirements.txt /var/www/ RUN pip install -r requirements.txt #### INSTALL NGINX RUN yum install -y nginx COPY conf/myproject_nginx.conf /etc/nginx/conf.d/ RUN systemctl enable nginx RUN chown -R nginx.nginx /var/www RUN chmod 755 /var/www ### SETUP uWSGI Emperor mode RUN mkdir /etc/uwsgi RUN mkdir /etc/uwsgi/vassals COPY conf/myproject_uwsgi.ini /etc/uwsgi/vassals # uWSGIのログディレクトリを作成 RUN mkdir /var/log/uwsgi RUN chown -R nginx:nginx /var/log/uwsgi # uWSGIをサービスに登録 COPY conf/uwsgi.service /etc/systemd/system/ RUN systemctl enable uwsgi </code></pre> <h5 id="docker/conf/requirements.txt"><a href="#docker%2Fconf%2Frequirements.txt">docker/conf/requirements.txt</a></h5> <pre><code class="txt">Django==2.2.7 cx-Oracle==7.2.3 uWSGI==2.0.18 </code></pre> <h5 id="docker/conf/myproject_nginx.conf"><a href="#docker%2Fconf%2Fmyproject_nginx.conf">docker/conf/myproject_nginx.conf</a></h5> <pre><code class="nginx"># the upstream component nginx needs to connect to upstream django { # myproject_uwsgi.iniで設定したsocketファイルを指定 # unix://<socketファイルのパス> server unix:///var/www/myproject.sock; } # configuration of the server server { listen 80; # IPアドレスを指定。ローカルなので、127.0.0.1を設定 server_name 127.0.0.1; charset utf-8; # Django static location /static { alias /var/www/myproject/static; } # Finally, send all non-media requests to the Django server. location / { include uwsgi_params; uwsgi_pass django; } } </code></pre> <h5 id="docker/conf/myproject_uwsgi.ini"><a href="#docker%2Fconf%2Fmyproject_uwsgi.ini">docker/conf/myproject_uwsgi.ini</a></h5> <pre><code class="ini">[uwsgi] # Djangoプロジェクトのパスを指定 chdir = /var/www/myproject # Djangoプロジェクトのwsgi.pyを指定 module = myproject.wsgi # venvのパスを指定 home = /var/www/venv # process-related settings: master master = true # maximum number of worker processes processes = 10 # socketファイルののパス socket = /var/www/myproject.sock # socketファイルのユーザと権限を設定 chown-socket = nginx:nginx chmod-socket = 666 # clear environment on exit vacuum = true # logfile logto = /var/log/uwsgi/%n.log </code></pre> <h5 id="docker/conf/uwsgi.service"><a href="#docker%2Fconf%2Fuwsgi.service">docker/conf/uwsgi.service</a></h5> <pre><code>[Unit] Description=uWSGI Emperor After=syslog.target [Service] User=nginx Group=nginx # 環境変数の設定 Environment="ORACLE_HOME=/usr/lib/oracle/18.3" Environment="LD_LIBRARY_PAT=${ORACLE_HOME}/client64/lib:$LD_LIBRARY_PATH" Environment="PATH=$PATH:${ORACLE_HOME}/client64/lib" # EmperorモードでuWSGIを実行。venvにあるuwsgiを使う ExecStart=/var/www/venv/bin/uwsgi --master --emperor /etc/uwsgi/vassals --die-on-term --uid nginx --gid nginx --logto /var/log/uwsgi/emperor.log Restart=always KillSignal=SIGQUIT Type=notify StandardError=syslog NotifyAccess=all [Install] WantedBy=multi-user.target </code></pre> <h4 id="Dockerを起動"><a href="#Docker%E3%82%92%E8%B5%B7%E5%8B%95">Dockerを起動</a></h4> <pre><code class="shell"># dockerを立ち上げ $ docker-compose up -d </code></pre> <p>これでうまくビルドされて立ち上がれば、<br /> <code>http://127.0.0.1</code>にアクセスできる。</p> <p><code>myproject_nginx.conf</code>の<code>server_name</code>で、<code>127.0.0.1</code>を指定しているので、<br /> <code>http://127.0.0.1</code>じゃないとDjangoアプリにアクセスできないので注意。</p> <p><code>http://localhost</code>だと、<code>myproject_nginx.conf</code>の設定が適用されず、<br /> nginxのデフォルトページが表示される。</p> <h5 id="よく使うログインとか停止とかはこんな感じ。"><a href="#%E3%82%88%E3%81%8F%E4%BD%BF%E3%81%86%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3%E3%81%A8%E3%81%8B%E5%81%9C%E6%AD%A2%E3%81%A8%E3%81%8B%E3%81%AF%E3%81%93%E3%82%93%E3%81%AA%E6%84%9F%E3%81%98%E3%80%82">よく使うログインとか停止とかはこんな感じ。</a></h5> <pre><code class="shell"># コンテナにログイン $ docker-compose exec web /bin/bash # 停止 $ docker-compose stop # 削除 $ docker-compose rm # Dockerfile ビルド $ docker-compose build # Dockerfile ビルド(キャッシュなし) $ docker-compose build --no-cache # コンテナをせんぶ削除 $ docker rm `docker ps -a -q` </code></pre> <h5 id="うまくいかないときにみるところ"><a href="#%E3%81%86%E3%81%BE%E3%81%8F%E3%81%84%E3%81%8B%E3%81%AA%E3%81%84%E3%81%A8%E3%81%8D%E3%81%AB%E3%81%BF%E3%82%8B%E3%81%A8%E3%81%93%E3%82%8D">うまくいかないときにみるところ</a></h5> <p>以下の場所にログファイルが出力されるので見てみる。</p> <ul> <li><code>/var/log/messages</code> ... systemdのログ</li> <li><code>/var/log/nginx/error.log</code> ... nginxのエラーログ</li> <li><code>/var/log/uwsgi/emperor.log</code> ... uWSGI Emperorのログ</li> <li><code>/var/log/uwsgi/myproject_uwsgi.log</code> ... myproject_uwsgi.iniのログ</li> <li><code>/var/www/myproject/django.log</code> ... Djangoプロジェクトのログ</li> </ul> <p>あとは、「パスが正しいか」「権限、オーナーが正しいか」などを見てみるといいかも。</p> <hr /> <h3 id="コンピュート・インスタンスで公開してみる"><a href="#%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%83%88%E3%83%BB%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%81%A7%E5%85%AC%E9%96%8B%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B">コンピュート・インスタンスで公開してみる</a></h3> <h4 id="仮想インスタンスの作成"><a href="#%E4%BB%AE%E6%83%B3%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%81%AE%E4%BD%9C%E6%88%90">仮想インスタンスの作成</a></h4> <p>ここから選択。</p> <p><img width="1367" alt="oracle_5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/58f5c6f6-a84b-435e-eadf-96a795fe8ba8.png"></p> <p>こんな感じで入力。<br /> 「<strong>パブリックIPアドレスの割当</strong>」を選択しておく。</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/71e54b71-dad2-9b33-3120-73ef26aae734.png" alt="oracle_6.png" /></p> <p>ちゃんと「パブリックIPアドレスの割当」を選択していると、<br /> ここにIPアドレスが表示される</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/2a714a85-2389-506d-4a8c-9197fb9ca208.png" alt="oracle_7.png" /></p> <p>デフォルトのユーザは<code>opc</code>なので、<br /> こんな感じで、sshでログインできる。</p> <pre><code class="shell">$ ssh opc@<IPアドレス> </code></pre> <h4 id="セキュリティルールを設定"><a href="#%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3%E3%83%AB%E3%83%BC%E3%83%AB%E3%82%92%E8%A8%AD%E5%AE%9A">セキュリティルールを設定</a></h4> <p>HTTP(ポート80)でアクセスできるようにセキュリティルールを設定する<br /> ただ、セキュリティルールを設定する場所は少しわかりにくい。。</p> <p>仮想インスタンスの詳細にアクセスして、<br /> 「仮想クラウド・ネットワーク」を選択</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/8c83e806-cb22-481f-a7c4-1903c7766685.png" alt="oracle_8.png" /></p> <p>左下に「ネットワーク・セキュリティ・グループ」を選択。<br /> 「ネットワーク・セキュリティ・グループの作成」を選択すると、追加できるようになる。</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/107254d4-5c9f-155d-5fb2-f9ba13c9d621.png" alt="oracle_9.png" /></p> <p>「名前」と「コンパートメント」に作成を設定</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/4464efc9-a245-3858-707c-811f12a166d9.png" alt="oracle_10.png" /></p> <p>ルールの追加を以下のように設定して、「作成」をクリック</p> <p><img width="1404" alt="oracle_11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/f604553d-7ea4-925d-944b-2410bd920e91.png"></p> <p>これで作成できたので、仮想インスタンスの詳細にもどって、<br /> 「ネットワーク・セキュリティ・グループ」の「編集」を選択</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/8c96405c-539f-9197-40b0-782c30b85079.png" alt="oracle_12.png" /></p> <p>さっき作ったセキュリティグループを設定</p> <p><img width="783" alt="スクリーンショット 2019-11-11 0.19.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/12823048-83d2-1278-68a6-dcd45dace136.png"></p> <h4 id="環境構築"><a href="#%E7%92%B0%E5%A2%83%E6%A7%8B%E7%AF%89">環境構築</a></h4> <p>Dockerfileでやったような感じで、<br /> Django+nginx+uWSGIな環境を構築してく。</p> <p>DockerイメージのOracleLinuxとは違い、</p> <ol> <li>リポジトリが最初から有効化されている</li> <li>SELinuxが有効化されている</li> </ol> <p>という感じなので、ちょっと変更が必要。</p> <h5 id="資材を仮想インスタンスに送る"><a href="#%E8%B3%87%E6%9D%90%E3%82%92%E4%BB%AE%E6%83%B3%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%81%AB%E9%80%81%E3%82%8B">資材を仮想インスタンスに送る</a></h5> <p>Dockerのときに使った資材を仮想インスタンスに送る。</p> <pre><code class="shell">$ scp -r docker opc@<IPアドレス>:~/ $ scp -r myproject/ opc@<IPアドレス>:~/ </code></pre> <p>送信したら、ログインして確認。</p> <pre><code class="shell">$ ssh opc@<IPアドレス> $ pwd /home/opc $ ls docker myproject </code></pre> <p>ログイン後のディレクトリ構成はこんな感じ</p> <pre><code>/home/opc ├── docker/ │   ├── conf/ │   │   ├── myproject_nginx.conf │   │   ├── myproject_uwsgi.ini │   │   └── uwsgi.service │   ├── wallet │   │   ├── ... │   │   └── tnsnames.ora │   ├── Dockerfile │   └── requirements.txt ├── myproject/ │   ├── myproject/ │   │   ├── settings.py │   │   └── wsgi.py │   ├── static/ │   └── manage.py ├── venv/ └── docker-compose.yml </code></pre> <h5 id="設定ファイルの変更"><a href="#%E8%A8%AD%E5%AE%9A%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E5%A4%89%E6%9B%B4">設定ファイルの変更</a></h5> <p>IPアドレスと<code>127.0.0.1</code>にしていたので変更する。</p> <h6 id="~/docker/conf/myproject_nginx.conf"><a href="#%7E%2Fdocker%2Fconf%2Fmyproject_nginx.conf">~/docker/conf/myproject_nginx.conf</a></h6> <pre><code class="diff"> server { - server_name 127.0.0.1; + server_name <IPアドレス>; } </code></pre> <h6 id="~/myproject/myproject/settings.py"><a href="#%7E%2Fmyproject%2Fmyproject%2Fsettings.py">~/myproject/myproject/settings.py</a></h6> <pre><code class="diff">-ALLOWED_HOSTS = ["127.0.0.1"] +ALLOWED_HOSTS = ["<IPアドレス>"] </code></pre> <h5 id="環境構築の実施"><a href="#%E7%92%B0%E5%A2%83%E6%A7%8B%E7%AF%89%E3%81%AE%E5%AE%9F%E6%96%BD">環境構築の実施</a></h5> <pre><code class="shell">$ sudo -s ### INSTALL ORACLE DATABASE $ yum install -y oracle-instantclient18.3-basiclite $ echo /usr/lib/oracle/18.3/client64/lib > /etc/ld.so.conf.d/oracle-instantclient.conf $ mkdir -p /usr/lib/oracle/18.3/network/admin $ /home/opc/docker/wallet/* /usr/lib/oracle/18.3/network/admin/ ### INSTALL PYTHON $ yum install -y python3 python3-devel gcc ### CREATE VIRTUAL ENV $ mkdir /var/www/ $ cp -r /home/opc/myproject /var/www $ cd /var/www/ $ python3 -m venv venv # 作成した仮想環境(venv)にactivateする $ source venv/bin/activate $ pip install -r /home/opc/docker/requirements.txt #### INSTALL NGINX $ yum install -y nginx $ cp /home/opc/docker/conf/myproject_nginx.conf /etc/nginx/conf.d/ $ systemctl enable nginx $ chown -R nginx.nginx /var/www # $ chmod 755 /var/www ### SETUP uWSGI Emperor mode $ mkdir -p /etc/uwsgi/vassals $ cp /home/opc/docker/conf/myproject_uwsgi.ini /etc/uwsgi/vassals # uWSGIのログディレクトリを作成 $ mkdir /var/log/uwsgi $ chown -R nginx:nginx /var/log/uwsgi # uWSGIをサービスに登録 $ cp /home/opc/docker/conf/uwsgi.service /etc/systemd/system/ $ systemctl enable uwsgi ##### ここから仮想インスタンス独自の設定 ### Firewallの設定 # httpを追加する $ firewall-cmd --permanent --add-service=http # firewallを再起動して変更を反映 $ systemctl restart firewalld.service ### SELinuxの設定 $ restorecon -RF /var/www ### サービスの起動 $ systemctl restart nginx $ systemctl restart uwsgi </code></pre> <p>一度、<code>http://<IPアドレス></code>にアクセスして確認してみる。<br /> エラーページが出ていたら、以下を実行</p> <pre><code class="shell"># 監査ログを確認 $ cat /var/log/audit/audit.log | grep nginx | audit2allow -m nginx # ポリシーファイルを作成 $ cat /var/log/audit/audit.log | audit2allow -M nginx # ポリシーファイルを適用 $ semodule -i nginx.pp </code></pre> <p>これで、<code>http://<IPアドレス></code>にアクセスして、<br /> Djangoの画面が表示されて、django-adminの画面が操作できればOK</p> <h1 id="おわりに"><a href="#%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB">おわりに</a></h1> <p>とりあえず、ローカルとインスタンス上の環境が作れたので、<br /> 色々することはできそう(<em>´ω`</em>)</p> <p>SSL対応、権限周りなど、本番としては足りないところがあるので、<br /> そのあたりは他の記事を参照ください〜ヽ(=´▽`=)ノ</p> <h2 id="こんなのつくってます!!"><a href="#%E3%81%93%E3%82%93%E3%81%AA%E3%81%AE%E3%81%A4%E3%81%8F%E3%81%A3%E3%81%A6%E3%81%BE%E3%81%99%21%21">こんなのつくってます!!</a></h2> <p>積読用の読書管理アプリ 『積読ハウマッチ』をリリースしました!<br /> <a target="_blank" rel="nofollow noopener" href="https://tsundoku.site">積読ハウマッチ</a>は、Nuxt.js+Firebaseで開発してます!</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/572d4947-f40b-e4dc-1c9c-bc584cd2a66c.png" width="200"/></p> <p>もしよかったら、遊んでみてくださいヽ(=´▽`=)ノ</p> <p>要望・感想・アドバイスなどあれば、<br /> 公式アカウント(<a target="_blank" rel="nofollow noopener" href="https://twitter.com/MemoryLoverz">@MemoryLoverz</a>)や開発者(<a target="_blank" rel="nofollow noopener" href="https://twitter.com/kira_puka">@kira_puka</a>)まで♪</p> <h1 id="参考にしたサイトさま"><a href="#%E5%8F%82%E8%80%83%E3%81%AB%E3%81%97%E3%81%9F%E3%82%B5%E3%82%A4%E3%83%88%E3%81%95%E3%81%BE">参考にしたサイトさま</a></h1> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://docs.djangoproject.com/ja/2.2/ref/databases/#oracle-notes">データベース | Django ドキュメント | Django</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://oracle.github.io/python-cx_Oracle/">cx_Oracle - Python Interface for Oracle Database</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://cx-oracle.readthedocs.io/en/latest/user_guide/installation.html">cx_Oracle 7 Installation — cx_Oracle 7.3.0-dev documentation</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://www.oracle.com/database/technologies/instant-client/macos-intel-x86-downloads.html#ic_osx_inst">Instant Client for macOS (Intel x86)</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://oracle.github.io/odpi/doc/installation.html#macos">ODPI-C Installation — ODPI-C v3.2.2</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://shase428.hatenablog.jp/entry/2018/01/31/201543">Macでsqlplus使えるようにするメモ - ビットの海</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/oracle/python-cx_Oracle/issues/56">trouble running Oracle_cx on macOS · Issue #56 · oracle/python-cx_Oracle</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://docs.oracle.com/cd/E83857_01/iaas/compute-iaas-cloud/stcsg/accessing-oracle-linux-instance-using-ssh.html#GUID-D313B1A1-FB67-42C7-A7CC-958656A5207F">SSHを使用したOracle Linuxインスタンスへのアクセス</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://cloudii.atomitech.jp/entry/20190417/1555464532">コンピュート・インスタンスに予約済パブリックIPを付与する - Cloudii blog</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/chi9rin/items/af532d0dd9237cc65741#selinux-%E3%81%AE%E5%8B%95%E4%BD%9C%E3%83%A2%E3%83%BC%E3%83%89">SELinux を使おう.使ってくれ. - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://serverfault.com/questions/413397/how-to-set-environment-variable-in-systemd-service">arch linux - How to set environment variable in systemd service? - Server Fault</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/cof123/items/6c9d4b01f0057a9a8de0">EC2にnginx+uwsgi+python でHello World - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/takahirono7/items/fd6f9239f0f88eb65a7c">uwsgiのsystemd化(pyenv環境) - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/yasunori/items/64606e63b36b396cf695#%E3%83%AD%E3%82%B0%E3%83%AD%E3%83%BC%E3%83%86%E3%83%BC%E3%83%88%E3%81%A7%E3%83%AD%E3%82%B0%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E8%A6%8B%E5%A4%B1%E3%82%8F%E3%81%AA%E3%81%84">ちゃんと運用するときのuWSGI設定メモ - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://www.saintsouth.net/blog/setup-django-app-with-uwsgi-and-nginx/#toc-9">Nginx に uWSGI + Django アプリ を組み込む | SaintSouth.NET</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/5t111111/items/e170fead91261621b054#uwsgi-emperor">Ubuntu 12.04でpyenvを利用して速攻でPython3.4 + Nginx + uWSGI + FlaskなWebアプリケーション実行環境を作る - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://www.mathpython.com/ja/django-nginx-conf/">nginxでDjangoを使うときの設定ファイル:クライアント、nginx、uwsgiの流れを整理しよう - MathPython</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://uwsgi-docs.readthedocs.io/en/latest/tutorials/Django_and_nginx.html">Setting up Django and your web server with uWSGI and nginx — uWSGI 2.0 documentation</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://pythonspeed.com/articles/activate-virtualenv-dockerfile/">Elegantly activating a virtualenv in a Dockerfile</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/hana_shin/items/bd9ba363ba06882e1fab">firewall-cmdコマンドの使い方 - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/yakumo/items/8ac195337414aabd39c0">Oracle Cloud で Compute にWebサーバーを立てたメモ - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/fiftystorm36/items/b2fd47cf32c7694adc2e">venv: Python 仮想環境管理 - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="http://blog.higty.xyz/archives/242/">SELinux + Nginx ポリシー設定 - URAGAMI</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://www.blog.umentu.work/centos7nginx-selinux%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%97%E3%83%9B%E3%83%BC%E3%83%A0%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA%E9%85%8D%E4%B8%8B%E3%81%AEweb%E3%82%B3%E3%83%B3%E3%83%86/">[CentOS7][Nginx] SELinuxを設定しホームディレクトリ配下のWebコンテンツを公開を許可 | from umentu import stupid</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/tifa2chan/items/e9aa408244687a63a0ae#%E5%81%9C%E6%AD%A2%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E3%81%AE%E7%A2%BA%E8%AA%8D">Dockerイメージとコンテナの削除方法 - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/gold-kou/items/44860fbda1a34a001fc1#rm">いまさらDockerに入門したので分かりやすくまとめます - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/okhrn/items/d8580e66546d166f489a">Dockerネットワーク設定 - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/zembutsu/items/9e9d80e05e36e882caaa">Docker Compose - docker-compose.yml リファレンス - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/tifa2chan/items/e9aa408244687a63a0ae">Dockerイメージとコンテナの削除方法 - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/prgseek/items/e557a371d7bd1f57b9b1#-docker-composeyml">Docker Compose で複数コンテナ構築&管理 - Qiita</a></li> </ul> きらぷか@積読ハウマッチ/SSSAPIなど tag:crieit.net,2005:PublicArticle/15481 2019-10-15T07:49:45+09:00 2019-10-15T12:20:21+09:00 https://crieit.net/posts/Oracle-Cloud-Laravel Oracle CloudでLaravelを動かしてみた <p>Oracle CloudではサーバーとRDBがAlways Freeにより永久無料で使えるという事なのでLaravelを動かせるか試してみました。Google Cloud Platformもサーバーの無料枠はありますが、RDBは今のところHeroku以外で自由なフレームワークから利用できるクラウドサービスは知りません。これでもしLaravelも無料で動かせるようになれば最高です。</p> <p>ちなみにデータベースはOracleです。このあたりWeb系の人は慣れてない人が多いかもしれませんので注意です。僕もよく分からず試しました。</p> <h2 id="注意点"><a href="#%E6%B3%A8%E6%84%8F%E7%82%B9">注意点</a></h2> <p>クラウドサービスにありがちですが、サーバーは無料だけど、それを動かすための他の何かが有料、だったり、微妙な設定により有料になってしまう場合がある、等のようなこともありえます。</p> <p>Oracle Cloudは登録したばかりだと1ヶ月間は期間限定で無料枠がついているため、本当にAlways Freeにより無料になっているのか、1ヶ月無料のせいで無料に見えてしまっているのかの判断ができません。</p> <p>ということで当記事も無料でOracle Cloudを使ってみる、という趣旨ではなく、あくまでもタイトルそのままの通り、Oracle CloudでLaravelを動かしてみた、というだけの話となります。また1ヶ月経って色々明らかになったらまた更新します。</p> <p>ちなみに、人によってはまだAlways Freeのインスタンスが作成できない、という声も上がっているようです。まだ供給不足の可能性がありますのでうまくいかない場合は日をおいて試してみる必要があるかもしれません。(2019年9月時点)</p> <p>(ちなみに、メモらずにばーっと試してから書いているため抜けのある手順などももしかしたらあるかもしれません)</p> <h2 id="Oracle Cloudに新規登録"><a href="#Oracle+Cloud%E3%81%AB%E6%96%B0%E8%A6%8F%E7%99%BB%E9%8C%B2">Oracle Cloudに新規登録</a></h2> <p>ひとまずOracle Cloudに新規登録してアカウントを作成しておく必要があります。新規登録にはクレジットカードと電話番号の登録が必要です。</p> <p>僕の場合、いつも使っているクレジットカードだとなぜかエラーになって登録できなかったため、別のカードを登録しました。念の為複数のカードを用意しておいて方が良いかもしれません。</p> <h2 id="インスタンスを作成"><a href="#%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%82%92%E4%BD%9C%E6%88%90">インスタンスを作成</a></h2> <p>Oracle Cloudにログインできたら、早速インスタンスを作成します。具体的には恐らくOracle Cloud Infrastructureという枠のCompute Cloud Serviceというサービスになると思います。コンソールのメニューでいうとこの画像のように、「コンピュート」→「インスタンス」でアクセスできるページです。</p> <p><a href="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5da31c49440b7.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5da31c49440b7.png?mw=700" alt="" /></a></p> <p>ここにインスタンスの作成ボタンがありますのでそちらをクリックしてインスタンスを作成していきます。いまのところ、作成画面はすごくシンプルのようです。</p> <p><a href="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5da31d1c96187.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5da31d1c96187.png?mw=700" alt="" /></a></p> <p>命名はそのままでも適当に変更するでも良いでしょう。</p> <h3 id="イメージの選択"><a href="#%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8%E3%81%AE%E9%81%B8%E6%8A%9E">イメージの選択</a></h3> <p>イメージ・ソースの変更ボタンをクリックすると、OSのイメージを変更することができます。下記のように、Always Free対象が書かれているので分かりやすいです。</p> <p><a href="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5da31d82868f7.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5da31d82868f7.png?mw=700" alt="" /></a></p> <p>ここから好きなものを選択しましょう。僕はせっかくなのでデフォルトのOracle Linuxの最新版である7.7を選択してみました。</p> <p>僕はこれで適当にインスタンスを作成してしまったのですが、今「シェイプ、ネットワーク、ストレージ・オプション」の設定を開いて見てみたところ便利なものがあったので、一応紹介しておきます。</p> <h3 id="パブリックIPアドレス"><a href="#%E3%83%91%E3%83%96%E3%83%AA%E3%83%83%E3%82%AFIP%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9">パブリックIPアドレス</a></h3> <p>何も設定せずインスタンスを作成してしまうと、パブリックIPアドレスが割り当てられません。そうすると当然ブラウザからアクセスすることができません。それどころかSSHで接続もできません(できるのかもしれませんが分からなかった&それっぽいものがあったけど無理だった)。そのためあとでIPを作成して割り当てる必要があるのですが、このオプションを見ると「パブリックIPアドレスの割当て」という設定があるようです。恐らくこちらを選択しておくと作成しておいてくれるので後で設定する必要がなくなって便利なのではないかと思います。</p> <p>ちょっと忘れつつありますが、もしあとで設定する場合はインスタンス作成後、グローバルメニューに「ネットワーキング」→「パブリックIP」というメニューがあるため、そこで追加できたような気がします。</p> <h3 id="SSHキーの追加"><a href="#SSH%E3%82%AD%E3%83%BC%E3%81%AE%E8%BF%BD%E5%8A%A0">SSHキーの追加</a></h3> <p>SSHキーの追加のメニューもありました。SSH接続のために必要で、これもあとで設定できるので必ずしもここで設定する必要はないのですが、まあ、もう自分のPCに鍵があるのであれば指定しておくと良いと思います。公開鍵を指定してください。間違えて秘密鍵を指定しないようにしてください。</p> <h3 id="作成実行"><a href="#%E4%BD%9C%E6%88%90%E5%AE%9F%E8%A1%8C">作成実行</a></h3> <p>他もざっと見てみましたが、とりあえずはこれくらいで、他はデフォルトで大丈夫なのではないかと思います。問題なければ「作成」ボタンをクリックして作成してしまいましょう。</p> <h2 id="インスタンスにSSH接続"><a href="#%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%81%ABSSH%E6%8E%A5%E7%B6%9A">インスタンスにSSH接続</a></h2> <p>なにはともあれ作成したインスタンスにSSHでアクセスする必要があります。</p> <p>インスタンス詳細画面の左メニューに「コンソール接続」というメニューがあります。これは作成したのかどうか覚えてないのですが、一つコンソール接続があります。</p> <p><a href="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5da3221a3a48c.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5da3221a3a48c.png?mw=700" alt="" /></a></p> <p>ここのメニューでSSHもしくはVNCで接続する方法が説明されているようですが、僕の場合試してみてもうまくいかず、よく分かりませんでした。</p> <p>ということで、普通にシェルでSSH接続を試してみたらできました。デフォルトでopcというユーザーが作られており、これでsudo出来るらしいです。</p> <pre><code class="bash">ssh opc@パブリックIPアドレス </code></pre> <h2 id="インスタンス内で色々設定"><a href="#%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E5%86%85%E3%81%A7%E8%89%B2%E3%80%85%E8%A8%AD%E5%AE%9A">インスタンス内で色々設定</a></h2> <p>とにかくLaravelを動かせるように色々設定していきます。Oracle LinuxはAmazon Linuxと同様、Red Hatベースのようですのでyumを使って色々とインストールしていきます。</p> <p>今回、ちょうどいいシンプルなプロジェクトがなかった且つどれがOracle Linux内ですぐ動かせるのかよく分かっていなかったので、直接中でLaravelをインストールして動かしてみることにしました。既存のプロジェクトを動かしてみたい場合はGit等もインストールしておいてください。</p> <h3 id="Apacheをインストール"><a href="#Apache%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">Apacheをインストール</a></h3> <p>とにかくApacheだとたいして設定しなくてもPHPをすぐ動かせるのでApacheをインストールしました。</p> <pre><code>sudo yum install httpd sudo systemctl enable httpd sudo systemctl restart httpd </code></pre> <h3 id="Firewallの設定"><a href="#Firewall%E3%81%AE%E8%A8%AD%E5%AE%9A">Firewallの設定</a></h3> <p>このままだとポートが開いておらず、Webサーバーにアクセスできません。とりあえず80番ポートを開きます。</p> <p>ポートを確認</p> <pre><code class="sh">sudo firewall-cmd --list-ports </code></pre> <p>ポートの設定を追加</p> <pre><code class="sh">sudo firewall-cmd --permanent --add-port=80/tcp </code></pre> <p>追加した設定を反映&再度確認</p> <pre><code class="sh">sudo firewall-cmd --reload sudo firewall-cmd --list-ports </code></pre> <p>これでサーバー内のポート設定はできました。しかしまだアクセスできないと思います。あとはコンソールのネットワークの設定も同様に必要っぽいです。</p> <h3 id="コンソールでポートの設定"><a href="#%E3%82%B3%E3%83%B3%E3%82%BD%E3%83%BC%E3%83%AB%E3%81%A7%E3%83%9D%E3%83%BC%E3%83%88%E3%81%AE%E8%A8%AD%E5%AE%9A">コンソールでポートの設定</a></h3> <p>これもちょっとうろ覚えなのですが、インスタンス詳細画面に「プライマリVNIC情報」という項目があり、そこに「パブリック・サブネット」というリンクがあると思います。それをクリックします。</p> <p><a href="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5da327a73d237.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5da327a73d237.png?mw=700" alt="" /></a></p> <p>すると下の方にサブネットの一覧が表示されます。「パブリック・サブネット」という名前のものが最初からあると思いますので、それをクリックします。</p> <p><a href="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5da327ea5edc0.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5da327ea5edc0.png?mw=700" alt="" /></a></p> <p>するとセキュリティリストというものの一覧が出てきます。それの名前をクリックします。</p> <p><a href="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5da328336da52.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5da328336da52.png?mw=700" alt="" /></a></p> <p>ここでようやく「イングレス・ルール」というものが出てきます。最初からSSHの22ポートの設定があるためそれっぽい感じです。雰囲気で下記のような感じで追加でhttpとhttpsのポートを設定しました。</p> <p><a href="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5da32909d83fc.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5da32909d83fc.png?mw=700" alt="" /></a></p> <p>これでIP直のURLでアクセスできるようになっていると思うので一応試しておくと良いと思います。問題なければApacheの最初のページが表示されます。</p> <h3 id="PHPをインストール"><a href="#PHP%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">PHPをインストール</a></h3> <p>こんな操作ログが残っていました。yum-config-managerなんて昔からありましたっけ? むちゃくちゃ便利ですね。というか、もしかしたらyum-utilsは最初から入っていたかもしれませんので、そうであれば最初の3行は不要かもです。</p> <pre><code class="sh">sudo yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm sudo yum install http://rpms.remirepo.net/enterprise/remi-release-7.rpm sudo yum install yum-utils sudo yum-config-manager --enable remi-php73 sudo yum install php php-mcrypt php-cli php-gd php-curl php-zip php-mbstring php-xml php-oci8 sudo systemctl restart httpd </code></pre> <p>php-oci8というものをインストールしていますが、これがOracleと接続するためのパッケージです。</p> <h3 id="libclntsh.soをインストール"><a href="#libclntsh.so%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">libclntsh.soをインストール</a></h3> <p>このままだと、<code>/usr/lib64/php/modules/oci8: cannot open shared object file</code>という、<code>libclntsh.so.19.1</code>というファイルが足りないぞ、というエラーがでてLaravelが動作しません。というか、PHPコマンド実行時に毎回Warningが出ます。<code>php-oci8</code>というPHPとOracleのInstant Clientを接続するパッケージはインストールされていますが、Instant Clientがインストールされていないためそのあたりのライブラリも入っていないようです。これをインストールします。</p> <p>下記のページからrpmをダウンロードできます。</p> <p><a target="_blank" rel="nofollow noopener" href="https://www.oracle.com/database/technologies/instant-client/linux-x86-64-downloads.html">Instant Client for Linux x86-64 (64-bit)</a></p> <p>一番最新のBasic Packageをダウンロードしてインストールしました。</p> <pre><code class="sh">wget https://download.oracle.com/otn_software/linux/instantclient/193000/oracle-instantclient19.3-basic-19.3.0.0.0-1.x86_64.rpm sudo yum install oracle-instantclient19.3-basic-19.3.0.0.0-1.x86_64.rpm </code></pre> <p>不安な場合は、zipファイルの方をダウンロードして中身を確認し、必要なlibclntsh.soが入っているかを確認してみると良いと思います。</p> <p>もしかしたらApacheとPHPのあとにこれをインストールした場合はhttpdの再起動も必要かもしれません。</p> <h3 id="Composerをインストール"><a href="#Composer%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">Composerをインストール</a></h3> <p>Composerもインストールしておきます。</p> <pre><code class="sh">sudo su - curl -sS https://getcomposer.org/installer | php sudo mv composer.phar /usr/local/bin/composer </code></pre> <p>上記の場合スーパーユーザーでインストールしているので、完了したらexit等で元のユーザーに戻っておいてください。</p> <h3 id="Laravelをインストール"><a href="#Laravel%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">Laravelをインストール</a></h3> <p>とりあえず素のLaravelを動かします。ドキュメントどおりにLaravelをインストールします。今回は<code>/var/www/app</code>としてインストールします。<code>/var/www</code>にcdしておきます。ディレクトリの権限とかはうまいこと設定しておいてください。</p> <pre><code class="sh">composer create-project --prefer-dist laravel/laravel app </code></pre> <p>あとstorageディレクトリに書き込み権限が付いていない場合はつけておきます。</p> <pre><code>chmod 0777 storage/ find storage -type d -exec chmod 0777 {} \; find storage -type f -exec chmod 0666 {} \; </code></pre> <p>キーを作成しておきます。</p> <pre><code>php artisan key:generate </code></pre> <p>まずはこれの最初のページが表示されることを目標に進めていきます。</p> <h4 id="Apacheの設定"><a href="#Apache%E3%81%AE%E8%A8%AD%E5%AE%9A">Apacheの設定</a></h4> <p>Laravelをインストールしたディレクトリ用のバーチャルホストの設定を行います。<code>/etc/httpd/conf.d/app.conf</code>というファイルを作成して書き込みます。ServerNameは適宜自分のものに合わせておいてください。</p> <pre><code class="xml"><VirtualHost *:80> DocumentRoot /var/www/app/public ServerName octest.alphabrend.net </VirtualHost> <Directory "/var/www/app/public"> AllowOverride All Options FollowSymLinks </Directory> </code></pre> <p>設定できたらhttpdを再起動しておきます。</p> <pre><code>sudo systemctl restart httpd </code></pre> <h4 id="SELinux"><a href="#SELinux">SELinux</a></h4> <p>SELinuxが動作しているためうまく動きません。適切な設定が必要ですが、今回は試しのため無効にしてあります。</p> <pre><code>sudo setenforce 0 </code></pre> <h4 id="アクセスしてみる"><a href="#%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B">アクセスしてみる</a></h4> <p>これで恐らくLaravelの最初のページにはアクセスできるようになっているのではないかと思います。<code>http://バーチャルホストで設定したホスト名</code>でアクセスしてみてください。</p> <p>ディレクトリの所有権のエラーが出る場合にはもしかしたらstorageディレクトリの所有者をapacheにしておく必要があるかもしれません。</p> <pre><code>sudo chown -R apache:apache storage </code></pre> <p>あとはおかしいな、と思ったらとりあえずhttpdを再起動してみると良いかもしれません。</p> <h2 id="Oracleデータベースを利用する"><a href="#Oracle%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E3%82%92%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B">Oracleデータベースを利用する</a></h2> <p>さて、ここまでは単なるインスタンスの設定だったのである意味どうでもよい話でしたが、引き続き肝となるOracleのデータベースへの接続を行ってLaravelが動作するようにしていきます。</p> <p>今回利用するのはOracle Autonomous Transaction Processingというデータベースで、略してATPと呼ばれているようです。コンソールのメニューにもありますのでそちらを開きます。</p> <p><a href="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5da3359a49212.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5da3359a49212.png?mw=700" alt="" /></a></p> <h3 id="データベースを作成する"><a href="#%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B">データベースを作成する</a></h3> <p>「Autonomous Databaseの作成」ボタンをクリックして作成画面を開きます。</p> <p>すこしスクロールすると、「Always Freeの構成オプションのみを表示」という設定があります。Always Freeで試したい場合はこちらを有効にしておくと良いでしょう。必要な設定は自動的に切り替わります。途中で有料の設定を選択してしまった場合はこちらも勝手に解除されるので確認にもなります。</p> <p>「管理者資格証明の作成」というところでパスワードを設定します。admin(小文字)とこのパスワードでデータベースに接続できますので覚えておいてください。</p> <p>基本的には他の設定は全部そのままで大丈夫だったと思います。問題なければ一番下の「Autonomous Databaseの作成」ボタンをクリックしてデータベースを作成します。</p> <p>ちなみに、Always Freeの場合は一度も接続していない場合、ちょっと時間がたつとデータベースは停止してしまいます。接続したことがあっても、1週間くらいアクセスがなければ停止するようです。初期設定時はよく止まっていますので、止まっていたら適宜起動してください。</p> <h3 id="クライアント資格証明"><a href="#%E3%82%AF%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%B3%E3%83%88%E8%B3%87%E6%A0%BC%E8%A8%BC%E6%98%8E">クライアント資格証明</a></h3> <p>データベースの詳細画面を開くと、「DB接続」というボタンが表示されているためこれをクリックします。すると「クライアント資格証明(ウォレット)のダウンロード」という項目がありますので、このダウンロードボタンをクリックしてダウンロードしておきます。これを利用してデータベースに接続するようです。</p> <p>そのためこれをサーバーに設置します。何か方法があるのかもしれませんが、よく分からなかったためとりあえず自分のPC上でscpを使って送信しました。</p> <pre><code>scp ダウンロードしたファイル opc@パブリックIP:~ </code></pre> <p>本来であればこれらのファイルを<code>/usr/lib/oracle/19.3/client64/lib/network/admin</code>に配置するらしいのですが、Laravelからは権限の問題でアクセスができませんでした。そのため、とりあえず<code>/php_oracle</code>というディレクトリを作り、ここに配置しました。</p> <p>ちなみに必要なファイルは下記ですのでコピーしておいてください。</p> <ul> <li>tnsnames.ora</li> <li>sqlnet.ora</li> <li>cwallet.sso</li> <li>ewallet.p12</li> </ul> <p>アクセスできる権限を与えておきます。</p> <pre><code>sudo chown -R apache:apache /php_oracle </code></pre> <p>Laravel側でも環境変数でこのディレクトリの位置を指定できますのであとで説明します。</p> <p>というかどうも全体的に所有者による権限の問題が頻発してました。詳しくは忘れたのか知らないのか分かりませんでしたが、改めて調査する時間をとるのが面倒だったのでとりあえず対処療法ばかりでやっています。すぐわかる方は適切な方法で対処してください。</p> <h3 id="Laravelでの接続設定"><a href="#Laravel%E3%81%A7%E3%81%AE%E6%8E%A5%E7%B6%9A%E8%A8%AD%E5%AE%9A">Laravelでの接続設定</a></h3> <p>LaravelからOracleへの接続ですが、Laravelでは標準での接続方法が提供されていません。そのためパッケージをインストールする必要があります。</p> <p><a target="_blank" rel="nofollow noopener" href="https://github.com/yajra/laravel-oci8">yajra/laravel-oci8: Oracle DB driver for Laravel 4|5|6 via OCI8</a></p> <p>これを利用することでMySQL等と同様に接続して利用できるようになります。Composerでインストールします。</p> <pre><code>composer require yajra/laravel-oci8 </code></pre> <p>そして設定用のファイルを生成します。</p> <pre><code>php artisan vendor:publish --tag=oracle </code></pre> <p>このファイルの内容は環境変数から指定できるようになっているため、直接変更はせず.envで設定します。</p> <p>注意点として、APP_ENVはproduction、APP_DEBUGはfalseにしておきましょう。IPがパブリックなため、デバッグ状態のままエラーが発生すると環境変数が丸見えになってしまい危険です。</p> <p>データベースの部分は下記のような感じです。ただ、そもそもクライアント資格証明で接続すると思うので、DB_HOST~DB_PASSWORDは設定不要のものもあるかもしれません。適宜試してみてください。</p> <pre><code class="ini">DB_CONNECTION=oracle DB_TNS=DB201910021336_MEDIUM DB_HOST=adb.ap-tokyo-1.oraclecloud.com DB_PORT=1522 DB_DATABASE=DB201910021336 DB_USERNAME=admin DB_PASSWORD=設定したパスワード DB_SERVER_VERSION=18c TNS_ADMIN=/php_oracle </code></pre> <p><code>DB_TNS</code>は、OracleコンソールのDB接続ボタンを押した時に表示される「TNS名」という部分です。5つあってよく分からなかったので適当にMEDIUMを選びました。</p> <p><code>DB_HOST</code>と<code>DB_PORT</code>はTNS名の右に表示されている接続文字列という部分から適当に抽出しました。</p> <p><code>DB_DATABASE</code>は作成したデータベースの名前です。<code>DB_USERNAME</code>はadmin(小文字)固定、<code>DB_PASSWORD</code>はデータベースを作成した時に設定したものです。</p> <p><code>TNS_ADMIN</code>は先程クライアント資格証明を設定したフォルダを指定します。</p> <h3 id="マイグレーションしてみる"><a href="#%E3%83%9E%E3%82%A4%E3%82%B0%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B">マイグレーションしてみる</a></h3> <p>さて、実際にマイグレーションしてみましょう。</p> <pre><code class="sh">php artisan migrate </code></pre> <p>問題なければいつものようにマイグレーションが実行されるはずです。</p> <p>storageディレクトリの権限がどうのこうのというエラーになる場合は所有者を変更したりしてみてください。</p> <pre><code>sudo chown -R opc:opc storage </code></pre> <p>Webでアクセスする場合にはまたapacheに戻しておいてください。</p> <h3 id="ブラウザでアクセスしてみる"><a href="#%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%81%A7%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B">ブラウザでアクセスしてみる</a></h3> <p>次にブラウザでアクセスしてみますが、せっかくですのでDBから取得した情報も表示するようにします。<code>routes/web.php</code>のウェルカムページにユーザー取得処理を追加しておきます。実際には取得前に追加する処理も入れておくとよいでしょう。</p> <pre><code class="php">Route::get('/', function () { $users = \App\User::get(); return view('welcome', compact('users')); }); </code></pre> <p>そしてwelcome.blade.phpにも下記の表示を追加します。</p> <pre><code class="html"> <div> @foreach ($users as $user) <div>Name: <span>{</span><span>{</span> $user->name <span>}</span><span>}</span></div> @endforeach </div> </code></pre> <p>問題なければこのような感じでデータが表示されます。</p> <p><a href="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5da3432430410.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/6e2af66c610d88bc766649f72032893a5da3432430410.png?mw=700" alt="" /></a></p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>ということでOracle CloudでLaravelをDB込で動かすところまでをざっと雑に試してみました。サーバーの知識が必要なためちょっと難易度は高いかもしれませんが、これが永久無料だとするとかなり最高ですね。GCEの永久無料枠よりもスペックは高いですし、そもそも2台まで使えるというのがすごいです。</p> <p>まだ良くわかっていないことも多いため気分が乗ったらまた色々試してみたいと思います。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/15464 2019-10-08T09:41:26+09:00 2019-10-08T09:41:26+09:00 https://crieit.net/posts/VB-NET-Oracle-5d9bdb36dc86b 【VB.NET】Oracleに接続してデータを操作(追加・更新・削除)してみる <p>引き続きVB.NET。</p> <p>プログラムは前回のものを参考にしてください。<br /> <a target="_blank" rel="nofollow noopener" href="https://www.doraxdora.com/blog/2017/12/29/post-3579/" target="_blank" rel="noopener noreferrer" data-blogcard="1">【VB.NET】Oracleに接続してデータを検索してみる</a></p> <h2 id="プログラム修正"><a href="#%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E4%BF%AE%E6%AD%A3">プログラム修正</a></h2> <h3 id="更新処理"><a href="#%E6%9B%B4%E6%96%B0%E5%87%A6%E7%90%86">更新処理</a></h3> <pre><code> ''' <summary> ''' 更新ボタンクリックイベント ''' </summary> ''' <param name="sender"></param> ''' <param name="e"></param> Private Sub btnUpdate_Click(sender As Object, e As EventArgs) Handles btnUpdate.Click Using conn = New OracleConnection("Data Source=localhost;User Id=USER01;Password=USER01;") ' データベースオープン conn.Open() ' データ更新 For i = 0 To dgvCat.Rows.Count - 1 ' テーブルから対象のデータを取得 Dim no As Integer = dgvCat(0, i).Value ' シーケンス列としていないので、 ' 最初に件数を取得して No を計算する Dim cmd As OracleCommand = New OracleCommand("SELECT COUNT(*) FROM TBLCAT WHERE No = " + no, conn) Dim cnt As Decimal = cmd.ExecuteScalar() If (cnt = 0) Then ' データ追加 Dim query = "INSERT INTO TBLCAT VALUES (" + (cnt + 1) + ", '" + dgvCat(1, i).Value + "'" + ", '" + dgvCat(2, i).Value + "'" + ", " + dgvCat(3, i).Value + "'" + ", '" + dgvCat(4, i).Value + "'" + ", '" + dgvCat(5, i).Value + "')" cmd = New OracleCommand(query, conn) cmd.ExecuteNonQuery() Else ' データ変更 Dim query = "UPDATE TBLCAT SET" + " NAME = '" + dgvCat(1, i).Value + "'" + ", SEX = '" + dgvCat(2, i).Value + "'" + ", AGE = " + dgvCat(3, i).Value + ", KIND_CD = '" + dgvCat(4, i).Value + "'" + ", FAVORITE = '" + dgvCat(5, i).Value + "' " + "WHERE NO = " + dgvCat(0, i).Value cmd = New OracleCommand(query, conn) cmd.ExecuteNonQuery() End If Next conn.Close() End Using AddRowFlg = False ' データ再検索 search() MessageBox.Show("データを更新しました。") End Sub </code></pre> <h3 id="削除処理"><a href="#%E5%89%8A%E9%99%A4%E5%87%A6%E7%90%86">削除処理</a></h3> <pre><code> ''' <summary> ''' 削除ボタンクリックイベント ''' </summary> ''' <param name="sender"></param> ''' <param name="e"></param> Private Sub btnDelete_Click(sender As Object, e As EventArgs) Handles btnDelete.Click Using conn = New OracleConnection("Data Source=localhost;User Id=USER01;Password=USER01;") ' データベースオープン conn.Open() ' 選択されている行 For Each r As DataGridViewRow In dgvCat.SelectedRows Dim Cat As Cat = CType(dgvCat.DataSource(), List(Of Cat)).Item(r.Index) ' データ削除 Dim query As String = "DELETE FROM TBLCAT WHERE NO = " + Cat.No ' クエリ実行 Dim cmd As OracleCommand = New OracleCommand(query, conn) cmd.ExecuteNonQuery() Next conn.Close() End Using ' データ再検索 search() MessageBox.Show("データを削除しました。") End Sub </code></pre> <p> </p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>起動後の画面は、SQLiteの時と変わらないので割愛しました。</p> <p>次回以降は、一応他のDBもやっていこうかと思います。</p> <p>ではでは。</p> doraxdora tag:crieit.net,2005:PublicArticle/15458 2019-10-07T09:43:37+09:00 2019-10-07T09:43:37+09:00 https://crieit.net/posts/VB-NET-Oracle 【VB.NET】Oracleに接続してデータを検索してみる <p>またVB.NETですが。<br /> WPFでもやりましたが Oracle に接続してとりあえずのことをやってみます。</p> <p>プログラムは前回のもの、データベースの作成なんかはWPFを参考にしてください。</p> <p><a target="_blank" rel="nofollow noopener" href="https://www.doraxdora.com/blog/2017/09/02/post-2322/" target="_blank" rel="noopener noreferrer" data-blogcard="1">【WPF】Oracleを使ってデータを DataGrid に表示する</a></p> <p><a target="_blank" rel="nofollow noopener" href="https://www.doraxdora.com/blog/2017/12/28/post-3569/" data-blogcard="1">【VB.NET】データグリッドビューの行を動的に追加する</a></p> <h2 id="参照の追加"><a href="#%E5%8F%82%E7%85%A7%E3%81%AE%E8%BF%BD%E5%8A%A0">参照の追加</a></h2> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/12/ESP000001-1.jpg" alt="参照の追加" /></p> <p>ソリューション・エクスプローラーの「参照」を右クリックして「参照の追加」を選択します。</p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/12/ESP000002-1.jpg" alt="dll の追加" /></p> <p>参照の追加画面が表示されるので、「参照」ボタンをクリックします。</p> <p><img src="https://www.doraxdora.com/wp-content/uploads/2017/12/ESP000003-1.jpg" alt="dll の追加" /></p> <p>Oracle.DataAcess.dllを選択し、「追加」ボタンをクリックして完了です。</p> <h2 id="プログラム修正"><a href="#%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E4%BF%AE%E6%AD%A3">プログラム修正</a></h2> <h3 id="宣言の追加"><a href="#%E5%AE%A3%E8%A8%80%E3%81%AE%E8%BF%BD%E5%8A%A0">宣言の追加</a></h3> <p>下記の記述を追加します。</p> <pre><code>Imports System.Data Imports System.Data.OracleClient </code></pre> <h3 id="起動時の処理"><a href="#%E8%B5%B7%E5%8B%95%E6%99%82%E3%81%AE%E5%87%A6%E7%90%86">起動時の処理</a></h3> <pre><code> ''' <summary> ''' フォームロード時の処理 ''' </summary> ''' <param name="sender"></param> ''' <param name="e"></param> Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load Using conn As New OracleConnection("Data Source=localhost;User Id=USER01;Password=USER01;") ' データベースオープン conn.Open() ' 種別コンボボックスの内容をデータベースから取得して設定 ' データを取得 Dim cmd As OracleCommand = New OracleCommand("SELECT * FROM MSTKIND", conn) Dim da As OracleDataAdapter = New OracleDataAdapter(cmd) Dim dt As DataTable = New DataTable() da.Fill(dt) ' コンボボックスに値を設定 Dim sources As List(Of Kind) = New List(Of Kind) Dim k As Kind = New Kind() k.KindCd = "" k.KindName = "指定なし" sources.Add(k) For Each row As DataRow In dt.Rows k = New Kind() k.KindCd = row("KIND_CD").ToString() k.KindName = row("KIND_NAME").ToString() sources.Add(k) Next Me.cmbKind.DataSource = sources Me.cmbKind.DisplayMember = "KindName" ' データベースクローズ conn.Close() End Using End Sub </code></pre> <h3 id="検索処理"><a href="#%E6%A4%9C%E7%B4%A2%E5%87%A6%E7%90%86">検索処理</a></h3> <pre><code> ''' <summary> ''' 検索処理 ''' </summary> Private Sub search() Using conn As New OracleConnection("Data Source=localhost;User Id=USER01;Password=USER01;") ' データベースオープン conn.Open() ' 検索条件を指定してデータを取得 Using con As New DataContext(conn) Dim searchName As String = txtName.Text Dim searchKind As String = CType(cmbKind.SelectedValue, Kind).KindCd ' 種別マスタ取得 ' 種別コンボボックスの内容をデータベースから取得して設定 ' データを取得 Dim cmd As OracleCommand = New OracleCommand("SELECT * FROM MSTKIND", conn) Dim da As OracleDataAdapter = New OracleDataAdapter(cmd) Dim dt As DataTable = New DataTable() da.Fill(dt) Dim kindList As List(Of Kind) = New List(Of Kind) Dim k As Kind = New Kind() For Each row As DataRow In dt.Rows k = New Kind() k.KindCd = row("KIND_CD").ToString() k.KindName = row("KIND_NAME").ToString() kindList.Add(k) Next ' 猫一覧取得 Dim Sql As String = "SELECT * FROM TBLCAT" Dim where As String = "" If (searchName <> "") Then where = " WHERE NAME LIKE '" + searchName + "%'" End If If (searchKind <> "") Then If (where <> "") Then where += " AND" Else where = " WHERE" End If where += " KIND_CD = '" + searchKind + "'" End If Sql += where cmd = New OracleCommand(Sql, conn) da = New OracleDataAdapter(cmd) dt = New DataTable() da.Fill(dt) ' データグリッドビューに設定 Dim i As Integer = 0 dgvCat.Rows.Clear() For i = 0 To dt.Rows.Count() - 1 ' 行追加 dgvCat.Rows.Add() ' No(プライマリなので編集不可) Dim no = New DataGridViewTextBoxCell() no.Value = dt.Rows(i)("No") dgvCat(0, i) = no dgvCat(0, i).ReadOnly = True ' 名前 Dim name = New DataGridViewTextBoxCell() name.Value = dt.Rows(i)("Name") dgvCat(1, i) = name ' 性別 Dim sex = New DataGridViewComboBoxCell() sex.Items.AddRange({"♂", "♀"}) sex.DisplayStyle = DataGridViewComboBoxDisplayStyle.ComboBox dgvCat(2, i) = sex dgvCat(2, i).Value = dt.Rows(i)("Sex") ' 年齢 Dim age = New DataGridViewTextBoxCell() age.Value = dt.Rows(i)("Age") dgvCat(3, i) = age ' 種別 Dim kind = New DataGridViewComboBoxCell() kind.DataSource = kindList kind.DisplayMember = "KindName" kind.ValueMember = "KindCd" kind.DisplayStyle = DataGridViewComboBoxDisplayStyle.ComboBox dgvCat(4, i) = kind dgvCat(4, i).Value = dt.Rows(i)("Kind_Cd") ' 好物 Dim favorite = New DataGridViewTextBoxCell() favorite.Value = dt.Rows(i)("Favorite") dgvCat(5, i) = favorite Next End Using ' データベースクローズ conn.Close() End Using End Sub </code></pre> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>ちょっと画面は取り忘れましたが、これでOracleからデータ取得、表示ができます。</p> <p>次回もOracleの予定です。</p> <p>ではでは。</p> doraxdora tag:crieit.net,2005:PublicArticle/15193 2019-07-03T09:45:14+09:00 2019-07-03T09:45:14+09:00 https://crieit.net/posts/WPF-Oracle-DataAccess 【WPF】「Oracle.DataAccess」を利用してデータ操作(追加、更新、削除)してみる <p>引き続き、Oracle.DataAccess を使ってデータの登録、更新、削除をしてみます。</p> <p>前回の記事はこちら。<br /> <a target="_blank" rel="nofollow noopener" href="https://www.doraxdora.com/blog/2017/09/02/post-2322/" target="_blank" rel="noopener noreferrer" data-blogcard="1">【WPF】「Oracle.DataAccess」を利用して取得したデータを DataGrid に表示してみる</a></p> <p>今回も、Entity Framework などは使わずに OracleCommand で実装していますので、サクッと書きます。</p> <h2 id="プログラムの修正"><a href="#%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%81%AE%E4%BF%AE%E6%AD%A3">プログラムの修正</a></h2> <h3 id="登録更新フォーム表示時の処理"><a href="#%E7%99%BB%E9%8C%B2%E6%9B%B4%E6%96%B0%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E8%A1%A8%E7%A4%BA%E6%99%82%E3%81%AE%E5%87%A6%E7%90%86">登録更新フォーム表示時の処理</a></h3> <p>SubWindow.xaml.cs</p> <pre><code> public SubWindow(CatModel SelectedCat) { InitializeComponent(); // データを取得 // 種別マスタを取得してコンボボックスに設定する using (var conn = new OracleConnection("Data Source=localhost;User Id=USER01;Password=USER01;")) { // データを取得 OracleCommand cmd = new OracleCommand("SELECT * FROM MSTKIND", conn); OracleDataAdapter da = new OracleDataAdapter(cmd); DataTable dt = new DataTable(); da.Fill(dt); // コンボボックスに値を設定 List<Kind> sources = new List<Kind>(); Kind k = new Kind(); k.KindCd = "00"; k.KindName = "指定なし"; sources.Add(k); foreach (DataRow row in dt.Rows) { k = new Kind(); k.KindCd = row["KIND_CD"].ToString(); k.KindName = row["KIND_NAME"].ToString(); sources.Add(k); } // コンボボックスに設定 this.cmb_kind.ItemsSource = sources; this.cmb_kind.DisplayMemberPath = "KindName"; if (SelectedCat == null) { // 追加処理の場合 this.Title = "追加"; this.btn_add.Visibility = Visibility.Visible; this.btn_mod.Visibility = Visibility.Collapsed; } else { this.SelectedCat = SelectedCat; // 更新処理の場合 this.Title = "更新"; this.btn_add.Visibility = Visibility.Collapsed; this.btn_mod.Visibility = Visibility.Visible; // 値の設定 this.txt_name.Text = SelectedCat.Name; foreach (ComboBoxItem i in this.cmb_sex.Items) { if (i.Content.ToString().Trim() == SelectedCat.Sex.Trim()) { this.cmb_sex.SelectedItem = i; } } this.txt_age.Text = SelectedCat.Age.ToString(); foreach (Kind kind in sources) { if (kind.KindCd == SelectedCat.Kind) { this.cmb_kind.SelectedItem = kind; break; } } this.txt_favorite.Text = SelectedCat.Favorite; } } } </code></pre> <h3 id="追加処理"><a href="#%E8%BF%BD%E5%8A%A0%E5%87%A6%E7%90%86">追加処理</a></h3> <p>SubWindow.xaml.cs</p> <pre><code> private void btn_add_Click(object sender, RoutedEventArgs e) { this.IsCancel = false; // データを追加する using (var conn = new OracleConnection("Data Source=localhost;User Id=USER01;Password=USER01;")) { conn.Open(); // シーケンス列としていないので、 // 最初に件数を取得して No を計算する OracleCommand cmd = new OracleCommand("SELECT COUNT(*) FROM TBLCAT", conn); decimal cnt = (decimal)cmd.ExecuteScalar(); // クエリ作成 String query = "INSERT INTO TBLCAT VALUES (" + ++cnt + ", '" + this.txt_name.Text + "'" + ", '" + (this.cmb_sex.SelectedItem as ComboBoxItem).Content + "'" + ", " + this.txt_age.Text + ", '" + (this.cmb_kind.SelectedItem as Kind).KindCd + "'" + ", '" + this.txt_favorite.Text + "')"; // クエリ実行 cmd = new OracleCommand(query, conn); cmd.ExecuteNonQuery(); conn.Close(); MessageBox.Show("データを追加しました。"); } this.Close(); } </code></pre> <h3 id="更新処理"><a href="#%E6%9B%B4%E6%96%B0%E5%87%A6%E7%90%86">更新処理</a></h3> <p>SubWindow.xaml.cs</p> <pre><code> private void btn_mod_Click(object sender, RoutedEventArgs e) { this.IsCancel = false; // データを更新する using (var conn = new OracleConnection("Data Source=localhost;User Id=USER01;Password=USER01;")) { conn.Open(); // クエリ作成 String query = "UPDATE TBLCAT SET" + " NAME = '" + this.txt_name.Text + "'" + ", SEX = '" + (this.cmb_sex.SelectedItem as ComboBoxItem).Content + "'" + ", AGE = " + this.txt_age.Text + ", KIND_CD = '" + (this.cmb_kind.SelectedItem as Kind).KindCd + "'" + ", FAVORITE = '" + this.txt_favorite.Text + "' " + "WHERE NO = " + SelectedCat.No; // クエリ実行 OracleCommand cmd = new OracleCommand(query, conn); cmd.ExecuteNonQuery(); conn.Close(); MessageBox.Show("データを更新しました。"); } this.Close(); } </code></pre> <h3 id="削除処理"><a href="#%E5%89%8A%E9%99%A4%E5%87%A6%E7%90%86">削除処理</a></h3> <p>MainWindow.xaml.cs</p> <pre><code> private void del_button_Click(object sender, RoutedEventArgs e) { logger.Info("削除ボタンクリック"); // データを削除する using (var conn = new OracleConnection("Data Source=localhost;User Id=USER01;Password=USER01;")) { conn.Open(); int checkCount = 0; List<CatModel> list = this.dataGrid.ItemsSource as List<CatModel>; String query; foreach (CatModel cat in list) { if (cat.IsChecked) { checkCount++; // クエリ作成 query = "DELETE FROM TBLCAT WHERE NO = " + cat.No; // クエリ実行 OracleCommand cmd = new OracleCommand(query, conn); cmd.ExecuteNonQuery(); } } conn.Close(); if (checkCount == 0) { MessageBox.Show("削除対象にチェックがされていません。"); return; } } // データ再検索 searchData(); MessageBox.Show("データを削除しました。"); } </code></pre> <p> </p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>そのうちまた違った方法で試してみたいと思いますが、Oracleはとりあえずここまでです。</p> <p>ではでは。</p> doraxdora tag:crieit.net,2005:PublicArticle/14900 2019-04-02T18:05:06+09:00 2019-04-02T18:09:36+09:00 https://crieit.net/posts/SQL-NULL-0 SQLでNULLを0として出力する方法 <p>MySQLで外部結合したときに、COUNT()の結果が0件だとNULL値が返却されてしまったため、NULLを0として表示する関数を調べました。<br /> ついでに他のDBについても書きました。</p> <h2 id="関数"><a href="#%E9%96%A2%E6%95%B0">関数</a></h2> <p><strong>IFNULL (a, 0)</strong><br /> <a target="_blank" rel="nofollow noopener" href="https://dev.mysql.com/doc/refman/5.6/ja/control-flow-functions.html#function_ifnull">MySQL</a>、<a target="_blank" rel="nofollow noopener" href="http://www.sqlitetutorial.net/sqlite-functions/sqlite-ifnull/">SQLite</a></p> <p><strong>COALESCE (a, 0)</strong><br /> <a target="_blank" rel="nofollow noopener" href="https://dev.mysql.com/doc/refman/5.6/ja/comparison-operators.html#function_coalesce">MySQL</a>、<a target="_blank" rel="nofollow noopener" href="http://www.sqlitetutorial.net/sqlite-functions/sqlite-coalesce/">SQLite</a>、<a target="_blank" rel="nofollow noopener" href="https://www.postgresql.jp/document/10/html/functions-conditional.html">PostgreSQL</a>、<a target="_blank" rel="nofollow noopener" href="https://docs.oracle.com/cd/E96517_01/sqlrf/COALESCE.html#GUID-3F9007A7-C0CA-4707-9CBA-1DBF2CDE0C87">Oracle</a></p> <p><strong>NVL (a, 0)</strong><br /> <a target="_blank" rel="nofollow noopener" href="https://docs.oracle.com/cd/E96517_01/sqlrf/NVL.html#GUID-3AB61E54-9201-4D6A-B48A-79F4C4A034B2">Oracle</a></p> <p><strong>ISNULL (a, 0)</strong><br /> <a target="_blank" rel="nofollow noopener" href="https://docs.microsoft.com/ja-jp/sql/t-sql/functions/isnull-transact-sql?view=sql-server-2017">SQL Server</a></p> <h2 id="使い方"><a href="#%E4%BD%BF%E3%81%84%E6%96%B9">使い方</a></h2> <p>第1引数(この場合カラムa)がNULLだった場合、関数は第2引数(この場合は0)を返します。<br /> 第1引数がNULLでなければ、関数はそのまま第1引数を返します。</p> <p>これらは同じような使い方ができますが、COALESCE()だけ仕様が異なり、引数を無限に設定することができます。<br /> COALESCE()は第1引数から順に「その値がNULLかどうか」を判定し、NULLであれば次の引数へ、NULLでなければその値を返却します。<br /> 全ての引数がNULLだった場合は、諦めてNULLを返却します。</p> ウラル