Kohei Nozaki's blog 

@ResourceアノテーションでDataSourceを注入してみる


Posted on Sunday Feb 02, 2014 at 05:23PM in Technology


直接JDBCを使う必要がでてきた時用。

環境

  • WildFly8.0.0.CR1
  • Oracle JDK7u51
  • PostgreSQL 9.2.4

準備

データソースを確認

こんなデータソースを使ってみることにする

[standalone@localhost:9990 /] /subsystem=datasources/data-source=TestDS:read-attribute(name=jndi-name)
{
    "outcome" => "success",
    "result" => "java:jboss/jdbc/TestDS"
}
[standalone@localhost:9990 /] 

HogeServlet.java

このサーブレットにDataSourceを注入します。try-with-resourcesが便利ですね。@Resourceアノテーションのlookup属性には、“java:comp/env/“の後にXMLファイルで定義した論理名を書く

package com.example;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

@WebServlet("/HogeServlet")
public class HogeServlet extends HttpServlet {

    @Resource(lookup = "java:comp/env/jdbc/hoge")
    DataSource dataSource;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try(PrintWriter pw = response.getWriter();
            Connection cn = dataSource.getConnection();
            Statement st = cn.createStatement();
            ResultSet rs = st.executeQuery("select now()")){
            while(rs.next()){
                pw.write(String.valueOf(rs.getTimestamp(1)));
            }
        }catch(SQLException e){
            throw new ServletException(e);
        }
    }
}

web.xml

この環境の場合はなくても動くようだが一応。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <resource-ref>
        <res-ref-name>jdbc/hoge</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
    </resource-ref>
</web-app>

jboss-web.xml

WEB-INFの下に置く。ここでデータソースのJNDI名とResourceアノテーションのlookup属性で指定した名前のひも付けを行う。

<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
    <resource-ref>
        <res-ref-name>jdbc/hoge</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <jndi-name>java:jboss/jdbc/TestDS</jndi-name>
    </resource-ref>
</jboss-web>

動かしてみる

テストの際はどうするか

jboss-web.xmlを別のものに差し替えればOK。HogeServletには手を入れずに参照するDBを切り替えることができる。

備考

JPAのpersistence.xmlからはweb.xmlとjboss-web.xmlで定義した論理名を参照できない

persistence.xmlからもweb.xmlとjboss-web.xmlで定義した論理名 “jdbc/hoge” を使う事が出来れば、jboss-web.xmlを差し替えるだけでJPAから参照するデータソースも切り替えられるので楽だなと思ったのだが、どうやらそれは出来ないらしい[2]。“java:comp/env/jdbc/hoge” とかも試してみたが駄目だった。persistence.xmlにはAPサーバに定義してあるJNDI名を直接指定してやる必要があるみたい。残念。WebSphereだとできたりするみたいだけど一般的には駄目っぽい[5]。

今回の例だとこう書いてやる必要がある。

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="datasource">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <jta-data-source>java:jboss/jdbc/TestDS</jta-data-source>
    </persistence-unit>
</persistence>

ただアプリケーションローカルでweb.xmlかアノテーションで定義したデータソースを使う場合は共用が可能らしい[3]。アプリの資源に接続情報べた書きになるので避けたい気もするが用途によっては良いのかもしれない。

@Resourceで直接JNDI名を参照する

特に論理名を通じて利用する必要がないなら、HogeServlet.javaで以下のようにすれば直接JNDI名からデータソースを拾って来れる。jboss-web.xmlもweb.xmlも不要になる。

ただし複数箇所でJNDI名の直書きが発生するのはあまりよろしくないので、CDIのProducerを使うか、前述の手段で論理名を通して参照した方が良いような気はする。

package com.example;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

@WebServlet("/HogeServlet")
public class HogeServlet extends HttpServlet {

    @Resource(lookup="java:jboss/jdbc/TestDS")
    DataSource dataSource;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try(PrintWriter pw = response.getWriter();
            Connection cn = dataSource.getConnection();
            Statement st = cn.createStatement();
            ResultSet rs = st.executeQuery("select now()")){
            while(rs.next()){
                pw.write(String.valueOf(rs.getTimestamp(1)));
            }
        }catch(SQLException e){
            throw new ServletException(e);
        }
    }
}

参考文献

  1. JBoss でのデータソースの定義のしかた (DB2/400)
  2. Beware of soapy frogs: Java EE 6 - Traps, pitfalls and warts list
  3. DataSource Resource Definition in Java EE 6 (Enterprise Tech Tips)
  4. Java EE 7 Deployment Descriptors | Antonio's Blog
  5. WebSphere Application Server Version 8 Information Center


ログ出力の設定をしてみる


Posted on Sunday Feb 02, 2014 at 10:43AM in Technology


環境

  • PostgreSQL 9.2.4
  • OS X 10.9.1

何をするか

  • OS XのsyslogをPostgreSQLからのログ出力を受け入れられるように設定する
  • PostgreSQLのログをsyslogへ出力するようにする
  • 実行されるSQLのログを取ってみる

OS Xのsyslogの設定

/etc/syslog.confを編集する

一番下の行を追加する。こんな感じ。flat file logsは/etc/asl.confに設定されているとか書かれているのでそっちに書いた方がいいのかもしれないけど面倒なのでここで

# Note that flat file logs are now configured in /etc/asl.conf

install.*                                               @127.0.0.1:32376
local0.*                                                /var/log/postgresql

設定内容を反映させる

sudo launchctl unload /System/Library/LaunchDaemons/com.apple.syslogd.plist
sudo launchctl load /System/Library/LaunchDaemons/com.apple.syslogd.plist

こんなんでもよい

ps -Af | awk '/\/usr\/sbin\/syslogd$/{print "sudo kill -HUP " $2}' | sh

ログを出力してみる

kyle-no-MacBook:etc kyle$ logger -p local0.notice hogehoge
kyle-no-MacBook:etc kyle$ ls -l /var/log/postgresql 
-rw-r--r--@ 1 root  wheel  58  2  2 10:55 /var/log/postgresql
kyle-no-MacBook:etc kyle$ cat /var/log/postgresql 
Feb  2 10:55:06 kyle-no-MacBook.local kyle[880]: hogehoge
kyle-no-MacBook:etc kyle$ 

ちゃんと出ていますね。「コンソール」からも内容を見られるのは便利かも

PostgreSQLの設定

$PG_HOME/data/postgresql.confを編集

sudo su postgres -c 'vi /Library/PostgreSQL/9.2/data/postgresql.conf'

以下内容にする

log_destination = 'syslog'
syslog_facility = 'LOCAL0'
syslog_ident = 'postgres'
log_statement = 'all' 

一番下がSQLをログに出す設定。大量に出るので要注意

再起動

sudo su postgres -c 'pg_ctl -D /Library/PostgreSQL/9.2/data restart'

ログを見てみる

kyle-no-MacBook:~ kyle$ psql
Password: 
psql (9.2.4)
Type "help" for help.

kyle=# select now();
             now              
------------------------------
 2014-02-02 11:32:20.67332+09
(1 row)

kyle=# \q
kyle-no-MacBook:~ kyle$ cat /var/log/postgresql.log 
Feb  2 11:20:21 kyle-no-MacBook.local kyle[1002]: hogehogehoge
Feb  2 11:31:24 kyle-no-MacBook.local postgres[1073]: [1-1] 2014-02-02 11:31:24 JST LOG:  database system was shut down at 2014-02-02 11:31:23 JST
Feb  2 11:31:24 kyle-no-MacBook.local postgres[1077]: [1-1] 2014-02-02 11:31:24 JST LOG:  autovacuum launcher started
Feb  2 11:31:24 kyle-no-MacBook.local postgres[1071]: [1-1] 2014-02-02 11:31:24 JST LOG:  database system is ready to accept connections
Feb  2 11:31:30 kyle-no-MacBook.local postgres[1083]: [2-1] 2014-02-02 11:31:30 JST LOG:  incomplete startup packet
Feb  2 11:32:20 kyle-no-MacBook.local postgres[1098]: [2-1] 2014-02-02 11:32:20 JST LOG:  statement: select now();
kyle-no-MacBook:~ kyle$ 

出てますね

その他

できればSQLのログはシビリティをdebugとかにしたいので若干調べた[6]が、よくわからん。現状無理ということだろうか

参考文献

  1. Linux管理者への道(3):システム管理の基礎 syslogdの設定をマスターしよう (2/3) - @IT
  2. ログ関連の設定 — Let's Postgres
  3. 第10回Mac OS X Server勉強会 Mac OSXシステム管理 読書会「ログ」 - サイト更新停滞ちうっ
  4. 新世代syslogデーモン徹底活用(1):syslogdの限界と次世代シスログデーモン (1/3) - @IT
  5. PostgreSQL/PostgreSQLでSQLステートメントをログファイルに出力する方法 - 調べる.db
  6. [GENERAL] log_statement and syslog severity - Google グループ