`

使用 Spring 框架调用 DB2 存储过程

    博客分类:
  • Work
阅读更多

使用 Spring 框架调用 DB2 存储过程

developerWorks
文档选项
<noscript></noscript>
将此页作为电子邮件发送

将此页作为电子邮件发送

<!----><!---->
<!---->

级别: 中级

赵 雄伟, 软件工程师, IBM CSDL
郑 溪龙, 软件工程师, IBM CSDL

2006 年 7 月 05 日

Spring 框架已经作为逻辑层被广泛的用于轻量级的J2EE开发中。本文将给出一个使用Spring 框架和Struts来调用存储过程的完整例子,包括如何传入参数,如何获得传出参数,如何获得结果集以及如何获得多个结果集。
<!----><!----><!---->

Spring 框架已经作为逻辑层被广泛的用于轻量级的J2EE开发中。Spring 框架可以很好的和Struts, WebWork, Hibernate等其他开源项目集成在一起。尤其在重构现有应用的使用,Spring 框架可以提供很多帮助。存储过程可以用来封装业务逻辑,控制用户权限,以及做日常的增删改查(CRUD)。在重构已有系统的时候,一般存储过程中的业务逻辑并不需要改变,只是调用存储过程的方式需要进行调整。Spring 框架提供了完整的存储过程封装,数据源管理的功能,使用Spring 框架,开发人员可以很容易的构建轻量级J2EE应用。本文将给出一个使用Spring 框架和Struts来调用存储过程的完整例子,包括如何传入参数,如何获得传出参数,如何获得结果集以及如何获得多个结果集。

读者定位为具有DB2和Web开发经验的开发和设计人员。

读者可以学习到如何使用Spring框架来调用存储过程,可以通过文中的代码快速构建一个使用Spring框架的Web应用。本文的例子将包括使用Apache Struts进行网页表单的提交和验证,使用Spring框架来调用具有输入输出参数和返回结果集的存储过程,结果集将通过DisplayTag来进行显示。

Spring是一个广泛应用于逻辑层的开源框架,它使构建J2EE应用程序的Java开发人员可以直达实质问题的核心,而不是在提供服务的细节上花费大量时间。您可以通过developerWorks的文章"Spring 系列: Spring 框架简介"来了解Spring框架。Spring框架中一个重要的模块就是Spring DAO,它允许开发者在不同数据访问技术间切换,而且Spring提供了统一的异常处理机制,在切换的同时不用考虑异常处理。

当前很多应用程序使用存储过程来封装业务逻辑,在重构已有应用的时候,只是更改调用存储过程的方式。在调用存储过程方面现在大多直接采用JDBC的操作处理,这种方法需要创建数据库连接、创建statement语句、关闭ResultSet、关闭statement、关闭数据库连接、处理异常等等,一方面这些代码与业务逻辑不相关,另一方面也可能会给应用引入bug。因此很多人更青睐于使用数据持久化框架。在数据持久化框架中Hibernate 倍受人们关注,它主要提供Java对象与关系数据库的映射(O/R Mapping),这样只需关心操作java对象而不必关心底层数据。在Hibernate 3.0中也提供了对存储过程查询的支持,但是要求存储过程必须返回一个结果集,并且关键的是应用要遵循O/R Mapping的设计要求来架构应用系统。Spring DAO为JDBC提供了抽象层,使得开发者更高效的使用JDBC,它提供了对存储过程的支持,通过抽象类org.springframework.jdbc.object.StoredProcedure我们可以方便的调用存储过程,支持输入参数、输出参数和多个结果集。下面将通过一个实例详细的介绍使用Spring框架来调用存储过程的方法。

实例将实现在页面表单输入客户代码custNum,然后通过存储过程查询数据库中客户信息,得到所有客户信息和所查客户信息,并将其返回结果在页面上显示。您可以下载实例代码,代码可以在Eclipse环境中运行,对照代码看这篇文章更直观。

1. 编写DB2存储过程

我们首先来看DB2的存储过程。存储过程一般被用来返回数据库中表的数据或者对表的数据进行更改。在这里我们使用存储过程从表中获得结果集。

首先我们需要建立DB2环境:

1) 把远程DB2服务器编制到本地。在这里我们远程的DB2主机地址是zxl01.cn.ibm.com,端口是50001


清单1
db2 CATALOG TCPIP NODE node01 REMOTE zxl01.cn.ibm.com SERVER 50001

2) 在本地建立远程DB2的别名。在这里我们使用testDB作为别名。


清单2
db2 CATALOG DB testDB AT NODE node01

3) 创建customer数据表


清单3
DROP TABLE DSW.CUSTOMER
@
CREATE TABLE DSW.CUSTOMER 
(
    CUST_NUM                 VARCHAR(10) NOT NULL,
    CUST_NAME                VARCHAR(35) NOT NULL,
    ADDRESS                  VARCHAR(35) NOT NULL,
    CITY                     VARCHAR(35) NOT NULL,
    COUNTRY                  VARCHAR(3)  NOT NULL,
    ADD_DATE                 TIMESTAMP     NOT NULL
)
@
ALTER TABLE DSW.CUSTOMER 
    ADD CONSTRAINT CUSTOMER_PK
PRIMARY KEY (CUST_NUM)
@

4) 创建存储过程


清单4
DROP PROCEDURE DSW.S_CUSTOMER
@
CREATE PROCEDURE DSW.S_CUSTOMER (
  OUT poStatus     INTEGER,
  IN  piCust_num      VARCHAR(10)
)
LANGUAGE SQL
SPECIFIC DSW.S_CUSTOMER
RESULT SETS 2

P1: BEGIN NOT ATOMIC
   -------------------------------------------------------------
   -- CONDITION declaration
   -------------------------------------------------------------
   DECLARE sqlReset    CONDITION for sqlstate '80100';

   -- Generic Variables
   DECLARE SQLCODE      INTEGER       DEFAULT 0;
   DECLARE SQLSTATE     CHAR(5)       DEFAULT '00000';
  
   -- Generic handler variables
   DECLARE hSqlcode     INTEGER       DEFAULT 0;
   DECLARE hSqlstate    CHAR(5)       DEFAULT '00000';

   DECLARE v_Cnt INT;

   -- Cursor for returning RS to the client
   DECLARE cursor1 CURSOR WITH RETURN TO CLIENT FOR (
	   SELECT CUST_NUM, CUST_NAME FROM DSW.CUSTOMER
   );

   DECLARE cursor2 CURSOR WITH RETURN TO CLIENT FOR (
	   SELECT * FROM DSW.CUSTOMER
	   WHERE CUST_NUM = piCust_num
   );
   
   OPEN cursor1;
   
   OPEN cursor2;

   SET poStatus = 2;
   RETURN poStatus;

END P1
@

5) 插入测试数据


清单5
INSERT INTO DSW.CUSTOMER (CUST_NUM,CUST_NAME,ADDRESS,CITY,COUNTRY)
VALUES('1','Steven','shang di','BeiJing','CHN')
@
INSERT INTO DSW.CUSTOMER (CUST_NUM,CUST_NAME,ADDRESS,CITY,COUNTRY)
VALUES('2','David','shang di','BeiJing','CHN')
@
INSERT INTO DSW.CUSTOMER (CUST_NUM,CUST_NAME,ADDRESS,CITY,COUNTRY)
VALUES('3','Tony','shang di','BeiJing','CHN')
@
INSERT INTO DSW.CUSTOMER (CUST_NUM,CUST_NAME,ADDRESS,CITY,COUNTRY)
VALUES('4','Maggie','shang di','BeiJing','CHN')
@





回页首


2. 创建基于Spring+Struts框架的web应用

将Spring框架集成到现有的Web应用中十分容易,在web.xml中的Listener部分增加一个Spring的ContextLoaderListener同时设置contextConfigLocation参数,指向Spring的配置文件位置。如清单6所示。在web.xml中还有对于Struts的支持,读者可以参考developerworks上的Struts专题来了解如何使用Struts。


清单 6. web.xml.
<!---->	


将Spring和Struts进行整合的方法有很多,developerworks上的文章"使用 Spring 更好地处理 Struts 动作"中介绍了几种方法,可以参照。





回页首


3. 使用Spring framework建立数据源

在Spring的配置文件applicationContext-service.xml中我们对使用到的Java类和数据源进行了配置。通过指定driverClassName、url、username、password等属性就可以创建数据源。在清单7中我们使用直接连接数据库的方式,我们也可以使用在应用服务器中配置的DataSource来连接数据库,只需要更改为不同的Reference就可以改变对数据库的连接方式。在这方面,Spring框架显示出了很强的灵活性。


清单7. applicationContext-service.xml.
<!---->
<!---->"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app id="WebApp"></web-app>
<display-name></display-name>SpringSproc
<!---->
<context-param></context-param>
<param-name></param-name>contextConfigLocation
<param-value></param-value>
/WEB-INF/applicationContext-service.xml


<listener></listener>
<listener-class></listener-class>
org.springframework.web.context.ContextLoaderListener


<servlet></servlet>
<servlet-name></servlet-name>action
<servlet-class></servlet-class>
org.apache.struts.action.ActionServlet

<load-on-startup></load-on-startup>1

<servlet-mapping></servlet-mapping>
<servlet-name></servlet-name>action
<url-pattern></url-pattern>*.do

<welcome-file-list></welcome-file-list>
<welcome-file></welcome-file>index.html


<!---->

在Java代码SearchAction.java中将连接实例化。这也是Spring中的核心思想之一:控制反转(Inversion of Control)。清单8中(1)是把一个在applicationContext-service.xml中配置的bean实例化成对象,(2)调用getBean方法得到基于接口SearchDAO(具体见清单9) 的实例SearchImpl bean,然后再通过(3)调用具体的方法去执行存储过程。


清单8. Code in Struts SearchAction.java.
private static ApplicationContext ctx = null;
public Object getBean(String name) {                  |(1)
		if (ctx == null) {
			ctx = WebApplicationContextUtils
					.getRequiredWebApplicationContext
					(servlet.getServletContext());
		}
		return ctx.getBean(name);
	}
SearchDAO mgr = (SearchDAO) getBean("SearchImpl"); |(2)
Map map = mgr.execute(custNum);                        |(3)


清单9. Code in SearchDAO.java.
package com.springsproc.dao;

import java.util.List;

public interface SearchDAO {
	public Map execute(String custNum);
}





回页首


4. 使用Spring framework为存储过程传入参数

用户在web页面上填入custNum,提交后经Struts的validation验证传入action的FormBean中,然后再从FormBean中得到custNum,并由清单8中(3)传入Spring framework。





回页首


5. 使用Spring framework获得存储过程的传出参数和结果集

Spring framework提供了调用存储过程的方法,下面对几个相关的类和接口做简单介绍,你也可以通过Spring API获得更多详细信息。

  • org.springframework.jdbc.object.StoredProcedure 这是一个抽象类,通过declareParameter方法来声明存储过程的输入输出参数,再由execute方法来调用存储过程。
  • org.springframework.jdbc.core.SqlParameter 用来代表存储过程的参数。
  • org.springframework.jdbc.core.ResultSetSupportingSqlParameter SqlParameter的子类,是SqlOutParameter、SqlReturnResultSet这些支持结果集参数类的公共基类。
  • org.springframework.jdbc.core.SqlOutParameter ResultSetSupportingSqlParameter的子类,用来代表存储过程的输出参数。
  • org.springframework.jdbc.core.SqlReturnResultSet ResultSetSupportingSqlParameter的子类,用来代表调用存储过程的输出结果集。
  • org.springframework.jdbc.core.RowMapper 这是一个接口,通常为JdbcTemplate的查询方法或者存储过程返回结果集使用。

了解了Spring为我们提供的这些关于存储过程的方法和接口后,来看看具体的实现方法。如清单10所示。SearchDAOImpl.java中有三个内部类,其中SearchCustomersProcedure来负责声明数据库连接和存储过程名(2)、输入参数(6)、输出参数(5)以及输出结果集(3)(4),DemoRowMapper和DemoRowMapper2来负责取得结果集中的数据。其中(3)创建一个名为"resultSet"的结果集,通过DemoRowMapper(7)来取得结果集中的数据,当有多个结果集的时候需要重复这个过程,如(6)(8)。最后由execute方法(1)填入输入参数并执行存储过程调用。


清单10. Code in SearchDAOImpl.java.
public Map execute(String custNum) {
		SearchCustomersProcedure sp = new SearchCustomersProcedure(dataSource);
		Map map = new HashMap(1);
		map.put("piCust_num", custNum);
		Map results = sp.execute(map);              |(1)
		return results;
}

private class SearchCustomersProcedure extends StoredProcedure {
	SearchCustomersProcedure(DataSource dataSource) {
		super(dataSource, sprocName);                |(2)   
		declareParameter(new SqlReturnResultSet("resultSet",
				new DemoRowMapper()));      |(3)
		declareParameter(new SqlReturnResultSet("resultSet2",
				new DemoRowMapper2()));     |(4)

		declareParameter(new SqlOutParameter("poGenStatus", Types.INTEGER));  
		|(5)
		declareParameter(new SqlParameter("piCust_num", Types.VARCHAR));  
		|(6)	}
}

private class DemoRowMapper implements RowMapper {          |(7)
	public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
		Customer customer = new Customer();
		customer.setCustNum(rs.getString(1));
		customer.setCustName(rs.getString(2));
		return customer;
	}
}

private class DemoRowMapper2 implements RowMapper {         |(8)
	public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
		Customer customer = new Customer();
		customer.setCustName(rs.getString(1));
		customer.setCustNum(rs.getString(2));
customer.setCustAddress(rs.getString(3));
		customer.setCustCity(rs.getString(4));
		customer.setCustCountry(rs.getString(5));
		return customer;
	}
}





回页首


6. 在Web页面上显示结果集 (使用DisplayTag)

在SearchAction从SearchDAOImpl取得数据以后,将数据以attribute方式存入request中,如清单11中(1)(2)所示。在页面中使用DisplayTag将request中的数据以表格形式显示出来。可以指定列名或者按某些列排序,如清单12中(1);也可以不做任何处理,只是将数据显示出来,如清单12中(2)。可以在DisplayTag Homepage得到更多关于DisplayTag的详细信息。


清单11. Code in Struts SearchAction.java.
List list = (List)map.get("resultSet");
List list2 = (List)map.get("resultSet2");
String poGenStatus = map.get("poGenStatus").toString();
log.info("poGenStatus is:" + poGenStatus);
                                   
request.setAttribute("customerList",list);  |(1)
request.setAttribute("MyCustomers",list2);  |(2)
                                   
return mapping.findForward("list");


清单12. Code in Struts SearchByCustNumber.jsp
|(1)
<display:table id="customers" requesturi="" cellspacing="2" cellpadding="2" defaultsort="1" name="customerList">
    
    <display:column title="Customer number" headerclass="sortable" headerstyleclass="header" property="custNum" sort="true"></display:column>
    <display:column title="Customer name" headerclass="sortable" headerstyleclass="header" property="custName" sort="true"></display:column>
</display:table>

|(2)
<display:table id="myCustomer" requesturi="" cellspacing="2" cellpadding="2" defaultsort="1" name="myCustomer">
</display:table>

这样使用Spring framework调用存储过程的实例就完成了,运行该实例,如下图所示:







回页首


使用Spring framework的优点

Spring框架提供了一些接口和类,封装了对数据库的处理,极大地简化了对数据库的操作。开发人员可以把更多的精力放在业务逻辑上。数据库连接等信息写在配置文件中,在运行期装入bean中进行连接操作实例化的方法使系统更加灵活,可以在部署应用的时候很方便的更改,不仅提高了团队开发的效率,也提高了系统的可维护性。





回页首


总结

本文以一个实例介绍了使用Spring框架调用存储过程的方法,通过本文您已经可以使用Spring框架结合不同类型的存储过程来对DB2中的数据进行操作。并且参照这个实例您可以创建基于Struts + Spring框架的web应用系统。

分享到:
评论

相关推荐

    这是一个可以和spring 整合的db 封装

    4. **DB2特定的API**:`commons-db2.jar`可能包含了专门针对DB2的JDBC驱动和其他特定于DB2的功能,例如类型映射、存储过程调用等。 5. **配置与集成**:将这个db封装整合到Spring项目中,通常需要在Spring的配置...

    spring boot 常用数据库操作例子

    综上所述,这个示例提供了Spring Boot和JPA结合使用的基本用法,包括多数据库支持、存储过程调用、原生SQL查询以及结果转换为DTO的实践。这对于学习和理解如何在Spring Boot应用中进行高效、灵活的数据库操作是非常...

    整合flex-spring-mybatis

    本文档旨在详细介绍如何将Flex技术与Spring框架及MyBatis框架进行有效整合,以实现一个高性能且易于维护的企业级应用。通过整合这三种技术,可以充分利用Flex丰富的用户界面特性、Spring的依赖注入与事务管理功能...

    Hibernate Junit测试增删改查(DB2版本的)

    在DB2版本的环境中,Hibernate可以很好地支持其特性,如事务管理、存储过程调用等。DB2是一种强大的关系型数据库管理系统,广泛应用于企业级应用,具有高度的稳定性和安全性。 接下来,我们进入Junit测试的环节。...

    项目jar包下载

    总的来说,这个项目为开发者提供了一个实际的环境,让他们能够学习和实践如何在Java项目中集成DB2数据库、MyBatis和Spring框架,从而提升自己的技能和经验。通过深入研究这个项目,开发者可以更好地理解数据库操作、...

    Spring+Hibernate下的数据库连接动态切换

    为了实现这一功能,我们将采用Spring框架进行整体架构的设计与管理,并利用Hibernate作为持久层框架。Spring提供了强大的AOP支持以及灵活的配置机制,而Hibernate则具备出色的ORM映射能力,二者结合可以高效地实现...

    Springboot整合Druid与Mybatis的多数据源切换

    **Mybatis** 是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。Mybatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。Mybatis可以使用简单的XML或注解进行配置和原始映射,将接口和Java的...

    springboot-AOP实现多数据源动态切换(Druid连接池)

    1. **Spring AOP(面向切面编程)**:AOP是Spring框架的核心特性之一,它允许我们定义方法拦截器或切面来跨多个点应用横切关注点。在这里,我们使用AOP来在运行时动态改变数据源。 2. **Druid连接池**:Druid是阿里...

    SpringMVC配置多数据源实战

    在Controller层,根据业务需求,调用对应的Service方法,Service方法中通过`@Transactional`注解来指定使用哪个数据源。 7. **注意点** - 确保数据库驱动已添加到项目依赖。 - 在实际业务中,可能需要根据具体...

    mybatis-sql-dialect

    不同的数据库管理系统(DBMS)有着各自的SQL方言,这些差异可能体现在语法、函数支持、特定的存储过程等方面。例如,MySQL支持`LIMIT`子句进行分页查询,而Oracle则使用`ROWNUM`和子查询。MyBatis-SQL-Dialect包...

    SpringBoot多数据源配置(方式三:基于AOP切面动态切换需要使用哪个数据源).docx

    - **动态代理**: 使用Spring AOP(面向切面编程)来拦截数据访问层(DAO层)的方法调用,根据一定的规则(如注解或上下文变量)选择合适的DataSource。 - **数据库路由**: 根据查询条件自动选择合适的数据源。 本篇...

    Java大型CRM源码带小程序 vue+springboot.zip

    2. **SpringBoot**:SpringBoot是基于Spring框架的快速开发工具,简化了Spring应用的初始搭建以及开发过程。在这个CRM系统中,SpringBoot提供了依赖注入、自动配置、内嵌Web服务器等功能,使得后端开发更为高效和...

    SpringBoot操作多数据源(JPA+JdbcTemplate)

    1. **Spring Boot**: 它是基于Spring框架的轻量级开发工具,简化了Spring应用的初始搭建以及开发过程,提供了自动配置、内嵌式Web服务器等特性。 2. **JPA**: Java Persistence API 是Java EE平台的一个规范,用于...

    java 数据库编程.pdf

    Java通过JDBC调用存储过程来执行一系列操作,存储过程可以提供比单个SQL语句更复杂的数据库交互。 知识点八:数据库连接和查询优化 数据库连接和查询优化是提高数据库性能的关键,包括合理的数据库设计、索引优化、...

    ssh双数据源登录实例

    在Spring框架中,我们可以使用`DataSource`接口的实现,如Apache的`BasicDataSource`或Oracle的`UcpDataSource`。在`applicationContext.xml`中,为每个数据源创建一个bean,并分别设置连接URL、用户名、密码、驱动...

    hibernate方言汇总.docx和SSH的jar包名称

    - **性能优化**:特定数据库的方言通常包含对该数据库的优化机制,比如索引使用、存储过程调用等,这有助于提高查询效率。 - **异常处理**:方言还负责将特定数据库的异常转换为Hibernate的异常,便于开发者进行统一...

    liferayPortal

    - Spring HTTP:基于Spring框架的HTTP客户端和服务端支持。 - WSRP (full support for 1.0 and 2.0):Web Services for Remote Portlets规范的支持。 - WebDAV:一种基于HTTP的协议,用于用户编辑和管理存储在远端的...

    Activiti工作流课程.pdf

    在Activiti的后续版本中,提供了更多的特性,包括与Spring框架的整合,通过Spring管理Activiti的配置和事务管理。整个安装和配置过程不仅涉及到Activiti本身的组件安装和配置,还需要对Java开发环境(如JDK)、...

    jeecms 多数据源处理例子

    在Jeecms中,通过Spring框架提供的DataSource支持,我们可以轻松地配置和管理多个数据源。 **配置多数据源步骤:** 1. **创建数据源bean**:在Spring的配置文件(如`applicationContext.xml`)中,为每个数据源...

    多次面试考题总结.zip

    DB2的知识点包括SQL查询、事务处理、并发控制、存储过程、备份与恢复、性能优化以及数据库安全性。在面试中,你可能需要理解ACID(原子性、一致性、隔离性和持久性)属性,掌握如何创建索引、视图,以及如何解决死锁...

Global site tag (gtag.js) - Google Analytics