开发动态sql

1 动态sql 简介
2
  1 使用execute immediate 处理ddl 操作
    create or replacee procedure drop_table(table_name varchar2)
    is
     sql_statement varchar2(100);
    begin
       sql_statement:='drop table'||table_name;
       execute immediate sql_statement;
   调用
       exec drop_table('worker');
    end;
    2) 使用 execute immediate 处理dcl 操作
    create or replace procedure grant_sys_priv
    (priv varchar2,username varchar2)
    is
    begin
     sql_stat:='gruant'||priv||'to'||username;
     execute immediate sql_stat;
    end;

   exec grant_sys_priv('create session','scott');
   3 使用execute immediate 处理dml 操作
     1) 处理无占位符和returning 子句的dml 语句
     delcare
      sql_stat varchar2(100);
     begin
      sql_stat:='update emp set sal=sal*1.1 where deptno=44';
      execute immediate sql_stat;
     end;
      2) 处理包含占位符的dml语句
       delare
        sql_stat varchar2(100);
       begin
         sql_stat:='update emp set sql=sql*(1+:percent/100)'
                 ||'where deptno=:dno';
         execute immediate sql_stat using &1,&2;
       end;
      3) 处理包含returning 子句的dml语句
       declare
         salary number(6,2);
         sql_stat varchar2(200);
       begin
         sql_stat:='update emp set sal=sal*(1:percent/100)'
            ||'where empno=:eno returning sal into :salary';
         execute immediate sql_stat using &1,&2;
            returning into salary;
       end;
       输入1的值 15
       输入2的值 2222
       新工资;2223
      4) 使用execute immediate 处理单行查询
        declare
          sql_stat varcchar2(100);
          emp_record emp%rowtype;
        begin
          sql_stat:='select * from emp where empno=:eno';
          execute immediate sql_stat into emp_record using &1;
       end;
 3 处理多行查询语句
   declare
      type empcurtyp is ref cursor;
      emp_cv empcurtyp;
      emp record emp%rowtype;
      sql_stat varchar2(100);
   begin
      sql_stat:='select * from em where deptno=:dno';
      open emp_cv for sql_stat using &dno;
      loop
         fetch emp_cu into emp_record;
         exit when emp_cv%notfound;
      end loop;
      close emp_cv;
   end;
4 在动态sql 中使用bulk语句
   1) 在 execute immediate 语句中使用动态bulk 语句
     declare
       type ename_table_type is table of emp.ename%type
        index by binary_integer;
       type sal_table_type is table of emp.sal%type
        index by binary_integer;
       ename_table ename_table_type;
       sa_table sal_table_type;
       sal_stat varchar2(100);
       begin
         sql_stat:='update emp set sal=sal*(1+:percent/100)'
           || 'where deptno=:dno'
           ||'returning ename,sal into :name,:salary';
       execut immediate sql_stat using &percent,&dno
         returning bulk collect into ename_table,sal_table;
       for i in 1..ename_table.count loop
       ....
       end loop;
     end;
    2) 使用bulk 子句处理多行查询
      sql_stat:='select ename from emp where deptno=:dno';
      execute immediate sql_stat bulk collect into ename_table using &dno;
    3) 在fetch 语句中使用bulk 子句
      declare
        type empcurtyp is ref cursor;
        emp_cv empcurtyp;
        type ename_table_type is table of emp.ename%type;
         index by binary_integer;
        ename_table ename_table_type;
        sql_stat varchar2(100);
       begin
         sql_stat:='select ename from emp where job:=title';
         open emp_cv for sql_stat using '&job';
         fetch emp_cv bulk collect into ename_table;
    4) 在forall 语句中使用bulk 子句
      declare
        type ename_table_type is table of emp.ename%type;
        type sla_table_type is table of emp.sal%type;
        ename_table ename_table_type;
        sal_table sal_table_type;
        sql_stat varchar2(100);
      begin
        ename_table:=ename_table_type('scott','smith','clark');
        sql_stat:='update emp set sal=sal*1.1 where ename=:1'
            ||'returning sal into :2';
        forall i in 1..ename_table.count
          execite immediate sql_stat using ename_table(i)
            returning bulk collect into sal_table;       
      end;

posted @ 2006-10-11 14:43 康文 阅读(472) | 评论 (0)编辑 收藏

managing an oracle instance

1
  1)system parameter file -- spfile<sid>,spfile (oracle 9i or later) is a binary file ,it cann't been edited by the text editor. you can change it through "alter system XXX";
  in oracle 9.2.0,spfile is stored in the directory of ora92\datatase\spfile<sid>.ora.
  2)init parameter file(pfile)--init<sid>.ora  (early version) is a text file.it is stored in admin\<sid>\pfile.
 2
   Entries are specific to the instance being accessed;
   there are two kinds of parameters:
      explicit: having an entry in the file
      implicit: no entry within the file,but assuming the oracle default values;
   Multiple files can be used for a single datasbase to optimize performance in different situation.
    static parameter file,pfile (init.ora)
    persistent parameter file,spfile(spfile<sid>.ora);
3 order being used
 first spfile<sid> then int<sid>.ora
 select name,value from v$system_parameter
4 spfile spfilesid.ora
  1)Binary file with the abiility to make changes persistent across shutdown and startup
  2)Maintained by oracle server
  3)Record parameter value change made with the alter system command
  4)Can specify wether the change being made is tempory or persistent
  5)value can be delete or reset to allow an instance to revert to the default value;
    e.g
    alter system set timed_statistics=false scope=memory;
   alter system set timed_statistics=false scope=spfile;
   startup force-- restart oracle
   select name,value from v$system_parameter where name like 'time%';
   alter system set timed_statistics=false scope=both;
  6) not all entries can be modified.to see more ,you can lool up v$system_parameter.in this table the isses_modifiable and issys_modifiable will tell which one  can be modified in session,and which one can be modified in sys, and which one cann't be modified.
   e.g
   select name,isses_modifiable from v$system_parameter where isses_modifiable='true';
   alter session set timed_statistics=false;
   e.g
   select name,issys_modifiable from v$system_parameter where issys_modifiable<>'false';
  
   .issys_modifiable may have two values immediate or deffered.
    immediate means alter this entry will take effect on the current session ,while derrered will take effect on a new session.
 
5 pfile initsid.ora
  .the pfile is a text file than can be modigied with an operation system editor.
  .modifications to the file are made manually.
  .changes to the file take effect on the next startup
6 Creating an spfile
   spfile can be created from initsid.ora file using thee create spfile command,whick can be executed before or after instance startup.
   create spfile from pfile. -- you must shutdown the instance befofe or you can use the fellow statement:
    create spfile='d:\oracle\oracle\ora92\database\spfile.ora' from pfile;
 yo caan backup the
7 Oracle Managed files(OMF)
  1) OMF are created and deleted by the oracle server as directed by sql commands
  2) OMF are established by parameters:
     DB_CREATE_DEST: set to give the default location for data files
     DB__CREATE_OMLINE_LOG_DEST_N: set to gieve the default locations for online redo logs and control files,up to a mazimum of 5 locations.
    e.g 1
    show parameter db_create
    e.g 2
    create tablespace test1;--report error,Do not konw where create the data file
    alter system set db_create_file_dest='d:\oracle\oradb';
    create tablespace test1; -- is ok;
    e.g 3
    alter database add logilfe group 6;
    -- if you do not specify the db_create_online_log_dest_N ,the log file will create at     --the location which is specified by the db_create_file_dest.
    e.g 4
    drop table test1; -- oracle alse remove it's physicial file;
    alter database drop logfile group 6-- also romove the physical file.
    e.g 5
    create tablespace test1
    datafile 'd:\oracle\oradb\test1.dbf' size 2m;
    drop tablespace test1 -- if you create tablespace or others object in this way ,you                           --will cann't remove the physical file.
    drop table test1 including comtents and datafiles;
8 Starting up a database mount
 startup nomomount :instance started for this instance;create db.create controlfule
     1) create alert_sid.log  startup log which is stored in <oracle_home>\admin\<sid>\bdump
     2) start instance include allocating memory and start bpprocess
    select * from v$instance;
    select * from v$bgprocess;
    select * from V$sga;
  alter database mount;
    open control files for the instance;
    select* from v$database;
    select* from v$tablespace;
    select* from datafile;
    select* from log;
 alter database open;
    all files opened as describled by the control file for this instance;
9 start up
  start pfile=...\initsid.ora;   (alter session set nls_language=american)
  alter database open read only; you can not change database to read only after the database has been created.
  startup database restrict;
  alter system enable restricted session;-- only people with restricted privilege can                                          --access the database;
   alter restricted session to kkk;
   alter disable restricted session
10 opening a database in read only mode
   a databse can be opened as read only database alter database open read only;
   a read-only database can be used to :
     execute queries
     execute disk sorts using locally managed
     take data files offline and online ,not tableespaces
     perform recovery of offline data files and tablespace;
11Shutting down teh database
  normal: wait until current sessions end,wait until current trasactions end ,force a checkpoint and close files.
  tansactional:wail until current transaction end.force a checkpoint and close files
  immediate :force a checkpoint and close the files
  abort     : do nothing ,just close the files. when startup ,need recovery.
12 Managing an instance by monitoring Diagnostic Files
  Diagnostic files contain information about significant events encounted while the instance is operational.
   .user to resolve problem or to better manager the database.
   .server types of dignostic files exist:
      alertsid.log  --which location is specified by the background_dump_dest                                   --entry in the initsid.ora.tje default value is                     --<ora_home>\admin\sid\bdump
      background trace files -- the same as above;
      user_tace files
13 alert log file
   the alertsid.log file recored the command and result of major event while the database is operational.
   .it is userd for day-to-day operational information or dignosing database errors
   .ench entry has a time stamp associated with it.
   .the dba manager the alertsid.log file.
   .its location is defined by background_dump_dest.
14 enabling or disabling user tracing
    . sessin level using the alter session
      alter session set sql_trace=true;
    session level by execcuting dbms
    

posted @ 2006-10-11 14:42 康文 阅读(348) | 评论 (0)编辑 收藏

archetecture query

1 hierachical Queries
 select [level],colun,expr......
 from table
 [where condition(s)]
 [start with condition(s)]
 [connect by prior condition(s)]
 
 where condition
  exprcompparison_operator expr

2 Starting Point
 .Specifies the condition that must be met
 .Accepts any valid condition
3 Waling the Tree
  connect by prior column1=column2
  walk from the top donw ,using the employees table
   top donw
     column1=parentkey
     column2=childkey
   bottom up
     column1=child key
     column2=parent key

  select level,last_name
  from employees
  start with last_name='king'
  connect by prior employee_id=manager_id;

posted @ 2006-10-11 14:42 康文 阅读(182) | 评论 (0)编辑 收藏

extension to dml in oracle

1 over of multitable insert statements
 1)the insert...select statement can be userd to insert row into multiple table as part of a single dml statement.
 2) multitable insert statements can be used in data warehousing systems to transfer data from one or more operational sources to source to a set of target table.
 3) they providde significant performance improvement over
    single dml versuls multiple insert...select statement
    single dml versus a proceedduree to do mutiple inserts using if ,,, then syntax.
2
  unconditional insert
  insert all
    into sal_history values (EMPID,HIREDATE,SAL)
    into mgr_history values (EMPID,MGR,SAL)
  select employee_id EMPID,hire_date JIREDATE,
         salary SAL,manager_id MGR
  from employees
  where employee_id>200;
3 Conditional insert all
  insert all
   when sal>1000 then
     into sal_history values(empid,hiredate,sal)
   when mgr>200 then
     into mgr_history values(empid,mgr,sal)
   select emp_id empid,hire_date hiredate,salary sal,manager_id mgr,
   from employees
   where employee_id>200;
4 Conditional first insert
  insert first
    when sal >25000  then
      into special_sal values(deptid,sal)
    when hiredate like ('%00%') then
      into hiredate_history_00 values(deptid,hiredate)
    when hiredate like ('%99%') then
      insert hiredate_history_99 values(ddeptid,hiredate)
    else
      into hiredate_history values(deptid,hiredate)
    select ddepartmeent_id deptid,sum(salary) sal,
     max(hire_date) hiredate
    from employees
    group by department_id;
5 Pivoting insert
 insert all
  into sales_info values (employee_id,week_id,sales_mon)
  into sales_info values (employee_id,week_id,sales_tue)
  into sales_info values (employee_id,week_id,sales_wed)
  into sales_info values (employee_id,week_id,sales_thur)
  into sales_info values (employee_id,week_id,sales_fri)
  select employee_id,weekid,sales_mon,sales_tue,sales_wed,sales_thur,sales_fri
  from sales_source_data;
6 create index with create table statement
  create table new_emp
  (employee_id number(6)
         primary key using index
         (create index emp_id_idx on new_emp(employee_id)),
   first_name varchar2(20),
   last_name varchar2(25)
  )

posted @ 2006-10-11 14:41 康文 阅读(194) | 评论 (0)编辑 收藏

Managing Passswordd Security and Resources

1 Profiles
  1)a profile is a named set of password and resource limits
  2)Profiles are assigned to user by the create user or alter user command
  3)can be enable or disable
  4)can relate to the default profile.
2 Password Management
  Password history,account locking,password expiration and aging ,password verificcation.
3Enabling Password Management
  1)set up passwordd management by using profiles and assign them to users
  2)lock unlock and expire accounts usign the create user or alter user
  3)alwarys enforcing
   e.g
   create user test identified by test;
   alter user test account lock;
   alter user test account unlock;
   alteer user test password expire;
4 Passowrd Account locking
  FAIKED_LOGIN_ATTEMPS: number of failed login attemts before lockout of the account
  PASSWORD_LOCK_TIME : number of days the account is locked after the specified number of                        failed login attemps
  e.g
  create profile profile1 limit
  password_lock_time 1/1440  -- one muinuts
  failed_login_attempts 3;
 
  alter user test
  profile profile1;

  alter profile profile1 limit
  passowrd_lock_time 1/24  --one hour
5 passowrd expiration and aging
 passwowd_life_time lifetime of the passowrd in days  after which the password expires(有效期)
 password_grace_time grace period in days for changing the password after the first                      successful login afteer the password has expired(锁定期)
 e.g
 alter profile profile1 limit
 password_life_time 2
 password_grace_time 3;
6 password history
 password_reuse_time:number of days before a passowrd and be resued
 password _reuse_max:maxum number of times password can bee reused
 e.g
 alter profile profile1 limit
 password_reuse_time 10
 password_reuse_max 3;
7passowrd Verification(study latter)
8drop a profile
 drop profile profile1 (cascade);
the user will use the default profile.it will take effect on the new session.
9 Resource Management
 Resource mangement limits can be enforced at the session level,the call level or both
 limits can be defined by profiles using the create profile command
 enable resource limints with the
  .resource_limit initialization parameter
   alter system command
 e.g
 alter system set resource_limit=true;
10 setting a Resdource limits at session level
  cup_per_session : total cpu time measured in hundredths of seconds (百分之一秒)
  sessions_per_user: number of coucurrent sessions allowed for each username
  connect_time:elapsed connect time measured in minutes
  idle_time :periods of inactive time measured in minutes
  logical_reads_per_session: number of data blocks
  private_sga :measure in reads
  e.g
  alter profile profile1 limit
  cpu_per_session 100000
  connect_time 60
  idle_time 5;
 
  alter user test profile profile1

11 Setting Resource limits at call level 
 e.g
 alter profile profile1
 cpu_per_call 1000  -- cup time per call in
 logical_reads_per_call --number of data balock that can be read per call
 
  create profile develper_prof limit
   session_per_user2
   cpu_per_session 10000
   idle_time 60
   connect_time 480
12 Managing Resources using database resource manager
   1)Provides the oracle server with more control over resorce management decisions
   2)elements of database resorcee manager
    resource consumer group
    resourcee plan
    resource allocation method
    resource plan directives
   3)dbms_resource_manager package is uerd to create and maintain elements
   4)requires administer_resource_manager privilege
    desc dbms_resoource_manager
13 0btaining password and resource limits informaiton
  information about password and resource limits can be obtained by querying the data dictonary
   dba_users
   select * from users;
   dba_profiles
   select * from dba_profiles where profile='PROFILE1'

posted @ 2006-10-11 14:41 康文 阅读(205) | 评论 (0)编辑 收藏

jdbc-batch processing

the addBatch() method is basically nothing more than a tool fro assigning a bunch of sql statements to a jdbc statement object for execution together

PreparedStatement stmt=conn.prepareStatement(
      "update account set balance=? where acct_id=?");
int[] rows;
for(int i=0;i<accts.length;i++){
    stmt.setInt(1,i);
    stmt.setLong(2,i);
    stmt.addBatch();
  }
rows=stemt.executeBatch();

posted @ 2006-10-11 14:40 康文 阅读(206) | 评论 (0)编辑 收藏

翻页的实现

1 oracle 的实现
 语句一
SELECT ID, [FIELD_NAME,...] FROM TABLE_NAME WHERE ID IN ( SELECT ID FROM (SELECT ROWNUM AS NUMROW, ID FROM TABLE_NAME WHERE 条件1 ORDER BY 条件2) WHERE NUMROW > 80 AND NUMROW < 100 ) ORDER BY 条件3;
语句二:
SELECT * FROM (( SELECT ROWNUM AS NUMROW, c.* from (select [FIELD_NAME,...] FROM TABLE_NAME WHERE 条件1 ORDER BY 条件2) c) WHERE NUMROW > 80 AND NUMROW < 100 ) ORDER BY 条件3;

select * from (select rownum as numrow from table_name where numrow>80 and numrow<100 )
不能直接使用 select * from rownum>100 and rownum<200;
in oracle return null;
2 sql server 的实现
3 mysql 的实现

select id from table_name where id in
                                   select * from (select rownum as numrow ,id from tabl_name)
                                             where numrow>80 and num<100;                                           
                                                

posted @ 2006-10-11 14:39 康文 阅读(185) | 评论 (0)编辑 收藏

jdbc-prepare sql

1 prepared sql
oracle provide two kinds of prepared SQL prepared statements and store procedures.Prepared SQL provide an advantage over the simple sql statements you have convered so far.if you execute the same prepared sql more than once,the database remains ready for your sql without having to rebuild the query plan.
 1) Prepared Statements
 PreparedStatement statement=conn.preparedStatement(
     "update account set balance=? where id=?");
 for(int i=0;i<accounts.length;i++){
    statement.setFloat(1,accounts[i].getBalance());
    statement.setInt(2,i);
    statement.execut();
    stateement.clearParameters();
 }
 commit();
 statement.close;
 2) Stored Procedure
 try {
    CallableStatement statement;
    int i;
 
    statement = c.prepareCall("{call sp_interest[(?,?)]}");
 
    statement.registerOutParameter(2, java.sql.Types.FLOAT);
    for(i=1; i<accounts.length; i++) {
        statement.setInt(1, accounts[i].getId( ));
        statement.execute( );
        System.out.println("New balance: " + statement.getFloat(2));
    }
    c.commit( );
    statement.close( );
    c.close( );
}

posted @ 2006-10-11 14:38 康文 阅读(374) | 评论 (0)编辑 收藏

java 调用存储过程 转载

本文阐述了怎么使用DBMS存储过程。我阐述了使用存储过程的基本的和高级特性,比如返回ResultSet。本文假设你对DBMS和JDBC已经非常熟悉,也假设你能够毫无障碍地阅读其它语言写成的代码(即不是Java的语言),但是,并不要求你有任何存储过程的编程经历。
存储过程是指保存在数据库并在数据库端执行的程序。你可以使用特殊的语法在Java类中调用存储过程。在调用时,存储过程的名称及指定的参数通过JDBC连接发送给DBMS,执行存储过程并通过连接(如果有)返回结果。
使用存储过程拥有和使用基于EJB或CORBA这样的应用服务器一样的好处。区别是存储过程可以从很多流行的DBMS中免费使用,而应用服务器大都非常昂贵。这并不只是许可证费用的问题。使用应用服务器所需要花费的管理、编写代码的费用,以及客户程序所增加的复杂性,都可以通过DBMS中的存储过程所整个地替代。
你可以使用Java,Python,Perl或C编写存储过程,但是通常使用你的DBMS所指定的特定语言。Oracle使用PL/SQL,PostgreSQL使用pl/pgsql,DB2使用Procedural SQL。这些语言都非常相似。在它们之间移植存储过程并不比在Sun的EJB规范不同实现版本之间移植Session Bean困难。并且,存储过程是为嵌入SQL所设计,这使得它们比Java或C等语言更加友好地方式表达数据库的机制。
因为存储过程运行在DBMS自身,这可以帮助减少应用程序中的等待时间。不是在Java代码中执行4个或5个SQL语句,而只需要在服务器端执行1个存储过程。网络上的数据往返次数的减少可以戏剧性地优化性能。

使用存储过程

简单的老的JDBC通过CallableStatement类支持存储过程的调用。该类实际上是PreparedStatement的一个子类。假设我们有一个poets数据库。数据库中有一个设置诗人逝世年龄的存储过程。下面是对老酒鬼Dylan Thomas(old soak Dylan Thomas,不指定是否有关典故、文化,请批评指正。译注)进行调用的详细代码:

try{
int age = 39;

String poetName = "dylan thomas";

CallableStatement proc = connection.prepareCall("{ call set_death_age(?, ?) }");

proc.setString(1, poetName);

proc.setInt(2, age);

cs.execute();

}catch (SQLException e){ // ....}

传给prepareCall方法的字串是存储过程调用的书写规范。它指定了存储过程的名称,?代表了你需要指定的参数。
和JDBC集成是存储过程的一个很大的便利:为了从应用中调用存储过程,不需要存根(stub)类或者配置文件,除了你的DBMS的JDBC驱动程序外什么也不需要。
当这段代码执行时,数据库的存储过程就被调用。我们没有去获取结果,因为该存储过程并不返回结果。执行成功或失败将通过例外得知。失败可能意味着调用存储过程时的失败(比如提供的一个参数的类型不正确),或者一个应用程序的失败(比如抛出一个例外指示在poets数据库中并不存在“Dylan Thomas”)

结合SQL操作与存储过程

映射Java对象到SQL表中的行相当简单,但是通常需要执行几个SQL语句;可能是一个SELECT查找ID,然后一个INSERT插入指定ID的数据。在高度规格化(符合更高的范式,译注)的数据库模式中,可能需要多个表的更新,因此需要更多的语句。Java代码会很快地膨胀,每一个语句的网络开销也迅速增加。
将这些SQL语句转移到一个存储过程中将大大简化代码,仅涉及一次网络调用。所有关联的SQL操作都可以在数据库内部发生。并且,存储过程语言,例如PL/SQL,允许使用SQL语法,这比Java代码更加自然。下面是我们早期的存储过程,使用Oracle的PL/SQL语言编写:

create procedure set_death_age(poet VARCHAR2, poet_age NUMBER)

poet_id NUMBER;

begin SELECT id INTO poet_id FROM poets WHERE name = poet;

INSERT INTO deaths (mort_id, age) VALUES (poet_id, poet_age);

end set_death_age;

很独特?不。我打赌你一定期待看到一个poets表上的UPDATE。这也暗示了使用存储过程实现是多么容易的一件事情。set_death_age几乎可以肯定是一个很烂的实现。我们应该在poets表中添加一列来存储逝世年龄。Java代码中并不关心数据库模式是怎么实现的,因为它仅调用存储过程。我们以后可以改变数据库模式以提高性能,但是我们不必修改我们代码。
下面是调用上面存储过程的Java代码:

public static void setDeathAge(Poet dyingBard, int age) throws SQLException{

Connection con = null;

CallableStatement proc = null;

try {

con = connectionPool.getConnection();

proc = con.prepareCall("{ call set_death_age(?, ?) }");

proc.setString(1, dyingBard.getName());

proc.setInt(2, age);

proc.execute();

finally {

try { proc.close(); }

catch (SQLException e) {}

con.close();

}

}

为了确保可维护性,建议使用像这儿这样的static方法。这也使得调用存储过程的代码集中在一个简单的模版代码中。如果你用到许多存储过程,就会发现仅需要拷贝、粘贴就可以创建新的方法。因为代码的模版化,甚至也可以通过脚本自动生产调用存储过程的代码。

Functions

存储过程可以有返回值,所以CallableStatement类有类似getResultSet这样的方法来获取返回值。当存储过程返回一个值时,你必须使用registerOutParameter方法告诉JDBC驱动器该值的SQL类型是什么。你也必须调整存储过程调用来指示该过程返回一个值。
下面接着上面的例子。这次我们查询Dylan Thomas逝世时的年龄。这次的存储过程使用PostgreSQL的pl/pgsql:

create function snuffed_it_when (VARCHAR) returns integer ''declare

poet_id NUMBER;

poet_age NUMBER;

begin

--first get the id associated with the poet.

SELECT id INTO poet_id FROM poets WHERE name = $1;

--get and return the age.

SELECT age INTO poet_age FROM deaths WHERE mort_id = poet_id;

return age;

end;'' language ''pl/pgsql'';

另外,注意pl/pgsql参数名通过Unix和DOS脚本的$n语法引用。同时,也注意嵌入的注释,这是和Java代码相比的另一个优越性。在Java中写这样的注释当然是可以的,但是看起来很凌乱,并且和SQL语句脱节,必须嵌入到Java String中。
下面是调用这个存储过程的Java代码:

connection.setAutoCommit(false);

CallableStatement proc = connection.prepareCall("{ ? = call snuffed_it_when(?) }");

proc.registerOutParameter(1, Types.INTEGER);

proc.setString(2, poetName);

cs.execute();

int age = proc.getInt(2);

如果指定了错误的返回值类型会怎样?那么,当调用存储过程时将抛出一个RuntimeException,正如你在ResultSet操作中使用了一个错误的类型所碰到的一样。

复杂的返回值

关于存储过程的知识,很多人好像就熟悉我们所讨论的这些。如果这是存储过程的全部功能,那么存储过程就不是其它远程执行机制的替换方案了。存储过程的功能比这强大得多。
当你执行一个SQL查询时,DBMS创建一个叫做cursor(游标)的数据库对象,用于在返回结果中迭代每一行。ResultSet是当前时间点的游标的一个表示。这就是为什么没有缓存或者特定数据库的支持,你只能在ResultSet中向前移动。
某些DBMS允许从存储过程中返回游标的一个引用。JDBC并不支持这个功能,但是Oracle、PostgreSQL和DB2的JDBC驱动器都支持在ResultSet上打开到游标的指针(pointer)。
设想列出所有没有活到退休年龄的诗人,下面是完成这个功能的存储过程,返回一个打开的游标,同样也使用PostgreSQL的pl/pgsql语言:

create procedure list_early_deaths () return refcursor as ''declare

toesup refcursor;

begin

open toesup for SELECT poets.name, deaths.age FROM poets, deaths -- all entries in deaths are for poets. -- but the table might become generic.

WHERE poets.id = deaths.mort_id AND deaths.age < 60;

return toesup;

end;'' language ''plpgsql'';

下面是调用该存储过程的Java方法,将结果输出到PrintWriter:
PrintWriter:

static void sendEarlyDeaths(PrintWriter out){

Connection con = null;

CallableStatement toesUp = null;

try {

con = ConnectionPool.getConnection();

// PostgreSQL needs a transaction to do this... con.

setAutoCommit(false); // Setup the call.

CallableStatement toesUp = connection.prepareCall("{ ? = call list_early_deaths () }");

toesUp.registerOutParameter(1, Types.OTHER);

toesUp.execute();

ResultSet rs = (ResultSet) toesUp.getObject(1);

while (rs.next()) {

String name = rs.getString(1);

int age = rs.getInt(2);

out.println(name + " was " + age + " years old.");

}

rs.close();

}

catch (SQLException e) { // We should protect these calls. toesUp.close(); con.close();

}

}

因为JDBC并不直接支持从存储过程中返回游标,我们使用Types.OTHER来指示存储过程的返回类型,然后调用getObject()方法并对返回值进行强制类型转换。
这个调用存储过程的Java方法是mapping的一个好例子。Mapping是对一个集上的操作进行抽象的方法。不是在这个过程上返回一个集,我们可以把操作传送进去执行。本例中,操作就是把ResultSet打印到一个输出流。这是一个值得举例的很常用的例子,下面是调用同一个存储过程的另外一个方法实现:

public class ProcessPoetDeaths{

public abstract void sendDeath(String name, int age);

}

static void mapEarlyDeaths(ProcessPoetDeaths mapper){

Connection con = null;

CallableStatement toesUp = null;

try {

con = ConnectionPool.getConnection();

con.setAutoCommit(false);

CallableStatement toesUp = connection.prepareCall("{ ? = call list_early_deaths () }");

toesUp.registerOutParameter(1, Types.OTHER);

toesUp.execute();

ResultSet rs = (ResultSet) toesUp.getObject(1);

while (rs.next()) {

String name = rs.getString(1);

int age = rs.getInt(2);

mapper.sendDeath(name, age);

}

rs.close();

} catch (SQLException e) { // We should protect these calls. toesUp.close();

con.close();

}

}

这允许在ResultSet数据上执行任意的处理,而不需要改变或者复制获取ResultSet的方法:

static void sendEarlyDeaths(final PrintWriter out){

ProcessPoetDeaths myMapper = new ProcessPoetDeaths() {

public void sendDeath(String name, int age) {

out.println(name + " was " + age + " years old.");

}

};

mapEarlyDeaths(myMapper);

}

这个方法使用ProcessPoetDeaths的一个匿名实例调用mapEarlyDeaths。该实例拥有sendDeath方法的一个实现,和我们上面的例子一样的方式把结果写入到输出流。当然,这个技巧并不是存储过程特有的,但是和存储过程中返回的ResultSet结合使用,是一个非常强大的工具。

结论

存储过程可以帮助你在代码中分离逻辑,这基本上总是有益的。这个分离的好处有:
&#8226; 快速创建应用,使用和应用一起改变和改善的数据库模式。
&#8226; 数据库模式可以在以后改变而不影响Java对象,当我们完成应用后,可以重新设计更好的模式。
&#8226; 存储过程通过更好的SQL嵌入使得复杂的SQL更容易理解。
&#8226; 编写存储过程比在Java中编写嵌入的SQL拥有更好的工具--大部分编辑器都提供语法高亮!
&#8226; 存储过程可以在任何SQL命令行中测试,这使得调试更加容易。

并不是所有的数据库都支持存储过程,但是存在许多很棒的实现,包括免费/开源的和非免费的,所以移植并不是一个问题。Oracle、PostgreSQL和DB2都有类似的存储过程语言,并且有在线的社区很好地支持。
存储过程工具很多,有像TOAD或TORA这样的编辑器、调试器和IDE,提供了编写、维护PL/SQL或pl/pgsql的强大的环境。
存储过程确实增加了你的代码的开销,但是它们和大多数的应用服务器相比,开销小得多。如果你的代码复杂到需要使用DBMS,我建议整个采用存储过程的方式。

posted @ 2006-10-11 14:37 康文 阅读(189) | 评论 (0)编辑 收藏

披着盛装的稻草人-- 编程中的随笔

1 不是使用了spring ,hibernate 等企业级产品的框架,我们就是企业级产品了。不是我们采用了新瓶装旧酒的web 2.0 我们就走在技术的前沿了。我门所需要的是一个高性能的,健壮的 产品,是一个可以降低我们实施成本,一个可以树立我们企业品牌的产品。在这里我不得不对我们产品的所谓的架构们产品疑问,Archetectures,what are you doing?

2 在实现框架代码的时候,当你对采用那种实现方式犹豫不决的时,换个角度,想一想如果你是程序员,喜欢怎么这些框架。在实现框架的时候一定要考虑程序员是否能够理解你写框架的思路,除非万不得已不要用一些自以为很高明很巧妙,然而却很晦涩难懂的方法,那样的框架,程序员至少合格的程序员是不愿意使用的。我想程序员和编码工人最大的区别就是程序员不仅要知其然,还要知其所以然。

3 只有在不断实践中,才能激发你不断的求知欲。只有把学到的知识不断的应用道实践中,你才能在学习中得到满足。不要为了学习而学习(学院派,不好听点就是纸上谈兵),而是要从实际问题出发,在解决问题的过程中不断深入,不断总结,所以说,当你离开了编程的第一线,你将失去学习编程知识的欲望。当然如果你愿意,在别的领域还有更广阔的天空,但是请不要总是说自己原来编程怎么怎么,其实你已经被三振出局了。

4 想外行一样思考,想专家一样实践,一本书的名字,虽然书没有看过,但她的名子就已经非常有意思了。这岂不就是我们作需求,和作架构时的座右铭吗?既能象“外行”一样的站在客户的角度思考问题,又能象“专家”一样参与到整个产品的开发和实施当中,在实践中不断提高自我。然而,不幸的是许许多多的所谓的架构师,系统分析员们却正向着相反的方向迈进。“真正”的做到了,象“专家”一样思考,象“外行”一样实践,可悲呀可悲。
5设计做到什么样才叫做到位呢。我想只有真正的开发者才有权利发言。只有有它们才是设计的真正使用者和受害者。因为就我所知和所见,绝大多数设计都是设计者自己的游戏(当然,我可能是井底之蛙了没有见过什么好的设计),程序员所开发往往还是对着原形自己再进行一遍设计,且不说额外增加了多少工作量,浪费了多少时间,就工作质量而言,也是差强人意。毕竟大多数情况下,设计者或称为架构师的在技术方面的经验都更为丰富,对业务的理解也更为深入,另外由一个人进行设计在功能复用,和整体性能方面的考虑也更完整一些。但怎么做才能熊掌和鱼兼得呢?下面我发表一下我个人的看法:
  1 代码就是最好的设计,这句话不是我说的,是 xp开发届 中的一位大牛说的。之所以在这里引用别人的观点,并不是自己是一个xp 的fans,也并不时完全赞同xp 的理论,我只是觉得这句话得太对了,对程序员来说什么设计比代码读起来更亲切呢?。其实设计无非是向开发所着传达设计者的思想,告诉开发者系统需要开什么个对象,具有什么属性和行为,它们之间的调用关系又如何。我们在设计文档中经常使用的方法就是有class 图,协作图,和顺序图对上面所提到的进行描述。然而结果呢,面对这大量的令人畏惧的抽象图表,开发者可选择的也只有是“重整江河待后生了”。想想,这样的设计和代码能够同步吗,这样的设计文档还有什么用呢?所以说与其是这样还不如把设计变成代码,如对象属性可以这直接在代码中体现,方法可以只定义接口,实现方式可以作为代码的注释,向写需求分析用例似的来一步一步说明程序是需要怎样调用。当客户要求设文档的时候,只需要提出javadoc就可以了,而其保证和代码同步。而开发者呢,在开发前需要阅读用例,了解需求,然后在设计者已经搭好的代码框架中进行开发就可以了。如果需要修改的话,不用在去设计文档中更改,只需要修改一下代码注释就可以了,(程序员是比较懒的,不怎么愿意写写文档的)。当然了,让懒惰的程序员能够自觉地写好文档也不是一件容易事,下面也许能给你提供一个好的方法
  2 交差开发能够帮助完成最好的设计文档。
  3 设计者在开发阶段还作什么呢?                 
待续                                                               

posted @ 2006-10-11 14:36 康文 阅读(233) | 评论 (0)编辑 收藏

仅列出标题
共7页: 上一页 1 2 3 4 5 6 7 下一页 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

导航

统计

常用链接

留言簿(1)

随笔分类

随笔档案

文章档案

搜索

最新评论

阅读排行榜

评论排行榜