FAQ

S2Dao

なんか動かないのだけれど

updateの際に更新したくない列を指定したい

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

コネクションプーリングが行われていない?

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発行方法について

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

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でアクセスしたい

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とのコネクションを取得する方法は?

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を処理する場合の実装方法

S2サポーター (2006-04-29 (土) 19:26:23)

Question
複雑なSQLを処理する場合の実装方法について教え頂けませんでしょうか?

Answer
引数の値をSQL文に文字列として直接埋め込む。ドキュメント
「埋め込み変数コメント」を参照。

参考投稿
http://ml.seasar.org/archives/seasar-user/2005-December/000288.html
http://ml.seasar.org/archives/seasar-user/2005-December/000301.html

S2DAOで幾何データ演算子を使いたい

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を動的に変更したい

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を実行する方法は?

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

データベースアクセス時にタイムアウトさせたい

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


トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS