[[FAQ]] *S2Dao [#y06fcbbb] #contents **なんか動かないのだけれど [#f2049ffd] - DaoにはBEANアノテーションを、JavaBeans(Entity)にはTABLEアノテーションを書きましょう。 -- BEANアノテーションの例は、Class BEAN = Employee.class; -- TABLEアノテーションの例は、public static final String TABLE = "EMP"; - DaoにはS2DaoInterceptorを適用する必要があります。 - AbstractなDaoを使うことも可能ですが、何らかのDaoインタフェースをimplementsしている必要があります。 - バージョンアップしたら動かなくなったーー -- dao.diconなど同梱のdiconがupdateされている可能性があります。リリースノートを確認しましょう。 **updateの際に更新したくない列を指定したい [#neecea86] >[[S2サポーター]] (2006-04-29 (土) 19:48:55)~ ~ ''Question''~ S2Daoの開発の中で、updateBatchを投げる際、更新したくない列を指定~ したいのですが、方法がわかりません。~ ~ ''Answer''~ NO_PERSISTENT_PROPSアノテーションを使用すると更新対象に含まれなくなります。~ ~ http://www.seasar.org/s2dao.html#NoPersistentPropsAnnotation~ を参照されると良いと思います。~ ~ ''参考投稿''~ http://ml.seasar.org/archives/seasar-user/2005-November/000360.html~ http://ml.seasar.org/archives/seasar-user/2005-November/000361.html~ // **コネクションプーリングが行われていない? [#ufb3fde6] >[[S2サポーター]] (2006-04-29 (土) 19:46:22)~ ~ ''Question''~ S2DAOでconnectionPoolを利用しているのですが、コネクションのプーリングが~ 行なわれていないような動作をしているので、設定に漏れがあるのではないかと~ 思い、何かアドバイスを頂ければとメールさせて頂きました。~ ~ 実行ログを見ると、最初に1件のみ~ [物理的なコネクションを取得しました]を表示して、以降はDBにアクセスする~ と[論理的なコネクションを取得しました]と出力され、1つ物理コネクションを~ 使い回しているようなログが出力されています。~ ~ この時に、Oracleのv$sessionを見ると論理的なコネクションの数だけセッショ~ ンが張られています。~ ~ しばらくDBへのアクセスを行なわずにいるとログには[論理的なコネクション~ を取得しました]の表示がOracleに張られていたセッションの数だけ表示されま~ す。(この時、Oracelのセッションも開放されています)~ ~ 利用しているSeasarのバージョン~ Seasar2.2.10~ S2DAO1.0.28~ ~ 以下のように設定を行なっているのですが、何か過不足がありますでしょうか?~ ~ ---[j2ee.dicon]---------------------------------- <?xml version="1.0" encoding="Shift_JIS"?> <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container//EN" "http://www.seasar.org/dtd/components.dtd"> <components namespace="j2ee.dicon"> <component name="transactionManager" class="org.seasar.extension.jta.TransactionManagerImpl"/> <component name="requiredTx" class="org.seasar.extension.tx.RequiredInterceptor"/> <component name="requiresNewTx" class="org.seasar.extension.tx.RequiresNewInterceptor"/> <component name="mandatoryTx" class="org.seasar.extension.tx.MandatoryInterceptor"/> <component class="org.seasar.extension.jdbc.impl. BasicResultSetFactory"/> <component class="org.seasar.extension.jdbc.impl. BasicStatementFactory"/> <component name="xaDataSource" class="org.seasar.extension.dbcp.impl.XADataSourceImpl"> <property name="driverClassName"> "oracle.jdbc.driver.OracleDriver" </property> <property name="URL"> "jdbc:oracle:thin:@192.168.0.5:1521:white" </property> <property name="user">"serverwatcher"</property> <property name="password">"serverwatcher"</property> </component> <component name="connectionPool" class="org.seasar.extension.dbcp.impl.ConnectionPoolImpl "> <property name="timeout">600</property> <property name="maxPoolSize">10</property> <destroyMethod name="close"/> </component> <component name="dataSource" class="org.seasar.extension.dbcp.impl.DataSourceImpl"/> </components> ---------------------------------------------------- >~ ---[dao.dicon]-------------------------------------- <?xml version="1.0" encoding="Shift_JIS"?> <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container//EN" "http://www.seasar.org/dtd/components.dtd"> <components namespace="dao"> <include path="j2ee.dicon"/> <component class="org.seasar.dao.impl.DaoMetaDataFactoryImpl"/> <component name="interceptor" class="org.seasar.dao.interceptors.S2DaoInterceptor"> <aspect>dao.requiredTx</aspect> </component> </components> ---------------------------------------------------- >~ ''Answer''~ 原因は ServerControllerの constructorにありますね。~ S2Containerを要求ごとに diconファイルから構築しているので、結局のとこ~ ろVM空間上に複数のコンポーネントセットが存在することになります。~ ~ ということは、DataSourceもConnectionPoolも複数あるので、ログにあるよう~ な動きになります。~ ~ S2の挙動というよりかは、DIの適用パターンにあわせて設計・動きを少し変更~ されたほうがよろしいかと思います。~ ~ 私なら以下の方法を使います~ ~ 1. EditLogic が xxxDao を使う(必須)のであれば EditLogicのコンストラ クタに引数を追加し、default constructorを削除する。 これは public EditLogic(xxxDao dao) { this.dao = dao; } のようにする 2. EditLogicは diconに定義する(か、自動登録されるような規則に従った 上でAutoRegisterを使う) これでEditLogicのインスタンス管理はコンテナのもとにあります 3. EditLogicが必要な部分は S2を経由してインスタンスを取得するように します。たとえば、EditLogicが StrutsのActionなのであれば S2Struts を用います. new EditLogic() している場所を getComponent(EditLogic.class) のよ うにすればいいかと思いますが、この方法を用いるのであればインタフェー スと実装クラスに分離したほうが良いです。 (S2JSFの場合は特に意識する必要すらないと思います) ~ ~ ''参考投稿''~ http://ml.seasar.org/archives/seasar-user/2005-November/000446.html~ http://ml.seasar.org/archives/seasar-user/2005-November/000481.html~ // **S2DAO、S2JDBC等のSQL発行方法について [#ef02361c] >[[S2サポーター]] (2006-04-29 (土) 19:42:46)~ ~ ''Question''~ ~ S2DAO、S2JDBC等でSQLを発行する際にコンパイル済みのSQLを発行するのか、~ 毎SQLを生成して発行するのか、どちらなのでしょう?サンプルのログをみてい~ ると毎回生成しているように思えるのですが。。。~ ~ ''Answer''~ ~ PreparedStatementに格納してあるプリコンパイルされたSQLを発行しています。~ ~ ログではき出されているSQLは、Statementに渡される(発行する)SQLを~ そのまま表示している訳ではなく、ログにはき出すためにS2が、パラメータが~ 埋め込まれたSQLをせっせと作っています。~ ~ org.seasar.extension.jdbc.impl.BasicHandlerクラスの~ getCompleteSqlメソッドが参考になると思います。~ http://www.seasar.org/websvn/filedetails.php?repname=s2container&path=%2Ftrunk%2Fseasar2%2Fs2-extension%2Fsrc%2Fmain%2Fjava%2Forg%2Fseasar%2Fextension%2Fjdbc%2Fimpl%2FBasicHandler.java&rev=0&sc=0~ ~ ''参考投稿''~ http://ml.seasar.org/archives/seasar-user/2005-November/000431.html~ http://ml.seasar.org/archives/seasar-user/2005-November/000452.html~ // **S2DaoでJDKを変えるとClassCastException [#n8b74b01] >[[S2サポーター]] (2006-04-29 (土) 19:40:26)~ ~ ''Question''~ ~ S2DaoでJDK1.4.2_08だと動くコードがJDK1.4.2_10にして~ Daoのメソッドを呼ぶとClassCastExceptionでこけてしまうコードがあります。~ ~ DaoのメソッドはBigDecimalを返すメソッドで引数4つを取ります。~ public BigDecimal sumTest(String a, String b, String c, String d, String e); public static final String sumTest_ARGS = "a,b,c,d"; ~ SQLファイルは~ select sum(qty) from testdat s left outer join xx l on s.hoge = l.hoge and s.hoge2 = l.hoge2 where s.a = /*a*/'a' and s.b = /*b*/'b' and s.c = /*c*/'0' and l.d = /*d*/'1' ~ となっています(フィールド名等はサンプルです)~ スタックトレースは~ java.lang.ClassCastException at sun.nio.cs.ext.JISAutoDetect$Decoder.decodeLoop(Unknown Source) at sun.nio.cs.ext.JISAutoDetect$Decoder.decodeLoop(Unknown Source) at java.nio.charset.CharsetDecoder.decode(Unknown Source) at sun.nio.cs.StreamDecoder$CharsetSD.implRead(Unknown Source) at sun.nio.cs.StreamDecoder.read(Unknown Source) at java.io.InputStreamReader.read(Unknown Source) at java.io.BufferedReader.read1(Unknown Source) at java.io.BufferedReader.read(Unknown Source) at java.io.Reader.read(Unknown Source) at org.seasar.framework.util.ReaderUtil.readText(ReaderUtil.java:27) at org.seasar.framework.util.TextUtil.readText(TextUtil.java:18) at org.seasar.dao.impl.DaoMetaDataImpl.setupMethod(DaoMetaDataImpl.java:132) at org.seasar.dao.impl.DaoMetaDataImpl.setupSqlCommand(DaoMetaDataImpl.java:112) at org.seasar.dao.impl.DaoMetaDataImpl.<init>(DaoMetaDataImpl.java:103) at org.seasar.dao.impl.DaoMetaDataFactoryImpl.getDaoMetaData(DaoMetaDataFactoryImpl.java:42) at org.seasar.dao.interceptors.S2DaoInterceptor.invoke(S2DaoInterceptor.java:34) at org.seasar.framework.aop.impl.NestedMethodInvocation.proceed(NestedMethodInvocation.java:26) at org.seasar.framework.aop.interceptors.TraceInterceptor.invoke(TraceInterceptor.java:33) at org.seasar.framework.aop.impl.NestedMethodInvocation.proceed(NestedMethodInvocation.java:26) at org.seasar.framework.aop.interceptors.InterceptorChain.invoke(InterceptorChain.java:24) at test.TestDatDao$$EnhancedByS2AOP$$18622f3$$MethodInvocation$$sumTest5.proceed(MethodInvocationClassGenerator.java) at test.TestDatDao$$EnhancedByS2AOP$$18622f3.sumTest(TestDatDao$$EnhancedByS2AOP$$18622f3.java) ~ となっております。~ SQLを組み立てる時にこけている様な感じです。~ DAOのバージョンはs2-dao-1.0.28.jarでPostgreSQL8.0.3を使っております。~ JDKの違いやdaoのバージョンで何か注意する点等ありますでしょうか?~ ~ ''Answer''~ ~ JDK 1.4.2_10にはJISAutoDetectのバグがあります。~ http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=25802&forum=12~ ~ FIXされるまで1.4.2_10より前のバージョンを使われることをオススメします。~ ~ ''参考投稿''~ http://ml.seasar.org/archives/seasar-user/2005-November/000429.html~ http://ml.seasar.org/archives/seasar-user/2005-November/000430.html~ // **プライマリキーが無いテーブルにS2DAOでアクセスしたい [#v3762873] >[[S2サポーター]] (2006-04-29 (土) 19:33:05)~ ~ ''Question''~ ~ S2Daoのプライマリーキーの処理について伺います。~ ~ S2Daoを使ってDB2へのアクセスを勉強しております。~ テーブルにプライマリーキーが設定していないと、S2Daoが~ 「・・にプライマリーキーが見付りません」の例外を投げてきます。~ 当然テーブルに直接プライマリーキーが設定していれば問題が~ ありませんが、既存のテーブルに明示的に主キーではなく、~ Index(索引)の形で主キーを指定されていることです。~ ~ この場合はS2Daoをどのようにすれば~ 「・・にプライマリーキーが見付りません」の例外を回避できるのでしょうか。~ ~ ''Answer''~ UPDATEやDELETEなどの自動生成を行わなければ、プライマリキー~ がなくても問題ありません。~ したがって、UPDATEやDELETEをsqlファイルやsqlコメントで行えば~ 例外を回避できると思います。~ ~ ''参考投稿''~ http://ml.seasar.org/archives/seasar-user/2005-October/000626.html~ http://ml.seasar.org/archives/seasar-user/2005-October/000632.html~ // **S2で複数DBとのコネクションを取得する方法は? [#q70fa8ce] >[[S2サポーター]] (2006-04-29 (土) 19:30:14)~ ~ ''Question''~ j2ee.diconでの設定を利用すれば自動的に1個のコネクションを得られます。~ 複数DBとのコネクションを取得するにはどうすればよいのでしょうか。~ ~ ''Answer''~ ~ まず,j2ee.dicon をコピーして DB 接続ごとの dicon ファイルを~ 作成してください.~ 例えば ds1.dicon~ ~ <components namespace="ds1"> <include path="j2ee.dicon"/> <component name="dataSource" class="..."> ・・・ </component> <component name="xaDataSource" class="..."> ・・・ </component> <component name="connectionPool" class="..."> ・・・ </component> </component> ~ 必要なコンポーネントは 3 つだけです.~ transactionManager 等のコンポーネントは削除してください.~ ~ 同じように ds2.dicon も作成します.~ ~ そして j2ee.dicon から name 属性が以下の値になっている<component> 要素を削除します.~ ~ dataSource~ xaDataSource~ connectionPool~ ~ ds1.dicon で記述したコネクションを使用するコンポーネント用の~ dicon は ds1.dicon をインクルードします.~ 例えば app1.dicon~ <components namespace="app1"> <include path="ds1.dicon"/> ・・・ <components> ~ ds2.dicon で記述したコネクションを使用するコンポーネント用の~ dicon は ds2.dicon をインクルードします.~ 例えば app2.dicon~ ~ <components namespace="app2"> <include path="ds2.dicon"/> ・・・ <components> ~ もし,ds1.dicon と ds2.dicon に記述したコネクションを同時に~ 使用するコンポーネントがある場合は,両方をインクルードして~ コンポーネントのプロパティに明示的に DataSource を設定します.~ 例えば app3.dicon~ ~ <components namespace="app3"> <include path="ds1.dicon"/> <include path="ds2.dicon"/> <component name="..." class="..."> <property name="dataSource1">ds1.dataSource</property> <property name="dataSource2">ds2.dataSource</property> ・・・ </component> ・・・ </components> ~ ~ 最後に,app1.dicon や app2.dicon,app3.dicon 等を app.dicon に~ インクルードします.~ ~ <components> <include path="app1.dicon"/> <include path="app2.dicon"/> <include path="app3.dicon"/> ・・・ </components> ~ ~ 実際に確認していないので間違いがあるかもしれませんが,~ だいたいこんな感じでできるかと思います.~ ~ ''参考投稿''~ http://ml.seasar.org/archives/seasar-user/2005-October/000574.html~ http://ml.seasar.org/archives/seasar-user/2005-October/000575.html~ // **複雑なSQLを処理する場合の実装方法 [#j36201a2] >[[S2サポーター]] (2006-04-29 (土) 19:26:23)~ ~ ''Question''~ 複雑なSQLを処理する場合の実装方法について教え頂けませんでしょうか?~ ~ ''Answer''~ 引数の値をSQL文に文字列として直接埋め込む。[[ドキュメント:http://s2dao.seasar.org/ja/s2dao.html]]の~ 「埋め込み変数コメント」を参照。~ ~ ''参考投稿''~ http://ml.seasar.org/archives/seasar-user/2005-December/000288.html~ http://ml.seasar.org/archives/seasar-user/2005-December/000301.html~ // **S2DAOで幾何データ演算子を使いたい [#u7f14c3b] >[[S2サポーター]] (2006-04-29 (土) 18:45:30)~ ~ ''Question''~ s2daoを使用して、PostgresSQLの幾何データ型を扱っているのですが、~ PostgresSQLがサポートしている幾何データ演算子の中には~ ?# のように「?」を含む演算子があります。~ ~ 例:select A.name from road as A, road as B where A.path ?# B.path and~ B.name = 'hoge';~ ~ この演算子を使用したSQLを発行しようとすると、「?」がバインド変数とみなされ~ て、~ java.sql.SQLExceptionが発生してしまいます。~ ~ ログで実行されたSQLをみてみると、~ select A.name from road as A, road as B where A.path null# B.path and B.name~ = 'hoge';~ となっています。~ ~ org.seasar.framework.util.PreparedStatementUtilで~ java.sql.PreparedStatementを使用している以上、~ s2daoでPostgresSQLの幾何データ演算子を使用することはできないのでしょうか?~ ~ ちなみに、単独でjava.sql.Statementを使用して同じSQLを発行すると、~ 正常に問い合わせが行われました。~ ~ 何かよい方法があれば、教えてください。~ よろしくお願い致します。~ ~ ~ ''Answer''~ CREATE OPERATOR文を使用して、新しく作成したOPERATORの中でpath_interを~ 呼び出すことで、無事解決することができました。~ ~ ''参考投稿''~ http://ml.seasar.org/archives/seasar-user/2006-January/000175.html~ http://ml.seasar.org/archives/seasar-user/2006-January/000176.html~ http://ml.seasar.org/archives/seasar-user/2006-January/000177.html~ // **接続先DBを動的に変更したい [#z13fc424] >[[S2サポーター]] (2006-04-29 (土) 18:39:45)~ ~ ''Question''~ ~ j2ee.diconで定義しているxaDataSourceのdriverClassNameや、URLなどの値~ を、他外部ファイルの値にプログラム内で置き換え、変更後はその変更した~ 値でDBにアクセスすることは可能でしょうか?~ ~ 例) ・j2ee.diconファイルの情報 driverClassName =oracle.jdbc.driver.OracleDriver URL = jdbc:oracle:thin:@xxx:1521:yyy : ↓ 動的に、外部ファイルの内容に置き換えたい。 ・外部ファイルの情報 driverClassName =org.postgres.jdbc.driver.PostgresDriver URL=jdbc:postgresql://localhost:5432:yyy ~ j2ee.dicon 一部抜粋 --------- <component name="xaDataSource" class="org.seasar.extension.dbcp.impl. XADataSourceImpl"> <property name="driverClassName"> "oracle.jdbc.driver.OracleDriver" </property> <property name="URL"> "jdbc:oracle:thin:@xxx:1521:yyy" </property> <property name="user"> "aaa" </property> <property name="password"> "bbb" </property> </component> ----------------------------- ~ なぜ上記のような質問をしたかと言いますと、現在「S2DAOを使用しDBにア~ クセスするサーバ常駐プログラム」を開発しており、設定ファイルなどを使用~ して動的に接続先DBを変更できる仕様を検討しているためです。~ ~ 以下URLに記載されているように、DAOクラスにてprivate変数にDataSource~ を定義して、コネクション取得時にURLなどの情報を変更することもできそ~ うですが、なるべくDAO実装クラスを書きたくありません。~ (DAOインタフェースのみで対処したい)~ ~ http://www.seasar.org/dbcp.html~ ~ ~ ''Answer''~ 【Answer1】~ 私もアプリ起動中の動的な接続先データベースの変更~ (スキーマもDBMSも完全にコンパチで拠点だけ2つある(テスト系:本番系のよう~ な)イメージ)を以下の方法で実施しています~ ~ 1. connectionPoolを複数設定 (接続先ごとに)~ 2. DataSourceを継承したクラスを作成~ 2-1. connectionPoolを動的に変更できるsetterを準備しておく~ 3. 必要なときに setterを読んで接続先を変更する~ 4. あとは S2Daoでもなんでも...~ ~ ただし、この方法でS2Daoの接続先を変更する場合には、複数の接続先はDBMS~ も含めてほぼ?コンパチである必要があると思います。~ (DBMSの情報を取得していますから > S2DaoInterceptor)~ ~ ですので、ご質問の内容で driverClassまで置き換えることが前提となってい~ るようですのでこの方法ではS2Daoは誤動作する可能性があると思います。~ (DaoMetaDataImplのコンストラクタ内でDBMS情報を取得しているようです)~ ~ Daoインタフェースから参照しているエンティティも同様ですので、テーブル~ 構造が微妙に違う場合も同様の問題がありますね.~ ~ 当方はWebアプリということもあり以下のようなことになっています~ ~ a. sessionスコープの "コネクション先情報" コンポーネントを用意~ b. 継承したDataSourceから sessionスコープの上記コンポーネントをget~ (するとユーザーごとの接続先データベースが取得できる)~ c. connectionPoolのsetterは この"コネクション先情報"コンポーネントに格納する (=sessionに格納される)~ ~ このコンポーネントは ConnectionPoolのフィールドを1つだけ持つJavaBeanで~ 充分です。~ ~ やり方としてはエレガントではないかもしれませんがいまのところ機能してい~ ます。~ ~ ~ 【Answer2】~ <component name="props"> <initMethod>@org.seasar.framework.util.ResourceUtil @ getProperties('abc.properties')</initMethod> </component> <component name="xaDataSource" class="org.seasar.extension.dbcp.impl. XADataSourceImpl"> <property name="URL">props.URL</property> ... </component> ~ みたいなかんじでできますよ。~ abc.propertiesは、この例だとCLASSPATHに通されているディレクトリの~ ルートに置いてください。~ ~ 動的にっていっているところが意図するところと合ってないかもしれませんが。~ ~ ~ ''参考投稿''~ http://ml.seasar.org/archives/seasar-user/2006-March/005258.html~ http://ml.seasar.org/archives/seasar-user/2006-March/005259.html~ http://ml.seasar.org/archives/seasar-user/2006-March/005262.html~ // **条件を設定してCountを実行する方法は? [#nce57178] >[[S2サポーター]] (2006-04-29 (土) 18:37:25)~ ~ ''Question''~ S2DAOでcount(*)のSQLに条件を入れて実行すると必ず件数が0件と返ってきます。~ 条件なしに実行すると件数は取得できます。~ ~ 書き方が誤っているのでしょうか。~ 条件があっても件数を取得できる方法を教えていただけますでしょうか。~ ~ よろしくお願いします。~ ~ --------------------- 簡易ソース ---------------------- DAOクラス public static final Class BEAN = HogeDto.class; public static final String getCount_ARGS = "hoge"; int getCount(String hoge); DTOクラス 省略 SQLファイル SELECT COUNT(*) FROM AAAA WHERE HOGE = /*hoge*/ ------------------------------------------------------- ~ ''Answer''~ SQL自体は正しかったのですが、SQLコメントにyear,monthなど予約語で使われている~ ものを使用すると条件が無視されていることがわかりました。~ ~ なのでyear,monthのSQLコメントをintYear,intMonthに直して実行すると件数の取得ができました。~ ~ ~ ''参考投稿''~ http://ml.seasar.org/archives/seasar-user/2006-March/005349.html~ http://ml.seasar.org/archives/seasar-user/2006-March/005351.html~ http://ml.seasar.org/archives/seasar-user/2006-March/005355.html~ // **データベースアクセス時にタイムアウトさせたい [#i360044e] >[[S2サポーター]] (2006-04-29 (土) 18:36:01)~ ~ ''Question''~ S2daoを使ってDBにアクセスする際に、~ statementのqueryTimeoutを設定することはできないのでしょうか?~ ~ SQLを投げて処理が重くてかえってこない場合にタイムアウト~ にしたいのですが。。。~ ~ DBはオラクルを使っています。~ ~ ''Answer''~ もし、Dao全体で、1つのqueryTimeoutでいいのでしたら、~ org.seasar.extension.jdbc.StatementFactoryを自分で継承した~ クラスを作り、j2ee.diconの~ <component class="org.seasar.extension.jdbc.impl.BasicStatementFactory"/> のところを置き換えればできると思います。~ ~ Daoごとに、queryTimeoutの値を変えたいのでしたら、~ http://groovetube.org/index.php?itemid=183&catid=6~ こちらのページを参考にして、queryTimeoutごとにdao.diconを~ 作ればできなくはないと思います。~ ~ あるメソッドだけ、queryTimeoutの値を変えたい場合は申し訳ないのですが、~ 今はできないと思います。~ ~ ~ ''参考投稿''~ http://ml.seasar.org