01 Developing Successful Oracle Applications

  • You should do it in a single SQL statement if at all possible. And believe it or not, it is almost always possible.
  • If you can’t do it in a single SQL statement, do it in PL/SQL – as little PL/SQL as possible! Follow the saying that goes “more code = more bugs, less code = less bugs.”
  • if you can’t do it in PL/SQL, try a Java stored procedure. The itmes this is necessary are extremely rare nowadays with oracle9i and above.
  • if you can’t do it in Java, do it in a C external procedure. This is most frequently the approach when raw speed or using a third-parth API written in C is needed.
  • if you can’t do it in C external routine, you might want to seriously think about why it is you need to do it. –- 还是大师搞笑.

基本上 95% 的问题都可以通过 SQL, PL/SQL 解决.

看来, 连 developer 都需要了解 oracle 内部原理, 架构, 实现. 否则 oracle 就是个"黑盒”, 当你写 sql 语句时, 就可能出现问题.

With the database, you need to be aware of how it works but you don’t have to know everything inside and out.

bitmap index: bitmap 比如性别, 如果你使用bitmap索引, 当你插入新记录时, 比如你插入的记录在这个column的值是n, 那么在这个table中的所有的这个column 是 n 的列都会被 lock, 所以, 这时如果有人想要修改n到y, 那么在加锁时, 就会发现锁已经被占用, 从而进入等待.

Note: i will use autonomous transactions(自治事务) throughout(贯穿) this book to demonstrate locking, blocking, and concurrency issues. it is my firm belief that autonomous transactions are a feature that oracle should not have exposed to developers. Beyond using them as a demonstration tool, autonomous transactions have exactly one other use-as an error-logging mechanism.

看来这个自治事务只能在以下地方使用:

1) error-logging: 就是记录错误, 将错误信息保存在一个table 并且commit it, 自治事务的commit不会影响其他事务.

2) demonstrating concept: 即 用来 演示某些概念, 只是演示, 不能在生产库中进行. (比如演示两个事物锁的问题)

Bit-map 索引的问题, 注意如果删除了bitmap索引, 那么以下实验是成功的

create table t
( test_flag varchar2(1));

create bitmap index t_idx on t(test_flag);

insert into t values(‘N‘);

declare
pragma autonomous_transaction;
begin
    insert into t values(‘Y‘);
end;
/

实际上, 上边的例子, 我们创建B*Tree索引是很好的, 就不会出现这个问题.

When we created the index, we had to choose between the following approaches:
• Just create an index on the processed-flag column.

• Create an index only on the processed-flag column when the processed flag is N,

that is, only index the values of interest. We typically don’t want to use an index

when the processed flag is Y since the vast majority of the records in the table have

the value Y. Notice that I did not say “We never want to use….” You might want to

very frequently count the number of processed records for some reason, and then

an index on the processed records might well come in very handy.

上面说的, 只对 test_flag 这列的值等于 N 时创建的索引.

create index t_idx on t(decode(processed_flag, ‘N’, ‘N’));

80% ~ 90% 调优是在 application 层面

-- index for function
create table t
(     id    number primary key,
    test_flag    varchar2(1),
    payload        varchar2(20)
);

create index t_idx on t(decode(test_flag, ‘N‘, ‘N‘));    -- if test_flag == ‘N‘, return ‘N‘

insert into t
select r,
        case
        when mod(r, 2) = 0 then ‘N‘
        else ‘Y‘
        end,
        ‘payload ‘ || r
   from (select level r
           from dual
           connect by level <= 5)
/

select * from t;

create or replace function get_first_unlocked_row
return    t%rowtype
as
    resource_busy exception;
    pragma exception_init(resource_busy, -54);
    l_rec t%rowtype;
begin
    for x in (select rowid rid
                from t
               where decode(test_flag, ‘N‘, ‘N‘) = ‘N‘)
    loop
    begin
        select * into l_rec
          from t
         where rowid = x.rid and test_flag = ‘N‘
           for update nowait;
        return l_rec;
    exception
        when resource_busy then null;
        when no_data_found then null;
    end;
    end loop;
    return null;
end;
/

-- test function
declare
l_rec t%rowtype;
begin
    l_rec := get_first_unlocked_row;

    dbms_output.put_line(‘I got row ‘ || l_rec.id || ‘, ‘ || l_rec.payload);
    commit;
end;
/
-- 这条语句返回的结果是 , 2

declare
l_rec t%rowtype;
cursor c
is
select *
  from t
 where decode(test_flag, ‘N‘, ‘N‘) = ‘N‘    -- use decode function is for index
   for update
  skip locked;
begin
    open c;
    fetch c into l_rec;
    if (c%found)
    then
        dbms_output.put_line(‘I got row ‘ || l_rec.id || ‘, ‘ || l_rec.payload);
    end if;
    close c;
end;
/

-- 这条语句同样返回的结果是, 2

declare
l_rec t%rowtype;
pragma autonomous_transaction;
cursor c
is
select *
  from t
 where decode(test_flag, ‘N‘, ‘N‘) = ‘N‘    -- use decode function is for index
   for update
  skip locked;  -- 如果不使用这条语句, 那么整个这个过程就会被挂起, 等待
begin
    open c;
    fetch c into l_rec;
    if (c%found)
    then
        dbms_output.put_line(‘I got row ‘ || l_rec.id || ‘, ‘ || l_rec.payload);
    end if;
    close c;
    commit;
end;
/

-- 返回的结果是 4

How (and How Not) to Develop Database Applications

1. Understanding Oracle Architecture

2. Use a Single Connection in Oracle (多个查询共用1个连接 connnection)

对比sqlserver,

in SQL Server it is a very common practice to open a connection to the database for each concurrent statement you want to execute, If you are going to do five queries, you might well see five connections in SQL Server. but In Oracle,  if you want to do five queries or five hundred, the maximum number of connections you want to open is one.

3. Use Bind Variables

软解析与硬解析的对比, 另外如果不使用绑定变量时, 有可能出现 SQL INJECTION(SQL注入), 即当程序员在编写代码的时候, 没有对用户输入数据的合法性进行判断, 使应用程序存在安全隐患.

测试 sql injection

/*
 * This program will test SQL injection when you don‘t use bind variable.
 */

create or replace procedure inj(p_date in date)
as
    l_rec    all_users%rowtype;
    c        sys_refcursor;
    l_query    long;
begin
    l_query := ‘
        select *
          from all_users
         where created = ‘‘‘ || p_date || ‘‘‘‘;
        dbms_output.put_line(l_query);
        open c for l_query;

        for i in 1..5
        loop
                fetch c into l_rec;
                exit when c%notfound;
                dbms_output.put_line(l_rec.username || ‘.....‘);
        end loop;
        close c;
end;
/

-- you want to show
exec inj(sysdate);

-- show the dangerous part about this inj procedure
create table user_pw
( uname varchar2(30) primary key,
  pw varchar2(30)
);

insert into user_pw(uname, pw)
values(‘TKYTE‘, ‘TO SECRET‘);
COMMIT;
-- now, some user don‘t know user_pw table exist, simulation this table
-- +is very important.
grant execute on inj to scott;

-- so now, scott connect the database, and do as below
alter session set nls_date_format = ‘"‘‘union select tname, 0, null from tab--"‘;
exec leon.inj(sysdate);
/*
 * The result is:
 * -----------------------------------------
   select *
     from all_users
    where created = ‘‘union select tname, 0, null from tab--‘
 * -----------------------------------------
 * we know table information, some important table.
 */
-- in this way, scott can see the table user_pw(very important table)
-- now they want to try to select this important table.
select * from leon.user_pw;  -- but they can not, because they don‘t have privilege.

alter session set nls_date_format = ‘"‘‘union select tname || cname, 0, null from col--"‘;
exec leon.inj(sysdate);
/*
 * The result is:
 * -----------------------------------------
   select *
     from all_users
    where created = ‘‘union select tname || cname, 0, null from col--‘
 * -----------------------------------------
 * we know the column information in some important table.
 */

-- use bind variable to pertect you.
create or replace procedure NOT_inj(p_date in date)
as
    l_rec    all_users%rowtype;
    s        sys_refcursor;
    l_query    long;
begin
        l_query := ‘
        select *
          from all_users
         where created = :x‘;
        dbms_output.put_line(l_query);
        open c for l_query using P_DATE;
        for i in 1..5
        loop
                fetch c into l_rec;
                exit when c%notfound;
                dbms_output.put_line(l_rec.username || ‘....‘);
        end loop;
        close c;
end;
/

-- test not_inj
exec not_inj(sysdate);
/*
 * The result is:
 * -----------------------------------------
   select *
     from all_users
    where created = :x
 * -----------------------------------------
 */

-- so from now on, you must use bind variable. ^^

4. Understanding Concurrency Control

Concurrency issues are the hardest to track down; the problem is similar to debugging a multithreaded program.

locks are the mechanism that allows for concurrency.

If you or the database itself locks data unnecessarily, fewer people will be able to concurrently perform operations. Thus, understanding what locking is and how it works in your database is vital if you are to develop a scalable, correct application.

What is also vital is that you understand that each database implements locking differently.

The following points sum up Oracle’s locking policy:

• Oracle locks data at the row level on modification. There is no lock escalation to a block or table level.

• Oracle never locks data just to read it. There are no locks placed on rows of data by simple reads.

• A writer of data does not block a reader of data. Let me repeat: reads are not blocked by writes. This is fundamentally different from many other databases, where reads are blocked by writes. While this sounds like an extremely positive attribute (and it generally is), if you do not understand this thoroughly and you attempt to enforce integrity constraints in your application via application logic, you are most likely doing it incorrectly.

• A writer of data is blocked only when another writer of data has already locked the row it was going after. A reader of data never blocks a writer of data.

时间: 2024-08-29 11:42:17

01 Developing Successful Oracle Applications的相关文章

01 Developing Successful Oracle Application

本章提要-------------------------------本章是概述性章节1. 介绍了了解数据库内部结构对于开发的重要性2. 介绍了如何才能开发好的数据库应用程序-------------------------------1. 基本上 95% 的问题都可以通过 SQL解决, %5 PL/SQL 和 C 解决 自治事物的作用( 不推荐使用自治事物 )    1) error-logging: 记录错误, 无论你的transaction是否提交, 都需要知道你曾经做过的内容    2)

wsse:InvalidSecurity Error When Testing FND_PROFILE Web Service in Oracle Applications R 12.1.2 from SOAP UI (Doc ID 1314946.1)

wsse:InvalidSecurity Error When Testing FND_PROFILE Web Service in Oracle Applications R 12.1.2 from SOAP UI (Doc ID 1314946.1) Modified: 10-Nov-2013 Type: PROBLEM   In this Document   Symptoms   Cause   Solution   References Applies to: Oracle E-Bus

Globalization Guide for Oracle Applications Release 12

Section 1: Overview Section 2: Installing Section 3: Configuring Section 4: Maintaining Section 5: Using Section 6: Customizing Section 7: Translating Section 8: Troubleshooting Appendix A: Migrating to Unicode Appendix B: Locale Data Section 1. Over

Oracle Applications Multiple Organizations Access Control for Custom Code

文档 ID 420787.1 White Paper Oracle Applications Multiple Organizations Access Control for Custom Code Checked for relevance on 12-JAN-2011 See Change Record This document discusses how to update the customization code that is affected by the access co

Oracle E-Business Suite Maintenance Guide Release 12.2(Patching Procedures)

更多内容参考: http://docs.oracle.com/cd/E51111_01/current/acrobat/122ebsmt.zip Preparing for Patching For patches that have manual steps, the patch readme file instructs you to use Oracle Patch Application Assistant (PAA) to create customized instructions

安装oracle即时客户端

一.需求 数据库和应用没在同一台主机上,所以需要安装oracle即时客户端,也可以是oracle的客户端.只不过客户端比较庞大. 二.安装oracle即时客户端 下载Oracle即时客户端程序包 http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html 数据库版本是11.2.0.3.0 Instant Client Package - Basic: All files required

FNDCPASS Troubleshooting Guide For Login and Changing Applications Passwords

In this Document   Goal   Solution   1. Error Starting Application Services After Changing APPS Password Using FNDCPASS   2. Log In Fails With: You Don't Have Permission To Access /pls/.../fnd_icx_launch.launch On This Server   3. APP-FND-01564: ORAC

Part 2: Oracle E-Business Suite on Cloud FAQ

Running Oracle E-Business Suite on Oracle Cloud is simple, but it doesn't take too much effort to come up with several great questions about this new set of options.  We have published a document that answers those questions: Oracle E-Business Suite

ORACLE 11.2.0.1升级到11.2.0.3

ORACLE 11.2.0.1升级到11.2.0.3 最近听了李光老师的关于oracle的升级公开课,深有感悟,之前一直想自己测试的,没有下定决心,这几天自己在虚拟机上测试了一下,测试的过程如下,当然这个只是一些基本的步骤,实际的生产环境我想比这个复杂的多了,但是不用急,慢慢来,循序渐进吧... 1. 数据库情况 单实例非ASM存储 ORACLE_SID : orcl ORACLE_HOME: /u01/app/oracle/product/11.2.0/dbhome_1 1. 数据库原始状态