2.4 ビーンズコード
package com.business; import java.sql.*; import com.google.appengine.api.rdbms.AppEngineDriver; public class acctBean{ String rv = ""; Connection con = null; public acctBean(){ try{ DriverManager.registerDriver(new AppEngineDriver()); //(1) con = DriverManager.getConnection( "jdbc:google:rdbms://branecosmology:business/business" ,"user1", "pass1"); //(2) } catch (SQLException e) { return; } } public String addJournal(String check_no, String debit_code, String debit_acct, String debit_amt, String credit_code, String credit_acct, String credit_amt, String remark){ try{ String sql = "insert into journal values(?, ?, ?, ?, ?, ?, ?, ?)"; //(3) PreparedStatement ps = con.prepareStatement(sql); //(4) //(3)登録パラメータのセット ps.setString(1, check_no); ps.setString(2, debit_code); ps.setString(3, debit_acct); ps.setInt(4, Integer.parseInt(debit_amt)); ps.setString(5, credit_code); ps.setString(6, credit_acct); ps.setInt(7, Integer.parseInt(credit_amt)); ps.setString(8, remark); ps.executeUpdate(); //(5) rv = "{\"stat\": \"OK:仕訳データ登録成功 伝票番号=" + check_no + "\"}"; }catch(SQLException e){ rv = "{\"stat\": \"NO:SQLエラー =\"" + e.toString() + "\"}"; }catch(Exception e){ e.printStackTrace(); rv = "{\"stat\": \"NO:SQLエラー =\"" + e.toString() + "\"}"; }finally{ try{ con.close(); }catch(Exception e){} } return rv; } public String getAcctName(String acct_code){ try{ String sql = "select acct_name from acct_mas where acct_code= ?"; //(6) PreparedStatement ps = con.prepareStatement(sql); //(7) ps.setString(1, acct_code); //(8) ResultSet rs = ps.executeQuery(); //(9) if(rs.next()) { rv = "{\"stat\": \"" + "参照成功:\" , \"acct_name\": \"" + rs.getString("acct_name") + "\"}"; } else { rv = "{\"stat\": \"NO:参照不成功\"}"; } con.close(); }catch(SQLException e){ rv = "{\"stat\": \"NO:SQLエラー\"" + e + "\"}"; }finally{ try{ con.close(); }catch(Exception e){} } return rv; } public String getAllAcct(){ try{ String sql = "select acct_code, acct_name from acct_mas"; PreparedStatement ps = con.prepareStatement(sql); ResultSet rs = ps.executeQuery(); rv = "{ \"acct\":["; while(rs.next()) { //(10) String acct_code = rs.getString("acct_code"); String acct_name = rs.getString("acct_name"); rv + = "{\"acct_code\": \"" + acct_code + "\", \"acct_name\": \"" + acct_name + "\"},"; } rv = rv.substring(0, rv.length() - 1) + "]}"; return rv; }catch(SQLException e){ return "{\"stat\": \"NO:SQLエラー\"}"; }finally{ try{ con.close(); }catch(Exception e){} } } }
acctBeanには仕訳情報を登録するためのgetAcctNameメソッドがあり、サーブレット(acctSvlt)から呼び出されて登録処理を行います。Cloud SQLでのMySQLデータ操作については前にも見ていますが、ここで簡単に処理手順を確認してみます。
acctBeanはインスタンス化されるとコンストラク呼び出しが行われます。コンストラクタでは、(1)でCloud SQL用のJDBCドライバインスタンス(new AppEngineDriver())を生成してDriverManagerに登録し、(2)では引数で指定されたデータベースのURLに接続を行っていますが、getConnectionの引数は次の書式で記述します。
getConnection("jdbc:google:rdbms://instance_name/database", "user", "password");
acctBeanでは、MySQLに勘定データを登録するaddJournalメソッドと、勘定コードから勘定名を返すgetAcctNameメソッド、それにアカウント全件参照用のgetAllAcctメソッドが記述されています。それぞれMySQLへのアクセスが記述されていますが、その内容はJavaからデータベースにアクセスする一般的なアクセス書式(ここでは動的SQL)で記述されています。つまり、Cloud SQLを使用する場合は、コンストラクタ内でのデータベース接続書式が若干異なるだけで、SQLでデータベースアクセスを行う部分のコード記述は一般的なJavaからのデータベースアクセス書式と同様で、Cloud SQLのための特別のコード記述は必要ありません。従って以下の内容は、通常のJavaからのデータベースアクセス書式によるものです。
addJournalメソッド
addJournalメソッドでは(3)で登録用SQL文(動的SQL)を定義して、(4)のprepareStatementでプリコンパイルされたSQL文のオブジェクト(ps)を生成します。登録(insert into)は、psにsetStringメソッドなどでパラメータをセットした後、(5)のexecuteUpdateメソッドによってSQL文が実行されます。
getAcctNameメソッド
getAcctNameメソッドでは、(6)で参照系のSQL文("SELECT")を指定しますが、その後(7)のSQL文オブジェクト(ps)の生成、(8)のパラメータセットは同じです。ただし参照系ではexecuteQueryメソッドでSQL文を実行します(9)。
getAllAcctメソッド
getAllAcctメソッドもexecuteQueryでのSQL文実行までは前と同じですが、全件参照(または条件参照)では実行により返されるレコード数が複数になるため、(10)のwhile(rs.next())で返されたレコードの先頭から最後までを順次取り出して、変数への値セットと、レスポンス様のJSONフォーマットへの組立てを行っています。
まとめ
今回は、Cloud SQLとWeb Storage(HTML5)の組み合わせによる、クラウドを使用した仕訳情報入力と、画面操作およびストレスのない処理スピードを実現するための工夫について見てきました。しかし、今回のサンプルでは仕訳データ登録の部分で、0.4秒程度ですがまだ待ちが発生しています。次回はHTMLのWeb Workersを使用して、クラウドへの非同期仕訳データ送信を、コンカレントに実行することによって、すべてのデータアクセス待ち時間を実質ゼロにしてしまうサンプルを紹介する予定です。