pureQuery 是一种高性能 Java;数据访问平台其目标主要是简化数据访问应用程序的开发和管理它由工具API 和运行时组成本文介绍 pureQuery 带注释的方法风格 —— 这是一种简单灵活的风格属于命名查询(namedquery)范例可以静态或动态地执行 SQL本文先解释为什么开发人员要选择使用带注释的方法风格编写 pureQuery 应用程序再解释带注释的方法风格与 pureQuery 内联编程风格之间的差异并简要概述 pureQuery 带注释的方法的强大特性 概述 本文讨论与带注释的方法的编程风格相关的以下主题 描述带注释方法的编程风格 选择使用带注释方法编程风格的原因 使用带注释的方法风格开发 pureQuery 应用程序的步骤 描述代码生成给出生成的代码示例 描述在 pureQuery 接口中定义带注释的方法的需求 使用 pureQuery 接口执行 SQL 介绍带注释的方法风格的一些选择特性例如批处理生成的 RowHandlers 和 ParameterHandlers生成的键以及使用 XML 配置文件修改代码生成器的输出 如果您已经准备好开始编程那么可以跳到 技术性崩溃接下来介绍一个简单的例子展示为什么开发人员要选择使用带注释的方法风格开发 pureQuery 应用程序 什么是带注释的方法编程风格? 为了介绍带注释的方法编程风格首先需要理解这两种 pureQuery 编程风格的背景知识 内联编程风格 的开发目的是为了满足客户对快捷简便的编程风格的需求这种风格很容易被熟悉 Java? Database Connectivity(JDBC)的开发人员掌握 —— 其特点就是可以更快更简单地编程内联风格最初的目标是减少 JDBC 程序员熟悉的一些重复的编程任务同时提供一个 API工具可以轻松地利用该 API 将数据访问开发与 Java 开发联系在一起由于应用程序中定义 SQL 语句的方式这种编程被称作 内联在内联风格中SQL 语句是在运行时声明或构造的并作为 String 的实例传递给公共的 Data 接口方法内联风格可以最大化编程速度和开发灵活性并支持动态执行后期文章将提供对公共 Data 接口 API 的概述关于内联风格的更多信息可以在 pureQuery 文档中找到(参见 参考资料) 本文主要讨论带注释的方法编程风格这种风格的演化和内联编程风格相似但是它还有另外一个目标那就是最大化编写的 pureQuery 应用程序的可配置性和安全性带注释的方法风格是专门为同时支持动态和静态数据库访问而设计的其目的是满足对类似于 Java Persistence API(JPA)的用于数据访问的命名查询编程接口的客户需求 —— 更快更简单地编程必要时能够支持静态执行 与内联编程风格一样带注释的方法也起源于应用程序定义 SQL 语句的方式在带注释的方法风格中SQL 字符串被定义为 Java 的一个元素pureQuery AnnotationpureQuery 为此目的定义的方法注释有 @Select (注释 SQL 查询) @Update (注释 SQL DML 语句)和 @Call (注释 SQL CALL 语句)这些注释被放在用户定义接口内的用户定义方法声明中代码生成器预处理接口为每个已声明的带有注释的方法生成实现代码生成的实现代码使用 pureQuery 运行时执行注释中定义的 SQL 语句在注释元素中预先定义 SQL 字符串可以简化静态执行支持 Data Studio 对带注释的方法风格的工具支持包括一个代码生成器它可以创建用户编写的带注释的方法的实现代码生成的结果就是第二个实现类该实现类被编译并用于执行初始接口中声明的 SQL 语句图 说明了用户定义的带注释的方法接口代码生成器和生成的实现类之间的关系 图 pureQuery 带注释的方法的代码生成 一个有趣的例子 本节介绍一个虚构的例子Silver Castles 的数据访问开发小组Silver Castles 是一家正在不断发展的公司销售各种银制产品该公司正在 Silver Castles 网站上开发一个新的基于 Web 的店面并且已经决定使用 pureQuery 环境来开发数据访问应用程序的持久层当他们观看了 pureQuery 工具演示 并阅读了 pureQuery 教程 之后很快就决定使用 pureQuery他们了解到使用 motivating 快速开发测试和部署用于多平台的基于 Java 的数据访问持久层非常容易当这个小组决定何时使用带注释的方法编程风格何时使用内联编程风格时还会受到其他一些因素的影响有一个叫做 Bob 的开发人员决定成为带注释的方法编程风格方面的专家他收集了一些知识以帮助小组决定何时使用这两种编程风格后面介绍了这些知识 决定使用带注释的方法 Bob 首先审视了带注释的方法编程风格几小时后他回到小组并给出一份清单上面列出带注释的方法风格的一些亮点 范例 遵从命名查询的风格目标是等同或超过现有对象关系映射器和持久化解决方案的功能 鼓励将持久层(CRUD)语句与应用程序在带注释接口中的其余部分分离其结果是开发中对 SQL 语句的更改不会扩散到整个应用程序也不会影响负责其他层的开发人员带注释的接口为管理整个应用程序的 SQL 语句提供一个集中控制点 SQL 语句文本是在开发时知道的但是可以提前对 SQL 语句文本进行分析以便开发人员优化输出对象的分配 静态支持 pureQuery 带注释的方法编程风格使得执行静态 SQL 成为一个部署选项而不是设计选项带注释的方法代码可以动态地部署也可以使用 IBM Data Servers 上的静态 SQL 包来部署而不必修改任何代码 从应用程序开发人员和前端应用程序的角度透明转换到静态执行 选择针对静态执行进行部署可以获得静态 SQL 的全部好处安全性能监控和预运行时优化 代码生成 最小化手动编写代码先声明接口方法签名和 SQL 语句然后由 pureQuery 代码生成器产生数据访问代码实现 返回查询结果由 pureQuery 预处理为多种对象例如已填充的 pureQuery bean 的 Iterators或者列名的 Lists或者列值 Maps 要对数据访问进行预处理和后处理使用 Hook 定制生成的代码的行为 使用 XML 配置文件 为每个目标数据库定义不同的 SQL 开发和使用带注释的方法 下面的清单 显示了 Bob 编写的 pureQuery 接口的一部分亲自体验带注释的方法风格他使用该接口向小组成员解释带注释的方法风格的基础pureQuery 带注释的接口是带注释的方法风格的构建块pureQuery 接口由以下部分组成 一个 Java interface 定义包含 一个或多个方法声明 对于每个方法声明有一个 pureQuery 数据访问注释 @Select @Update 或 @Call 每个注释包括一个 SQL 语句其中包含方法被调用时要执行的 SQL 语句(也可以选择在一个配置文件而不是注释元素中提供该 SQL 语句) 对于每个方法声明有一个 Java 返回类型表明 pureQuery 运行时将数据访问结果返回给调用者时需要使用的对象格式 对于每个方法签名有一些 Java 参数类型包括表明用于执行 SQL 语句的参数的对象类型
除了以上描述的那些方法声明或定义外接口定义文件不包含任何其他方法声明或定义定义好 pureQuery 接口之后应用程序的其他层在概念上可以将该接口当作一个数据库 —— 可以很容易地通过调用声明的 Java 数据访问方法来从 Java 中访问当另一个应用程序层调用一个带注释的方法时它将收到执行相关联的 SQL 语句的结果形式为一个适当格式化的 Java 对象开发其他应用程序层时不需要 SQL 方面的知识 清单 pureQuery 带注释的方法风格的接口 package comibmdbpureQuery; import javautilIterator; import comibmpdqannotationSelect; public interface CustomerData { // Select all PDQ_SCCUSTOMERs and populate Customer beans with results @Select(sql=select CID NAME COUNTRY STREET CITY PROVINCE ZIP PHONE INFO from PDQ_SCCUSTOMER) Iterator<Customer> getCustomers(); // Select PDQ_SCCUSTOMER by parameters and populate Customer bean with results @Select(sql=select CID NAME COUNTRY STREET CITY PROVINCE ZIP PHONE INFO from PDQ_SCCUSTOMER where CID = ?) Customer getCustomer(int cid); } 生成一个实现 定义好上述接口后Data Studio 中的 pureQuery 项目工具自动将它提供给 pureQuery 代码生成器pureQuery 代码生成器产生该接口的一个实现放在一个名为 CustomerDataImpljava 的文件中为便于读者查看清单 中给出了生成的文件注意生成的文件中的所有代码(清单 )都不是由开发人员手动编写的 您不需要查看生成的代码如果您想看看 Silver Castle 应用程序如何使用以上接口可以跳到 下一步接下来了解更多关于生成的代码的信息 代码生成器和生成的代码 代码生成器以用户定义的 pureQuery 接口为输入例如由 SilverCastles 开发人员定义的简单的 CustomerData它生成的代码用来执行针对接口中每个方法进行注释的每个 SQL 语句它还生成用于将结果处理为所声明类型的代码生成的代码调用 pureQuery 运行时来执行每个方法所需的处理 关于生成的代码有一些重要的注意事项 生成的元素对于每个声明的方法生成的元素包括方法定义一个内部 pureQuery StatementDescriptor一个生成的 RowHandler 或 ResultHandler 以及一个内部 pureQuery ParameterHandler 实现类名称生成的实现文件的名称以初始的用户定义接口的名称为基础在名称后面加上 Impl在这个例子中开发人员编写了 CustomerData 接口代码生成器产生 CustomerDataImpl 类生成的类实现 CustomerData 接口数据访问应用程序的其他层不会使用实现类的名称它们总是引用和使用用户定义接口但是知道实现文件的名称还是有用的以便检查生成的代码 实现超类除了实现用户定义接口外生成的实现类还扩展内部的 pureQuery 类 BaseData后者实现外部的 Data 接口这个超类是 pureQuery 运行时的一部分负责处理访问数据库和处理结果的固定的重复的操作 看到生成的代码时不要感到困惑开发人员不需要查看这些代码除非他们执意要这么做 使用带注释的方法 至此项目已经构建完毕Data Studio pureQuery 工具已经调用了 pureQuery 代码生成器并且接口实现也已经生成并编译开发人员现在可以通过调用 pureQuery 带注释的接口中声明的带注释的方法从应用程序的其他层访问数据这个过程很简单应用程序通过发送给 DataFactory 的一个请求实例化 pureQuery 接口的一个实例(概念上的数据库)然后它调用数据访问方法如下所示 清单 调用带注释的方法 javasqlConnection con = ; // use the DataFactory to instantiate the CustomerData interface CustomerData cd = DataFactorygetData(CustomerDataclass con); // execute the SQL for getCustomers() and get the results in Customer beans Iterator<Customer> cust = cdgetCustomers(); // the application can now consume the Iterator of Customer beans
通过几行代码就访问了数据库执行了所需的 SQL 语句并将结果处理成方便的 Customer 类的数据 bean 的 Iterator因此应用程序可以直接使用更加令人印象深刻的是即使要实现持久层方法开发人员也只需声明这里所调用的方法pureQuery 代码生成器和运行时会处理其余的工作 分解带注释的方法风格 本节将这个示例分解成带注释方法编程风格的几个重要组成部分pureQuery 文档包含对这些和其他 pureQuery 编程概念的完整描述(参见 参考资料) pureQuery 接口 在以上例子中用户定义的 pureQuery 接口被命名为 CustomerData合理地命名接口以反映它所代表的信息源这样做很有帮助如 Silver Castles 示例一样例如CustomerData 方法检索和更新关于公司客户的信息 如上所述pureQuery 接口只包含带注释的方法的声明 带注释的方法的声明 pureQuery 接口中的每个方法声明包含以下必要元素 三个 pureQuery 注释中的一个@Select@Update 或 @Call 对于每个注释有一个 sql=<string> 元素其中的 string 包含一个有效的 SQL 语句这个 SQL 语句将在方法被调用时执行(可选地也可以在一个 XML 配置文件中提供 SQL 语句) 一个标准的 Java 方法声明 已声明的返回类型 方法声明的返回类型表明 SQL 语句的结果返回什么样的对象格式取决于所使用的注释受支持的返回类型有所不同例如对于查询可以返回各种集合和简单类型对于更新可以使用标准的更新计数格式除了其他格式外 StoredProcedureResult 返回类型可以方便地封装存储过程调用的结果 还可以由 pureQuery 引擎将结果处理成用户定义 pureQuery bean 的一个集合在我们的示例中开发人员声明的返回类型是 Customer bean 的一个 IteratorpureQuery 使用一组 bean 约定和需求 将数据库查询结果直接映射到用户定义的 bean 类pureQuery bean 中的注释 可以覆盖默认的映射行为而且可以由用户提供的 RowHandler 将结果手动映射到 bean否则生成的 RowHandler 将在把 bean 结果返回给调用者之前自动执行默认的映射将结果映射到用户定义的 bean 类 声明的参数类型 带注释的方法声明中的参数类型决定 pureQuery 如何在运行时获得 SQL 语句参数值SQL 语句中的参数占位符与带注释的方法中声明的参数之间可能存在一对一的映射但是也不一定如此pureQuery 遵从 参数占位符语法规则 来决定如何从带注释的方法的参数列表中声明的参数映射 SQL 语句参数 与其他数据访问 API 相比pureQuery 中的参数可以采用更多种类的类型例如一个声明的 pureQuery bean 参数可以为 一些 SQL 语句参数占位符 提供运行时值对于 pureQuery 带注释的方法pureQuery bean 和 Java 集合类型都受支持请查看带注释的方法 语法图以获得可能声明的参数类型的完整列表带注释方法的声明的参数类型可以在很大程度上影响 SQL 语句的执行例如可以通过使用带注释的方法 @Update 中的某些参数类型发起批量更新对于批量更新需要使用一个集合参数多次执行一条 SQL 语句每次执行时使用不同的参数值 带注释的方法的参数可以直接使用也可以赋给变量以利用 pureQuery 引擎的特定处理功能批量更新处理是 pureQuery 引擎底层自动优化代码和改进开发的一个例子对数据 bean 参数的特殊 pureQuery 处理还可以节省开发时间和精力例如 @GeneratedKey pureQuery bean 注释使 pureQuery 引擎可以用插入或更新操作后生成的数据库值自动更新 bean 参数的字段 Hook 由于大多数代码都是使用带注释的方法的风格生成的pureQuery 开发小组中有些人一开始有所顾虑Bob 解释道 Hook 在执行生成的代码期间为进行特殊处理提供了一种简单的方法现在不需要手动编写方法调用以便将每个应用程序调用围绕一个带注释的接口方法而是采用另一种方法定义一个 Hook 以注册到带注释的接口在进入和退出每个带注释的方法时pureQuery 运行时回调 Hook这提供了一种回调机制以便将生成的数据访问代码与特殊的处理关联起来Hook 定义所需的 pre() 方法Hook 进行注册后在进入一个带注释的方法时得到调用每个 Hook 还将定义一个 post() 方法当该 Hook 注册后在从一个带注释的方法返回控制之前该方法会被立即调用 Hook 方法为特殊的运行时回调处理提供上下文感知以防 pre() 和 post() 的用户定义实现需要它这种感知是通过 pre() 和 post() 方法调用中的参数获得的可以根据这些参数的值设计不同的特殊处理例如取决于调用 Hook 方法的接口方法的名称提供给那个方法的运行时参数值或者该方法执行的 SQL 语句类型的不同处理也会有所不同此外还以 Data 参数的形式提供了 Hook 所注册的 pureQuery 接口的一个句柄这些值都可以供 Hook 的实现者查看和修改此外返回值在被返回给调用者之前还可以供 post() 方法的实现者使用下面是 Bob 为了向 Silver Castles 小组进行演示而编写的 Hook 处理代码的一个例子 清单 用于特殊处理的 Hook public static class TrackingHook implements Hook { public void pre(String methodName Data objectInstance SqlStatementType sqlStatementType Object parameters) { Systemoutprintln(methodName + **Customer data has been accessed**); } public void post(String methodName Data objectInstance Object returnValue SqlStatementType sqlStatementType Object parameters) { // do nothing } } 至此已经使用 Hook 定义了特殊的处理开发人员可以通过向进行实例化的接口注册他们的 Hook 的一个实例以确保可以运行清单 展示如何注册一个 Hook 清单 注册一个 Hook Connection con = ; // use the DataFactory to instantiate the interface and // provide an instance of Hook to be registered with the instance CustomerData cd = DataFactorygetData(CustomerDataclass con new TrackingHook()); // execute the SQL for getCustomers() and get the results // the pre() and post() methods are automatically called Iterator<Customer> cust = cdgetCustomers(); // the application now consumes the Iterator of Customer beans
这是有关 Hook 的特殊处理的一个非常简单的例子请参阅 pureQuery 文档中的 Hook 示例以查看可以使用 Hook 实现的更复杂的类型示例 针对多目标的开发 Bob 向他的小组解释了带注释的方法的最后一个特性使用 XML 配置文件 将 SQL 语句与应用程序的 Java 代码实现完全分离这样一来当将 Java 应用程序部署到一个要求不同 SQL 语句的目标数据库时就可以避免重复编写该 Java 应用程序例如如果小组想将同一个应用程序部署到一个遗留数据源上且该数据源使用稍有不同的模式那么他们不需要重新编写带注释的接口或 pureQuery bean 清单 展示了用于初始模式的 SQL 语句 清单 用于初始模式的 SQL 语句 select CID NAME COUNTRY STREET CITY PROVINCE ZIP PHONE INFO from PDQ_SCCUSTOMER 清单 展示了用于遗留模式的 SQL 语句 清单 用于遗留模式的 SQL 语句 select CUSTID NAME COUNTRY STREET CITY PROV ZIP PHONE INFO from PDQ_SCCUSTOMER 注意在清单 中CID 和 PROVINCE 列的名称变成了 CUSTID 和 PROV这改变了用于发出查询的 SQL 语句也改变了从结果到 Customer 数据 bean 的默认映射 清单 展示了 customer pureQuery bean 清单 Customer pureQuery bean package comibmdbpureQuery; public class Customer { // Class variables protected int cid; protected String name; protected String country; protected String street; protected String city; protected String province; protected String zip; protected String phone; protected String info;
小组无需编写新的带注释的接口或 Customer bean 类来支持遗留模式只需使用一个 XML 配置文件向生成器提供附加的输入以支持遗留模式下面列出了 XML 配置文件的一个片段它展示了如何覆盖一个 SQL 字符串和用户定义 bean 类映射为了将应用程序部署到遗留系统上小组将初始的带注释的接口定义和下面的 XML 文件提供给生成器生成器产生正确的生成代码从而部署到遗留数据库上 清单 生成替换代码的 XML 配置文件 <?xml version= encoding=UTF?> <entitymappings xmlns=> <namednativequery name= comibmdbpureQueryCustomerData#getCustomers()> <query><![CDATA[select CUSTID NAME COUNTRY STREET CITY PROV ZIP PHONE INFO from PDQ_SCCUSTOMER]]> </query> </namednativequery>
<entity class=com comibmdbpureQueryCustomer> <attributes> <basic name=cid> <column name=CUSTID /> </basic> <basic name=province> <column name=PROV /> </basic> </attributes> </entity> </entity> </entitymappings> 要了解关于将 XML 配置文件提供给生成器以便为 pureQuery 接口提供备选 SQL 语句和/或对象映射的更多信息请参阅 pureQuery 在线文档 结束语 本文概要地介绍了 pureQuery 带注释的方法编程风格以及开发小组选择使用 pureQuery 带注释的方法进行编程的动机本文还列出了开发带注释的方法风格的应用程序所需的步骤另外也介绍了这种风格的部分特性 如果您有兴趣进一步了解如何开发 pureQuery 带注释的方法风格的应用程序请访问本文正文和参考资料小节中提供的 pureQuery 在线文档其他文章和相关教程的链接 |