SpringとHibernateの連携をどうこうの前に
SpringMVCってめんどくさい気がする。慣れてないだけなのだろうか?
SpringとHibernateの連携がどうこう考える前に、データベースコネクションについて、あまりにも今までなんとなくやってきたので、メモして自分がどれだけきちんと分かっていないかを考える記事。
mysqlにDriverManagerでアクセスする。ま、さすがにこれは分かる。
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { Class.forName("com.mysql.jdbc.Driver"); String url = "jdbc:mysql://localhost:3306/kijitora"; Connection con = DriverManager.getConnection(url, "kijitora","kijitora"); Statement st = con.createStatement(); ResultSet rs = st.executeQuery("select * from user;"); while (rs.next()) { String name = rs.getString("name"); System.out.println(name); } } catch (Exception e) { e.printStackTrace(); } }
次にDataSourceを使う場合
private DataSource ds; public void init() throws ServletException { try { InitialContext ic = new InitialContext(); ds = (DataSource) ic.lookup("java:comp/env/jdbc/mysql"); } catch (Exception e) { e.printStackTrace(); } } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { Connection con = ds.getConnection(); Statement st = con.createStatement(); ResultSet rs = st.executeQuery("select * from user;"); while (rs.next()) { String name = rs.getString("name"); System.out.println(name); } } catch (SQLException e) { e.printStackTrace(); } }
ds = (DataSource) ic.lookup("java:comp/env/jdbc/mysql");
このコードで、JNDIで例えば以下のserver.xmlの記述とかを読み込むようだ
以下Tomcat5.5以上の場合のserver.xmlの記述(
nameで指定した"jdbc/mysql"をic.lookup()の引数の"java:comp/env/"のあとに記述する。
<Context path="contextpath"> <Resource name="jdbc/mysql" auth="Container" type="javax.sql.DataSource" factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory" maxActive="2" maxWait="10000" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/kijitora" username="kijitora" password="kijitora" /> </Context>
http://programnet.hp.infoseek.co.jp/practicaldb/connectionpool.html
Tomcatはコネクションプーリングの機能が内臓されています。ここではアプリケーション単位で設定しておきたいので、アプリケーション設定ファイルに記述していきます。なおTomcat全体に設定したいならserver.xmlに記述してください。
今回はserver.xmlに記述してみた。でも上のserver.xmlの指定でも、アプリケーション単位で設定していることにならないかい?あとで調べる。
こうするとさっきの
ds = (DataSource) ic.lookup("java:comp/env/jdbc/mysql");
で、datasourceが獲得できて、ds.getConnection();でコネクションが獲得できる。
それでだな、コネクションプーリングって何かってことなんだが、
今回の場合、server.xmlの
こんなおかしなコードでちょっと試してみた
private void makeConnection() { Connection con1 = null; Connection con2 = null; Connection con3 = null; try { con1 = ds.getConnection(); con2 = ds.getConnection(); con3 = ds.getConnection(); } catch (SQLException e) { try { con1.close(); con2.close(); con3 = ds.getConnection(); } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); } }
すると、con3に代入の部分で3つ目のConnectionが取得できない。
で、エラーになる。catchの中でcon1とcon2をcloseすると、ds.getConnection()でコネクションを取得できた。
なるほどTomcatがコネクションプールをしてくれているみたいだなー。
コネクションプールを自分で実装するときは
http://www.atmarkit.co.jp/fjava/rensai/jsp2_04/jsp2_04_2.html的
感じになるのかな?
ちなみにDriverManagerでアクセスしたときに取得したConnectionオブジェクトは、
org.mysql.jdbc.Connectionというクラスであり、
DataSourceを使うほうでは、このorg.mysql.jdbc.Connectionクラスのオブジェクトをラップした感じのクラスのオブジェクトだった。
ただ、DataSourceから取得のConnectionインタフェイスの実装クラスをgetClass()してみたが、
org.apache.tomcat.dbcp.dbcp.PoolingDataSource$PoolGuardConnectionWrapperとなっていて、
インスペクションすると、org.apache.tomcat.dbcp.dbcp.PoolableConnection@75de1cのような感じもあり?????
でね、org.apache.tomcat.dbcp.dbcp.PoolableConnection@75de1cなら、createStatement()呼ぶのわかるんだけれど、
org.apache.tomcat.dbcp.dbcp.PoolingDataSource$PoolGuardConnectionWrapperだとすると、そんなメソッド呼べないはずだよね?
そもそもこの$マークはなんだ!知らないよ! ←追記:インナークラスのことか?つまりPoolingDataSourceのインナークラスがPoolGuardConnectionWrapperということ?
ちょっと保留。
僕もそうだけれど、いきなり業務でJavaプログラムをはじめたときにフレームワークがすでにあって、「これ使って」とか言われた場合、こうした一連のことをずいぶんと華麗にフレームワークは行ってくれたりするので、どういう経緯で、JDBCのデータアクセスが抽象化されていったのかという過程を知らない人間には、わからないし、一生分からないで終わる事だってありうる。
それはやだ。
僕の場合は、今まで業務ではこの辺はSeasar2がやってくれていたりして、
例えば2.3ならj2ee.diconに2.4だとjdbc.diconとかにその辺の設定が書かれているみたいです。
datasource,connectionPool,xaDataSourceとかだな。
ちゃんと見たことないので、以上の前提のもと、少しソースとか見てみようかなと思っています。Springめんどくさい。