ITPub博客

首页 > Linux操作系统 > Linux操作系统 > [转载]学习如何用 Jython 编写 DB2 JDBC 工具

[转载]学习如何用 Jython 编写 DB2 JDBC 工具

原创 Linux操作系统 作者:dinner1007 时间:2019-02-23 10:30:05 0 删除 编辑

学习如何用 Jython 编写 DB2 JDBC 工具


您希望降低用 DB2 UDB JDBC 编写的工具的开发和维护成本吗?在这篇文章中,Victor Yang 解释了如何借助 Jython 来做到这一点。

简介

DB2 ®Universal Database ™(UDB)JDBC 驱动程序已被证明是一种强大的,并且得到 IBM 支持的技术。Jython 是 Python 编程语言百分之百的纯 Java 实现(请参阅 参考资料)。

首先,我们将告诉您 Jython 为何在编写 DB2 JDBC 工具方面功能强大、使用方便且充满乐趣。然后,我们将展示如何安装带有 DB2 JDBC 驱动程序的 Jython。最后,我们将演示几个查询示例,以及一个在 Jython 中使用批量插入的 QA 工具。




回页首


为何使用 Jython?

以下是 Neo 的一个真实故事。Neo 是全职的服务器端 Java 开发人员。他使用 Python 编写实用程序,例如解析 XML 或通过 HTTP 协议连接充当信用卡网关和订单履行网关的 Web 服务。因为 Python 的类型是动态的,且具有简洁的数据结构语法,比如列表和字典,所以 Neo 发现它通常可以减少代码行。

Neo 在处理一个股票交易应用程序,该应用程序是用部署在 AIX 上的 WebSphere Application Server 5.x 和 DB2 8.x 构建的。在实时系统中,每隔几分钟就要向表 STOCKQUOTE 输入 10,000 条 XML 格式的记录,以更新股票行情。执行批量输入的代码是作为另一系统的组成部分而由另一团队完成的,所以他无法获得源代码。此外,STOCKQUOTE 上有一个触发器,一旦股票价格下跌至一个预定义的阈值如 $10,该触发器就发出警报。项目经理给 Neo 分配了任务,让他用 Mercury Interactive 的 LoadRunner 或 Segue 的 SilkPerformermeasure 等自动化加载测试工具,测量在批量输入的情况下触发器所带来的性能影响。因此,Neo 需要编写一个批量输入的仿真器(simulator),用于模拟向 STOCKQUOTE 表加载 10,000 行记录。

开始,Neo 希望用纯 java JDBC 编写该仿真器,但是冗长的类型声明、编辑/编译/测试周期将占用他大量宝贵的开发时间。而且,因为 Python 的效率收益过去给 Neo 留下了深刻印象,所以他想是否可以用 Python 编写代码来使用 DB2 JDBC 驱动程序。如果可行,他就可以在几小时之内,用 Python 整洁的列表和字典等数据结构,以及列表理解(list comprehension)等整洁的函数编程功能来编写这个代码。在进行一些研究之后,他发现 Jython 十分方便,且正适合该工作。因为十分熟悉 DB2 JDBC 的编程,并拥有 Jython 参考资料,所以 Neo 在几小时之内就编写并测试了批量插入仿真器。他十分惊讶于 Jython 的强大功能,Jython 中包含了两大最佳领域:巨大的 Java 库和整洁的 Python 功能。因此,批量输入仿真器的最终代码比用纯 Java JDBC 所编写的源代码要少很多。源代码的总量影响很大,因为它可以减少程序员在编程时需要处理的细节。因此,降低源代码量将减小软件的复杂性,从而节省成本。




回页首


Jython JDBC 安装

安装 Jython 2.1

为了运行本文中的示例,您需要安装 Jython 2.1 和 JVM。您可以从 Jython 主页(请参阅 参考资料)获得 Jython。如果将 Jython 安装路径添加到平台上的 PATH 环境变量中,安装就十分方便。

Charming Jython(请参阅 参考资料)也包含了安装 Jython 的章节。

启用 DB2 UDB V8 中的 SAMPLE 数据库

本文所展示的示例使用了 SAMPLE 数据库。既可以通过运行与 DB2 一起发布的 db2sampl 程序来创建 SAMPLE 数据库,也可以从 DB2 安装工具菜单中的 FirstSteps 来创建。此外,还必须创建 DB2 ID/口令。本文中,我们使用 vyang/jythonrocks。

如何在 Jython 中连接 SAMPLE 数据库

这里,我们将展示如何在 Jython 中用流行的 type 2 和 type 4 驱动程序连接 SAMPLE 数据库。关于所有 JDBC 驱动程序的详细描述,请参阅 参考资料


Type 2 JDBC 驱动程序(CLI JDBC 驱动程序)
 from java.lang import * 
 from java.sql import * 
 Class.forName("COM.ibm.db2.jdbc.app.DB2Driver").newInstance() 
 con = DriverManager.getConnection( 'jdbc:db2:sample','vyang','jythonrocks')


Type 4 JDBC 驱动程序(DB2 UDB V8 中新增的)

from java.lang import * 
from java.sql import * 
Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance()
con = DriverManager.getConnection( 'jdbc:db2://db2host:50000/sample','vyang','jythonrocks') 

除了以下几点之外,以上连接 SAMPLE 数据库的代码看上去与 JDBC java 代码十分相似:

  • Jython 需要导入每一个 Java 包,包括 java.lang。
  • Jython 字符串可以使用单引号,也可以使用双引号。
  • Jython 的类型是动态的,因此不需要将 con的类型声明为 java.sql.Connection。



回页首


查询示例

现在,我们已经知道如何安装 Jython 和连接 DB2,应该开始查看示例了。下列示例在 Windows 2000 上使用 SAMPLE 数据库和 type 2 CLI JDBC 驱动程序。您可以从本页底部的下载小节中下载这些示例。

一个简单的动态查询(select1.jy)

select1.jy 将按升序从 EMPLOYEE 表(包含在 sample 数据库中)中选出所有薪水超过 $20,000 的雇员。

从命令控制台“jython select1.jy”运行 select1.jy。


图 1. “jython select1.jy”的输出
select1.jpg

以下是 Jython 代码。


清单 1. select1.jy
from java.lang import *
from java.sql import *
# load DB2 JDBC type 2 driver (app driver)
Class.forName("COM.ibm.db2.jdbc.app.DB2Driver").newInstance()
con = DriverManager.getConnection( 'jdbc:db2:sample','vyang','jythonrocks')
stmt = con.createStatement()
sql='select firstname,lastname,salary from employee where salary > 20000 order by salary' 
rs = stmt.executeQuery(sql)
employeeList=[]
while (rs.next()):
    row={}
    row['firstname']=rs.getString(1)
    row['lastname']=rs.getString(2)
    row['salary']=rs.getDouble(3)
    employeeList.append(row)
    
rs.close()
stmt.close()
con.close()
print 'employee salary over $20,000'
print '============================'
print 'firstname lastname salary'
print '============================'
# print the result 
for e in employeeList:
    print e['firstname'],e['lastname'],'$'+ str(e['salary']) 
 

以上代码在概念上与纯 Java JDBC 编程极其相似。但是,如果仔细查看,就会发现用 Jython 编写的代码更少一些。

注意:

  • 无需为 Connection、Statement、Result 声明类型,虽然这在纯 Java JDBC 编程中是必要的。它们的类型是动态解析的。
  • 对于结果集处理,与 java.util 中的 Vector/ArrayList 相比,使用 employeeList(Jython 列表)和 row(Jython 字典)来保存 java.sql.ResultSet 要容易得多。
  • 对于 employeeList 内容的输出,最后的 2 行代码就可以很好地完成。

SQL 字符串的格式化(select2.jy)

运行“jython select2.jy”。其功能与 select1.jy 相当。惟一的区别就是它使用 Jython 字典来保存 String 模板里的名称-值对,并使用 % 运算符来将该模板转换为有意义的 SQL 字符串。

基于 Jython 内置字典的字符串格式化与 C 中 printf 的一样强大,我们可以使用 % 运算符来关联字典。设想如果用 Java 来实现会怎样。

下列代码的结果是“select firstname,lastname,salary from employee where salary > 20000 order by salary”,与 select1.jy 中的完全一样。


清单 2. (select2.jy)基于字典的 SQL 字符串格式化
sqlTemplate = 'SELECT %(columns)s FROM %(tables)s WHERE %(constraints)s' 
dict = {'columns':      'firstname,lastname,salary',
        'constraints' : 'salary>20000',
        'tables' :      'employee'}
sql = sqlTemplate % dict
print sql

函数风格的结果集处理(select3.jy)

我们需要将结果写入文件中,以便进一步进行分析。为了说明如何在这里使用 Jython 的函数编程功能,下列代码中使用了 lambda 函数和列表理解,虽然也可以用命令式(imperative)编程风格来完成。


清单 3. (select3.jy)使用 lamda 和列表理解
# lambda function
toStr=lambda e: e['firstname']+','+e['lastname']+',$'+ str(e['salary'])
# an example of list comprehension
# write the result into a file called "salaries.txt"
print '======================================'
print 'the results are saved in salaries.txt'
print '======================================'
try:
    f=open('salaries.txt','w')
    f.writelines([toStr(e)+'
' for e in employeeList])
finally:
    f.close()

注意:

  • 一般来说,lambda 函数接收任何数目的参数,并返回单个表达式的值。它类似于 Java 中的匿名类,除了它是一个可在需要时作为参数来传递的第一级对象之外。Lambda 函数 toStr() 将为输出转换雇员的值(作为一个字典)。
  • ([toStr(e)+' ' for e in employeeList]) 通过 Jython 的列表理解,用 lambda 函数 toStr 将每个结果变成 slaries.txt 中的一行。将之与通过循环编写的等效代码进行比较。
  • Jython 中文本文件的处理只有简单的三行代码:open()、readlines/writelines (taking a list) 和 close()。再次设想如果用 java.io 编写会怎样。

获取图形(select4.jy)

让我们来尝试用 HTML 显示结果。还可以用红色突出显示薪水超过 $40,000 的那些雇员。

本示例中,我们使用 SWT。SWT 是一种软件组件,它以一种与操作系统无关的方式为 Eclipse 平台交付原生窗口部件(native widget)功能。这就是使 IBM WSAD(Websphere Studio Application Developer)以本机代码的速度运行的秘诀。


图 2. “select4.bat”的输出
swt.jpg

清单 4 展示了需要从 SWT 导入的包。


清单 4. (select4.jy)导入 SWT 包
from org.eclipse.swt import *
from org.eclipse.swt.graphics import *
from org.eclipse.swt.layout import *
from org.eclipse.swt.widgets import *
from org.eclipse.swt.browser import *

清单 5 展示了如何使用 SWT 显示 HTML 格式的结果。


清单 5. (select4.jy)显示 HTML 格式的结果
# display in browser with HTML
display = Display()
shell = Shell (display)
shell.setLayout(FillLayout())
browser = Browser(shell, SWT.NONE)
browser.setText(toHtml(employeeList))
browser.setSize(400,500)
shell.pack()
shell.open()
while not shell.isDisposed():
    if not display.readAndDispatch():
        display.sleep
display.dispose()

注意:

  • 该代码片断几乎与用于 SWT 应用程序的一模一样。
  • 对于格式化 HTML,我们在 Jython 函数 toHtml(employeeList) 中使用基于元组的字符串格式化,该函数将 employeeList 变成 HTML 格式的字符串。



回页首


有意思的插入

现在,我们将看到如何在 Jython 中进行插入。

假定 Joe 是一名 QA,他需要为功能测试在 SAMPLE 数据库中创建新的雇员。在 Jython 中,Joe 进行少量工作就可以编写他自己的脚本。

例如,Joe 可以在 SAMPLE 数据库中通过运行“jython batchinsert.jy joescript.txt”,创建三名新雇员。


清单 6. joescript.txt
createEmployee(firstName='JOHN',midinit='M',lastName='DOE',salary=32888.55,sex='M',workdept='A01',
job='DESIGNER')
createEmployee(firstName='MANAGER',midinit='M',lastName='DOE',salary=50000,sex='M',workdept='A01',
job='MANAGER')
createEmployee(firstName='SARA',midinit='M',lastName='DOE',salary=40000,sex='F',workdept='C01',
job='DESIGNER')

如果 Joe 想要添加另一名 Employee,就只需用他喜欢的文本编辑器编辑“joescript.txt”。

脚本背后的功能十分简单。Jython 有一个名为 execfile(filename) 的内置函数。如果我们将 createEmployee() 实现为 Jython 函数,用于向 EMPLOYEE 表插入一行记录,那么 execfile('joescript.txt') 将按照 Joe 需要的数目插入雇员。

换言之,我们利用 Jython 的解释器,并可以为 Joe 派生一个像这样的小的测试语言。该解决方案也是可扩展的。如果 Joe 需要在脚本中删除或更新雇员,就只需要添加另一函数。对于 Joe 来说,最酷的事情就是学习曲线很短。他可以立刻编写这样的脚本,而没有意识到正在进行 Jython 函数调用。


清单 7. (batchinsert.jy)createEmployee 函数
from java.lang import *
from java.sql import *
import sys
def createEmployee(**args):
    global stmt
    sqlTemplate=
    "INSERT into EMPLOYEE (EMPNO,FIRSTNAME,MIDINIT,LASTNAME,SALARY,SEX,EDLEVEL, HIREDATE, WORKDEPT,JOB) 
    values ((select RTRIM(CHAR(MAX(INT(EMPNO))+1)) from EMPLOYEE), 
    '%(firstName)s', '%(midinit)s','%(lastName)s', 
    %(salary).2f,'%(sex)s' ,18, CURRENT DATE,'%(workdept)s','%(job)s')" 
    # dictionary based SQL string formatting
    sql=sqlTemplate % args
    
    stmt.addBatch(sql)
    
# load DB2 JDBC type 2 driver
Class.forName("COM.ibm.db2.jdbc.app.DB2Driver").newInstance()
con = DriverManager.getConnection( 'jdbc:db2:sample', 'vyang','jythonrocks');
con.setAutoCommit(0)
stmt = con.createStatement()
execfile(sys.argv[1])
stmt.executeBatch()
stmt.close()
# commit
con.commit()
con.close()

这里有许多新内容。

  • con.setAutoCommit(0) 用于关闭自动提交(auto commit),就像 JDBC 调用中的 con.setAutoCommit(false) 一样。
  • 用于成批插入的 stmt.addBatch(sql)stmt.executeBatch() 能有效地加快批量插入的速度。该技术还在 Neo 的加载仿真器中用于进行大容量的插入。
  • global stmt 将使 stmt 成为一个共享的全局变量,很适用于该环境中。
  • def createEmployee(**args) 接收参数为字典 args ,并显示 Jython 函数声明是多么灵活。
  • sql=sqlTemplate % args 使用基于字典的 SQL 字符串格式化,我们在 select2.jy 中已经了解。



回页首


结束语

本文中,我们展示了一些简单示例,可作为开发人员进行探索的起点。我们相信在继续探索时,还会有更多益处和问题。

此外,Jython 得益于与巨大 Java 库以及诸如 IBM DB2 JDBC 驱动程序这样的 API 的无缝集成。基于其语言特征,Jython 非常适合于自动化测试和加载测试等任务,这些任务都需要快速的应用程序开发。正如 Charming Jython(请参阅 参考资料)中所描述的,“Jython 绝不是要您抛弃 Java 语言。Jython 会是一个非常方便的补充,对于快速检查和构造原型、测试以及处理那些比较适合使用其方法的编码任务是很有用的。”

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/374079/viewspace-130364/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2018-08-23

  • 博文量
    445
  • 访问量
    285172