Sybase学习笔记

Sybase学习笔记

    前段时间从Sybase网站上当的Sybase ASE 15 Windows版(以下简称Sybase),这几天没事,便简单了解了一下。
一、安装
    将下载的ase1500_de_win.zip文件解压缩,双击setup.exe。由于整个安装过程都有提示,因此不需要做太多说明,唯一要注意的是在选择安装类型时,如果想使用ODBC、OleDb或者ADO.net进行开发,一定要选择自定义安装,因为在默认情况下被安装的只有JDBC驱动,其他驱动是不会安装的。
    安装完之后,可以在“控制面板”->“性能和维护”->“管理工具”的“数据源 (ODBC)”中查看一下:

其中的“Adaptive Server Enterprise”就是Sybase的ODBC驱动。
    不过至此我们的安装工作还没有结束,如果不想看到自己输入的中文变成乱码,就按照下面方法去做。
    请点击“开始”菜单->“所有程序”->“Sybase”->“Adaptive Server Enterprise”->“Server Config”,打开“Configure Sybase Server”窗口。在窗口左侧的Product栏中选择Adaptive,然后点击“Configure Adaptive Server...”按钮,打开“Existing Servers”窗口。在窗口选中服务器,然后点击Continue按钮进入下一窗口。输入用户名和密码,默认用户名为sa,密码为空,点击Continue。此时如果服务没启,Sybase会提示,点击“确定”,稍等片刻,“Configure Adaptive Server”窗口就出现了。

在窗口中点击“Language”按钮,打开“Language Options”窗口。

点击Character下的“Add/Remove”按钮,打开“Install Character Sets”窗口,在Available栏中选中“Unicode 3.1 UTF-8 CHaracter Set”,即utf8字符集,点击“Add”按钮,点击OK。下面再点击Character下的“Set Default”按钮,打开“Change Default Character Set”窗口,默认选中的是“Code Page 850 (Multilingual) character set”,即cp850字符集。这个字符集不对,请选中刚刚添加的utf8字符集,点击OK,回到“Language Options”窗口,然后再点击OK。由于我们对服务重新进行了设置,因此接下来需要等待一段时间。
    设置完成后,打开“运行”窗口,输入命令“services.msc /s”,打开“服务”。请选中“Sybase SQLServer _ IMAGE”,IMAGE是我的Sybase服务名,点击“启动服务”按钮,等待片刻后,系统提示此次启动失败,重启操作系统。重启后,再次在“服务”中启动Sybase,如果还是提示错误,不要管他,再次启动服务一切就OK了。
    服务启动后,请点击“开始”菜单->“所有程序”->“Sybase”->“Sybase Central v4.3”,打开Sybase Central,这是一个Sybase客户端工具。在左侧的Folders中点开Adaptive Server Enterprise,选中Default,右建,选择“Connect...”,打开Connect窗口。

在窗口中填写User ID为sa,Password为空,Server name选择IMAGE,Character set和Language分别设置为cp936和Chinese。注意,这里客户端设置的字符集是cp936,而非cp850、utf8或者eucgb。设置好后,点击OK,就可以开始对Sybase的操作了。
二、简单操作
1.创建数据库设备
    数据库设备其实就是一个用来保存数据的文件,一个数据库通常会指定保存在一个或多个数据库设备中。
    在Sybase Central的Folders中找到Database Devices(数据库设备),选中,然后在Details中双击“Add Database Device”。在弹出窗口的“Device Path”中设置存放路径和文件名称,我设置的是F:/YPJCCK/DataBase/Sybase/zhengTest.dat,点击Next。新界面是用来设置设备编号和文件大小的,这里我只设置Size为64M。点击Next,无需修改,再次点击Next:

这个界面是用来展示设置信息的,用户可以根据这些信息确定自己之前的设置是否正确。请注意Preview按钮,点击该按钮后即通过可查看到创建设备的SQL语句。Sybase Central在创建视图、存储过程及触发器等对象时同样会提供该功能。确认信息无误,点击Finish创建设备。
    如果想在设备创建后查看SQL语句,请在Details中选中相应设备,右键,点击Generate DDL就可以了。
    如果想删掉设备,请在Details中选中相应设备,右键,点击Delete:

这个界面是用来确认删除对象的,确认后点击Yes即可。这里也请注意Preview按钮,点击该按钮后同样可以查看到删除设备的SQL语句,而且Sybase Central在删除表、视图、存储过程及触发器等对象时也都提供了该功能。
2.创建数据库
    在Sybase Central的Folders中找到Databases(数据库),选中,然后在Details中双击“Add Database”。在弹出窗口中设置数据库名称,我设置的是zhengTest,点击Next。新界面是用来为数据库指定设备的,可以指定多个,请点击Add按钮:

在弹出窗口中选中设备zhengTest,然后设置Size为32,点击OK返回,再点击Finish,数据库就被创建了。
    如果想在数据库创建后查看SQL语句,请在Details中选中zhengTest,右键,点击Generate DDL。不过数据库的Generate DDL下还有两个子菜单,第一个为Create Database DDL,选择后只会看到创建数据库本身的SQL语句;第二个为Database Object DDL,点击后会出现一个对话框:

这个对话框列出了数据库中的所有对象类型,但要注意,在这个对话框中,选择了哪个类型,属于那个类型的对象的就不会出现在弹出窗口中,而没有选择的则会出现。Sybase Central对表、视图、存储过程、触发器等对象都提供了Generate DDL。
    如果想删掉数据库,只要选中zhengTest,右键,点击Delete,或者在Interactive SQL(Sybase自带的一个SQL命令执行工具,) 中执行命令:
    drop database zhengTest
即可。Sybase Central对表、视图、存储过程、触发器等对象也都提供了Delete。
3.创建数据表
    在Sybase Central的Folders中找到zhengTest->User Tables并选中,然后在Details中双击“Add Table”,打开“New Table”窗口:

在窗口中设置Name为book,添加两个字段:
    bookcode    nvarchar(10)    主键
    bookname    nvarchar(50)
然后点击“Save and Close”按钮,这样book表就创建好了。
    下面选中book表,右键,点击“View Data in Interactive SQL”,就可以在Interactive SQL中查询book的数据了。不过由于我们还没有向book表中添加过任何数据,因此看到的结果为空。请在Interactive SQL中执行以下命令:
    insert into book (bookcode, bookname) values ('0000000001', 'test')
    go
    insert into book (bookcode, bookname) values ('0000000002', '测试')
    go
然后再次执行select * from book,此时就看到刚刚插入的数据了。
    不过我现在又有了个新的想法,为book表增加一个anthor,即作者字段。但一个作者似乎可以创作很多书,要是每条记录都将作者信息重复填写一遍,好麻烦啊,该怎么办呢?
    请在Sybase Central中创建一个新表author,字段如下:
    authorcode    nvarchar(10)    主键
    authorname    nvarchar(20)
创建之后,在Interactive SQL中向author表插入一条数据:
    insert into author (authorcode, authorname) values ('0000000001', 'Smile')
    下面选中book,右键,点击Edit,修改book表如下:

新增加bookauthor字段,类型为nvarchar(10),由于增加该字段之前表中已有数据,为防止出错须选中Allow Nulls,即允许该字段为空。修改之后,在Interactive SQL中更新book表中的数据:
    update book set bookauthor = '0000000001'
这时再次查询数据:
    select bookcode, bookname, authorname from book, author where bookauthor *= authorcode
就看到期待已久的结果了。
    如果想删掉表,只要选中book,右键,点击Delete,或者在Interactive SQL 中执行命令:
    drop table dbo.book
即可。
4.创建视图
    视图是虚拟的表,其特点是操作简单、使用安全。
    请在Sybase Central的Folders中找到zhengTest->Views并选中,然后在Details中双击“Add View(Wizard)”,打开“Add Trigger”向导。在第一个界面中输入视图名v_book,点击Next进入下一个界面。

这个界面是用来编写代码的,除可以在文本域中编写外,还提供有“SQL Editor”和“Load”两个按钮,前者点击后会调出一个Sybase自带的编辑器,下面在编辑器中编写代码如下:
    CREATE VIEW dbo.v_book
    AS select bookcode, bookname, authorname 
        from book, author 
        where bookauthor *= authorcode
然后点击“Save view and close”回到刚才的界面;后者用于加载已经完成的SQL语句,这里不使用。点击Finish按钮,Sybase提示视图v_book已存在,因为刚才在编辑器中点击的是“Save view and close”,即保存视图并关闭。此时点击OK,然后点击Cancel即可。类似的界面在后面编写存储过程和触发器的时候还会遇到。
    下面选中视图v_book,右键,点击“View Data in Interactive SQL”,就可以在Interactive SQL中使用v_book来查询数据了。
    如果想删掉视图,只要选中v_book,右键,点击Delete,或者在Interactive SQL 中执行命令:
    drop view dbo.v_book
即可。
5.创建存储过程
    存储过程是一组存储在数据库服务器段执行特定操作的SQL语句,具有创建时编译、可重复使用、安全性高等特点。

    最简单的存储过程(查询):
    在Sybase Central的Folders中找到zhengTest->Stored Procedures并选中,然后在Details中双击“Add Procedures(Wizard)”,打开“Add Stored Procedure”向导。在第一个界面中填写存储过程名称,例如simple_query,点击Next。在接下来的两个界面中不必进行任何操作,直接点击Next。在第四个界面中输入代码:
    CREATE PROCEDURE dbo.simple_query
    AS select bookcode, bookname, authorname 
        from book, author 
        where bookauthor *= authorcode
点击Finish。至此,存储过程创建完毕。
    这个存储过程最为简单,即没有参数,也没有返回值,更没有任何逻辑处理。
下面选中存储过程simple_query,右键,点击“Execute with Interactive SQL”,在Interactive SQL中会生成一条语句“exec dbo.simple_query”,其中exec全拼为execute,表示执行存储过程。执行后,会返回一个结果集,即SQL语句的执行结果。

    下面来看一个内容相对完整的存储过程例子:
    CREATE PROCEDURE dbo.simple_demo
    (
        @i_mesg nvarchar(100) = 'Y',            --输入参数,设置默认值为'Y'
        @o_mesg nvarchar(100) output       --输出参数
    )
    AS
    BEGIN
        if @i_mesg = 'Y'    --逻辑处理
        begin
            select @o_mesg = '运行正常!'    --在Sybase中需要使用select语句为变量赋值
            return 0        --返回值
        end

        select @o_mesg = '运行异常!'
        return -1           --返回值
    END
这个存储过程虽然没有调用数据表,但带有输入参数、输出参数、逻辑处理和返回值,因此内容相对完整。这里请注意,返回值只能是整数,而输出参数也可以用来将值传入并设置默认值。
下面在Interactive SQL中执行以下代码:
    declare @o_mesg nvarchar(100),      --定义变量
                   @ret int
    exec @ret = dbo.simple_demo 'N', @o_mesg output     --执行存储过程,注意,输出参数必须标以output,否则不会输出任何值
    print '%1!--------%2!', @ret, @o_mesg               --输出结果
按F5键执行,输出结果:-1--------运行异常!
    下面将这段代码写到存储过程当中:
    CREATE PROCEDURE dbo.simple_call
    AS
    BEGIN
        declare @o_mesg nvarchar(100),
                       @ret int
        exec @ret = dbo.simple_demo 'N', @o_mesg output
        print '%1!--------%2!', @ret, @o_mesg
    END
这是一个存储过程调用存储过程的例子了。

    下面再新建一个simple_execute存储过程,代码如下:
    CREATE PROCEDURE dbo.simple_execute
    AS
    BEGIN
        execute ('select * from v_book')
    END
这个存储过程含有两个内容:一个SQL语句的动态执行,即Sybase中允许将SQL语句处理成一个字符串或字符串变量来执行;一个是对视图的访问。

    下面再看几个存储过程的例子。
    通过游标读取数据示例:
CREATE PROCEDURE dbo.p_query_list
AS
BEGIN
    declare @bc nvarchar(10)
                 ,@bn nvarchar(50)
                 ,@an nvarchar(20)
    --定义游标
    declare book_curs cursor for 
    select bookcode, bookname, authorname 
        from book, author 
        where bookauthor *= authorcode
        order by bookcode

    open book_curs --打开游标

    --循环游标读取数据
    fetch book_curs into @bc, @bn, @an
    while (@@sqlstatus = 0)
    begin
        print '编号:%1!|名称:%2!|作者:%3!', @bc, @bn, @an
        fetch book_curs into @bc, @bn, @an
    end

    close book_curs --关闭游标
    deallocate cursor book_curs --释放游标
END

    通过变量读取数据示例:
CREATE PROCEDURE dbo.p_query_detail
@query      nvarchar(10)
AS
BEGIN
    declare @bookcode   nvarchar(10),
                  @bookname   nvarchar(50),
                  @authorname nvarchar(20)
    /* top用来指定取得结果集的前n条数据,这里使用top 1即表示取得结果集的第一条记录,否则当结果集中有多条记录时,只有最后一条记录的值才会被赋值给变量 */
    select top 1 @bookcode = bookcode, @bookname = bookname, @authorname = authorname from v_book where bookcode = @query

    print '编号:%1!|名称:%2!|作者:%3!', @bookcode, @bookname, @authorname
END
执行:在Sybase Central中选中p_query_detail,右键,点击“Execute with Interactive SQL”,由于p_query_detail有一个输入参数,因此Central会弹出一个Call窗口:

在窗口中填值时一定要注意,由于数据类型为nvarchar(10),为字符串,因此一定要在值的两边加上单引号“’”。然后点击OK,在Interactive SQL中按F5键执行该存储过程。

    使用存储过程插入数据示例:
CREATE PROCEDURE dbo.p_insert
@bookname   nvarchar(50),
@bookauthor nvarchar(10),
@mesg       nvarchar(200) = 'ok' output
AS
BEGIN
    declare @bookcode nvarchar(10)

    --使用月、日、时、分、秒组成bookcode
    select @bookcode = convert(nvarchar(10), datepart(mm,getdate())*100000000 + datepart(dd,getdate())*1000000 + datepart(hh,getdate())*10000 + datepart(mi,getdate())*100 + datepart(ss,getdate()))
   
    --插入数据到book表
    insert into book (bookcode, bookname, bookauthor) values (@bookcode, @bookname, @bookauthor)
    if @@error <> 0 --异常处理
    begin
        select @mesg = '新增数据异常!' + convert(nvarchar(3), @@error)
        rollback    --事务回滚
        return -1
    end

    commit  --事务提交
    return 0
END
执行:在Interactive SQL中尝试执行以下代码调用p_insert存储过程:
    declare @mesg nvarchar(200),
                   @flag int
    exec @flag = p_insert 'NUnit学习笔记', '0000000001', @mesg output
    if @flag <> 0
    begin
        print @mesg
    end
    else
    begin
        print '程序运行正常!'
    end
    go

    使用存储过程修改数据示例:
CREATE PROCEDURE dbo.p_update
@bookcode   nvarchar(10),
@bookname   nvarchar(50),
@bookauthor nvarchar(10)
AS
BEGIN
    update book set bookname = @bookname, bookauthor = @bookauthor where bookcode = @bookcode
END

    使用存储过程删除数据示例:
CREATE PROCEDURE dbo.p_delete
@bookcode nvarchar(10)
AS
BEGIN
    delete book where bookcode = @bookcode
END

    如果想删掉存储过程,只要选中simple_query,右键,点击Delete,或者在Interactive SQL 中执行命令:
    drop procedure dbo.simple_query
即可。
6.创建触发器
    触发器是因某一行为而自动做出反应并进行特定操作的一组SQL语句,可以理解为表的事件。例如在对表进行插入、修改或删除数据等操作时,都会导致触发器被触发。这里我会创建三个触发器,分别对应book表的插入、修改和删除操作。

    insert触发器:
    在Sybase Central的Folders中找到zhengTest->User Tables->book->Triggers并选中,然后在Details中双击“Add Trigger(Wizard)”,打开“Add Trigger”向导。在第一个界面中填写触发器名称,例如t_insert,点击Next;在第二个界面中选择Insert,点击Next;在第三个界面中输入代码:
CREATE TRIGGER dbo.t_insert ON dbo.book
    For INSERT AS
BEGIN
    declare @bookcode   nvarchar(10),
                   @bookname   nvarchar(50),
                   @bookauthor nvarchar(20)
    select @bookcode = bookcode, @bookname = bookname, @bookauthor = bookauthor from inserted

    print '编号:%1!|名称:%2!|作者:%3!', @bookcode, @bookname, @bookauthor
END
点击Finish。至此,insert触发器创建完毕。
    触发器其实也可以认为是一种存储过程,就像我们在VB、VC、Delphi、Swing等开发中写的事件处理方法一样,只不过这个存储过程即没有参数,也没有返回值,更不允许返回结果集,例如select * from book这种语句是绝对不能写到触发器中的。此外,触发器中有两个逻辑表,inserted和deleted,前者代表新插入或更新的值,后者代表数据表中已存在并将被更新掉或删除掉的值,这里用到了inserted。下面赶紧向book表中插入一条数据,看看效果吧!

    update触发器,代码:
CREATE TRIGGER dbo.t_update ON dbo.book
    For UPDATE AS
BEGIN
    IF UPDATE (bookname)
    BEGIN
        rollback transaction
    END

    declare @o_mesg nvarchar(100),
                   @ret int
    exec @ret = dbo.simple_demo 'N', @o_mesg output
    print '%1!--------%2!', @ret, @o_mesg
END
这里需要说明的是IF UPDATE (bookname),该语句判断bookname字段是否被更新,在这里,bookname被更新便会导致回滚,即数据永远无法通过update bookname字段的方式更改。当有多个字段需要作这种判断时,只要写作“IF UPDATE(bookcode) and|or UPDATE(bookname)”即可。此外,逻辑表inserted、deleted在update触发器中同样有效,相关说明请见insert触发器。

    delete触发器,代码:
CREATE TRIGGER dbo.t_delete ON dbo.book
    For DELETE AS
BEGIN
    declare @bc nvarchar(10)
                 ,@bn nvarchar(50)
                 ,@ba nvarchar(10)
    --定义游标
    declare del_curs cursor for 
        select bookcode, bookname, bookauthor 
        from deleted
        order by bookcode

    open del_curs --打开游标

    --循环游标读取数据
    fetch del_curs into @bc, @bn, @ba
    while (@@sqlstatus = 0)
    begin
        print '编号:%1!|名称:%2!|作者:%3!', @bc, @bn, @ba
        fetch del_curs into @bc, @bn, @ba
    end

    close del_curs --关闭游标
    deallocate cursor del_curs --释放游标
END
这里使用了逻辑表deleted和游标来查询被删除的数据。

    注意,insert、update、delete触发器在每张表中都只允许创建一个,如果再次创建,例如insert触发器,无论使用什么名字,如test_trigger,之前创建的insert触发器都会被覆盖掉。此外,Sybase也允许在一个触发器中指定多个操作,例如:
CREATE TRIGGER dbo.t_author ON dbo.author
 For INSERT, DELETE, UPDATE AS
BEGIN
    print 'author表的触发器被执行!'
END
这个触发器就同时被指定了insert、update和delete操作。
    此外,我们还可以指定触发器失效或者有效,只要选中触发器,右键,点击Disable/Enable,或者在Interactive SQL 中执行命令:
    alter table dbo.book disable| enable trigger dbo.t_insert
即可。
    如果想删掉触发器,只要选中触发器,右键,点击Delete,或者在Interactive SQL 中执行命令:
    drop trigger dbo.t_insert
即可。
三、使用Java访问Sybase
    我写了两个Java访问Sybase的例子,IDE任意,驱动位于${Sybase安装目录}/jConnect-6_0/devclasses下, 将文件jconn3d.jar引入即可。

    第一个例子的代码如下:
package net.test.db.sybase;

import java.sql.*;

public class TestQuery {

 public static void main(String[] args) {
     Connection cn = null;
     CallableStatement cs = null;
     ResultSet rs = null;

     try {
        // 初始化连接对象
        Class.forName("com.sybase.jdbc3.jdbc.SybDriver");
        cn = DriverManager.getConnection("jdbc:sybase:Tds:image:5000/zhengTest?charset=cp936&jconnect_version=3", "sa", "");

        cs = cn.prepareCall("{call simple_query()}"); // 获得声明对象

        rs = cs.executeQuery(); // 执行,当有结果集时使用executeQuery()方法执行

        while (rs.next()) {
            System.out.print("编号:" + rs.getString(1));
            System.out.print("|名称:" + rs.getString(2));
            System.out.println("|作者:" + rs.getString(3));
        }

        if (rs != null)
            rs.close(); //关闭结果集
        if (cs != null)
            cs.close(); // 关闭声明
        if (cn != null)
            cn.close(); // 关闭连接
    } catch (Exception ex) {
        ex.printStackTrace();
    } finally {
        rs = null;
        cs = null;
        cn = null;
    }
 }
}
这个例子演示的是如何访问存储过程simple_query,该存储过程会返回一个结果集。这里需要注意两点:由于simple_query会返回一个结果集,因此需要使用cs.executeQuery()方法执行;在设置连接字符串的时候,设置了charset=cp936,即将客户端的字符集设置成cp936,这样查看结果时才不会乱码。

    第二个例子的代码如下:
package net.test.db.sybase;

import java.sql.*;

public class TestDemo {

 public static void main(String[] args) {
  Connection cn = null;
  CallableStatement cs = null;

  try {
   // 初始化连接对象
   Class.forName("com.sybase.jdbc3.jdbc.SybDriver");
   cn = DriverManager.getConnection("jdbc:sybase:Tds:image:5000/zhengTest?charset=cp936&jconnect_version=3","sa", "");

   cs = cn.prepareCall("{?=call simple_demo(?,?)}"); // 获得声明对象

   // 设置参数
   cs.registerOutParameter(1, Types.INTEGER);
   cs.setString(2, "N");
   cs.registerOutParameter(3, Types.VARCHAR);

   cs.execute(); // 执行,当没有返回结果集时,为防止出错,使用execute()方法作执行

   // 输出处理结果
   System.out.println(cs.getInt(1));
   System.out.println(cs.getString(3));

   if (cs != null)
    cs.close(); // 关闭声明
   if (cn != null)
    cn.close(); // 关闭连接
  } catch (Exception ex) {
   ex.printStackTrace();
  } finally {
   cs = null;
   cn = null;
  }
 }
}
这个例子演示的是动态访问存储过程simple_demo,该存储过程带有一个输出参数,并有一个返回值,在JDBC中,返回值和输出参数可以认为是一回事。这里需要注意的是,由于这个存储过程没有结果集,因此执行时应该使用cs.execute()方法。
四、使用VB.net/C#访问Sybase
    我写了两个VB.net/C#访问Sybase的例子,IDE使用SharpDevelop 2.1,环境为.net Framework 2.0,驱动位于${Sybase安装目录}/DataAccess/ADONET/dll下, 引用其中的文件Sybase.Data.AseClient.dll到项目中即可。

    第一个例子的VB.net代码如下:
Imports Sybase.Data.AseClient

Public Class TestQuery
 Sub New()
  Dim cn As AseConnection = Nothing
  Dim cmd As AseCommand = Nothing
  Dim rd As AseDataReader = Nothing
   
  Try
   '初始化连接对象
   cn = New AseConnection("Data Source=image;Port=5000;UID=sa;PWD=;Database=zhengTest;CharSet=cp936;")
    
   cn.Open() '打开连接
    
   cmd = New AseCommand("exec simple_query", cn) '获得命令对象
    
   rd = cmd.ExecuteReader() '执行,当有只读记录集时使用ExecuteReader()方法执行

   While rd.Read() 
    Console.Write("编号:" & rd.GetString(0))
    Console.Write("|名称:" & rd.GetString(1))
    Console.WriteLine("|作者:" & rd.GetString(2))
   End While

   If rd IsNot Nothing Then
    rd.Close() '关闭只读记录集
   End If
   If cmd IsNot Nothing Then
    cmd.Dispose() '销毁命令对象
   End If
   If cn IsNot Nothing Then
    cn.Close() '关闭连接对象
   End If
  Catch ex As AseException
   Console.WriteLine(ex.Message)
  Finally
   rd = Nothing
   cmd = Nothing
   cn = Nothing
  End Try
 End Sub
End Class
    C#代码如下:
using System;
using Sybase.Data.AseClient;

namespace zhengTest_Sybase
{
 public class TestQuery
 {
  public TestQuery()
  {
   AseConnection cn = null;
   AseCommand cmd = null;
   AseDataReader rd = null;
   
   try
   {
    //初始化连接对象
    cn = new AseConnection("Data Source=image;Port=5000;UID=sa;PWD=;Database=zhengTest;CharSet=cp936;");
    
    cn.Open(); //打开连接
    
    cmd = new AseCommand("exec simple_query", cn); //获得命令对象
    
    rd = cmd.ExecuteReader(); //执行,当有只读记录集时使用ExecuteReader()方法执行

    while(rd.Read())
    {
     Console.Write("编号:" + rd.GetString(0));
     Console.Write("|名称:" + rd.GetString(1));
     Console.WriteLine("|作者:" + rd.GetString(2));
    }
    
    if (rd != null)
     rd.Close(); //关闭只读记录集
    if (cmd != null)
     cmd.Dispose(); //销毁命令对象
    if (cn != null)
     cn.Close(); //关闭连接对象
   }
   catch( AseException ex )
   {
    Console.WriteLine(ex.Message);
   }
   finally
   {
    rd = null;
    cmd = null;
    cn = null;
   }
  }
 }
}
跟第一个Java例子一样,也是演示如何访问simple_query存储过程并对记录集进行操作的。这里请注意几点:第一,连接字符串中Data Source=image指的不是数据源,而是服务器,与设置Server=image效果一样;第二,连接字符串中的CharSet=cp936用来设置字符集,但从当前环境看,这个设置不是必须的,至于我是如何知道该参数有效的,我将字符集设置成cp850后出现乱码了;第三,由于simple_query会返回一个结果集,因此需要使用ExecuteReader方法来执行,这点与Java很类似。

    第二个例子的VB.net代码如下:
Imports System.Data
Imports Sybase.Data.AseClient

Public Class TestDemo
 Sub New()
  Dim cn As AseConnection = Nothing
  Dim cmd As AseCommand = Nothing

  Try
   '初始化连接对象
   cn = New AseConnection("Data Source=image;Port=5000;UID=sa;PWD=;Database=zhengTest;")
   
   cn.Open()'打开连接
   
   cmd = New AseCommand("simple_demo", cn) '获得命令对象
   cmd.CommandType = CommandType.StoredProcedure '设置命令类型为存储过程

   '设置参数
   cmd.Parameters.Add("RETURN_VALUE", AseDbType.[Integer]).Direction = ParameterDirection.ReturnValue
   cmd.Parameters.Add("@i_mesg", "N")
   cmd.Parameters.Add("@o_mesg", AseDbType.NVarChar, 50).Direction = ParameterDirection.Output

   cmd.ExecuteNonQuery() '执行,当没有返回结果集时,使用ExecuteNonQuery()方法作执行

   '输出处理结果
   Console.WriteLine(cmd.Parameters(0).Value)
   Console.WriteLine(cmd.Parameters(2).Value)

   If cmd IsNot Nothing Then
    cmd.Dispose() '销毁命令对象
   End If
   
   If cn IsNot Nothing Then
    cn.Close() '关闭连接对象
   End If
  Catch ex As AseException
   Console.WriteLine(ex.Message)
  Finally
   cmd = Nothing
   cn = Nothing
  End Try
 End Sub
End Class
    C#代码如下:
using System;
using System.Data;
using Sybase.Data.AseClient;

namespace zhengTest_Sybase
{
 public class TestDemo
 {
  public TestDemo()
  {
   AseConnection cn = null;
   AseCommand cmd = null;
   
   try
   {
    //初始化连接对象
    cn = new AseConnection("Data Source=image;Port=5000;UID=sa;PWD=;Database=zhengTest;");
    
    cn.Open(); //打开连接
    
    cmd = new AseCommand("simple_demo", cn); //获得命令对象
    cmd.CommandType = CommandType.StoredProcedure; //设置命令类型为存储过程
    
    //设置参数
    cmd.Parameters.Add("RETURN_VALUE", AseDbType.Integer).Direction = ParameterDirection.ReturnValue;
    cmd.Parameters.Add("@i_mesg", "N");
    cmd.Parameters.Add("@o_mesg", AseDbType.NVarChar, 50).Direction = ParameterDirection.Output;
    
    cmd.ExecuteNonQuery(); //执行,当没有返回结果集时,使用ExecuteNonQuery()方法作执行
    
    //输出处理结果
    Console.WriteLine(cmd.Parameters[0].Value);
    Console.WriteLine(cmd.Parameters[2].Value);
    
    if (cmd != null)
     cmd.Dispose(); //销毁命令对象
    if (cn != null)
     cn.Close(); //关闭连接对象
   }
   catch( AseException ex )
   {
    Console.WriteLine(ex.Message);
   }
   finally
   {
    cmd = null;
    cn = null;
   }
  }
 }
}
跟第二个Java例子类似,演示如何访问simple_demo存储过程。不过ADO.net调用存储过程的方式与JDBC不同,只允许在命令对象中输入过程名作为语句,而且不支持“?”占位符。关于参数设置中用到的RETURN_VALUE、@i_mesg、@o_mesg,分别代表simple_demo的返回值和两个参数。由于simple_demo不会返回记录集,因此需要使用ExecuteNonQuery方法来执行。这里推荐一下文章《将存储过程用于命令》,该文对ADO.net访问存储过程进行了比较详细的介绍,从.net Framework自带文档或网上都能找到。

    另外,再提供两个连接字符串:
    Sybase for OLED:PROVIDER=ASEOLEDB;Server=image;Port=5000;User Id=sa;Password=;Initial Catalog=zhengTest;CharSet=cp936;
请注意字符串中的Initial Catalog=zhengTest,表示要访问我在Sybase中创建的zhengTest数据库,而CharSet=cp936是用来设置字符集的,不设置会乱码。
    Sybase for ODBC:DSN=zhengTest_Sybase;UID=sa;PWD=;CharSet=cp936;
字符串中的DSN=zhengTest_Sybase表示访问我在ODBC中设置的数据源zhengTest_Sybase(如何在ODBC中设置数据源就不演示了),而CharSet=cp936也是用来设置字符集的,但在当前环境中不是必须的。
 关于OLEDB和ODBC的使用,与示例类似,请参考其他ADO.net书籍或文档。
五、使用Perl访问Sybase
     我使用的Perl是5.8.8 build 820,虽然默认不带数据库访问接口,但可以使用工具ppm下载到DBI。
     打开命令行工具,输入ppm search dbi,查找dbi,有183个结果,我们需要的是第56个——DBI v1.57。下面执行命令ppm install dbi,如果提示错误,请尝试ppm install 56,即安装查询结果中的第56个。不过安装结束后,暂时还是无法使用DBI来连接数据库,因为DBI提供的只是一套数据库接口,而不是数据库驱动,因此还需要安装dbd-ado和dbd-odbc,安装方法同dbi。
    不过您或许已经注意到了,我使用的dbi版本不是最新的1.58,而且驱动也不是dbd-sybase,的确,因为这些都没有安装包,只能从http://www.perl.com/CPAN/上下载源码自己编译。我自己倒是也做了不少尝试,包括安装FreeTDS,在cygwin和WinGW中make,结果都失败了,自己推测原因大约是Perl和DBI、DBD-SYBASE之间版本不对应,毕竟这些东东每个版本接口都会有所变化。最后在经过一周的折磨之后,终于连编译Ruby的dbd_sybase模块的想法统统放弃了。

     这里也是两个例子。第一个例子的代码如下:
use DBI;
#创建连接对象,类型为ADO
$dbh=DBI->connect('DBI:ADO:PROVIDER=ASEOLEDB;Server=image;Port=5000;User Id=sa;Password=;Initial Catalog=zhengTest;CharSet=cp936;');

$sth=$dbh->prepare('exec simple_query' ); #获得声明对象
$sth->execute; #当有结果集时,使用execute方法

while (@row=$sth->fetchrow_array) {
  print '编号:', $row[0];
  print '|名称:', $row[1];
  print '|作者:', $row[2], "/n";
}

$sth->finish if $sth; #关闭声明

$dbh->disconnect if $dbh; #断开连接
也是演示如何访问simple_query存储过程并对结果集进行操作的。这里请注意两点:第一,本例使用的驱动类型为ADO,其连接字符串中,Initial Catalog=zhengTest表示要访问我在Sybase中创建的zhengTest数据库,而CharSet=cp936则表示设置字符集为cp936,目的在于避免乱码;第二,由于simple_query会返回一个结果集,因此需要使用execute方法来执行,这点与前面很类似。

    第二个例子的代码如下:
use DBI;
#创建连接对象,类型为ODBC
$dbh=DBI->connect('DBI:ODBC:DSN=zhengTest_Sybase;UID=sa;PWD=;CharSet=cp936;');

$sql='{?=call simple_demo(?,?)}';
$ret='';
$msg='';

$sth=$dbh->prepare($sql); #获得声明对象

#设置参数
$sth->bind_param_inout(1, /$ret, 1);
$sth->bind_param(2, 'N');
$sth->bind_param_inout(3, /$msg, 100);

$sth->execute; #执行

#输出处理结果
print $ret, "/n";
print $msg, "/n";

$sth->finish if $sth; #关闭声明

$dbh->disconnect if $dbh; #断开连接
也是演示动态访问simple_demo存储过程的。这里需要注意的是,本例使用的驱动类型为ODBC,其连接字符串中,DSN=zhengTest_Sybase表示访问我在ODBC中设置的数据源zhengTest_Sybase,而CharSet=cp936则表示设置字符集为cp936,这里是必须的。
六、使用Ruby访问Sybase
    我使用的Ruby是1.8.6-25,已安装Rails 1.2.3。由于Ruby默认不带数据库访问接口,因此请先从http://rubyforge.org/projects/ruby-dbi下载ruby-dbi,当前版本0.1.1。由于Ruby版本的DBI是从Perl版本演变过来的,因此两者有很多相似之出。
    下载完dbi-0.1.1.tar.gz文件之后,解压缩,在命令行中定位到解压后的目录下,例如F:/ruby-dbi,执行命令:
    ruby setup.rb config --with=dbi,dbd_ado,dbd_odbc
    ruby setup.rb setup
    ruby setup.rb install
此时dbi接口连带dbd_ado、dbd_odbc驱动就都安装到系统中了。
    据说dbi所提供的驱动仅是表层的,如果要使用还需要安装底层驱动,例如PostgreSQL,就还需要安装ruby-postgres。不过似乎是因为我安装了Rails的缘故(Rails带有activerecord,据说里边包含了很多驱动),我在使用的过程中倒也没被要求安装底层驱动。
    此外,我也没有使用dbd_sybase驱动。不知道为什么,dbd_sybase居然需要编译,而我在cygwin和Windows命令行下都进行过尝试,还安装了MinGW(GCC的Windows版本),甚至查找了perl-dbi和freetds的资料,结果还是失败。最可恨的是dbd_sybase调用的接口居然跟freetds和ruby中定义的接口不一致,后来看了dbd_sybase代码才发现,居然是2001年的。最后,dbd_sybase到底没装上,可是make倒学会了。汗!

    这里也是还个例子。第一个例子的代码如下:
require 'dbi'
#创建连接对象,类型为ADO
dbh=DBI.connect('DBI:ADO:PROVIDER=ASEOLEDB;Server=image;Port=5000;User Id=sa;Password=;Initial Catalog=zhengTest;CharSet=cp936;')

sth=dbh.prepare('exec simple_query') #获得声明对象
sth.execute #当有结果集时,使用execute方法

while row=sth.fetch do
  print '编号:', row[0]
  print '|名称:', row[1]
  print '|作者:', row[2], "/n"
end

sth.finish if sth #关闭声明

dbh.disconnect if dbh #断开连接

    第二个例子的代码如下:
require 'dbi'
#创建连接对象,类型为ODBC
dbh=DBI.connect('DBI:ODBC:DSN=zhengTest_Sybase;UID=sa;PWD=;CharSet=cp936;')

sql='{?=call simple_demo(?,?)}' #支持该代码
ret=''
msg=''

sth=dbh.prepare(sql)  #获得声明对象

#设置参数
sth.bind_param(1, ret)
sth.bind_param(2, 'N')
sth.bind_param(3, msg)

sth.execute  #执行

#由于dbi不支持输出参数,因此这里无法获取simple_demo的返回值与输出参数

sth.finish if sth #关闭声明

dbh.disconnect if dbh #断开连接
演示动态访问simple_demo存储过程。不过由于dbi不支持存储过程的输出参数,注意是存储过程,所以在这个示例中没有获取返回值的代码。

    也不知道为什么,dbi只支持函数的输出参数,而不支持存储过程的输出参数,似乎SQL Server和DB2的存储过程也同样无法返回输出参数。
    由于本文只是使用Ruby访问Sybase,因此没打算对dbi作深入介绍。如果对dbi有兴趣,建议在网上找一篇名为《firstworks Programming with SQL Relay using the Ruby DBI API》的文章,虽然是英文的,但内容很全面,对多种数据库都有介绍,值得一看。
    别告诉我你英文不好,我英文也不好,不也是用着金山词霸就那么看了吗^_^
七、小结
    本文只是对Sybase操作的简单介绍,像索引、序列这些都没有作说明,而且给出的Java、.net、Perl和Ruby示例也都比较简单,如果希望了解更多内容,还请参考其他书籍或文档。
    此外,SQL Server与Sybase系出同门,大约是在Sybase 6的时候微软不愿再同Sybase公司合作而分成两支的,因此如果手头缺少Sybase资料,也不妨参考一下SQL Server的文档。不过作为一款大型数据库,Sybase至今已发布了15个大的版本,却不知道为什么,在程序汉化和帮助文档方面做得始终很差,而且提供的功能也很弱,像用户自定义函数、try-catch语句和row_number函数这些,至今没有,因此在使用SQL Server文档的时候,如果发现某些功能在Sybase中实现不了,请不要奇怪。

posted @ 2011-08-30 11:48 木子非 阅读(...) 评论(...) 编辑 收藏