http://www.ibatis.com 简介
本文是初学者的快速入门教程,涵盖了SQL Map的一个简单而典型的应用。每个主题更详细的信息可以参考《iBatis SQL Maps 2.0 开发指南》。
本文是《iBatis SQL Maps Tutorial》的中文版,仅供读者参考。最权威的以Clinton Begin的官方文档为准,它可以从http://www.ibatis.com网站下载。如果中文翻译有错误,请通知译者(email:toleu@21cn.com,Blog:http://starrynight.blogdriver.com/)。 准备使用SQL Map
SQL Map架构能应用于设计不好的数据库模型甚至是设计不好的对象模型。尽管如此,您在设计数据库模型和对象模型时,还是应该遵循最佳的设计原则。这样,您会获得更好的性能和更简洁清晰的设计方案。
设计最容易开始的地方是分析应用的业务逻辑。分析什么是应用的业务对象,什么是数据模型以及两者之间的关系。作为快速入门第一个例子,我们使用一个简单的Java Bean Person类。
Person.java
package examples.domain; //imports implied…. public class Person { private int id;
private String firstName; private String lastName; private Date birthDate;
private double weightInKilograms; private double heightInMeters; public int getId () { return id; }
public void setId (int id) { this.id = id; }
//…let’s assume we have the other getters and setters to save space… }
Person类有了,如何将Person类映射成数据表呢?SQL Map对Java Bean和数据表之间的关系没有限制,如一个数据表映射成一个Java Bean,或多个表映射成一个Java Bean,或多个Java Bean映射成一个数据表等。因为使用SQL Map您可以充分发挥SQL语句的全部潜力而很少限制。下面这个例子,我们使用一个简单的表,将一个表映射成一个Java Bean,Java Bean和表是一对一的关系。 Person.sql
CREATE TABLE PERSON(
PER_ID NUMBER (5, 0) NOT NULL,
PER_FIRST_NAME VARCHAR (40) NOT NULL,
PER_LAST_NAME VARCHAR (40) NOT NULL, PER_BIRTH_DATE DATETIME ,
PER_WEIGHT_KG NUMBER (4, 2) NOT NULL, PER_HEIGHT_M NUMBER (4, 2) NOT NULL, PRIMARY KEY (PER_ID) )
SQL Map的配置文件
现在准备好了学习环境,让我们从学习SQL Map的配置文件开始,配置文件是SQL MAP的配置信息统一设置的地方。 SQL Map配置文件是XML文件,我们可以它设置各种属性,JDBC DataSource和SQL Map。在配置文件中,可以方便地统一配置DataSource不同的实现。SQL Map框架包括DataSource的iBATIS实现:SimpleDataSource类,Jakarta DBCP(Commons),和可通过J(java)N(naming)D(directory)I(interface)上下文查找的DataSource(即应用服务器中的DataSource)。详细的使用方法在以后的章节讨论。在本例中,我们使用Jakarta DBCP。对于上面的例子,配置非常简单,如下所示:
SqlMapConfigExample.xml http://www.ibatis.com Clinton Begin 著 刘涛(toleu@21cn.com) 译 iBATIS SQL Maps 入门教程 Page 4 of 10 PUBLIC \"-//iBATIS.com//DTD SQL Map Config 2.0//EN\" \"http://www.ibatis.com/dtd/sql-map-config-2.dtd\">
< sqlMapConfig>
useStatementNamespaces=\"false\" /> SqlMapConfigExample.properties # This is just a simple properties file that simplifies automated configuration # integration tools for different environments… etc.) # These values can be used in any property value in the file above (e.g. “${driver}”) # Using a properties file such as this is completely optional. driver=oracle.jdbc.driver.OracleDriver url=jdbc:oracle:thin:@localhost:1521:oracle1 username=jsmith password=test SQL Map的映射文件 现在DataSource已经配置好了,并且有了统一的SQL Map配置文件,我们还需要SQL Map的映射文件。映射文件包括SQL语句和参数对象和结果对象的映射。 继续上面的例子,我们从一个简单的查询语句开始,为Person类和PERSON表之间创建一个SQL Map映射文件。 Person.xml PUBLIC \"-//iBATIS.com//DTD SQL Map 2.0//EN\" \"http://www.ibatis.com/dtd/sql-map-2.dtd\"> 上面的例子是SQL Map最简单的形式。它使用了SQL Map框架中一个特性,根据匹配的名字将ResultSet的列映射成Java Bean的属性(或Map的key值)。#value#符号是输入参数,该符号表示使用了基本类型的包装类作为输入参数(即Integer,但不仅限于此类型)。 http://www.ibatis.com Clinton Begin 著 刘涛(toleu@21cn.com) 译 iBATIS SQL Maps 入门教程 Page 6 of 10 以上的方法虽然很简单,但有一些限制,无法指定输出字段的数据类型,无法自动地在结果对象中载入相关的信息(即Java Bean无法使用复杂的属性);以上的方法对性能还有轻微的不利影响,因为需要读取ResultSetMetaData的信息。使用resultMap,可以克服以上的不足,但现在只需要一个简单的例子,以后我们再转向其他不同的方法(无须修改Java代码)。 大多数的应用不仅需要从数据库中读取数据,还需要修改数据。我们已有了一个SELECT查询语句的mapped statement简单例子,下面看看INSERT,UPDATE和DELETE的mapped statement什么样子。幸运的是,它们其实没什么区别。接下来,我们完成Person SQL Map其他部分,以实现修改数据的功能。 Person.xml PUBLIC \"-//iBATIS.com//DTD SQL Map 2.0//EN\" \"http://www.ibatis.com/dtd/sql-map-2.dtd\"> PERSON (PER_ID, PER_FIRST_NAME, PER_LAST_NAME, PER_BIRTH_DATE, PER_WEIGHT_KG, PER_HEIGHT_M) VALUES (#id#, #firstName#, #lastName#, #birthDate#, #weightInKilograms#, #heightInMeters#) SET PER_FIRST_NAME = #firstName#, PER_LAST_NAME = #lastName#, PER_BIRTH_DATE = #birthDate#, PER_WEIGHT_KG = #weightInKilograms#, PER_HEIGHT_M = #heightInMeters# WHERE PER_ID = #id# WHERE PER_ID = #id# 使用SQL Map框架编程 好了,我们完成了所有的配置文件和映射文件,就剩下的应用的编码工作了。首先要设置SQL Map,读入刚创建好的SQL Map XML配置文件。为简化这个工作,可以使用SQL Map架构中提供的Resources类。 String resource = “com/ibatis/example/sql-map-config.xml”; Reader reader = Resources.getResourceAsReader (resource); SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader); 以上的SqlMapClient对象是线程安全,并且应持久生存。对于一个特定的应用,只需进行一次SqlMap配置。因此,它可以作为基类的一个静态对象(即DAO对象的基类),或者,如果您想让它有更大的作用范围,可以把它封装在方便使用的类中。例如: public class MyAppSqlConfig { private static final SqlMapClient sqlMap; static { try { String resource = “com/ibatis/example/sql-map-config.xml”; Reader reader = Resources.getResourceAsReader (resource); sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader); } catch (Exception e) { // If you get an error at this point, it matters little what it was. It is going to be // unrecoverable and we will want the app to blow up good so we are aware of the // problem. You should always log such errors and re-throw them in such a way that // you can be made immediately aware of the problem. e.printStackTrace(); throw new RuntimeException (“Error initializing MyAppSqlConfig class. Cause: ”+e); } } public static SqlMapClient getSqlMapInstance () { return sqlMap; } } 从数据库读取对象 既然SqlMap对象已完成初始化,就可以方便地使用它了。首先,我们用它从数据库中读取一个Person对象。(在本例中,假设PERSON表中已存在10条记录,PER_ID从1到10)。 要从数据库中得到一个Person对象,只需要SqlMap实例,mapped statement的名字和一个Person ID号。让我们读入PER_ID是5的Person对象。 … SqlMapClient sqlMap = MyAppSqlMapConfig.getSqlMapInstance(); // as coded above … Integer personPk = new Integer(5); Person person = (Person) sqlMap.queryForObject (“getPerson”, personPk); … 把对象写入数据库 现在已有了一个从数据库中读出的Person对象,接着修改Person对象的height和weight属性,并将它写入数据库。 … person.setHeightInMeters(1.83); // person as read from the database above person.setWeightInKilograms(86.36); … sqlMap.update(“updatePerson”, person); … 要删除这个Person对象,也很容易。 … sqlMap.delete(“deletePerson”, person); … 类似地,也可以创建一个新的Person对象。 Person newPerson = new Person(); newPerson.setId(11); // you would normally get the ID from a sequence or custom table newPerson.setFirstName(“Clinton”); newPerson.setLastName(“Begin”); newPerson.setBirthDate (null); newPerson.setHeightInMeters(1.83); newPerson.setWeightInKilograms(86.36); … sqlMap.insert (“insertPerson”, newPerson); … 附录:容易出错的地方 本附录是译者添加的,列出了初学者容易出错的地方,作为完成快速入门课程后的学习笔记,可以让初学者少走些弯路。仅供参考。 1) 在parameterMap和resultMap中,字段数据类型是java.sql.Types类定义的常量名称。常用的数据类型包括BLOB,CHAR,CLOB,DATE,LONGVARBINARY, INTEGER,NULL,NUMERIC,TIME,TIMESTAMP和VARCHAR等。 2) 对于数据表中NULLBALE的字段,必须在parameterMap和resultMap中指定字段的数据类型。 3) 对于数据类型是DATE,CLOB或BLOB的字段,最好在parameterMap和resultMap中指定数据类型。 4) 对于二进制类型的数据,可以将LONGVARBINARY映射成byte[]。 5) 对于文本类型较大的数据,可以将CLOB映射成String。 6) Java Bean必须拥有缺省的构造器(即无参数的构造器)。 7) Java Bean最好实现Serializable接口,以备应用的进一步扩展。 因篇幅问题不能全部显示,请点此查看更多更全内容