引论
随着Hibernate逐渐成为其他架构之首现今的许多工作都是在对象关系(OR)映射域上进行但是那些对象关系映射工具有一个问题大部分数据库管理员似乎对这些对象关系(OR)映射工具所产生的查询不放心不幸的是这些数据库管理员不了解架构所产生的查询是多么的优越并且使你的应用程序更加灵活他们觉得随着数据库成为应用程序的主要瓶颈应该完全控制SQL查询以便他们能分析和调试以促进性能
但有个问题是如果不使用对象关系(OR)映射工具那么你将花费很多资源在书面形式上和维护低级JDBC代码由于以下原因每个JDBC应用程序都将含有重复代码
连接和事务管理
设置java对象为查询参数
转换SQL ResultSets 为 java 对象
生成查询字符串
iBatis 的 SQLMaps 架构帮助我们在相当大的程度上减少了正常情况下访问关系数据库的java代码的总量它考虑到了当前三个比较关心的问题所以它可以将一个简单的 JavaBean 对象映射到 PreparedStatement 参数和 ResultSet 值SQLMaps 的原理其实很简单提供一个简单的架构来提供%的JDBC功能
这篇文章是关于如何使用 SQLMaps 架构的进阶辅导我们将建立一个简单的 Struts 应用程序并且用 SQLMaps 配置它为开始接着我们将演示如何执行基本的数据库操作比如 SELECT INSERT UPDATE 等等然后我们将演示 SQLMaps 为连接和事务管理提供的操作在最后我们将试着使用一些高级的 SQLMaps 功能部件比如缓存和分页
SQLMaps 的基本思想
使用 SQLMaps 架构你必须建立一个XML文件列出所有你希望在应用程序中执行的SQL查询对于每个SQL查询你来指定哪个java类可以交换参数和ResultSet(结果集)
在你的java代码中如果你想要执行一个特殊的查询你需要创建一个对象来传递查询参数和必要的条件然后传递这个对象和查询的名字让 SQLMaps 执行一旦查询被执行SQLMaps 将为你指定的接受查询结果的类创建一个句柄并且将它和数据库返回的ResultSet 中的值存储在一起
一个简单的使用SQLMaps的应用程序(Hello World)
我们将创建一个简单的Struts应用程序开始来演示什么是使用SQLMaps的应用程序所需要的这个例子的代码是来自以下资源部分在这个例子中我们用一个Jsp页面要求用户输入contactId属性一旦它被提交我们用它在CONTACT 表中搜索一个连接并且用另一个Jsp页面展示给用户接下来一步一步说明
拷贝ibatissqlmapjar 和 ibatiscommonjar 到你的 webinf/lib 文件夹中
在你的java源文件夹中创建一个 SqlMapConfigxml 文件像这样
<sqlMapConfig><settings useStatementNamespaces=false /><transactionManager type=JDBC><dataSource type=SIMPLE ><property name=JDBCDrivervalue=COMibmdbjdbcappDBDriver/><property name=JDBCConnectionURLvalue=jdbc:db:SAMPLE/><property name=JDBCUsernamevalue=dbadmin/><property name=JDBCPasswordvalue=admindb/></dataSource></transactionManager><sqlMap resource=Contactxml/></sqlMapConfig>
SqlMapConfigxml 是SQLMaps的部署描述信息包括以下元素
<sqlMapConfig>是文件的根元素<settings>被用来定义应用程序级别的设置例如 useStatementNamespaces 属性被用来定义是否要用准备说明的全限定名它可以有一些另外的属性用于控制缓存和初始化要知道更进一步的细节请查看文档
<transactionManager> 被用来定义你想要在你的应用程序中使用的事务管理在我们的例程中我们要用Connection 对象的 commit 和 rollback 方法来管理事务所以我们用JDBC作为事项管理程序它包含 <dataSource> 作为子元素<dataSource>用来定义你要使用的连接管理的类型在我们的例程中我们要用SQLMaps自带的连接池实现如此我们将使用一个SIMPLE类型的数据源为了建立连接池SQLMaps要求像JDBC驱动名称URL和密码这些信息因此我们使用<property>元素来传递这些信息稍后我们将更加详细地讨论各种各样可用的事务和连接管理选项
<sqlMap>元素被用来表明 SQLMap 配置文件这些文件如早先讨论的列出了你希望执行的SQL查询
创建一个JavaBean类Contactjava有属性 firstName lastName 和 contactId 和相应的getset方法这个类将被用来向ResultSet传递查询参数并读取值
public class Contact implements Serializable{ private String firstName; private String lastName; private int contactId; //Getter setter methods for firstName //lastName and contactId property}
建立一个Contactxml文件我们将在文件中列出所有要执行的与表Contact有关的SQL查询
<sqlMap namespace=Contact><typeAlias alias=contacttype=ntactContact/><select id=getContactparameterClass=int resultClass=contact>select CONTACTID as contactId FIRSTNAME as firstName LASTNAME as lastName from ADMINISTRATORCONTACT where CONTACTID = #id#</select></sqlMap>
文件中使用的标签如下
<sqlMap>是文件的根元素正常情况下你的应用程序将有不止一个表由于你要把与不同表有关的查询分开成不同的名称空间(namespace)<namespace> 元素就是被用来指定在此文件中查询应被放置的名称空间
<typeAlias> 用来说明Contact 类的全限定名的一个简称在此说明后这个简称可以被用来替代全限定名
在SQLMaps架构中 <select> 元素用来声明SQLMaps架构中的SELECT查询它的值就是你能指定的要执行的查询id属性被用来指定通知SQLMaps 执行特殊查询的名称parameterClass 被用来指定传递查询参数的类resultClass 提供从ResultSet返回值的类的名称
在Action类的 execute() 方法内我们建立了一个SqlMapClient的句柄它被用来和SQLMaps相互作用我们必须向SqlMapClientBuilder传递SqlMapConfigxml文件它被用来读取配置设置
DynaActionForm contactForm =(DynaActionForm)form;Reader configReader =ResourcesgetResourceAsReader(SqlMapConfigxml);SqlMapClient sqlMap =SqlMapClientBuilderbuildSqlMapClient(configReader);Contact contact = (Contact)sqlMapqueryForObject(getContactcontactFormget(contactId));requestsetAttribute(contactDetail contact);return mappingfindForward(success);
当你要执行一个SELECT 查询时应该使用 SQLMaps 的 queryForObject 方法在Contactxml文件中我们已经指定parameterClass为int所以我们在传递查询的名称的时候传递一个integer作为contactId (ie getContact)
SQLMaps 将返回一个Contact 类的对象
基本数据库操作
现在我们要返回我们的所关注的使用SQMLaps如何表示一些基本的数据库操作
Insert操作
我们从如何执行一个开始Insert操作开始
<insert id=insertContact parameterClass=contact>INSERT INTO ADMINISTRATORCONTACT( CONTACTIDFIRSTNAMELASTNAME)VALUES(#contactId##firstName##lastName#);</insert>
<insert> 元素被用来声明一个Insert的SQL查询它有一个parameterClass 属性用来指明哪个JavaBean类将被用来传递(request)请求参数在插入新的记录时我们要使用contactId属性的值所以我们必须在SQL查询中使用一个#contactId#
public void contactInsert() throws SQLException IOException {sqlMapstartTransaction();try {sqlMapstartTransaction();Contact contact = new Contact();contactsetContactId();contactsetFirstName(John);contactsetLastName(Doe);sqlMapinsert(insertContactcontact);mitTransaction();} finally{sqlMapendTransaction();}}
在我们的java代码中我们建立了一个Contact 对象存放它的值然后调用sqlMapinsert()方法传递我们要执行的查询的名称和 Contact 这个方法将插入一个新的Contact并且返回新插入的Contact的主键
缺省情况下SQLMaps 把每个DML方法当作工作的一个单元但是你能使用 startTransaction commitTransaction 和 endTransaction 方法来划分事务处理通过调用 startTransaction() 方法你可以启动一个事务处理此方法也能从连接池中获得一个连接在这个事务中这个连接对象将被用来执行查询如果这个事务的所有查询都被成功执行应该调用 commitTransaction 方法提交你的改动不考虑你的事务成功与否