おきらくmanholeの日記

id:manhole

2004-09-18

Oracleへ出し入れするとコードが変わってしまう文字 03:04

http://d.hatena.ne.jp/kare/20040914#p2 では 0x301c ('~')のみの対応だったので、他の文字ってどうだったかなぁとちょっと気になってテストしました。

※Oracle8.0.6です。

Oracleへ出し入れするとコードが変わってしまう文字には、次のものがありました。

DBへ入れる前                DBから取り出した
文字    コード              文字    コード
----    ----------------    ----    ----------------
¢      0x00a2 (162  )      ¢      0xffe0 (65504)
£      0x00a3 (163  )      £      0xffe1 (65505)
\       0x00a5 (165  )      \       0x005c (92   )
?       0x00a6 (166  )      ¦      0xffe4 (65508)
¬      0x00ac (172  )      ¬      0xffe2 (65506)
?       0x2014 (8212 )      ―      0x2015 (8213 )
?       0x2016 (8214 )      ∥      0x2225 (8741 )
?       0x2212 (8722 )      -      0xff0d (65293)
?       0xba59 (47705)      昂      0x6602 (26114)
~      0xff5e (65374)      ?       0x301c (12316)

表示できないのは'~'だけですね。


Oracleのドキュメントは読みづらい。。。

SugarSugar2012/02/16 17:35At last! Someone with real exprteise gives us the answer. Thanks!

irbphydomirbphydom2012/02/17 03:35UffQG0 <a href="http://fhrgyxdawuav.com/">fhrgyxdawuav</a>

vuojlnpvuojlnp2012/02/22 02:58h7ebJD <a href="http://kesjkanmhqil.com/">kesjkanmhqil</a>

2004-08-01

assertMapListEquals が追加されてる 09:24

  • S2TestCaseでDataSetとMap, MapのList, Bean, BeanのListをassertEquals()で比較が可能。

http://d.hatena.ne.jp/higayasuo/20040731#1091266666

って書かれてたので、先日コケたテスト (id:manhole:20040724#1090620683) で試してみました。

S2Dao 1.0.3で、MapのAssertが通ることを確認しましたっ!

BarbarBarbar2013/11/25 15:26Why does this have to be the ONLY reblaile source? Oh well, gj! http://hgbfhe.com [url=http://vkalsoqfhym.com]vkalsoqfhym[/url] [link=http://neilnfzjod.com]neilnfzjod[/link]

2004-07-27

ちょっとした検証 - マルチスレッドセーフ 00:19

※これもメモ書きでっす。


どの単位でDaoやSelectHandlerのインスタンスを生成したら良いのか調べるため、Dao 1インスタンスをマルチスレッドで回してみました。

※SelectHandlerをnewするのは...

  • アクセスの度にnewする?
  • 1スレッドで1つnewする?
  • 複数スレッドで1インスタンスを共有可能? ←★結果はこれ。

S2DaoとJ2JDBCとを試してみて、どちらも MT Safe でした。

----

S2Daoの自動生成SQLだと、Handler (BasicSelectHandlerなど) は、SQL実行の度 (dao.getEmployeeの度) に生成された。

じゃあ BasicSelectHandler は Safe じゃないのかなと思ったけど、そんなことはなかった。

  • 複数スレッドで1つの BasicSelectHandler を共有するけれど、MT Safe に動いている。
    • BasicSelectHandlerの場合は、dicon ファイルで与える情報はフィールドに保持・複数スレッドで共有されるけれど、リードオンリーなので平気。
    • BeanResultSetHandler も同様にできている。

なので、SelectHandler や ResultSetHandler の亜種を自作する場合は、MT Safe になるようにすべし。少なくとも、フィールドを更新するように作る場合はマルチスレッドを考慮すること。

----

補足: あー、書き方が悪かったです。BasicSelectHandler のセッタを呼ばなければ MT Safe です。つまり、SelectHandler として使うぶんには Safe。ダウンキャストして、BasicHandler#setSql なんてやり出すとアウトです。(ふつーに使うぶんにはそんなことしませんケド。)


----

S2JDBCの場合のコード

  • EmployeeDao
package test.mt.s2jdbc;
import examples.dao.manhole.Employee;
public interface EmployeeDao {
    public Employee getEmployee(int empno);
}
  • EmployeeDaoImpl
package test.mt.s2jdbc;
import org.seasar.extension.jdbc.SelectHandler;
import examples.dao.manhole.Employee;
public class EmployeeDaoImpl implements EmployeeDao {
    private SelectHandler getEmployeeHandler_;
    public void setGetEmployeeHandler(SelectHandler getEmployeeHandler) {
        getEmployeeHandler_ = getEmployeeHandler;
    }
    public Employee getEmployee(int empno) {
        return (Employee)getEmployeeHandler_.execute(new Object[]{new Integer(empno)});
    }
}
  • dicon
<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container//EN"
"http://www.seasar.org/dtd/components.dtd">
<components>
  <include path="j2ee.dicon"/>
  <component class="test.mt.s2jdbc.EmployeeDaoImpl">
    <property name="GetEmployeeHandler">
      <component class="org.seasar.extension.jdbc.impl.BasicSelectHandler">
        <property name="sql">
"SELECT EMP.ename, EMP.empno, EMP.deptno FROM EMP EMP WHERE EMP.empno = ?"
        </property>
        <property name="resultSetHandler">
          <component class="org.seasar.extension.jdbc.impl.BeanResultSetHandler">
            <arg>@examples.dao.manhole.Employee@class</arg>
          </component>
        </property>
      </component>
    </property>
  </component>
</components>
  • テストコード
public void testMultiThread() {
    final EmployeeDao dao = dao_;
    final int times = 1000;
    Thread martinThread = new Thread() {
        public void run() {
            for (int i = 0; i < times; i++) {
                Employee emp = dao.getEmployee(7654);
                assertEquals("MARTIN", emp.getEname());
            }
        }
    };
    Thread scottThread = new Thread() {
        public void run() {
            for (int i = 0; i < times; i++) {
                Employee emp = dao.getEmployee(7788);
                assertEquals("SCOTT", emp.getEname());
            }
        }
    };
    Thread jamesThread = new Thread() {
        public void run() {
            for (int i = 0; i < times; i++) {
                Employee emp = dao.getEmployee(7900);
                assertEquals("JAMES", emp.getEname());
            }
        }
    };
    martinThread.start();
    scottThread.start();
    jamesThread.start();
    try {
        martinThread.join();
        scottThread.join();
        jamesThread.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

udagawaudagawa2004/10/14 17:58junit.extensions.ActiveTestSuite を調べるべし

FermelindaFermelinda2012/02/16 22:07Yeah, that's the tieckt, sir or ma'am

ygfcavayygfcavay2012/02/17 03:24YVU4Ks <a href="http://sifcegwoyjem.com/">sifcegwoyjem</a>

ioonuoexkioonuoexk2012/02/17 23:54cUrXAS , [url=http://qdbiiizmscxa.com/]qdbiiizmscxa[/url], [link=http://wrswniqhzqeq.com/]wrswniqhzqeq[/link], http://tlmzuwylpdsy.com/

qfqpcxtbqfqpcxtb2012/02/22 03:314g81UC <a href="http://xvihrpllbkvs.com/">xvihrpllbkvs</a>

2004-07-24

ちょっとした検証 - Excelから取得した期待値でassert 07:11

うーん、上手く動くと踏んだコードで、例外が投げられてしまいました。。。

org.seasar.extension.jdbc.ColumnNotFoundRuntimeException: [ESSR0068]テーブル(CaseInsensitiveMap)のカラム(NUMBERS)が見つかりません
    at org.seasar.extension.dataset.impl.DataTableImpl.getColumn(DataTableImpl.java:128)
    at org.seasar.extension.dataset.impl.DataRowImpl.getValue(DataRowImpl.java:57)
    at org.seasar.extension.dataset.impl.DataRowImpl.equals(DataRowImpl.java:139)
    at org.seasar.extension.dataset.impl.DataTableImpl.equals(DataTableImpl.java:291)
    at org.seasar.extension.dataset.impl.DataSetImpl.equals(DataSetImpl.java:115)
    at junit.framework.Assert.assertEquals(Assert.java:62)
    at org.seasar.dao.unit.BeanAssert.assertEquals(BeanAssert.java:31)
    at org.seasar.dao.unit.S2DaoTestCase.assertEquals(S2DaoTestCase.java:22)
    at org.seasar.dao.unit.S2DaoTestCase.assertEquals(S2DaoTestCase.java:26)
    at test.xlsExpected.EmployeeDaoTest.testGetEmployeeNumbersPerDepartment(EmployeeDaoTest.java:26)
    (以下略)

やろうとしたことは、Employeeから

  • 部署毎の所属社員数を算出する
  • 所属社員数の降順でソートする

というSQL (下記EmployeeDao.diconに記載) を発行し、Excelに書いた期待値(下記に記載)とassertする、ということ。

妙な例外メッセージに思えるあたり、何か勘違いしちゃってるかも。

----

  • [テストケース] EmployeeDaoTest
package test.xlsExpected;

import java.util.List;

import org.seasar.dao.unit.S2DaoTestCase;
import org.seasar.extension.dataset.DataSet;

public class EmployeeDaoTest extends S2DaoTestCase {

    private EmployeeDao dao_;

    public EmployeeDaoTest(String arg0) {
        super(arg0);
    }
    
    protected void setUp() throws Exception {
        include("test/xlsExpected/EmployeeDao.dicon");
    }

    public void testGetEmployeeNumbersPerDepartment() {
        DataSet expected = readXls("getEmployeeNumbersPerDepartment.xls");
        List actual = dao_.getEmployeeNumbersPerDepartment();
        System.out.println("expected=" + expected);
        System.out.println("actual=" + actual);
        assertEquals(expected, actual);
    }
}
  • [Dao] EmployeeDao
package test.xlsExpected;

import java.util.List;

public interface EmployeeDao {

    public List getEmployeeNumbersPerDepartment();

}
  • [Dao実装] EmployeeDaoImpl
package test.xlsExpected;

import java.util.List;

import org.seasar.extension.jdbc.SelectHandler;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;

public class EmployeeDaoImpl implements EmployeeDao {

    private static final String PATH = "test/xlsExpected/EmployeeDao.dicon";

    public List getEmployeeNumbersPerDepartment() {
        S2Container container = S2ContainerFactory.create(PATH);
        container.init();
        try {
            SelectHandler handler = (SelectHandler)container
                    .getComponent("getEmployeeCountPerDepartment");
            return (List)handler.execute(null);
        } finally {
            container.destroy();
        }
    }
}
  • [dicon] EmployeeDao.dicon
<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container//EN"
"http://www.seasar.org/dtd/components.dtd">
<components>
    <include path="j2ee.dicon"/>
    <component class="test.xlsExpected.EmployeeDaoImpl"/>
    
    <component name="getEmployeeCountPerDepartment"
        class="org.seasar.extension.jdbc.impl.BasicSelectHandler">
        <property name="sql">
"
SELECT 
    COUNT(*) AS NUMBERS
   ,DEPTNO
  FROM EMP
  GROUP BY DEPTNO
  ORDER BY 1 DESC
"
        </property>
        <property name="resultSetHandler">
            <component class="org.seasar.extension.jdbc.impl.MapListResultSetHandler"/>
        </property>
    </component>
</components>
  • [テストの期待値] getEmployeeNumbersPerDepartment.xls
    • Excelの"EMP"シートに記載
NUMBERS  DEPTNO
-------  ------
      6      30
      5      20
      3      10

----

  • テストケース実行時のコンソール出力結果

# テストケースに書いたSystem.outの内容を含みます。

## 期待値は正しいんだよな...

DEBUG 2004-07-24 07:28:02,512 [main] 
SELECT 
    COUNT(*) AS NUMBERS
   ,DEPTNO
  FROM EMP
  GROUP BY DEPTNO
  ORDER BY 1 DESC

DEBUG 2004-07-24 07:28:02,621 [main] 物理的なコネクションを取得しました
DEBUG 2004-07-24 07:28:02,621 [main] 論理的なコネクションを取得しました
DEBUG 2004-07-24 07:28:02,934 [main] 論理的なコネクションを閉じました
DEBUG 2004-07-24 07:28:02,934 [main] 物理的なコネクションを閉じました
expected=EMP:NUMBERS, DEPTNO
{6, 30}
{5, 20}
{3, 10}

actual=[{numbers=6, deptno=30}, {numbers=5, deptno=20}, {numbers=3, deptno=10}]

higayasuohigayasuo2004/07/24 08:14BeanAssertは名前の通り、いまのところJavaBeansしから検証できません。(^^;DaoにSelectHandlerをセットするにはDIを使ってください。自分で取りにいくのではなく。

manholemanhole2004/07/24 08:21Map → Bean に変えたら OK になりました!

manholemanhole2004/07/24 08:24DIにするとSQL文を増やしたときSelectHandlerが複数になって困るかと思って、自分で取りに行く形にしました。(このコードでは1SQLだから平気ですけれど)

manholemanhole2004/07/24 09:32↑複数でもインジェクトOKですね、勘違いしてました。もしくは、SelectHandlerじゃなくてContainerをインジェクトするとか。家を出てから気づいたですよ...

BraimahBraimah2012/02/16 22:33This is a really inletlignet way to answer the question.

qdrciefqdrcief2012/02/17 02:32Jv7YsC <a href="http://hdggkonpuitz.com/">hdggkonpuitz</a>

ywoaxqexzekywoaxqexzek2012/02/18 00:01hGfmgM , [url=http://qellngqfpmkc.com/]qellngqfpmkc[/url], [link=http://yseewsptkwxy.com/]yseewsptkwxy[/link], http://vlgfqqxtftmv.com/

2004-07-23

ちょっとした検証 - S2DaoとS2JDBCを1つのDaoインタフェースで使う 01:56

※これも実験結果のメモ書きです。

----

Daoのメソッドによって

  • 自動生成SQL
  • S2JDBCで指定したSQL (diconファイルに書いたSQL)

を任意に使用できるか可能か試してみました。

----

  • Daoの自動生成以外にもSQL文を書く必要がある場合
    • 集計する
    • ソート順が変化する
    • UNION ALLする
    • ヒント句を使う
  • Daoの"BEAN"アノテーション以外の型でデータを返したい場合
    • 集計する場合など

----

  • [テストケース] EmployeeDaoTest
    • テストケースでは1つのDaoとして使用する
package examples.dao.manhole;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import org.seasar.dao.unit.S2DaoTestCase;
public class EmployeeDaoTest extends S2DaoTestCase {
    private EmployeeDao dao_;
    public EmployeeDaoTest(String arg0) {
        super(arg0);
    }
    public void setUp() {
        include("examples/dao/manhole/EmployeeDao.dicon");
    }
    public void testGetScott() {
        Employee emp = dao_.getEmployee(7788);
        assertEquals("SCOTT", emp.getEname());
    }
    public void testGetHighestSalEmployee() {
        Employee emp = dao_.getHighestSalEmployee();
        assertEquals("KING", emp.getEname());
    }
    public void testGetCount() {
        int count = dao_.getCount();
        assertEquals(14, count);
    }
    public void testGetEmployeeNumbersPerDepartment() {
        List actual = dao_.getEmployeeNumbersPerDepartment();
        assertEquals(3, actual.size());
        Map m = (Map)actual.get(0);
        assertEquals(new Integer(6), m.get("NUMBERS"));
        assertEquals(new BigDecimal(30), m.get("DEPTNO"));
    }
}
  • [Dao] EmployeeDao
    • 自動生成用のメソッド・手書きのSQL(S2Dao)用のメソッド、S2JDBC用のメソッドを全て宣言する
package examples.dao.manhole;
import java.util.List;
public interface EmployeeDao {
    public Class BEAN = Employee.class;
    public String getEmployee_ARGS = "empno";
    // 自動生成SQL
    public Employee getEmployee(int empno);
    // diconにSQLを書く
    public Employee getHighestSalEmployee();
    // *.sqlにSQLを書く
    public int getCount();
    // diconにSQLを書く, Employee.classとは異なる型(ここではMap)で返す
    public List getEmployeeNumbersPerDepartment();
}
  • [抽象Dao] AbstractEmployeeDao
    • S2JDBCのメソッドはここに実装する
    • S2Daoで処理するメソッドは実装しないため、このクラスはabstractにする
package examples.dao.manhole;
import java.util.List;
import org.seasar.extension.jdbc.SelectHandler;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;
public abstract class AbstractEmployeeDao implements EmployeeDao {
    private static final String PATH = "examples/dao/manhole/EmployeeDao.dicon";
    public Employee getHighestSalEmployee() {
        S2Container container = S2ContainerFactory.create(PATH);
        container.init();
        try {
            SelectHandler handler = (SelectHandler)container.getComponent("getHighestSalEmployee");
            Employee emp = (Employee)handler.execute(null);
            return emp;
        } finally {
            container.destroy();
        }
    }
    public List getEmployeeNumbersPerDepartment() {
        S2Container container = S2ContainerFactory.create(PATH);
        container.init();
        try {
            SelectHandler handler = (SelectHandler)container.getComponent("getEmployeeNumbersPerDepartment");
            return (List)handler.execute(null);
        } finally {
            container.destroy();
        }
    }
}
  • [SQL] AbstractEmployeeDao_getCount.sql
    • ファイル名にAbstractが付いちゃうのね...
SELECT COUNT(*) FROM EMP
  • [dicon] examples/dao/manhole/EmployeeDao.dicon
<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container//EN"
"http://www.seasar.org/dtd/components.dtd">
<components>
    <include path="j2ee.dicon"/>
    <component class="examples.dao.manhole.AbstractEmployeeDao">
        <aspect>
            <component class="org.seasar.dao.interceptors.S2DaoInterceptor"/>
        </aspect>
    </component>

    <component name="getHighestSalEmployee"
        class="org.seasar.extension.jdbc.impl.BasicSelectHandler">
        <property name="sql">
"
SELECT
    EMP.ename
   ,EMP.empno
   ,EMP.deptno
  FROM EMP
  WHERE SAL = (SELECT MAX(SAL) FROM EMP)
"
        </property>
        <property name="resultSetHandler">
            <component class="org.seasar.extension.jdbc.impl.BeanResultSetHandler">
                <arg>@examples.dao.manhole.Employee@class</arg>
            </component>
        </property>
    </component>

    <component name="getEmployeeNumbersPerDepartment"
        class="org.seasar.extension.jdbc.impl.BasicSelectHandler">
        <property name="sql">
"
SELECT
    COUNT(*) AS NUMBERS
   ,DEPTNO
  FROM EMP
  GROUP BY DEPTNO
  ORDER BY 1 DESC
"
        </property>
        <property name="resultSetHandler">
            <component class="org.seasar.extension.jdbc.impl.MapListResultSetHandler"/>
        </property>
    </component>
</components>
  • [Bean] Employee

下に載せたのと同じ

ちょっとした検証 - 自動生成されるSELECT文 08:01

Beanのアノテーションがどう影響するのかと思い、ちょっと確認してみる。

public String getEmployee_ARGS = "empno"; のとき

SELECT EMP.ename, EMP.empno, EMP.deptno FROM EMP WHERE  EMP.empno = 7788

public String getEmployee_ARGS = "ename"; のとき

SELECT EMP.ename, EMP.empno, EMP.deptno FROM EMP WHERE  EMP.ename = 7788

public String getEmployee_ARGS = "aaaaa"; のときは例外が発生する

org.seasar.extension.jdbc.ColumnNotFoundRuntimeException: [ESSR0068]テーブル(EMP)のカラム(aaaaa)が見つかりません

アノテーションが無い場合 (コメントアウトした)

SELECT EMP.ename, EMP.empno, EMP.deptno FROM EMP

----

わかったこと

  • アノテーションの値は、where句のカラム名になった。存在しないカラムの場合は例外が発生する。
  • テーブルの項目よりもBeanのプロパティが少ない場合は、Beanのプロパティ項目がSELECTされる。(実際には、EMP.JOBといったカラムが存在するがSELECTされていない)
  • アノテーションが無い場合は、where句が生成されない。→全検索になる

----

使用したのは以下のソース。(S2Daoのサンプルを簡略化したもの)

自動生成のテストが目的なので、*.sqlファイルはありません。

  • テストクラス
    • 上記SQLはtestGetScottを実行した際のもの
package examples.dao.manhole;
import org.seasar.dao.unit.S2DaoTestCase;
public class EmployeeDaoTest extends S2DaoTestCase {
    private EmployeeDao dao_;
    public EmployeeDaoTest(String arg0) {
        super(arg0);
    }
    public void setUp() {
        include("examples/dao/manhole/EmployeeDao.dicon");
    }
    public void testGetScott() {
        Employee emp = dao_.getEmployee(7788);
        assertEquals("SCOTT", emp.getEname());
    }
}
  • DAO
package examples.dao.manhole;
public interface EmployeeDao {
    public Class BEAN = Employee.class;
    public String getEmployee_ARGS = "empno";
    public Employee getEmployee(int empno);
}
  • Bean (S2サンプルのものから項目を幾つか削った)
package examples.dao.manhole;
import java.io.Serializable;
public class Employee implements Serializable {
    public static final String TABLE = "EMP";
    private long empno;
    private String ename;
    private short deptno;
以下Setter/Getterが続く
  • dicon (examples/dao/manhole/EmployeeDao.dicon)
    • 特殊なことは何もしていない
<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container//EN"
"http://www.seasar.org/dtd/components.dtd">
<components>
    <include path="j2ee.dicon"/>
    <component class="examples.dao.manhole.EmployeeDao">
        <aspect>
            <component class="org.seasar.dao.interceptors.S2DaoInterceptor"/>
        </aspect>
    </component>
</components>

BrendyBrendy2012/02/16 13:18Smart thinking - a cevler way of looking at it.

iqeemirnyiqeemirny2012/02/16 19:32V4EXp1 <a href="http://vffeiklxdzrh.com/">vffeiklxdzrh</a>

fsrcizmmadfsrcizmmad2012/02/17 17:568JhhFX , [url=http://mreyvbmnhtif.com/]mreyvbmnhtif[/url], [link=http://rczlragszegk.com/]rczlragszegk[/link], http://pfiskobgaqqf.com/

ziuqcpvgtisziuqcpvgtis2012/02/20 03:00OoXyQS <a href="http://hfjnoesmzvkk.com/">hfjnoesmzvkk</a>

2004 | 05 | 06 | 07 | 08 | 09 |