| 与Seasar2同样,S2Dao需要JDK1.4以上的系统环境。将s2-dao-x.x.x.zip解压缩后存入到某个目录下,启动Eclipse,选择「文件→导入→现有项目到工作区」操作,将S2Dao引入到Eclipse里。必要的Seasar2版本,请参阅Wiki的说明。
		在s2-dao-examples/src/main/java目录下有一些例子。
		 S2Dao必需的jar文件,1.0.41版本以后全部存放在lib目录下。在此之前的版本,则需要Seasar2的所有必须的jar文件和Seasar2本体(s2-framework/s2-extension)。为了能够简单的体验数据库功能,提供了HSQLDB作为RDBMS。
		lib/hsqldb.jar在运行HSQLDB时是必须的,但是在实际环境中则不需要。
		lib/s2-framework-2.3.xx-sources.jar和s2-extension-2.3.xx-sources.jar,可以用于在Eclipse上查看源程序,在S2Dao的运行中并不是必须的库文件。
		只要CLASSPATH里包含有lib目录下的jar文件(hsqldb.jar除外)和src目录下的j2ee.dicon(使用Seasar2.4的话则是jdbc.dicon),S2Dao就能够运行。如果是导入到Eclipse的场合则不需要任何设定。 dao.dicon是S2Dao的设定文件。想要更改设定的时候请参阅
		dao.dicon指南。
		 使用S2Pager功能的场合,必须修改j2ee.dicon的设定。(v1.0.36以后缺省设定为有效配置)。
		具体的设定内容请参阅S2Pager的资料。
		 使用S2Dao功能时,必须作成JavaBeans,Dao(.java),dicon文件,SQL文件(.sql)。
	    各文件之间的关系如下图所示。
   JavaBeans和表,Dao和JavaBeans,dicon文件和Dao,SQL文件和Dao相互之间是有关联的。各文件的实装以及设定方法的详细情况如下。
 
    	JavaBeans用来和表进行关联。
		为了将JavaBeans和表进行关联,必须进行以下的常量声明和方法的实装。 JavaBeans的构成和说明中使用的表如下所示。表:EMP 
 
			
			  | 列名 | 类型 | NotNull | 主键(key) |  
			  | EMPNO | NUMBER | 〇 | 〇 |  
			  | ENAME | VARCHAR | 
 | 
 |  
			  | DEPTNUM | NUMBER | 
 | 
 |  表:DEPT
 
 
			
			  | 列名 | 类型 | NotNull | 主键(key) |  
			  | DEPTNO | NUMBER | 〇 | 〇 |  
			  | DNAME | VARCHAR | 
 | 
 |  要和表进行关联,使用TABLE注释。
		TABLE注释使用以下的形式进行常量声明。  -  public static final String TABLE = “表名”; EMP表的声明为如下形式。 public static final String TABLE = "EMP"; 这也可以用于定义schema。schema名为"SCOTT"的场合,声明如下所示。 public static final String TABLE = "SCOTT.EMP";※如果从类名中除去包名得到的名字和表名一致的话,则没必要定义TABLE注释。 还有,使用dao.dicon来指定org.seasar.dao.impl.DecamelizeTableNaming的场合,从类名中除去包名的名字,如果是以大写字母定义并且单词之间使用_为分隔符,其与表名一致的话,也不必定义TABLE注释(1.0.44以后)。
 
 要和表的列项进行关联,使用COLUMN注释。COLUMN注释使用以下的形式进行常量声明。
 -  public static final String 属性名_COLUMN = "列名";employeeNo属性和EMPNO列名进行关联的场合,声明如下所示。 public static final String employeeNo_COLUMN = "EMPNO";※从列名中除去_(下划线)之后的名字和属性名一致的话,则不必定义COLUMN注释。
		表中不存在的属性会自动被忽略,无需做任何定义。 N:1映射指的是多条员工记录与一个部门记录进行关联时的映射。使用N:1映射的时候,必须各自声明RELNO常量和RELKEYS常量。
 RELNO常量的声明如下所示。
 -  public static final int 属性名_RELNO = 数值; RELNO常量是N:1映射的序列号。例如,假定AAA表和BBB表,CCC表之间具有N:1映射关系,那么BBB的序列号为0,CCC的序列号为1。
 在判断结果集合中的列名属于哪一个表时会用到RELNO。
 例如,像SELECT ..., BBB.HOGE AS HOGE_0, ... FROM AAA, BBB ...之类的SELECT指令中,HOGE_0指的就是BBB表中的HOGE列项。
 RELKEYS常量的声明如下所示。
 -  public static final String 属性名_RELKEYS = "N侧的表之列名: 1侧的表之列名"; N:1映射的键由RELKEYS常量指定。
		如果有复数个键的场合,用逗号( , )进行分隔。例如,mykey1:yourkey1, mykey2:yourkey2,像这样来表示。EMP表的DEPTNUM列项とDEPT表的DEPTNO列项之间进行关联时如下所示。
 
public static final int department_RELNO = 0;
public static final String department_RELKEYS = "DEPTNUM:DEPTNO";
 1侧的表之列名和N侧的表之列名相等的场合,1侧的表之列名可以省略。
		这种场合的定义如下所示。 public static final String department_RELKEYS = "DEPTNO"; 还有,如果1侧的表的列名和N侧的表的列名相等,而且1侧的表的列名是主键(primaryKey)的场合,RELKEYS常量的定义可以省略。 
	使用ID注释,可以由RDBMS自动生成ID(主键),自动生成的主键值被自动地设定到Bean里。
	从1.0.47版本开始可以对复数项属性名指定ID注释。
	复数指定的场合,Bean被视为与拥有复合主键的表相关联。
	 
	ID注释的语法定义为,属性名_ID = "identity"这样的形式。 
	 public static final String id_ID = "identity"; 也可以使用SEQUENCE,请将myseq的部分,换成实际使用的SEQUENCE。 
public static final String id_ID = "sequence, sequenceName=myseq";
 
	使用SEQUENCE的场合,1.0.47版本以后还可以指定allocationSize参数。
	如果指定allocationSize参数,访问SEQUENCE的回数将会减少,由此提高了INSERT的性能。
	对allocationSize参数进行赋值时,所指定的数值,必须小于或等于SEQUENCE的增量值。 
public static final String id_ID = "sequence, sequenceName=myseq, allocationSize=10";
 手动设定ID值的场合,不必指定任何值。表的主键信息,可以自动从表的定义(JDBC的元数据(metadata))得到。另外,还可以显式(explicitly)赋值为assigned。 
public static final String id_ID = "assigned";
 使用不同的RDBMS时,可以相应地切换所用到的ID注释(1.0.41版本以后)。比如,Identity只用于与MySQL对应,SEQUENCE只用于与Oracle对应。 
public static final String id_mysql_ID = "identity";
public static final String id_oracle_ID = "sequence, sequenceName=myseq";
 指定的RDB以外的缺省值也能被指定。(1.0.41版本以后) 
public static final String id_mysql_ID = "identity";
public static final String id_ID = "sequence, sequenceName=myseq";
 RDBMS的后缀和可以使用的ID的取得方法,如下表所示。 
			
				| DBMS | 后缀 | Identity | SEQUENCE |  
				| Oracle | oracle | × | ○ |  
				| DB2 | db2 | ○ | ○ |  
				| MSSQLServer | mssql | ○ | × |  
				| MySQL | mysql | ○ | × |  
				| PostgreSQL | postgre | × | ○ |  
				| Firebird | firebird | × | ○ |  
				| MaxDB | maxdb | × | ○ |  
				| HSQL | hsql | ○ | ○ |  
				| Derby | derby | ○ | ○ |  
				| H2 | h2 | ○ | ○ |  
				| Sybase(1.0.43版本以后) | sybase | ○ | × |  
				| 其他的DB | 无后缀 | × | × |  
使用VALUE_TYPE注释,可以将JavaBeans的String类型的属性和表的CLOB类型进行关联。
以下是将"aaa"属性和CLOB类型进行关联的例子。
 
// JavaBeans
public static String aaa_VALUE_TYPE = "stringClobType";
private String aaa;
public String getAaa() {
    return aaa;
}
public void setAaa(String aaa) {
    this.aaa = aaa;
}
<!-- xxx.dicon -->
<component name="stringClobType" class="org.seasar.extension.jdbc.types.StringClobType" />
dicon指定的"StringClobType.class",是Java和RDBMS之间进行类型变换用的类(class)。
在VALUE_TYPE注释里,要指定dicon中设定的组件(component)名。 从表的定义(JDBC的元数据)可以自动得到某列项是否是持久化对象的信息。另外,也可以用NO_PERSISTENT_PROPS进行显式(explicitly)赋值,指定非持久化的列项。如果NO_PERSISTENT_PROPS参数被赋值为空文字,那么不需使用JDBC的元数据,所有的属性都被视为持久化的对象。 
public static final String NO_PERSISTENT_PROPS = "dummy1, dummy2";
 VERSION_NO_PROPERTY用于从缺省的versionNo改变使用versionNo进行排他控制的属性名。如下所示。 public static final String VERSION_NO_PROPERTY = "myVersionNo"; TIMESTAMP_PROPERTY用于从缺省的timestamp值改变使用timestamp进行排他控制的属性名。如下所示。 public static final String TIMESTAMP_PROPERTY = "myTimestamp";列项的值用Bean的实例变量表示。实例变量的声明方式有两种。 此方式要求声明与表的列项对应的实例变量以及访问方法(access method)。
访问方法的名字要遵循JavaBeans的命名规则,形式如下。
getter method -  public 类型 get属性名()setter method -  public void set属性名(参数)NUMBER类型的EMPNO列项的场合,属性和访问方法(access method)的定义如下所示。(相关阅读:COLUMN注释) private long empno;
public long getEmpno() {
    return empno;
}
public void setEmpno(long empno) {
    this.empno = empno;
}
※列项允许为Null的场合,如果变量是基本类型(primitive),那么当列项为Null的时候,返回值为0。如果想得到Null,请使用包装类(假如是int,那么就用java.lang.Integer类)。 与以上定义的EMP表相关联的Bean如下所示。 
public class Employee {
    public static final String TABLE = "EMP";
    public static final int department_RELNO = 0;
    public static final String department_RELKEYS = "DEPTNUM:DEPTNO";
    private long empno;
    private String ename;
    private Short deptnum;
    private Department department;
    public Employee() {
    }
    public Department getDepartment() {
        return department;
    }
    public void setDepartment(Department department) {
        this.department = department;
    }
    public Short getDeptnum() {
        return deptnum;
    }
    public void setDeptnum(Short deptnum) {
        this.deptnum = deptnum;
    }
    public long getEmpno() {
        return empno;
    }
    public void setEmpno(long empno) {
        this.empno = empno;
    }
    public String getEname() {
        return ename;
    }
    public void setEname(String ename) {
        this.ename = ename;
    }
}
从1.0.47版本开始,如果与Seasar2.4一起使用的场合,与列项对应的实例变量能够作为public字段来声明。
因为此方式不需要访问方法(access method),Bean的记述变得相当简单。
 
使用这种方式的场合,与EMP表进行关联的Bean如下所示。
 
public class Employee {
    public static final String TABLE = "EMP";
    public static final int department_RELNO = 0;
    public static final String department_RELKEYS = "DEPTNUM:DEPTNO";
    public long empno;
    public String ename;
    public Short deptnum;
    public Department department;
}
Dao作为接口而作成。Dao本来的目的,就是通过把持久化的数据和处理逻辑相分离,来维持Bean的持久化。
	    Dao和JavaBeans的关系是1:1的关系,也即,有一个JavaBeans,就要作成一个Dao。
		通过调用Dao的方法(method),来执行与方法(method)相对应的SQL文件中的SQL指令。
		在作成Dao的时候,必须注意以下几点。 还有,SQL指令中用到的方法(method)的参数,WHERE子句,ORDER子句的追加,更新指令中包含的或者是没有包含的属性被指定的场合,使用以下的注释。 Dao的方法(method)名必须以下表中列出的单词开头。		
		如果想要更改命名规则,请参阅dao.dicon指南中的「DaoNamingConventionImpl」章节。
		 
			
			  | 处理 | 名称 |  
			  | 插入 | insert,add,create |  
			  | 更新 | update,modify,store |  
			  | 删除 | delete,remove |  
			  | 检索 | 以上各单词之外 |  BEAN注释用来指定Dao和哪一个JavaBeans(实体Entity)相关联。
	    1.0.46版本以后,如果Dao里仅仅定义了PROCEDURE注释,或者是利用SQL文件的方法(method),不需指定BEAN注释。BEAN注释以下列形式来声明常量。
 -  public static final Class BEAN = JavaBeans名.class; EmployeeDao类和Employee实体(Entity)进行关联的场合,定义如下。 	 public static final Class BEAN = Employee.class; 使用ARGS注释指定方法(method)的参数名,这样就可以在SQL指令中引用方法(method)的参数。因为方法(method)的参数名,不能从反射(reflection)中得到。ARGS注释以下列形式来声明常量。
 - public static final String 方法名_ARGS = "参数名"; public Employee getEmployee(int empno) 方法在Dao中被定义的场合,参数名的定义如下。 public static final String getEmployee_ARGS = "empno"; 方法(method)的参数与表的列名相对应的场合,在参数名中指定表的列名。例如,方法(method)的参数名是empno,表的列名是employeeno的场合,就指定为employeeno。
		如果是有复数个参数的场合,则用逗号分隔。只有一个参数的场合,ARGS注释可以省略。 使用QUERY注释,可以在自动生成的SELECT指令或者DELETE指令(DELETE指令的生成要在1.0.44版本以后)之后,追加WHERE子句或者ORDER BY子句。QUERY注释以下列形式来声明常量。
 -  public static final String 方法名_QUERY = "WHERE子句ORDER BY子句"; 用参数设定工资的上限和下限,从中抽出符合该条件的公司员工名单的例子如下所示。 
public static final String getEmployeesBySal_QUERY = "sal BETWEEN ? AND ? ORDER BY empno";
public List getEmployeesBySal(Float minSal, Float maxSal);
 上例中的“?”被称为绑定(bind)变量。根据QUERY注释中的记述,方法中的参数值将按顺序被代入到绑定(bind)变量”?”的部分。
		这里不需要ARGS注释。如果只记述ORDER BY子句的话,请用ORDER BY子句开始。还可以使用SQL注解(comment)。
		使用SQL注解(comment)的例子如下所示。
		 public static final String getEmployees_QUERY =
                      "job = /*job*/'CLERK'/*IF deptno != null*/ AND deptno = /*deptno*/20/*END*/";
上面的例子中,参数值deptno不为Null的场合,追加了deptno等于参数值的条件。有关SQL注解(comment)的详细说明,请参阅SQL注解(comment)项。 虽然通过调用Dao里定义的方法(method),可以执行相应的SQL文件中记述的SQL指令,但是在更新处理和检索处理中需要遵循各自的方法命名规约。
		在S2Dao里,根据方法的命名规约将自动决定SQL指令的内容。
		还有,S2Dao不支持方法的重载(Overload)。
		 
		INSERT处理进行INSERT处理的方法名,必须以insert,add,create开头。
		返回值可以指定为void或者int。
		int的场合,返回值为更新的行数。参数类型与实体(Entity)的类型要一致。方法的定义例如下所示。
 public void insert(Department department);
public int addDept(Department department);
public void createDept(Department department);
UPDATE处理 进行UPDATE处理的方法名,必须以update,modify,store开头。
		返回值可以指定为void或者int。int的场合,返回值为更新的行数。参数类型与实体(Entity)的类型要一致。方法的定义例如下所示。
 
public int update(Department department);
public int modifyDept(Department department);
public void storeDept(Department department);
 从v1.0.37开始,方法名的末尾附有UnlessNull的UPDATE处理的场合,被传递给参数的Bean的字段中,
		只有其值不为null的列项才会被当作更新对象(批处理的场合不能使用这一功能)。UnlessNull的值,可以根据dao.dicon的设定来改变。
		要想更改设定,请参阅dao.dicon指南的「DaoNamingConventionImpl」章节。
 方法的定义例如下所示。
 
public int updateUnlessNull(Department department);
 从v1.0.40开始,方法名的末尾附有ModifiedOnly的UPDATE处理的场合,
		被传递给参数的Bean的字段中,只有其值发生了变化(调用setter进行更新)的字段才会被当作更新对象(批处理的场合不能使用这一功能)。要利用这一功能,被传递给使用ModifiedOnly方法的Bean就必须实装getModifiedPropertyNames这一方法。
		getModifiedPropertyNames方法(method)的实装,有以下两种方式。
 
 
		ModifiedOnly可以根据dao.dicon的设定来改变。
		要想更改设定,请参阅dao.dicon指南中的「DaoNamingConventionImpl」章节。方法的定义例如下所示。
 
public int updateModifiedOnly(Emp emp);
DELETE处理 进行DELETE处理的方法名,必须以delete,remove开头。
		返回值可以为void或者int类型。
		int的场合,返回值为更新的行数。参数类型与实体(Entity)的类型要一致。方法的定义例如下所示。
 
public void delete(Department department);
public int removeDept(Department department);
检索(SELECT)处理 进行检索处理的场合,要指定返回值的类型。返回值的类型是java.util.List的实装的场合,SELECT指令将返回实体(Entity)的列表(List)。返回值是实体(Entity)型的数组(array)的场合,返回实体数组(Entity array)。返回值的类型是实体(Entity)的场合,将返回实体(Entity)。 
public List selectList(int deptno);
public Department[] selectArray(int deptno);
 从v1.0.43开始,除了实体(Entity)以外,还可以利用DTO或者Map作为检索处理的返回值。
		返回值为DTO类型的列表(List<Dto>)的场合,将返回DTO的列表(List)。
		返回值为DTO类型的数组(Dto[])的场合,将返回DTO的数组(array)。
		返回值为Map类型的列表(List<Map>)的场合,将返回Map的列表(List)。
		返回值为Map类型的数组(Map[])的场合,将返回Map的数组(array)。 
public List<EmpDto> selectAsDtoList(int deptno);
public EmpDto[] selectAsDtoArray(int deptno);
public List<Map> selectAsMapList(int deptno);
public Map[] selectAsMapArray(int deptno);
 除此以外的场合,S2Dao还想定了这样一种情况,也即,像SELECT count(*) FROM emp这样的指令,返回值为1行只有一个列项值的情况。 
public int selectCountAll();
 有时候在更新的时候,会发生不希望在SQL指令中包含某个属性的情况。
	在这种场合,就可以使用NO_PERSISTENT_PROPS注释。 public static final String insert_NO_PERSISTENT_PROPS = "sal, comm"; 像上面这样指定的话,在insert方法(method)中,sal和comm属性就不是持久化的对象。 有时候在更新的时候,会发生希望在SQL指令中只包含某个属性的情况。
	在这种场合,使用PERSISTENT_PROPS注释。 public static final String insert_PERSISTENT_PROPS = "deptno"; 像上面这样指定的话,在insert方法(method)中,PERSISTENT_PROPS注释所指定的属性,将和主键(primary key),versionNo,timestamp的属性一起成为持久化的对象。 从1.0.28版本开始,可以使用SQL注释。此功能和SQL文件同样,在注释(annotation)中能使用SQL指令和SQL注解(comment)。 SQL注释里有命名规约。 public static final String getAllEmployees_SQL = "SELECT
emp.*, dept.dname dname_0, dept.loc loc_0 FROM emp, dept
 WHERE emp.deptno = dept.deptno ORDER BY emp.empno;";复数DBMS的对应 可以指定不同的SQL注释来对应不同的DBMS。
 	根据java.sql.DatabaseMetadata#getDatabaseProductName(),S2Dao可以自动判断用的是哪一个DBMS。
 	在S2Dao里,对应于不同的DBMS,有不同的后缀,所以在SQL注释中追加后缀。
 	例如,Oracle的场合,因为后缀是oracle,所以有「getAllEmployees_oracle_SQL」这样的注释。DBMS和后缀的关系如下所示。 
			
				| DBMS | 后缀 |  
				| Oracle | oracle |  
				| DB2 | db2 |  
				| MSSQLServer | mssql |  
				| MySQL | mysql |  
				| PostgreSQL | postgre |  
				| Firebird | firebird |  
				| MaxDB | maxdb |  
				| HSQL | hsql |  
				| Derby | derby |  
				| H2 | h2 |  
				| Sybase(1.0.43以后) | sybase |  从1.0.31版本开始,使用PROCEDURE注释可以执行StoredProcedure或者StoredFunction(1.0.47版本以后,推荐使用PROCEDURE_CALL注释)。PROCEDURE注释可以用以下的任意一种形式指定。 -  public static final String 方法名_PROCEDURE = "catalog名.schema名.procedure名"; -  public static final String 方法名_PROCEDURE = "schema名.procedure名"; -  public static final String 方法名_PROCEDURE = "procedure名"; -  public static final String 方法名_PROCEDURE = "package名.procedure名";(Oracle/1.0.41以后) -  public static final String 方法名_PROCEDURE = "schema名.package名.procedure名";(Oracle/1.0.41以后) 
 	可支持的StoredProcedure的范围PROCEDURE注释支持以下的StoredProcedure
 	 
 		不过,有复数OUT或者INOUT参数的场合,方法(method)的返回值必须是Map类型。有返回值的StoredProcedure有复数个IN,OUT,INOUT参数的StoredProcedure返回ResultSet的StoredProcedure 还有,根据DBMS或者JDBC驱动(driver)的实装情况,有可能发生不能利用的情况。 
 		
 			| DBMS | 限制事项 |  
 			| Oracle | 所有的类型(pattern)均可利用。 |  
 			| DB2 | - |  
 			| MSSQLServer | - |  
 			| MySQL | 不支持StoredFunction |  
 			| PostgreSQL | 不支持有2个以上的OUT或者INOUT参数的StoredFunction |  
 			| Firebird | - |  
 			| HSQLDB | 不支持 |  
 			| Derby | 不支持StoredFunction |  
 	从1.0.47版本开始导入此功能。这一注释可以消除使用PROCEDURE注释进行PROCEDURE调用时产生的问题。
 	 
	使用PROCEDURE注释进行PROCEDURE调用时产生的问题如下所示。
	 
		由于是基于数据库的元数据(metadata)来执行Procedure,所以如果RDBMS不返回正确的元数据(metadata)就不能调用。像OUT参数或者是INOUT参数等,如果执行PROCEDURE之后,有复数个返回值存在的话,这些值被存贮到Map中从而失去了类型信息。取出时必须进行显式的cast变换处理。 
	使用PROCEDURE_CALL注释进行PROCEDURE调用时对以上问题,有如下的对应处理。
	 
		不使用数据库的元数据(metadata)。使用PROCEDURE名和参数类型信息来调用PROCEDURE。基本上只要RDBMS允许进行CallableStatement,调用就可以执行。传递给PROCEDURE的参数,无论是IN参数还是OUT参数,全部记录在DTO的字段里。返回值也被存贮到DTO的字段里,所以不会失去类型信息。 
	PROCEDURE_CALL注释的语法定义如下所示。
	 -  public static final String 方法名_PROCEDURE_CALL = "Procedure名";
	 
public static String hoge_PROCEDURE_CALL = "hogeProcedure";
public static String foo_PROCEDURE_CALL = "fooProcedure";
public Map hoge();
public void foo(FooDto dto);
 
	方法的参数必须为空或者是一个「DTO」类型。Procedure返回ResultSet的场合,返回值可以是DTO类型或者是DTO的List,Map类型。
	不返回ResultSet的场合请设定为void类型。
	在参数的DTO里,必须指定PROCEDURE_PARAMETER注释以便表示与Procedure的参数相对应的字段和参数类型。
	 
 	从1.0.47版本开始导入此功能。这一注释作为PROCEDURE_CALL注释所指定的方法(method)参数,在所用到的DTO里指定。PROCEDURE_PARAMETER注释的语法定义如下所示。
	 -  public static final String 字段名_PROCEDURE_PARAMETER = "Procedure的参数的类型名";
	 
public static class FooDto {
  public static String aaa_PROCEDURE_PARAMETER = "return";
  public static String bbb_PROCEDURE_PARAMETER = "in";
  public static String ccc_PROCEDURE_PARAMETER = "inout";
  private double aaa;
  private double bbb;
  private double ccc;
  //...
}
	PROCEDURE_PARAMETER的类型名可以指定的值只有return、in、out、inout几种。
	此注释的字段数和定义顺序必须和Procedure的参数顺序一致。 从1.0.47版本开始使用CHECK_SINGLE_ROW_UPDATE注释。在自动生成的SQL更新指令执行后,可以使用这一注释来选择是否要检查更新行数。
 	CHECK_SINGLE_ROW_UPDATE注释如果定义为false,那么即使是没有任何更新,也不会发生NotSingleRowUpdateRuntimeException例外。
 	CHECK_SINGLE_ROW_UPDATE注释可以在Dao全体范围内或者是方法(method)为单位的范围内指定。 
// 对Dao全体范围内的更新行数的检查设定为off的例子
public interface HogeDao {
    public static final boolean CHECK_SINGLE_ROW_UPDATE = false;
    // ...
public interface FugaDao {
    // 以方法(method)为单位的范围内更新行数的检查设定为off的例子
    
    public static final boolean insert_CHECK_SINGLE_ROW_UPDATE = false;
    insert(Fuga fuga);
    // ...dicon文件把Dao作为组件(compenent)注册到容器(container)中。要使用Dao功能,对已注册的Dao,必须进行AOP的应用。
    	dicon文件可以放在任何目录中,但通常与Dao放在同一个目录中。还有,1.0.36版本以后,在jar文件包里已包含有dao.dicon,所以缺省使用时不必配置dao.dicon。
    	dicon文件的详细设定方法,请参阅DIContainer。 S2DaoInterceptor的应用要使用Dao功能,就要对已注册了org.seasar.dao.interceptors.S2DaoInterceptor的Dao应用AOP。EmployeeDao.dicon关于AOP的介绍,请参阅AOP的网页。
 以下是将Dao(example.dao.EmployeeDao)注册为组件(compenent)的例子。
 
<components>
    <include path="dao.dicon"/>
    <component class="example.dao.EmployeeDao">
        <aspect>dao.interceptor</aspect>
    </component>
</components>
dao.dicon是用于设定S2Dao动作的文件。
	详情请参阅dao.dicon指南。
	 SQL文件里记述SQL检索,更新指令。
		一旦调用Dao里定义的方法(method),就可以执行对应的SQL文件中记述的SQL指令。
		请将作成的SQL文件与Dao放在同一个目录中。
		※S2Dao具有自动生成SQL指令的功能,没有SQL文件的场合,S2Dao可以自动生成SQL指令。 SQL文件名在S2Dao里,SQL文件名也有命名规约。 examples/dao/EmployeeDao_getAllEmployees.sql	复数DBMS的对应 可以指定不同的SQL文件来对应不同的DBMS。
		根据java.sql.DatabaseMetadata#getDatabaseProductName(),S2Dao可以自动判断用的是哪一个DBMS。
		在S2Dao里,对应于不同的DBMS,有不同的后缀,所以在SQL文件名中追加后缀。
		例如,Oracle的场合,因为后缀是oracle,所以有「EmployeeDao_getAllEmployees_oracle.sql」这样的文件名。DBMS和后缀的关系如下所示。 
			
				| DBMS | 后缀 |  
				| Oracle | oracle |  
				| DB2 | db2 |  
				| MSSQLServer | mssql |  
				| MySQL | mysql |  
				| PostgreSQL | postgre |  
				| Firebird | firebird |  
				| MaxDB | maxdb |  
				| HSQL | hsql |  
				| Derby | derby |  
				| H2 | h2 |  
				| Sybase(1.0.43以后) | sybase |  SQL指令的记述在SQL文件中,可以记述像”SELECT * FROM EMP”, “DELETE FROM EMP WHERE EMPNO = 7788”这样的普通的SQL指令。
		另外,也可以使WHERE子句中的条件值发生动态变化。详情请参阅SQL注解(comment)。 从1.0.43版本开始导入SQL_FILE注释。
		在利用SQL文件的Dao的方法(method)里,如果使用SQL_FILE注释,找不到对应的SQL文件的场合,
S2Dao会产生例外。
		SQL_FILE注释可用于检测出记述不完整或者是忘记放置SQL文件等错误。 SQL_FILE注释的语法如下所示。 -  public static final String 方法名_SQL_FILE = null; 例如,Dao的getAllEmployees方法在利用SQL文件的场合如下所示。 
public String getAllEmployees_SQL_FILE = null;
public List getAllEmployees(); SQL文件的路径指定
		从1.0.47版本开始,在SQL_FILE注释里可以指定SQL文件的路径。
		因此,可以将SQL文件配置在与Dao不同的目录下。
		这里所说的路径,并非绝对路径,而是指classpath下的相对路径。
		 
public String getAllEmployees_SQL_FILE = "resource/sqlfile/employee_all.sql";
public List getAllEmployees(); 
		另外,与复数个DBMS对应的SQL文件也无需更改就可使用。
		例如上面的例子中,与Oracle连接的场合,
		如果有用于Oracle的SQL文件"resource/sqlfile/employee_all_oracle.sql",
		将会被优先利用。
		 S2Dao使用/**/或者--注解将方法(method)的参数和SQL指令的绑定变量进行关联。
		因为只是追加注解,所以即使是对SQL指令设定了关联之后,使用SQL*Plus等SQL工具依然可以直接执行这些SQL指令。
		先用SQL工具执行SQL指令,得到预想的结果之后再追加注解(comment)是一个好办法。 另外,如果只想对SQl指令使用具有说明性质的注解,可以在/*之后输入空格,这样就变成了一般的注解。
		例如,像/* hoge*/这样的写法,/*之后是一个空格,那么执行SQL指令时hoge就会被忽视掉。 绑定变量注解(Bind variable comment)在SQL指令中使用Dao中定义的方法的参数值的场合,可以在SQL指令中指定绑定变量注解。
		执行时,方法的参数值会自动地被置换成绑定变量注解右边的固定值。
		绑定变量注解的记法如下所示。  -  /*参数名*/固定值 参数为JavaBean的场合,记法如下所示。 -  /*参数名.属性名*/固定值 参数名必须和Dao里设定的ARGS注释的值保持一致。
		(不过,如果只有一个参数的话,则不受此约束) 
public String getEmployee_ARGS = "empno";
public Employee getEmployee(int empno);
 在Dao里定义了上述方法的场合,那么在SQL文件(EmploeeDao_getEmployee.sql)中就可以像下面这样使用绑定变量。getEmployee方法的参数值会自动的被赋值。 SELECT * FROM emp WHERE empno = /*empno*/7788 要在IN子句中使用绑定变量,可以用如下形式。 -  IN /*参数名*/(...) IN /*names*/('aaa', 'bbb')参数的类型为java.util.List或者是数组。上面的IN子句的场合,参数的定义如下所示。 String[] names = new String[]{"SCOTT", "SMITH", "JAMES"};String数组names会自动地被置换成绑定变量的部分。 使用LIKE的场合,记法如下所示。 ename LIKE /*ename*/'hoge' 使用通配符(wild card)的场合,将通配符嵌入到方法的参数值里。
		例如,指定条件为「含有"COT"」的场合,象下面这样在参数值里嵌入通配符。 employeeDao.findEmployees("%COT%");嵌入变量注解(Embedded variable comment)把Dao中定义的方法的参数作为文字列直接嵌入的场合,在SQL指令中指定嵌入变量注解。
		执行时,参数值会自动地被置换成嵌入变量注解右边的固定值。
		嵌入变量注解的记法如下所示。  -  /*$参数名*/固定值 参数为JavaBean的场合,记法如下所示。 -  /*$参数名.属性名*/固定值 使用嵌入变量注解的场合,调用Dao的程序中必须有防止SQL植入式(injection)攻击的处理。 IF注解(comment)使用IF注解,可以根据相应的条件改变要执行的SQL指令。IF注解的记法如下。  -  /*IF 条件*/ .../*END*/ 使用例如下所示。 /*IF hoge != null*/hoge = /*hoge*/'abc'/*END*/ IF注解的条件如果为真,则使用/*IF*/和/*END*/之间的部分。
		上述场合,只有参数hoge不为空(null)的情况下,才使用IF注解内的部分(hoge = /*hoge*/'abc')
		还有,作为IF注解的条件为假的处理部分,使用ELSE注解。
		条件为假的场合,使用/*ELSE*/之后的部分。ELSE注解的记法如下。
 
/*IF hoge != null*/hoge = /*hoge*/'abc'
  -- ELSE hoge is null
/*END*/
 如果条件为假,使用ELSE之后的部分(hoge is null)。 BEGIN注解(comment)当WHERE子句中的所有的IF注解(不包含ELSE注解)的条件为假的时候,使用BEGIN注解可以不输出WHERE子句。
		BEGIN注解和IF注解一起使用。BEGIN注解的记法如下所示。
 -   /*BEGIN*/WHERE子句/*END*/使用例如下所示。 
/*BEGIN*/WHERE
  /*IF job != null*/job = /*job*/'CLERK'/*END*/
  /*IF deptno != null*/AND deptno = /*deptno*/20/*END*/
/*END*/
 如上所示,job,deptno为空(null)的场合,不输出WHERE子句。
		job == null,deptno != null的场合,WHERE depno = ?、 job != null,deptno == null的场合,WHERE job = ?、
		job != null,deptno != null的场合,WHERE job = ? AND depno = ?。动态SQL指令正是如此。 使用EntityManager,可以对SELECT指令自动追加WHERE子句或者ORDER BY子句。语法和QUERY注释一样。
		主要用于生成动态的Query指令。使用EntityManager,要继承以下的类(class)。 - org.seasar.dao.impl.AbstractDao Dao的接口名,必须以"Dao"结尾。从继承AbstractDao的类所实装的接口中,
		S2Dao会把以"Dao"结尾接口当作Dao接口。EntityManager提供以下的方法(method)。 
			参数的记法和QUERY注释一样。Object类型的参数超过4个的场合,使用Object类型的数组。find()方法返回值类型为java.util.List。参数的种类如下所示。public List find(String query);
 public List find(String query, Object arg1);
 public List find(String query, Object arg1, Object arg2);
 public List find(String query, Object arg1, Object arg2, Object arg3);
 public List find(String query, Object[] args);
 
 
findArray()方法返回值类型为数组。参数的种类如下所示。public Object[] findArray(String query);
 public Object[] findArray(String query, Object arg1);
 public Object[] findArray(String query, Object arg1, Object arg2);
 public Object[] findArray(String query, Object arg1, Object arg2, Object arg3);
 public Object[] findArray(String query, Object[] args);
 
 
findBean()方法返回值类型为JavaBeans。参数的种类如下所示。public Object findBean(String query);
 public Object findBean(String query, Object arg1);
 public Object findBean(String query, Object arg1, Object arg2);
 public Object findBean(String query, Object arg1, Object arg2, Object arg3);
 public Object findBean(String query, Object[] args);
 
 
findObject()方法返回值为一个单独的值,类似于count(*)的结果。参数的种类如下所示。public Object findObject(String query);
 public Object findObject(String query, Object arg1);
 public Object findObject(String query, Object arg1, Object arg2);
 public Object findObject(String query, Object arg1, Object arg2, Object arg3);
 public Object findObject(String query, Object[] args);
 继承AbstractDao的类的实装的基本方法
			继承AbstractDao的类的使用例如下所示。继承org.seasar.dao.impl.AbstractDao对Dao进行实装(implements)被实装的Dao的接口名必须以"Dao"结尾。
 实装构造方法(constructor)把org.seasar.dao.DaoMetaDataFactory作为参数,调用super(org.seasar.dao.DaoMetaDataFactory)。
 对Dao中定义的方法(method)进行実装使用EntityManager中提供的方法(method)的场合,可以像getEntityManager().find(...);这样,使用getEntityManager()方法,得到EntityManager之后再进行调用。
 
 
package examples.dao;
import java.util.List;
import org.seasar.dao.DaoMetaDataFactory;
import org.seasar.dao.impl.AbstractDao;
public class Employee2DaoImpl extends AbstractDao implements Employee2Dao {
    public Employee2DaoImpl(DaoMetaDataFactory daoMetaDataFactory) {
        super(daoMetaDataFactory);
    }
    public List getEmployees(String ename) {
        return getEntityManager().find("ename LIKE ?", "%" + ename + "%");
    }
}
详细的用法请参阅使用EntityManager的Example。 要自动生成SQL更新指令,只要遵循方法(method)名的命名规约,定义一个将JavaBeans作为参数的方法即可,
	    不需要作成SQL文件。例如要生成Insert指令的场合,只需遵循命名规约做如下定义。 
public int insert(Department department);
 S2Dao可以自动地进行排他控制。设定方法是,创建一个有排他控制的列项的表,在JavaBeans里定义一个变量versionNo,类型为int(或者Integer),使用VersionNo自动进行排他控制。
 例如,有两个用户取得了versionNo=0的同一个纪录,试图对其进行更新的场合,
        先更新的用户可以正常地完成更新处理。这时versionNo的值自动加1,更新后DB内的versionNo的值变为1。
        其后另一个用户要更新时,用户保存的versionNo值为0,
        但是实际上DB内的值已经是1,两者为不同的值,所以更新失败,产生NotSingleRowUpdatedRuntimeException例外。 要根据VersionNo的值来判断一个对象是刚插入DB的对象还是新创建的未持久化的对象,
        请在JavaBeans里将versionNo的初期值设定为-1。
        这样就可以做如下判断,versionNo == -1,是未持久化对象,versionNo >= 0,则是持久化对象。 除了VersionNo之外,S2Dao还可以用Timestamp来自动地进行排他控制。
	    只要定义一个Timestamp类型的名叫timestamp的属性,就可自动进行排他控制。
	    从Dao执行Insert处理时,会把new java.sql.Timestamp()的值赋给timestamp属性,然后发行Insert指令。
	    执行更新(Update・Delete)处理时,把JavaBeans的timestamp属性值与记录中的timestamp列项的值相比较,
	    如果不相等,就和VersionNo处理时同样,产生NotSingleRowUpdatedRuntimeException例外。
	    更新时如果Timestamp列项的值被设定为null,进行比较就会失败,务请注意。 使用更新系列的方法(method),像下面这样,把参数定义为实体(Entity)类的数组或是列表(List),就可以自动生成SQL更新指令,实现批处理更新功能。
		不过,批处理更新的场合,不能实现ID的自动生成处理。 还有,即使有versionNo或是timestamp设定,实体(Entity)的值并不等于更新后的DB的值。
		批处理更新后,请从DB中取得最新的实体(Entity)的数据。 int insertBatch(Employee[] employees) 从1.0.47版开始,可以像下面这样,把返回值的类型定义为int[],就可以取得每一个实体(Entity)的更新记录的数目。
		不过这一返回值是返回JDBC驱动程序(driver)的数值,根据驱动程序的情况,有时只能得到java.sql.Statement#SUCCESS_NO_INFO的值。 int[] insertBatch2(Employee[] employees) 根据方法的signatue,S2Dao也可以自动生成SELECT指令。只要在ARGS注释里指定列项名,就可以自动生成动态SQL指令,指令中的WHERE子句会根据参数值的变化而变化。 
SELECT * FROM emp
/*BEGIN*/WHERE
  /*IF job != null*/job = /*job*/'CLERK'/*END*/
  /*IF deptno != null*/AND deptno = /*deptno*/20/*END*/
/*END*/
 要自动生成与上述SQL指令相同的SQl指令,可以像下面这样定义。关于上述SQL的/**/记法,请参阅SQL注解一节。 
public static final String getEmployeeByJobDeptno_ARGS = "job, deptno";
public List getEmployeeByJobDeptno(String job, Integer deptno);
 指定用于N:1映射的列项的场合,使用「列项名_相关序号」。
		使用左联接执行一个SQL指令可以取得用于N:1映射的Bean。不支持左联接的RDBMS不能自动生成SELECT指令。
		像Oracle那样的,其左联接语法不同于标准联接语法的场合,S2Dao自动判断该RDBMS为Oracle,生成合适的SQL指令。 也可以使用DTO(Data Transter Object)作为参数。在这种场合,不能使用ARGS注释。
		在只有一个参数而且没有使用ARGS注释的场合,S2Dao就把参数视为DTO类型,使用DTO的属性自动生成SQL指令。
		属性名和列名不同的场合,可以使用COLUMN注释指定列名。如果是指定用于N:1映射的列项的场合,则使用列项名_相关序号进行指定。
		表中不存在的属性(列项)会自动被忽略掉。WHERE子句随着属性值的变化而变化,从而生成动态SQL指令。动态SQL指令的自动生成和以ORDER BY子句开头的QUERY注释可以一起使用。
 
package examples.dao;
public class EmployeeSearchCondition {
    public static final String dname_COLUMN = "dname_0";
    private String job;
    private String dname;
    ...
}
List getEmployeesBySearchCondition(EmployeeSearchCondition dto); 另外用同样的方法,也可以使用Entity作为参数。有关DTO的详细用法,请参阅自动生成SQL检索指令的案例(Example)一节。进一步而言,从v1.0.37开始,用同样的方法,还可以使用能与BEAN注释互换的类型作为参数。在这种场合,BEAN注释所定义的类型被作为DTO类型来使用。	
	例如,可以像下面这样定义Dao。
 
public class Employee implements Entity {
    private long empno;
    private String ename;
    ...
}
public interface GenericDao {
    Object select(Entity entity);
    List selectList(Entity entity);
}
public interface EmployeeDao extends GenericDao {
    Class BEAN = Employee.class;
}
执行Dao的基本方法如下所示。 
	以dicon文件中的路径(path)为参数生成S2Container从生成的S2Container调用getComponent,取得已注册的Dao	执行所得到的Dao的方法(method) S2Dao不做事务(transaction)控制。有关事务(transaction)控制的内容,请参阅事务的自动控制一节。使用例如下 
package examples.dao;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;
public class EmployeeDaoClient {
    private static final String PATH = "examples/dao/EmployeeDao.dicon";
    public static void main(String[] args) {
        S2Container container = S2ContainerFactory.create(PATH); /* 步骤1 */
        container.init();
        try {
            EmployeeDao dao = (EmployeeDao) container.getComponent(EmployeeDao.class);/* 步骤2 */
            System.out.println(dao.getAllEmployee(7788));/* 步骤3 */
        } finally {
            container.destroy();
        }
    }
}
作为前提条件,在案例中使用以下的表,JavaBeans和dao.dicon文件。表:EMP 
			
			  | 列名 | 逻辑名 | 类型 | NotNull | 主键 |  
			  | EMPNO | 员工工号 | NUMBER | 〇 | 〇 |  
			  | ENAME | 员工姓名 | VARCHAR | 
 | 
 |  
			  | JOB | 职务 | VARCHAR | 
 | 
 |  
			  | MGR | 上司 | NUMBER | 
 | 
 |  
			  | HIREDATE | 雇佣日 | DATE | 
 | 
 |  
			  | SAL | 工资 | NUMBER | 
 | 
 |  
			  | COMM | 手续费 | NUMBER | 
 | 
 |  
			  | DEPTNO | 部门号 | NUMBER | 
 | 
 |  
			  | TSTAMP | 时间印戳 | TIMESTAMP | 
 | 
 |  表:DEPT
 
			
			  | カラム名 | 論理名 | 型 | NotNull | 主キー |  
			  | DEPTNO | 部门号 | NUMBER | 〇 | 〇 |  
			  | DNAME | 部门名 | VARCHAR | 
 | 
 |  
			  | LOC | 工作地点 | VARCHAR | 
 | 
 |  
			  | VERSIONNO | 版本号 | NUMBER | 
 | 
 |  
 与EMP表相关联的JavaBeans如下所示。 
package examples.dao;
import java.io.Serializable;
import java.sql.Timestamp;
public class Employee implements Serializable {
    public static final String TABLE = "EMP";
    public static final int department_RELNO = 0;
    public static final String timestamp_COLUMN = "tstamp";
    private long empno;
    private String ename;
    private String job;
    private Short mgr;
    private java.util.Date hiredate;
    private Float sal;
    private Float comm;
    private int deptno;
    private Timestamp timestamp;
    private Department department;
    public Employee() {
    }
    public Employee(long empno) {
        this.empno = empno;
    }
    public long getEmpno() {
        return this.empno;
    }
    public void setEmpno(long empno) {
        this.empno = empno;
    }
    public java.lang.String getEname() {
        return this.ename;
    }
    public void setEname(java.lang.String ename) {
        this.ename = ename;
    }
    public java.lang.String getJob() {
        return this.job;
    }
    public void setJob(java.lang.String job) {
        this.job = job;
    }
    public Short getMgr() {
        return this.mgr;
    }
    public void setMgr(Short mgr) {
        this.mgr = mgr;
    }
    public java.util.Date getHiredate() {
        return this.hiredate;
    }
    public void setHiredate(java.util.Date hiredate) {
        this.hiredate = hiredate;
    }
    public Float getSal() {
        return this.sal;
    }
    public void setSal(Float sal) {
        this.sal = sal;
    }
    public Float getComm() {
        return this.comm;
    }
    public void setComm(Float comm) {
        this.comm = comm;
    }
    public int getDeptno() {
        return this.deptno;
    }
    public void setDeptno(int deptno) {
        this.deptno = deptno;
    }
    public Timestamp getTimestamp() {
        return this.timestamp;
    }
    public void setTimestamp(Timestamp timestamp) {
        this.timestamp = timestamp;
    }
    public Department getDepartment() {
        return this.department;
    }
    public void setDepartment(Department department) {
        this.department = department;
    }
    public boolean equals(Object other) {
        if (!(other instanceof Employee))
            return false;
        Employee castOther = (Employee) other;
        return this.getEmpno() == castOther.getEmpno();
    }
    public String toString() {
        StringBuffer buf = new StringBuffer();
        buf.append(empno).append(", ");
        buf.append(ename).append(", ");
        buf.append(job).append(", ");
        buf.append(mgr).append(", ");
        buf.append(hiredate).append(", ");
        buf.append(sal).append(", ");
        buf.append(comm).append(", ");
        buf.append(deptno).append(", ");
        buf.append(timestamp).append(" {");
        buf.append(department).append("}");
        return buf.toString();
    }
    public int hashCode() {
        return (int) this.getEmpno();
    }
}
与DEPT表相关联的JavaBeans如下所示。 
package examples.dao;
import java.io.Serializable;
public class Department implements Serializable {
    public static final String TABLE = "DEPT";
    private int deptno;
    private String dname;
    private String loc;
    private int versionNo;
    public Department() {
    }
    public int getDeptno() {
        return this.deptno;
    }
    public void setDeptno(int deptno) {
        this.deptno = deptno;
    }
    public java.lang.String getDname() {
        return this.dname;
    }
    public void setDname(java.lang.String dname) {
        this.dname = dname;
    }
    public java.lang.String getLoc() {
        return this.loc;
    }
    public void setLoc(java.lang.String loc) {
        this.loc = loc;
    }
    public int getVersionNo() {
        return this.versionNo;
    }
    public void setVersionNo(int versionNo) {
        this.versionNo = versionNo;
    }
    public boolean equals(Object other) {
        if (!(other instanceof Department))
            return false;
        Department castOther = (Department) other;
        return this.getDeptno() == castOther.getDeptno();
    }
    public String toString() {
        StringBuffer buf = new StringBuffer();
        buf.append(deptno).append(", ");
        buf.append(dname).append(", ");
        buf.append(loc).append(", ");
        buf.append(versionNo);
        return buf.toString();
    }
    public int hashCode() {
        return (int) this.getDeptno();
    }
}
各Example中引入(include)的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"/>
</components>
这个演习创建SQL文件,并由Dao执行文件中的SQL指令。作成的文件如下所示。
 
    		Dao(EmployeeDao.java)SQL文件(EmployeeDao_getAllEmployees.sql, EmployeeDao_getEmployee.sql, EmployeeDao_getCount.sql, EmployeeDao_getEmployeeByJobDeptno.sql, EmployeeDao_update.sql)dicon文件(EmployeeDao.dicon)执行用的类(EmployeeDaoClient.java) 作成Dao
    		将EMP表和相应的JavaBeans进行关联。定义方法(method)。全件检索方法(getAllEmployees()方法)
 以员工工号为条件抽出员工的方法(getEmployee(int empno)方法)
 计算员工人数的方法(getCount()方法)
 以员工的职务和部门号为条件抽出员工的方法(getEmployeeByJobDeptno(String job, Integer deptno)方法)
 更新员工记录的方法(update(Employee employee)方法)
使用ARGS注释将SQL指令和方法(method)的参数进行关联。取得EMP表的记录数的getCount()方法,只返回表的记录数,所以返回值定为int类型。 
package examples.dao;
import java.util.List;
public interface EmployeeDao {
    public Class BEAN = Employee.class;
    public List getAllEmployees();
    public String getEmployee_ARGS = "empno";
    public Employee getEmployee(int empno);
    public int getCount();
    public String getEmployeeByJobDeptno_ARGS = "job, deptno";
    public List getEmployeeByJobDeptno(String job, Integer deptno);
    public int update(Employee employee);
}
作成SQL文件
			EmployeeDao_getAllEmployees.sql对于Dao中定义的方法(method),做成相应的SQL文件。文件名为「类名_方法名.sql」。使用SQL注解(comment)作成动态SQL指令。 
SELECT emp.*, dept.dname dname_0, dept.loc loc_0 FROM emp, dept
WHERE emp.deptno = dept.deptno ORDER BY emp.empno
EmployeeDao_getEmployee.sql 
SELECT emp.*, dept.dname dname_0, dept.loc loc_0 FROM emp, dept
WHERE empno = /*empno*/7788 AND emp.deptno = dept.deptno
EmployeeDao_getCount.sql 
SELECT count(*) FROM emp
EmployeeDao_getEmployeeByJobDeptno.sql 
SELECT * FROM emp
/*BEGIN*/WHERE
  /*IF job != null*/job = /*job*/'CLERK'/*END*/
  /*IF deptno != null*/AND deptno = /*deptno*/20/*END*/
/*END*/
EmployeeDao_update.sql 
UPDATE emp SET ename = /*employee.ename*/'SCOTT'
WHERE empno = /*employee.empno*/7788
 作成dicon文件
			引入(include)dao.dicon文件。将刚才作成的Dao定义为组件(component)。对上述Dao应用dao.interceptor(S2DaoInterceptor)。 
<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container//EN"
"http://www.seasar.org/dtd/components.dtd">
<components>
   <include path="dao.dicon"/>
   <component class="examples.dao.EmployeeDao">
       <aspect>dao.interceptor</aspect>
   </component>
</components>
作成执行文件
			把刚才作成的dicon文件(EmployeeDao.dicon)的路径,作为org.seasar.framework.container.S2Container#create()方法的の第1参数,创建一个容器(container)。把组件中注册的类名(EmployeeDao.class),作为org.seasar.framework.container.S2Container#getComponent()方法的の第1参数,取得组件(component)。执行Dao里定义的方法(method)。 
package examples.dao;
import java.util.List;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;
public class EmployeeDaoClient {
    private static final String PATH = "examples/dao/EmployeeDao.dicon";
    public static void main(String[] args) {
        S2Container container = S2ContainerFactory.create(PATH);
        container.init();
        try {
            EmployeeDao dao = (EmployeeDao) container
                    .getComponent(EmployeeDao.class);
            List employees = dao.getAllEmployees();
            for (int i = 0; i < employees.size(); ++i) {
                System.out.println(employees.get(i));
            }
            Employee employee = dao.getEmployee(7788);
            System.out.println(employee);
            int count = dao.getCount();
            System.out.println("count:" + count);
            dao.getEmployeeByJobDeptno(null, null);
            dao.getEmployeeByJobDeptno("CLERK", null);
            dao.getEmployeeByJobDeptno(null, new Integer(20));
            dao.getEmployeeByJobDeptno("CLERK", new Integer(20));
            System.out.println("updatedRows:" + dao.update(employee));
        } finally {
            container.destroy();
        }
    }
}
执行结果
DEBUG 2004-10-12 11:07:01,117 [main] physical connection opened
DEBUG 2004-10-12 11:07:01,133 [main] logical connection opened
DEBUG 2004-10-12 11:07:01,914 [main] logical connection closed
DEBUG 2004-10-12 11:07:02,742 [main] SELECT emp.*, dept.dname dname_0, dept.loc loc_0
  FROM emp, dept WHERE emp.deptno = dept.deptno ORDER BY emp.empno
DEBUG 2004-10-12 11:07:02,758 [main] logical connection opened
DEBUG 2004-10-12 11:07:02,867 [main] logical connection closed
7369, SMIT, CLERK, 7902, 1980-12-17 00:00:00.0, 800.0, null, 20,
  1980-12-17 00:00:00.0, {0, RESEARCH, DALLAS, 0}
7499, ALLEN, SALESMAN, 7698, 1981-02-20 00:00:00.0, 1600.0, 300.0, 30,
  1980-12-17 00:00:00.0, {0, SALES, CHICAGO, 0}
7521, WARD, SALESMAN, 7698, 1981-02-22 00:00:00.0, 1250.0, 500.0, 30,
  1980-12-17 00:00:00.0, {0, SALES, CHICAGO, 0}
7566, JONES, MANAGER, 7839, 1981-04-02 00:00:00.0, 2975.0, null, 20,
  1980-12-17 00:00:00.0, {0, RESEARCH, DALLAS, 0}
7654, MARTIN, SALESMAN, 7698, 1981-09-28 00:00:00.0, 1250.0, 1400.0, 30,
  1980-12-17 00:00:00.0, {0, SALES, CHICAGO, 0}
7698, BLAKE, MANAGER, 7839, 1981-05-01 00:00:00.0, 2850.0, null, 30,
  1980-12-17 00:00:00.0, {0, SALES, CHICAGO, 0}
7782, CLARK, MANAGER, 7839, 1981-06-09 00:00:00.0, 2450.0, null, 10,
  1980-12-17 00:00:00.0, {0, ACCOUNTING, NEW YORK, 0}
7788, SCOTT, ANALYST, 7566, 1982-12-09 00:00:00.0, 3000.0, null, 20,
  2004-10-12 10:15:54.914, {0, RESEARCH, DALLAS, 0}
7839, KING, PRESIDENT, null, 1981-11-17 00:00:00.0, 5000.0, null, 10,
  1980-12-17 00:00:00.0, {0, ACCOUNTING, NEW YORK, 0}
7844, TURNER, SALESMAN, 7698, 1981-09-08 00:00:00.0, 1500.0, 0.0, 30,
  1980-12-17 00:00:00.0, {0, SALES, CHICAGO, 0}
7876, ADAMS, CLERK, 7788, 1983-01-12 00:00:00.0, 1100.0, null, 20,
  1980-12-17 00:00:00.0, {0, RESEARCH, DALLAS, 0}
7900, JAMES, CLERK, 7698, 1981-12-03 00:00:00.0, 950.0, null, 30,
  1980-12-17 00:00:00.0, {0, SALES, CHICAGO, 0}
7902, FORD, ANALYST, 7566, 1981-12-03 00:00:00.0, 3000.0, null, 20,
  1980-12-17 00:00:00.0, {0, RESEARCH, DALLAS, 0}
7934, MILLER, CLERK, 7782, 1982-01-23 00:00:00.0, 1300.0, null, 10,
  1980-12-17 00:00:00.0, {0, ACCOUNTING, NEW YORK, 0}
DEBUG 2004-10-12 11:07:02,883 [main] SELECT emp.*, dept.dname dname_0, dept.loc loc_0
  FROM emp, dept WHERE empno = 7788 AND emp.deptno = dept.deptno
DEBUG 2004-10-12 11:07:02,883 [main] logical connection opened
DEBUG 2004-10-12 11:07:02,914 [main] logical connection closed
7788, SCOTT, ANALYST, 7566, 1982-12-09 00:00:00.0, 3000.0, null, 20,
  2004-10-12 10:15:54.914, {0, RESEARCH, DALLAS, 0}
DEBUG 2004-10-12 11:07:02,914 [main] SELECT count(*) FROM emp
DEBUG 2004-10-12 11:07:02,914 [main] logical connection opened
DEBUG 2004-10-12 11:07:02,914 [main] logical connection closed
count:14
DEBUG 2004-10-12 11:07:02,929 [main] SELECT * FROM emp
DEBUG 2004-10-12 11:07:02,929 [main] logical connection opened
DEBUG 2004-10-12 11:07:02,945 [main] logical connection closed
DEBUG 2004-10-12 11:07:02,945 [main] SELECT * FROM emp
WHERE
  job = 'CLERK'
DEBUG 2004-10-12 11:07:02,945 [main] logical connection opened
DEBUG 2004-10-12 11:07:02,961 [main] logical connection closed
DEBUG 2004-10-12 11:07:02,961 [main] SELECT * FROM emp
WHERE
  deptno = 20
DEBUG 2004-10-12 11:07:02,961 [main] logical connection opened
DEBUG 2004-10-12 11:07:02,961 [main] logical connection closed
DEBUG 2004-10-12 11:07:02,961 [main] SELECT * FROM emp
WHERE
  job = 'CLERK'
  AND deptno = 20
DEBUG 2004-10-12 11:07:02,961 [main] logical connection opened
DEBUG 2004-10-12 11:07:03,008 [main] logical connection closed
DEBUG 2004-10-12 11:07:03,023 [main] UPDATE emp SET ename = 'SCOTT'
WHERE empno = 7788
DEBUG 2004-10-12 11:07:03,023 [main] logical connection opened
DEBUG 2004-10-12 11:07:03,023 [main] logical connection closed
updatedRows:1
DEBUG 2004-10-12 11:07:03,023 [main] physical connection closed
从"updatedRows"的值,可以确认更新的记录数。这一演习,放在s2dao/src/examples/dao目录下。
 这个演习,使用VersionNo进行排他控制,并且自动生成SQL更新(UPDATE, INSERT, DELETE)指令。这个演习不用作成SQL文件。作成的文件如下所示。
 
    		Dao(DepartmentDao.java)dicon文件(DepartmentDao.dicon)执行用的类(DepartmentDaoClient.java) 作成Dao
    		将DEPT表和相应的JavaBeans进行关联。定义用于更新处理的方法(method)。追加部门的方法(insert(Department department)方法)
 更新部门的方法(update(Department department)方法)
 删除部门的方法(delete(Department department)方法)
 
package examples.dao;
public interface DepartmentDao {
    public Class BEAN = Department.class;
    public void insert(Department department);
    public void update(Department department);
    public void delete(Department department);
}
作成dicon文件
			引入(include) dao.dicon文件。将刚才作成的Dao定义为组件(component)。对上述Dao应用dao.interceptor(S2DaoInterceptor)。 
<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container//EN"
"http://www.seasar.org/dtd/components.dtd">
<components>
  <include path="dao.dicon"/>
  <component class="examples.dao.DepartmentDao">
    <aspect>dao.interceptor</aspect>
  </component>
</components>
作成执行文件
			把刚才作成的dicon文件(DepartmentDao.dicon)的路径,作为org.seasar.framework.container.S2Container#create()方法的第一参数里,创建一个容器(container)。把组件中注册的类名(DepartmentDao.class),作为org.seasar.framework.container.S2Container#getComponent()メ方法的第一参数,取得组件(component)。执行Dao里定义的方法(method)。 
package examples.dao;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;
public class DepartmentDaoClient {
    private static final String PATH = "examples/dao/DepartmentDao.dicon";
    public static void main(String[] args) {
        S2Container container = S2ContainerFactory.create(PATH);
        container.init();
        try {
            DepartmentDao dao = (DepartmentDao) container
                    .getComponent(DepartmentDao.class);
            Department dept = new Department();
            dept.setDeptno(99);
            dept.setDname("foo");
            dao.insert(dept);
            dept.setDname("bar");
            System.out.println("before update versionNo:" + dept.getVersionNo());
            dao.update(dept);
            System.out.println("after update versionNo:" + dept.getVersionNo());
            dao.delete(dept);
        } finally {
            container.destroy();
        }
    }
}
执行结果
DEBUG 2004-09-09 19:22:10,588 [main] physical connection opened
DEBUG 2004-09-09 19:22:10,588 [main] logical connection opened
DEBUG 2004-09-09 19:22:11,447 [main] logical connection closed
DEBUG 2004-09-09 19:22:11,603 [main] logical connection opened
DEBUG 2004-09-09 19:22:11,603 [main] INSERT INTO DEPT (deptno, dname, versionNo, loc)
  VALUES(99, 'foo', 0, null)
DEBUG 2004-09-09 19:22:11,666 [main] logical connection closed
before update versionNo:0
DEBUG 2004-09-09 19:22:11,666 [main] logical connection opened
DEBUG 2004-09-09 19:22:11,666 [main] UPDATE DEPT SET dname = 'bar',
  versionNo = versionNo + 1, loc = null   WHERE deptno = 99 AND versionNo = 0
DEBUG 2004-09-09 19:22:11,666 [main] logical connection closed
after update versionNo:1
DEBUG 2004-09-09 19:22:11,666 [main] logical connection opened
DEBUG 2004-09-09 19:22:11,666 [main] DELETE FROM DEPT WHERE deptno = 99 AND versionNo = 1
DEBUG 2004-09-09 19:22:11,681 [main] logical connection closed
DEBUG 2004-09-09 19:22:11,681 [main] physical connect closed
 从输出结果可以看出,SQL指令是自动的被生成并执行的。而且由于在JavaBeans(Department)里,定义了int类型的versionNo属性,
    	versionNo会自动加1,根据这个值实现了排他控制。
    	在调用update方法之前,versionNo的值为0,但是在调用了update方法之后,versionNo的值变成了1。这一演习,放在s2dao/src/examples/dao目录下。
 这个演习,使用Timestamp进行排他控制并且自动生成SELECT指令。这个演习不用作成SQL文件。还有,演习中还定义了使用DTO作为参数的方法。
		作成的文件如下所示。 
    		Dao(EmployeeAutoDao.java)DTO(EmployeeSearchCondition.java)dicon文件(EmployeeAutoDao.dicon)执行用的类(EmployeeAutoDaoClient.java) 作成Dao
    		将EMP表和相应的JavaBeans进行关联。定义方法(method)。全件检索方法(getAllEmployees()方法)
 以职务和部门号为条件抽出员工的方法(getEmployeeByJobDeptno(String job, Integer deptno)方法)
 以员工工号为条件抽出员工的方法(getEmployeeByEmpno(int empno)方法)
 以指定的工资范围为条件抽出员工的方法(getEmployeesBySal(float minSal, float maxSal)方法)
 以指定的部门名为条件抽出员工的方法(getEmployeeByDname(String dname)方法)
 以DTO为条件抽出员工的方法(getEmployeesBySearchCondition(EmployeeSearchCondition dto)方法)
 更新员工记录的方法(update(Employee employee)メソッド)
 
package examples.dao;
import java.util.List;
public interface EmployeeAutoDao {
    public Class BEAN = Employee.class;
    public List getAllEmployees();
    public String getEmployeeByJobDeptno_ARGS = "job, deptno";
    public List getEmployeeByJobDeptno(String job, Integer deptno);
    public String getEmployeeByEmpno_ARGS = "empno";
    public Employee getEmployeeByEmpno(int empno);
    public String getEmployeesBySal_QUERY = "sal BETWEEN ? AND ? ORDER BY empno";
    public List getEmployeesBySal(float minSal, float maxSal);
    public String getEmployeeByDname_ARGS = "dname_0";
    public List getEmployeeByDname(String dname);
    public List getEmployeesBySearchCondition(EmployeeSearchCondition dto);
    public void update(Employee employee);
}
作成DTO
package examples.dao;
public class EmployeeSearchCondition {
    public static final String dname_COLUMN = "dname_0";
    private String job;
    private String dname;
    public String getDname() {
        return dname;
    }
    public void setDname(String dname) {
        this.dname = dname;
    }
    public String getJob() {
        return job;
    }
    public void setJob(String job) {
        this.job = job;
    }
}
作成dicon文件
			引入(include) dao.dicon文件。将刚才作成的Dao定义为组件(component)。对上述Dao应用dao.interceptor(S2DaoInterceptor)。 
<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container//EN"
"http://www.seasar.org/dtd/components.dtd">
<components>
  <include path="dao.dicon"/>
  <component class="examples.dao.EmployeeAutoDao">
    <aspect>dao.interceptor</aspect>
  </component>
</components>
作成执行文件
			把刚才作成的dicon文件(EmployeeAutoDao.dicon)的路径,作为org.seasar.framework.container.S2Container#create()方法的第一参数,创建一个容器(container)。把组件中注册的类名(EmployeeAutoDao.class),作为org.seasar.framework.container.S2Container#getComponent()方法的第一参数,取得组件(component)。执行Dao里定义的方法(method)。 
package examples.dao;
import java.util.List;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;
public class EmployeeAutoDaoClient {
    private static final String PATH = "examples/dao/EmployeeAutoDao.dicon";
    public static void main(String[] args) {
        S2Container container = S2ContainerFactory.create(PATH);
        container.init();
        try {
            EmployeeAutoDao dao = (EmployeeAutoDao) container
                    .getComponent(EmployeeAutoDao.class);
            dao.getEmployeeByJobDeptno(null, null);
            dao.getEmployeeByJobDeptno("CLERK", null);
            dao.getEmployeeByJobDeptno(null, new Integer(20));
            dao.getEmployeeByJobDeptno("CLERK", new Integer(20));
            List employees = dao.getEmployeesBySal(0, 1000);
            for (int i = 0; i < employees.size(); ++i) {
                System.out.println(employees.get(i));
            }
            employees = dao.getEmployeeByDname("SALES");
            for (int i = 0; i < employees.size(); ++i) {
                System.out.println(employees.get(i));
            }
            EmployeeSearchCondition dto = new EmployeeSearchCondition();
            dto.setDname("RESEARCH");
            employees = dao.getEmployeesBySearchCondition(dto);
            for (int i = 0; i < employees.size(); ++i) {
                System.out.println(employees.get(i));
            }
            Employee employee = dao.getEmployeeByEmpno(7788);
            System.out.println("before timestamp:" + employee.getTimestamp());
            dao.update(employee);
            System.out.println("after timestamp:" + employee.getTimestamp());
        } finally {
            container.destroy();
        }
    }
}
执行结果
DEBUG 2004-10-12 11:35:22,054 [main] physical connection opened
DEBUG 2004-10-12 11:35:22,069 [main] logical connection opened
DEBUG 2004-10-12 11:35:22,897 [main] logical connection closed
DEBUG 2004-10-12 11:35:23,726 [main] SELECT EMP.tstamp, EMP.empno, EMP.ename, EMP.job,
  EMP.mgr, EMP.hiredate, EMP.sal, EMP.comm, EMP.deptno, department.dname AS dname_0,
  department.deptno AS deptno_0, department.loc AS loc_0,
  department.versionNo AS versionNo_0 FROM EMP LEFT OUTER JOIN DEPT department
  ON EMP.deptno = department.deptno
DEBUG 2004-10-12 11:35:23,726 [main] logical connection opened
DEBUG 2004-10-12 11:35:23,866 [main] logical connection closed
DEBUG 2004-10-12 11:35:23,866 [main] SELECT EMP.tstamp, EMP.empno, EMP.ename, EMP.job,
  EMP.mgr, EMP.hiredate, EMP.sal, EMP.comm, EMP.deptno, department.dname AS dname_0,
  department.deptno AS deptno_0, department.loc AS loc_0,
  department.versionNo AS versionNo_0 FROM EMP LEFT OUTER JOIN DEPT department
  ON EMP.deptno = department.deptno WHERE  EMP.job = 'CLERK'
DEBUG 2004-10-12 11:35:23,866 [main] ogical connection opened
DEBUG 2004-10-12 11:35:23,882 [main] logical connection closed
DEBUG 2004-10-12 11:35:23,882 [main] SELECT EMP.tstamp, EMP.empno, EMP.ename, EMP.job,
  EMP.mgr, EMP.hiredate, EMP.sal, EMP.comm, EMP.deptno, department.dname AS dname_0,
  department.deptno AS deptno_0, department.loc AS loc_0,
  department.versionNo AS versionNo_0 FROM EMP LEFT OUTER JOIN DEPT department
  ON EMP.deptno = department.deptno WHERE EMP.deptno = 20
DEBUG 2004-10-12 11:35:23,882 [main] logical connection opened
DEBUG 2004-10-12 11:35:23,913 [main] loical connection closed
DEBUG 2004-10-12 11:35:23,913 [main] SELECT EMP.tstamp, EMP.empno, EMP.ename, EMP.job,
  EMP.mgr, EMP.hiredate, EMP.sal, EMP.comm, EMP.deptno, department.dname AS dname_0,
  department.deptno AS deptno_0, department.loc AS loc_0,
  department.versionNo AS versionNo_0 FROM EMP LEFT OUTER JOIN DEPT department
  ON EMP.deptno = department.deptno WHERE  EMP.job = 'CLERK' AND EMP.deptno = 20
DEBUG 2004-10-12 11:35:23,913 [main] logical connection opened
DEBUG 2004-10-12 11:35:23,929 [main] logical connection closed
DEBUG 2004-10-12 11:35:23,929 [main] SELECT EMP.tstamp, EMP.empno, EMP.ename, EMP.job,
  EMP.mgr, EMP.hiredate, EMP.sal, EMP.comm, EMP.deptno, department.dname AS dname_0,
  department.deptno AS deptno_0, department.loc AS loc_0,
  department.versionNo AS versionNo_0 FROM EMP LEFT OUTER JOIN DEPT department
  ON EMP.deptno = department.deptno WHERE sal BETWEEN 0.0 AND 1000.0 ORDER BY empno
DEBUG 2004-10-12 11:35:23,929 [main] logical connection opened
DEBUG 2004-10-12 11:35:23,944 [main] logical connection closed
7369, SMITH, CLERK, 7902, 1980-12-17 00:00:00.0, 800.0, null, 20,
  1980-12-17 00:00:00.0, {20, RESEARCH, DALLAS, 0}
7900, JAMES, CLERK, 7698, 1981-12-03 00:00:00.0, 950.0, null, 30,
  1980-12-17 00:00:00.0, {30, SALES, CHICAGO, 0}
DEBUG 2004-10-12 11:35:23,944 [main] SELECT EMP.tstamp, EMP.empno, EMP.ename, EMP.job,
  EMP.mgr, EMP.hiredate, EMP.sal, EMP.comm, EMP.deptno, department.dname AS dname_0,
  department.deptno AS deptno_0, department.loc AS loc_0,
  department.versionNo AS versionNo_0 FROM EMP LEFT OUTER JOIN DEPT department
  ON EMP.deptno = department.deptno WHERE  department.dname = 'SALES'
DEBUG 2004-10-12 11:35:23,944 [main] logical connection opened
DEBUG 2004-10-12 11:35:23,960 [main] logical connection closed
7499, ALLEN, SALESMAN, 7698, 1981-02-20 00:00:00.0, 1600.0, 300.0, 30,
  1980-12-17 00:00:00.0, {30, SALES, CHICAGO, 0}
7521, WARD, SALESMAN, 7698, 1981-02-22 00:00:00.0, 1250.0, 500.0, 30,
  1980-12-17 00:00:00.0, {30, SALES, CHICAGO, 0}
7654, MARTIN, SALESMAN, 7698, 1981-09-28 00:00:00.0, 1250.0, 1400.0, 30,
  1980-12-17 00:00:00.0, {30, SALES, CHICAGO, 0}
7698, BLAKE, MANAGER, 7839, 1981-05-01 00:00:00.0, 2850.0, null, 30,
  1980-12-17 00:00:00.0, {30, SALES, CHICAGO, 0}
7844, TURNER, SALESMAN, 7698, 1981-09-08 00:00:00.0, 1500.0, 0.0, 30,
  1980-12-17 00:00:00.0, {30, SALES, CHICAGO, 0}
7900, JAMES, CLERK, 7698, 1981-12-03 00:00:00.0, 950.0, null, 30,
  1980-12-17 00:00:00.0, {30, SALES, CHICAGO, 0}
DEBUG 2004-10-12 11:35:23,960 [main] SELECT EMP.tstamp, EMP.empno, EMP.ename, EMP.job,
  EMP.mgr, EMP.hiredate, EMP.sal, EMP.comm, EMP.deptno, department.dname AS dname_0,
  department.deptno AS deptno_0, department.loc AS loc_0,
  department.versionNo AS versionNo_0 FROM EMP LEFT OUTER JOIN DEPT department
  ON EMP.deptno = department.deptno WHERE  department.dname = 'RESEARCH'
DEBUG 2004-10-12 11:35:23,976 [main] logical connection opened
DEBUG 2004-10-12 11:35:23,976 [main] logical connection closed
7369, SMITH, CLERK, 7902, 1980-12-17 00:00:00.0, 800.0, null, 20,
  1980-12-17 00:00:00.0, {20, RESEARCH, DALLAS, 0}
7566, JONES, MANAGER, 7839, 1981-04-02 00:00:00.0, 2975.0, null, 20,
  1980-12-17 00:00:00.0, {20, RESEARCH, DALLAS, 0}
7788, SCOTT, ANALYST, 7566, 1982-12-09 00:00:00.0, 3000.0, null, 20,
  2004-10-12 10:15:54.914, {20, RESEARCH, DALLAS, 0}
7876, ADAMS, CLERK, 7788, 1983-01-12 00:00:00.0, 1100.0, null, 20,
  1980-12-17 00:00:00.0, {20, RESEARCH, DALLAS, 0}
7902, FORD, ANALYST, 7566, 1981-12-03 00:00:00.0, 3000.0, null, 20,
  1980-12-17 00:00:00.0, {20, RESEARCH, DALLAS, 0}
DEBUG 2004-10-12 11:35:23,976 [main] SELECT EMP.tstamp, EMP.empno, EMP.ename, EMP.job,
  EMP.mgr, EMP.hiredate, EMP.sal, EMP.comm, EMP.deptno, department.dname AS dname_0,
  department.deptno AS deptno_0, department.loc AS loc_0,
  department.versionNo AS versionNo_0 FROM EMP LEFT OUTER JOIN DEPT department
  ON EMP.deptno = department.deptno WHERE  EMP.empno = 7788
DEBUG 2004-10-12 11:35:23,991 [main] logical connection opened
DEBUG 2004-10-12 11:35:23,991 [main] logical connection closed
before tmestamp:2004-10-12 10:15:54.914
DEBUG 2004-10-12 11:35:23,991 [main] logical connection opened
DEBUG 2004-10-12 11:35:23,991 [main] UPDATE EMP SET tstamp = '2004-10-12 11.35.23',
  ename = 'SCOTT', job = 'ANALYST', mgr = 7566, hiredate = '1982-12-09 00.00.00',
  sal = 3000.0, comm = null, deptno = 20
  WHERE empno = 7788 AND tstamp = '2004-10-12 10.15.54'
DEBUG 2004-10-12 11:35:24,054 [main] logical connection closed
after timestamp:2004-10-12 11:35:23.991
DEBUG 2004-10-12 11:35:24,054 [main] physical connection closed
从输出的日志(log)可以看出,SQL指令是自动生成的。而且可以看到更新前后Timestamp的值发生了变化,根据这个值实现了排他控制。
 这一演习,放在s2dao/src/examples/dao目录下。
 这个演习,使用EntityManager,抽出名字中含有指定文字列的员工。作成的文件如下所示。
 
    		Dao(Employee2Dao.java)继承AbstractDao的类(Employee2DaoImpl.java)dicon文件(Employee2Dao.dicon)执行用的类(Employee2DaoClient.java) 作成Dao
    		接口名必须以"Dao"结尾。将EMP表和相应的JavaBeans进行关联。定义用于检索处理的方法。检索员工的方法(getEmployees(String ename))
 
package examples.dao;
import java.util.List;
public interface Employee2Dao {
    public Class BEAN = Employee.class;
    public List getEmployees(String ename);
}
作成一个继承AbstractDao的类
    		继承org.seasar.dao.impl.AbstractDao。实装(implements)Employee2Dao。实装getEmployees方法。抽出含有指定文字列的名字。 
package examples.dao;
import java.util.List;
import org.seasar.dao.DaoMetaDataFactory;
import org.seasar.dao.impl.AbstractDao;
public class Employee2DaoImpl extends AbstractDao implements Employee2Dao {
    public Employee2DaoImpl(DaoMetaDataFactory daoMetaDataFactory) {
        super(daoMetaDataFactory);
    }
    public List getEmployees(String ename) {
        return getEntityManager().find("ename LIKE ?", "%" + ename + "%");
    }
}
作成icon文件
			引入(include) dao.dicon文件。将继承AbstractDao的类定义为组件(component)。对已注册的组件应用dao.interceptor(S2DaoInterceptor)。 
<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container//EN"
"http://www.seasar.org/dtd/components.dtd">
<components>
    <include path="dao.dicon"/>
    <component class="examples.dao.Employee2DaoImpl">
        <aspect>dao.interceptor</aspect>
    </component>
</components>
作成执行文件
			把刚才作成的dicon文件(Employee2Dao.dicon)的路径,作为org.seasar.framework.container.S2Container#create()方法的第一参数,创建一个容器(container)。把组件中注册的类名(Employee2Dao.class),作为org.seasar.framework.container.S2Container#getComponent()方法的第一参数,取得组件(component)。指定检索条件为含有"CO"的名字。执行Dao里定义的方法(method)。 
package examples.dao;
import java.util.List;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;
public class Employee2DaoClient {
    private static final String PATH = "examples/dao/Employee2Dao.dicon";
    public static void main(String[] args) {
        S2Container container = S2ContainerFactory.create(PATH);
        container.init();
        try {
            Employee2Dao dao = (Employee2Dao) container
                    .getComponent(Employee2Dao.class);
            List employees = dao.getEmployees("CO");
            for (int i = 0; i < employees.size(); ++i) {
                System.out.println(employees.get(i));
            }
        } finally {
            container.destroy();
        }
    }
}
执行结果
DEBUG 2004-10-01 10:14:39,333 [main] physical connection opened
DEBUG 2004-10-01 10:14:39,333 [main] logical connection opened
DEBUG 2004-10-01 10:14:40,379 [main] logical connetion closed
DEBUG 2004-10-01 10:14:41,254 [main] SELECT EMP.empno, EMP.ename, EMP.job, EMP.mgr,
  EMP.hiredate, EMP.sal, EMP.comm, EMP.deptno, department.deptno AS deptno_0,
  department.dname AS dname_0,
  department.loc AS loc_0, department.versionNo AS versionNo_0 FROM EMP
  LEFT OUTER JOIN DEPT department ON EMP.deptno = department.deptno
  WHERE ename LIKE '%CO%'
DEBUG 2004-10-01 10:14:41,270 [main] logical connection opened
DEBUG 2004-10-01 10:14:41,426 [main] logical connection closed
7788, SCOTT, ANALYST, 7566, 1982-12-09 00:00:00.0, 3000.0, null, 20
  {20, RESEARCH, DALLAS, 0}
DEBUG 2004-10-01 10:14:41,442 [main] physical connection closed
这一演习,放在s2dao/src/examples/dao目录下。 |