设为首页 收藏本站
查看: 1708|回复: 0

[经验分享] iBatis 调用 PostgreSQL 存储过程返回结果集

[复制链接]

尚未签到

发表于 2016-11-21 08:46:53 | 显示全部楼层 |阅读模式
  最近在学习PostgreSQL,PostgreSQL有些很好的特性,比如可以用一维或多维数组做字段类型,可以省去一张关联表,如果在GIS领域应用的话,PostGIS为它增加了很强的空间计算能力,另外PostgreSQL对SQL的支持也比较标准和全面。
回到题目,接下来要在应用中使用PostgreSQL,回到我们的框架:Spring + Struts + iBatis,iBatis如何调用 PostgreSQL的存储过程呢?
PostgreSQL存储过程的语法类似Oracle,我们先看一个例子:

数据表: t_user

DSC0000.gif
CREATE TABLE t_user
(
  id serial NOT NULL,
  login_name character varying(20) NOT NULL,
  login_passwd character varying(20),
  name character varying(20) NOT NULL,
  sex smallint NOT NULL DEFAULT 1,
  phone character varying(10)[],
  privilege integer[],
  CONSTRAINT t_user_pkey PRIMARY KEY (id)
)
此处我们看到 t_user表中有 serial字段(这是一个SEQUENCE,用法与Oracle略同,有一点点差异),建表的时候,PostgreSQL会自动建一个SEQUENCE与id字段关联,并且默认值为 nextval(t_user_id_seq),其次我们看到phone字段的类型是varchar(10)这样的一个数组,privilege的类型是int的数组。

我们创建一个登录的存储过程:f_login_user()

CREATE OR REPLACE FUNCTION f_login_user(p_login_name in character varying, p_login_passwd in character varying)
RETURNS refcursor
AS
$BODY$
DECLARE
    p_user_cur refcursor;
BEGIN
    OPEN p_user_cur FOR SELECT * FROM t_user
        WHERE login_name = p_login_name AND login_passwd = p_login_passwd;
    RETURN p_user_cur;
END;
$BODY$ LANGUAGE 'plpgsql' VOLATILE;
存储过程有2个参数,登录名,登录密码,返回一个游标类型。我们准备用iBatis来调用这个存储过程,调用的方式为:{? = call f_login_user(?,?)}

接下来我们准备iBatis的SqlMap的xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "http://www.ibatis.com/dtd/sql-map-2.dtd">

<sqlMap namespace="UserDaoSqlMap">

    <typeAlias alias="user" type="org.kylin.emap.bean.UserBean"/>

    <resultMap id="userResultMap" class="user">
        <result property="id" column="id"/>
        <result property="loginName" column="login_name"/>
        <result property="loginPasswd" column="login_passwd"/>
        <result property="name" column="name"/>
        <result property="sex" column="sex"/>
        <result property="phone" column="phone" typeHandler="org.kylin.emap.util.ibatis.PgsqlStringArrayTypeHandler"/>
        <result property="privilege" column="privilege" typeHandler="org.kylin.emap.util.ibatis.PgsqlIntegerArrayTypeHandler"/>
    </resultMap>
        
    <parameterMap id="loginUserParameters" class="java.util.HashMap">
        <parameter property="result" jdbcType="OTHER" javaType="java.sql.ResultSet" mode="OUT"/>
        <parameter property="loginName" jdbcType="VARCHAR" javaType="java.lang.String" mode="IN"/>
        <parameter property="loginPasswd" jdbcType="VARCHAR" javaType="java.lang.String" mode="IN"/>
    </parameterMap>
   
    <select id="checkUser" resultMap="userResultMap" parameterClass="user">
        SELECT id, login_name, login_passwd, name, sex, phone, privilege
        FROM t_user
        WHERE login_name = #loginName# AND login_passwd = #loginPasswd#
    </select>
   
    <procedure id="loginUser" resultMap="userResultMap" parameterMap="loginUserParameters" >
         {? = call f_login_user(?,?)}
    </procedure>
   
</sqlMap>

注意看红色部分的字:在userResultMap中有typeHandler的描述,如phone字段,用org.kylin.emap.util.ibatis.PgsqlStringArrayTypeHandler这个类来处理数组类型,这个类是实现了iBatis的com.ibatis.sqlmap.client.extensions.TypeHandlerCallback,iBatis是很强啊,很方便扩展。

先看procedure的定义,用到了loginUserParameters做参数,返回userResultMap。
loginUserParameters描述了3个参数,按照调用方式: ? = call f_login_user(?, ?)的顺序,第一个参数是返回结果集的,这里的jdbcType填写OTHER,javaType填写java.sql.ResultSet,如果是ORACLE的存储过程通过游标返回结果集的话,jdbcType应该填写为ORACLECURSOR,看来iBatis专门为ORACLE做了开发,不过在PostgreSQL中不能用ORACLECURSOR,得用OTHER。

好了,现在我们看看DAO中如何通过SqlMapClient得到这个结果集:

DSC0001.gif     public UserBean loginUser(String loginName, String loginPasswd) throws DaoException {
DSC0002.gif
        HashMap<String, String> parameters = new HashMap<String, String>();
        parameters.put("loginName", loginName);
        parameters.put("loginPasswd", loginPasswd);
        return (UserBean)getSqlMapClientTemplate().queryForObject("UserDaoSqlMap.loginUser", parameters);
DSC0003.gif     }

当前这个例子,存储过程通过游标返回了一行数据,我们可以用queryForObject得到结果集,结果集也自动影射为UserBean了,很方便使用。

另外需要注意的问题:
1. PostgreSQL的存储过程支持 returns SETOF record 来返回多行记录,这种方法在存储过程中内部使用了游标,效率比较高,另外应用也不用关心游标的关闭和释放的问题。
2. 如果存储过程返回多个结果集,需要用 returns SETOF refcursor 来返回多个结果集。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-303197-1-1.html 上篇帖子: Postgresql数据库的一些字符串操作函数 下篇帖子: Postgresql: UUID的使用
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表