2006年8月2日
create user test1 identified by test1;
grant connect,create table to test1;
conn cyts_cc/cyts_cc@orcl2000;
create table(
id int)
tablespace user;
ERROR 位于第 1 行:
ORA-01950: 表空间'USERS'中无权限
conn cyts_cc/cyts_cc@orcl2000;
alter user test1 quota 1M on users;
create tab
(id int);
success
alter user test1 account lock;
conn test1/test1@orcl2000;
ERROR:
ORA-28000: the account is locked
1 Database Schema
a schema is a named collection of objects
b user is created and a corresponding schema is created
c user can be associated only with one schema
d username and schema are often userd interchangely.
2 Checklist for creating users
a idntfigy tablespaces in which the usr nedds to store objects
b decide on quotas for each tablespace
c assign a default tablespace and temporary tablespace.if you do not specify at the time of create user,system tablespace will be the defalut tablespace and temporary.it will affect the performance of the oralce.
d create user
e grant privileges and roles to user
desc dba_users;
select * from dba_users;
3 Creating a new user:
Database Authentiacation
set the initial password
create user aaron
identified by soccer
default tablespace data
temporary tablespace temp
guota 15m on data
password expire;
alter database default temporary tablespace temp;
4 Creating a new user operating System Authentication
os_authent_prefix initialllization parameter specifies the format of the username
defauts to ops$
create user arron
identified externally
default tablespace users
temporary tablespace temp
quota 15m on data
password expire;
conn /
show parameter os
os_authent_prefix string OPS$
create user ops$test3
identified externally
default tablespace us
temporary tablespace
quota 10m on users
thee test2 is an user of os ,which the oracle is installed.
5 Changing user quota on tablespace
alter user test3 quota 4m on users;
you cann't grant quota on temp and undotbs.
alter quota 0 on uers -- means that no new table space can be allocated and cannot change the exist object in the tablespaces
6 drop user
you cannot drop user who has connected to oracle
drop user (cascade)
7 Obtaining User information
information about uers can be obtained by qerying the data dictionary
dba_users
名称
-----------------------------
USERNAME
USER_ID
PASSWORD
ACCOUNT_STATUS
LOCK_DATE
EXPIRY_DATE
DEFAULT_TABLESPACE
TEMPORARY_TABLESPACE
CREATED
PROFILE
INITIAL_RSRC_CONSUMER_GROUP
EXTERNAL_NAME
dba_ts_quotas
名称
---------------
TABLESPACE_NAME
USERNAME
BYTES
MAX_BYTES
BLOCKS
MAX_BLOCKS
1 The Union Operator
The union operator returns results form both queries after eliminating duplications.\
select employee_id,job_id
from employees
uniion
select employ_id ,job_id
from job_history;
2 the all operator
The union all opertor reutrn result from both queries,including all duplications
3 interset
select ster_id,qty from sales where qty>20;
intersect
select ster_id,qty from sales where ster_id like '7%';
4 minus
select ster_id,qty from sales where qty>20
minus
select ster_id from sales where ster_id like '7%'
5 set operator guidelines
. teh expressions in the select list must match in number and data type;
. Parentheses can be used to alter the sequence of the execution
.The order by clause:
can appear only at the very end of the statement
will accept the column name,aliases from thee firest select statement ,or thee positional notation
.Duplicate row are atuomatically eliminated except in union all.
.Column names from the first query appear in the result
.The output is sorted in ascending order by default except in union all
6 matching the select statement
select department_id,to_number(null),location,hire_date
from employees
union
select department_id,location_id,to_date(null)
from departments;
select employee_id,job_id,salary
from employees
union
select employee_id,job_id,0
from job_history;
7 Controlling the order of the rows
select 'sing' as "my dream" ,3,a_dummy
from dual
union
select 'like''d like to teach',1
from dual
union
select 'the world to',2
from dual
order by 2;
1 开发过程
1) 建立过程:不带参数
create or replace procedure out_time
is
begin
dbms_output.put_line(systimestamp);
end;
a 使用execute 命令调用过程
set serveroutput on
exec out_time;
b 使用call 命令调用过程
set serveroutput on
call out_time();
2) 建立过程:带有in参数 默认为输入参数,另外也可以使用in 关键子显示的定义
create or replace procedure add_employee
(eno number,name varchar2,sal number,
job varchar default 'clerk',dno number)
is
e_integrity exception;
pragma exception_init(e_intgegrity,-2291);
begin
insert into emp(empno,ename,sal,job.deptno)
values(eno.name,sal,job,dno);
exception
when dup_val_on_index then
raise_application_error(-20000,'雇员号不能重复');
when e_integrity then
raise_application_error(-20001,'部门号不存在');
调用
exec add_employee(111,'clark',200,'manager',10);
3 建立过程,带有out 参数
create or replcace procedure query_employee
(eno number,name out varchar2,salary out number)
is
begin
select ename,sal,into name,salary from emp where empno=eno;
exception
when no_data_found then
raise_application_error(-20000,'G该雇员不存在');
end;
调用
var name varchar2(10)
var salary number
exec query_employee(7788,:name,:salary);
print name,salary;
4 建立过程,带有in out 参数
create or replace procedure compute
(num1,in out number,num2 in out number)
is
v1 number;
v2 number;
begin
v1:=num1/num2;
v2:=mod(num1,num2);
num1:=v1;
num2:=v2;
end;
调用
var n1 number
var n2 number
exec :n1:=100;
exec :n2:=30
exec compute(:n1,:n2)
print n1 n2
5) 为参数传递变量和数据 位置传递,名称传递,组合传递
create or replace procedure add_dept
(dno number,dname varchar2 default null,loc varchar default null)
is
begin
insert into dept values(dno.dname,loc);
end;
-- 位置传递
exec add_dept(50,'sales','new york');
exec add_dept(60);
exec add_dept(70,'admin');
-- 名称传递
exec add_dept(50,loc=>'new york');
exec add_dept(60,dname=>'sales',loc=>'new york');
6) 显示当前用户的所有程序及其源代码
select text from user_source where name='add_dept';
7) 删除过程
drop procedure add_dept;
2 开发函数
可以在sql语句和其他子过程中执行。
1 建立函数,不带任何参数
create or replace function get_user
return varchar2
is
v_user varchar2(100);
begin
select username into v_user from user_users;
return v_user;
end;
--使用变量接收函数返回值
var v2 varchar2(100)
exec :v1:=get_user
print v1;
-- 在sql 语句中直接调用函数
select get_user from dual;
-- 使用dbms_output 调用函数
set serveroutput on
exec dbms_output.put_line('get_user');
2) 建立函数,带有in 参数
create or replace function get_sal(name in varchar2)
reutnr number
as
v_sal emp.sal%type;
begin
select sal into v_sal from emp where upper(ename)=upper(name);
return v_sal;
exception
when no_data_found then
raise_application_error(-20000,'employee does not exist');
end;
3) 建立函数,带有out 参数
create or replace function get_info
(name varchar2,title out varchar2)
return varchar2
as
deptname dept.dname%type;
begin
select a,job,b,dname into title,deptname from emp a,dept b
where a.deptno=b.deptno
and upper(a.ename)=uppder(name);
return deptname;
end;
var job varchar2(20)
var dname varchar2(20)
exec :dname:=get_info('scott',job);
print dname job
4) 带有 in out 参数
create or replace function result
(num1,number,num2 in out nu8mber)
return number
as
v_result number(6);
v_remainder number;
begin
v_result:=num1/num2;
v_remainder:=mod(num1,num2);
num2:=v_remainder;
retrun v_result;
exception
when zero_divide then
raise_application_error(-20000,'zero divied');
end;
5) 函数调用的限制
-- 在sql 语句中只能调用存储函数
-- 在sql 语句中只能调用带有输入参数in ,而不能有输出参数out 和in out 参数的函数
-- 在sql 语句中调用的函数的参数必须是标准的sql 数据类型,不能是pl/sql 所特有的数据类型
-- 在sql 语句中调用的函数不能包含insert,update 和delete
6) 查看源代码
set pagesize 40
select text form user_source where name='result';
7) 删除函数
drop function result;
3 管理子程序
1) 列出当前用户的子程序
select object_name,created,status form user_objects
where object_type in ('procedure','function');
2)列出子程序源代码
select text from user_sorce where name='raise_salary'
3)类出子程序编译错误
-- show errors
--使用数据字典user_errors 确定错误原因和位置
select line||'/'||position as "line/col",text error
from user_errors where name='raise_salary';
4) 列出对象的依赖关系
-- 使用 user_dependenciess 确定直接依赖关系
select name,type from user_dependencies
where referenced_name='emp'
-- 使用 deptree 和 ideptree 确定依赖和见解依赖关系
select nested_level,name,type from deptree;
5) 重新编译子程序
当被应用对象的结构被修改以后,就会将相关依赖对象转变为无效invalid ,需要重新编译
1
alter table emp add remark varchar2(100);
2
select object_name,object_type from user_objects
where status='invalid'
3
alter procedure add_employee compile;
alter view dept10 compile;
alter function get_info compile;
1例外简介
1) 例外分类
预定义分类,非预定义分类,自定义例外。
2 处理预定义例外
1) 常用预定义例外
a access_into_null;
create type emp_type as object
(name varchar2(2),sal number(6,2));
declare
emp emp_type;
begin
emp.name:='scott';
exception
when access_into_null then
dbms_output.put_line('首先初始化对象emp');
b case_not_found
undef no
declare
v_val emp.sal%type;
begin
select sal into v_sal from emp where empno=&no;
case
when v_sal<1000 then
update emp set sal=sal+100 where empno=&no;
when v_sal<2000 then
update emp set sal=sal+150 where empno=&no;
when v_sal<3000 then
update emp set sal=sal+200 where empno=&no;
end case;
exception
when case_not_found then
dbms_output.put_line();
end;
c collection is null
在给集合元素(嵌套表或array类型)赋值前,必须首先初始化集合元素
declare type ename_table_type is table of emp.eanme%type;
ename_table ename_table_type;
begin
select e_name into ename_talbe(2) from emp where empno=$no;
exception
when collection_is_null then
dbms_output.put_lilne('必须使用构造方法初始化集合元素');
end;
d currsor_already_open
reopen curosr 如果用户已经使用了open 命令打开了显示游标,或执行for循环(隐式的打开游标)
delcare
cursor emp_surosr is select ename,sal,from emp;
begin
open emp_curosr;
for emp_record in emp_cursor loop
dbms_output.put_line(emp_record.eanme);
end loop;
exception
when cursor_already_open then
dbms_output.put_line("游标已经打开");
end;
e dup_val_on_index
begin
exception
when dup_val_on_index then
dbms_output.put_line("列上不能出现重复值");
end;
d invalid_curosr
delcare
curosr emp_cursor is select ename,sla from emp;
emp_record emp_crusor%rowtype;
begin
fetch emp_cursor into emp_record;
close emp_crusro;
exception
dbms_output.put_line("游标没有打开");
end;
f invalid_number can not convert char to nmuber successfully
begin
update mep set sal=sal+1oo;
exception
when invalid_number then
g no_data_found when select into is executed ,no row is returned
declare
v_sal emp.sal%type;
begin
select sal into v_cal form emp where lower(ename)=lower('&name');
exception
when no_data_found then
dbms_output.put_line('没有返回结果');
end;
h too_many_row ora -01422 there are too many are return when "select into" is executed
i zero_divide ora-01476
g subscript_beyond_count ora-065533
declare
type emp_array_type is varray(20) of varchar2(10);
emp_array emp_array_type;
begin
emp_array:=emp_array_type('scott','mary');
dbms_output.put_line('emp_array(3)');
exception
when subscript_beyone_count then
dbms_out.put_line('超出下标范围');
end;
k subscript_outside_limit
emp_array(-1);
l value_error the length of variable cannot contain the actual value;
declare
begin
end;
3 处理非预定义例外
delcare
e_integrity exception;
pragma exception_init(e_integrity,-2291);
begin
update emp set deptno=dno where empno=&no;
exception
when a_integrity then
end;
4 处理自定义例外
与oracle 错误没有任何联系,为业务逻辑所定义的例外
delcare
e_no_employee exception;
begin
update emp set deptno=&dno where empno=&eno;
if sql%notfound then
raise e_no_employee;
end if;
exception
when e_no_emplyee then
dbms_output.put_line('该雇员不存在');
5 使用错误例外函数
使用例外函数可以取得错误号以及相关的错误消息,sqlcode 用于取得oracle 的错误号,而sqlerrm
则用于取得与之相关的错误信息。
1 sqlcode 和 sqlerrm
为了在pl/sql 应用程序中处理其他为预料的到的oracle 错误,用户可以在例外处理部分的
when others 自句后,引用两个函数
declare
v_ename emp.ename%type;
begin
select ename into v_ename form emp where sal='&v_sal';
exception
when no_data_found then
when others then
dbms_output.put_line(sqlcode);
dbms_output.put_line(sqlerrm);
end;
2 raise_aaplicaition_error
只能在子程序中使用(过程,函数,包,触发器)
raise_application_error(error_number,message,[true|false]);
error_number 错误号,在-20000到-20999 之间
message 指定错误消息,不能超过2048
if v_comm is null then
raise_application_error(-20001,'该雇员无补助');
end if;
1建立包
1) 建立包规范: 用于定义包的公共组建,包括常量,变量,游标,过程和函数等
create or replace package emp_package is
g_deptno number(3):=30;
procedure add_employee(eno number,name varchar2,salary number dno number default g_deptno);
procedure fire_empoyee(eno number);
function get_sal(eno number) return number;
end emp_package;
2) 建立包体
用于实现包规范所定义的过程和函数。在包体中也可以单独定义私有组件,包括变量,常量,过程和函数等。但在包体中所定义的组件只能在包内使用,而不能由其他子程序引用。
create or replace package body emp_package is
function validate_deptno(v_deptno number)
return boolean;
is
v_temp int;
begin
select 1 into v_temp from dept where deptno=v_deptno;
return true;
exception
when no_data_found then
return false;
end;
procedure add_employee(eno number,name varchar2,salary number,dno number default g_deptno)
is
begin
if validate_deptno(dno) then
insert into emp(empno,ename,sal,deptno)
values(eno,name,salary,dno);
esle
raise_application_error(-20011,'部门不存在');
end if;
exception
when dup_val_on_index then
raise_application_error(-20011,'该雇员已存在')
end;
procedure fire_employee(eno number) is
begin
select from emp where empno=eno;
if sql%notfound then
raise application_error(-20012,'');
end if;
end;
function get_sal(eno number) return number
is
v_sal emp.sal%type;
begin
select sal into v_sal from emp where empno=eno;
return v_sal;
exception
when no_data_found then
raise_application_error(-200012,'');
end;
end emp_package;
3) 调用包组建
-- 在同一个包内调用组建 不需要加包名前缀,直接调用
create or replace paclage body emp_package is
procedure add_employee(eno number,name varchar2,salary number,dno number default g_deptno)
is
begin
validate_deptno(dno) then
exception
end;
-- 调用包公用变量
exec emp_package.g_deptno:=20
-- 调用公用过程
exec emp_package.add_employee(111,'mary,2000');
-- 调用远程数据库包的公用组件
exec
emp_paclage.add_employee@orasrv(1116,'scott',1200);
4) 查看包源代码
select text from user_source where name='emp_package' and type='package';
5) 删除包
drop packagee emp_package;
2 使用包重载
指多个具有相同名字的子程序,在调用的时候使用不同的参数传递。
1) 建立包规范
同名过程和函数必须具有不同的输入参数,但同名函数返回值的类型数据必须相同
create or replace package overload is
function get_sal(eno number) return number;
function get_sal(name varchar2) return number;
procedure fire_employee(eno number);
procedure fire_employee(name varchar2);
2) 建立包体
。。。
3) 使用包构造过程
初始化全局变量
1 建立包规范
create or replace packiage emp_package
is
minsal number(6,2);
maxsal number(6,2);
procedure upd_sal(eno number,salary number);
procedure upd_sal(name varhcar2,salary number);
end;-- 定义了两全局变量和三个公用过程
2 建立包体
create or replace package body emp_package is
procedure add_employee(cno number,name varchar2,salary number,dno number)
is
begin
if salary between minsal and maxsal then
insert into emp(empno,ename,sal,deptno)
........
-- 构造过程,位于子程序尾部,已begin 开始已end 结束
begin
select min(sal),max(sal) into minsal,maxsal from emp;
end;
end;
3 调用包公用组建
在同一次会话中第一次调用包的公用组建时,会自动执行其它构造函数,而将来调用其他组建时则不会再调用其构造过程。
4 使用纯度级别
1 家里包规范
create or replcace package purity is
minsal number(6,2);
maxsal number(6,2);
function max_sal return number;
function min_sal return number;
pragma restrict_references(max_sal,wnps);--wnps 不能修改包的变量(不能给包的变量赋值) --wnds 不能执行dml
pragma restrict_references(min_sal,wnps);--rnps 用于限制函数不能读取包变量
end;
1 What are Constrains
1) Constrains enforce on the table level
2) Constrains the deletion of a table if there are dependencies
2 Constrain Guidelines
1) Name a constraint or the oracle generate a name by the sys_cn format
2) Create a constraint either
--At the same time as the table is created.or
--After the table has been created
3)Define a constraint at the column or table level
4)view constraint in the data dictionary
3 Crete a constraint
create table test2
(id int not null,-- column level
lname varchar(20),
fname varchar(20),
constraint uk_test2_1 unique(lname,fname))--table level
4 The not null Constraint
create table employees(
employee_id number(6),
last_name varchar2(25) not null --system named
hire_date DATE
constraint emp_hire_date not null --User named
5Foreign key
create table test3
(rid int,
name varchar(30),
constraint fk_test3_1 foreign key(rid) reference test2(id));
froeign key constraint keywords
foreign key :Define the column in thee child table at the table constrain level.
references :Identifies the table and column in the parent table.
on delete cascade: Delete the dependent rows in the child table when a row in the parent table is deleted
on delete set null:Convert the dependent foreign key values to null when a row in the
parent table is deleted.
--parent table referenced table
--child table refernce other table
6 The check Constraint
Define a condition that each row must be satisfy
alter table test3
add constrain ch_test3 check(name like 's%')
7 Dropping a Constraint
1) Remove the manager constraint form the employee table
alter table test3
drop constriant test3_manager_fk
2) Remove the primary key constraint on the departments table and drop the associated
foreign key constraint on the employees.department_id column
alter table departments
drop primary key cascade
8 Disabling and enable Constraints
1)Execute the disable clause of the alter table statment to deactive an integrity constraint
2)Apply the cascade option to disable dependent integrity constrints
alter table employees
disable constraint emp_emp_id_pl cascade
3) enabling Constraints
.Active an integrity constraint currently disabled in the table definition by using the enable clause.
alter table employees
enable constraint emp_emp_id_pk;
a unique or a primary index is automatically created if you enable a unique key or a primary key constraint
8 View Constraints
select constraint_name,constriant_type,serch_condition
from user_constraints
where table_name='employees'
9 view the columns associated with constraints
select constraint_name,column_name
from user_cons_columns
where table_name='employees'
1Why Use Views
to restrict data access
to make complex query easy
to provide data independence
to provide defferent view of the same data
2 Creating a View
1)create [or replace] [force|noforce] view view
as subquery
force : create view wether the referenced object existed or not
desc view_name;
2)create a view by using column aliases in the subquery
create view salv50
as select employee_idIO_NUMBER,last_name NAME,slaary*12 ANN_SALARY
from employees
where department_id=50;
3 Modigy a View
1) Modigy the emplvu80 view by using create or replace view clause.Add an alias for each column name;
create or replace view empvu80
(id_number,name,sal,department_id)
as select employee_id,first_name||" "||last_name,salary.department_id
from employees
where department_id=80;
column aliases in the create view clause are listed in the same order as the columns in the subquery
note : alter view_name is not a valid command.
4 Create a Complex View
Create a complex view that contains group functions to display values from two tables
create view dept_sum_vu
(name,minsal,maxsal,avgsal)
as
select d.department_name,min(e.salary),max(e.salary),avg(e.salary)
from employees e,departments d
where e.department_id=d.department_id
group by d.department_name;
5 Rules for performs DML operaton on a view
1) You can perform DML operation on simple views
2) You can not romove a row if the view contains the following:
--group functions
--a group by clause
--the distinct keyword
-- rownum keyword
-- column defined by expressions
6 Using the with check option Clause
1) you can ensure that dml operatons performed on the view stay within the domain of the view by using the with check option clause.
create view test1
as
select * from emp where qty>10;
with check option;
update testview1 set qty=10
where ster_id=6830;
--when you doing the following update operation
update testview1 set qty=5 where id=10;
-- an error will report
--you violate the where clause
2)Any attempt to change the department number for any row in the view fails because it violates the with check option constraint
create or replace view empvu20
as
select * where department_id=20
with check option constriant empvu20_ck;
7 Denying DML Operations
1 You can ensure that no dml operations occur by adding the with read only option to your view definition.
2)Any attempt to a DML on any row in the view resuls in an oralce server error.
8 remove veiw
drop view_name
9 inline view
1) an inline view is a subquery with an alias that you can use within a sql statement.
2) a named subquery in the from clause of the main query is an exqmple of an inline view
3) an inline view is not a schema object.
10 Top-N Analysis
1)Top_N querise ask for the n largest or smallest values of a column.
2)Both largest values and smallest values sets considered Top-N queries
select * from (select ster_id,qty from sales);
example
To display the top three earner names and salaries from the employees
select rownum as rank,last_name,salary
from (select last_anme,slary from employee
order by slary desc)
where rownum<=3;
1 触发器简介
1) 触发事件
2) 触发条件
3) 触发操作
. 触发器代码的大小不能超过32k,如果使用大量代码建立触发器,应该先建立存储过程,然后再触发器中使用call语句调用存储过程。
. 触发器中正能含有select ,insert,update 和delete 语句,而不能含有ddl 语句,和事物控制语句。
2 建立dml 触发器
1) 触发时机
before,after 表示在执行dml操作之后触发器
2)触发事件
insert ,update 和delete 操作。也可以使用书法事件
3) dml 触发器是针对特定表进行的 因此必须制定dml 操作所对应的表
4) 触发器类型 用于指定当触发器事件之后,需要执行几次触发器操作。如果指定语句触发器类型
那么会执行一次触发器代码:如果指定行触发器类型,则会在每个被作用行上执行一次触发器代码。
5) 触发条件
用于指定执行行触发器代码的条件,只有为ture时,才会执行行触发器代码。
6) 如果使用pl/sql 存储过程,java 存储过程,或外部处处过程需要在触发器操作部分直接使用call
7) dml 触发器触发顺序
(1)dml 触发器在单行数据上的触发顺序。
对于单行数据而言,无论是语句此触发器,还是行触发器,触发器代码实际只执行一次,并且执行
顺序为before 语句触发器,before 行触发器,dml 操作,after 行触发器,after 语句触发器
(2) dml 触发器在多行数据上的触发顺序
before 语句触发器
before 行触发器
after 行触发器
before行触发器
after 行触发器
after语句触发器
语句触发器只被执行一次,而行触发器在每个行上都执行一次。
2) 语句触发器
当审计dml 操作,或确保dml操作安全执行时,可以使用语句触发器
1 建立before 语句触发器
create or replace trigger tr_sec_emp
before insert or update or delete on emp
begin
if to_char(sysdate,'DY','nls_dtate_language=AMERICAN') in ('sat','sun') then
railse_application_error(-200001,'不能在休息日改变雇员信息');
end if;
end;
2 使用条件谓词
inserting ,updating ,deleting
create or replace trigger tr_sec_emp
before insert or update or delete on emp
begin
if to_char(sysdate,'DY','nls_date_language=american')
in('sat','sun') then
case
when inserting then
raise_application('-20001','inserting');
when updating then
raise_application('-20002','updating');
when deleting then
raise_application('-20003','deleting');
end case;
end if;
end;
3 建立after 语句触发器
为了dml 操作,或者dml 操作后执行汇总运算
create table aduit_table(
name varchar2(20),ins int,upd int,del int,
starttime date,endtime date
);
create or replace trigger tr_aduit_emp
after insert or update or delete emp
declare
v_temp int;
begin
select count(*) into v_temp from aduit_table
where name='emp';
if v_temp=0 then
insert into audit_table values
('emp',0,0,0,sysdate,null);
end if;
case
when inserting then
update aduit_table set ins=ins+1,endtime=sysdate where name='emp';
when updating then
update audit_table set upd=upd+1,endtime=sysdate where name='emp';
when deleting then
update aduit_table set del=del+1,endtime=sysdate where name='emp';
end;
3) 行触发器
审计数据变化可以使用行触发器
1 建立不before 行触发器
为了取保数据符合商业逻辑或企业规则,对输入的数据进行复杂的约束,可以使用before行触发器
create or replace trigger tr_emp_sal
before update of sal on emp
for each row
begin
if :new.sal<:old.sla then
raisse_application_error(-200010,'工资只涨不降');
end if;
end;
2) 建立after 行触发器
为了审计dml 操作,可以使用语句触发器或oracle 系统提供的审计功能,而为了审计数据变化
,则应该使用after 行触发器
create table audit_emp_change(
name varchar2(10),odl number(6,2),
newsal number(6,2),time date);
create or replace trigger tr_sal_change
after update of sal on emp
for each row
declare
v_temp int;
begin
select count(*) into v_temp from audit_emp_change where name=:old.ename;
if v_temp =0 then
insert into audit_emp_change
values(:old,ename,:old.sal,:new,sal,sysdate);
else
update audit_emp_change
set oldsal=:old.sal,newsal=:new.sal,time=sysdate where name=:old.ename;
end if;
end;
)
3) 限制行触发器
当使用行触发器,默认情况下会咱每个被作用行上七星一次触发器代码,为了时得再特定条件下执行行触发器代码,需要使用when 子句
create or replace trigger tr_sal_change
after update of sal on emp
for each row
when(old.job='salesman')
declare
v_temp int..
2 dml 触发器使用注意事项
触发器代码不能从触发器所对应的基表中读取数据
3 dml 触发器
为了保证数据库满足特定的商业规则或企业逻辑,可以使用约束,触发器和子程序。约束性能最好,实现最简单,所以为售选,如果触发器不盟实现,可以选择触发器。
dml 触发器可以用于实现数据安全保护,数据审计,数据完整性,参照完整性,数据复制等功能。
1) 控制数据安全
create or replace trigger tr_emp_time
before insert or update or delete on emp
begin
if to_char(sysdate,'hh24') not between '9' and '17' then
raise_application_error(-20101,'not work time');
end if;
end;
2) 实现数据审计
使用数据审计只能审计sql 操作,而不会记载数据变化
audit insert,update,delete on emp by access
3)实现数据完整性
首选约束 alter table emp add constraint ck_sal check (sal>=800),但是在有些情况下只能使用触发器来实现数据完整性
create or replace trigger tr_check sal
before update of sal on emp
for each row
when (new.sla<old.sal or new.sal>1.2* old.sal)
begin
raise_application_error(,,,,,,)
end;
3) 使用引用完整性
采用 on delete cascade 可以进行集联删除,但是却不能进行集联更新。采用触发器实现集联更新
create or replace trigger tr_update
after update of sal on emp
for each row
begin
update emp set depno=:new.deptno where dentno=:old.deptno;
end;
4 建立instead of 触发器
对于简单视图可以直接进行insert update 和delete 等操作,但是对于复杂视图不允许进行insert,update 和delete 操作。
满足一下条件的为复杂视图
具有操作集合符 union,union all ,intersect,minus
具有分组函数 min,max,avg,sum,count
具有group by connect 编译 或start with
具有distinct
具有连接
为了在复杂视图上执行dml 操作,必须要基于instead-of 触发器,建立instead-of 触发器后,就可以基于复杂视图执行insert,update和delete 语句。
instead of 选项只使用于视图
基于视图建立触发器时,不能定义before 和 after
在建立视图时不能指定 with check option
当建立instead of 触发器时,必须指定for each row 选项
1) 建立复杂视图dept_emp
create or replace view dept_emp as
select a.deptno,a.dname,b,empno,b,ename
from dept a,emp b
where a,deptno=b.deptno;
2) 建立 instead-of 触发器
create of replacee trigger tr_instead_of_dept_emp
instead of insert on dept_emp
for each row
declare
v_temp int;
beegin
select count(*) into v_temp from dept where deptno=:new.deptno;
if v_temp=0 then
insert into dept(deptno,dname) values(:new.deptno,:new.dname);
end if;
select count(*)into v_temp from emp where empno=:new.empno;
if v_temp=0 then
insert into emp(empno,ename,deptno)
values(:new.deptno,:new.ename,:new.deptno);
end if;
end;
可以对视图执行insert 操作了
insert into dept_emp values(50,'admin','1223','mary')
5 管理触发器
1) 显示触发器信息
select trigger_name,status from user_triggers
where table_name='emp';
2)禁止触发器
alter trigger tr_check_sal disable;
3) 激活触发器
alter trigger tr_check_sal enable;
4) 禁止或激活表上的所有触发器
alter table emp disable all triggers;
alter table emo eanble all triggers;
5)重新编译触发器
alter trigger tr_check_sal compile;
6) 删除触发器
drop trigger tr_check_sal;
1 pl/sql 集合 处理单列多行数据库,使用的类型为标量类型
1)索引表
type ename_table_type is table of emp.ename%type
index by binary_integer;
ename_table ename_table_type;
begin
select ename into ename_table(-1) from emp
where empno=&no;
dbms_output.put_line('雇员名:'||ename_table(-1));
end;
set serveroutput no
declare
type area_table_type is table of number
index by varchar2(10);
rea_table area_table_type;
begin
area_table('beijing'):=1;
area_table('shanghai'):=2;
area_table('guangzhou'):=3;
dbms_output.put_line(area_table.first);
dbms_output.put_line(area_table.last);
end;
2) 嵌套表
索引表类型不能作为累得数据类型使用,但是嵌套表可以作为表类的数据类型使用。
当使用嵌套表元素时,必须先用其构造方法初始化其嵌套表:
a 在pl/sql 块中使用嵌套表
declare
type ename_table_type is table of emp.ename%type;
ename_table ename_table_type;
begin
ename_table:=eanme_table_type('2','2','3');
select ename into ename table(2) from emp where empno=&no;
dbms_ouput.put_line(ename_table(2));
end;
b 在表中使用嵌套表
create type phone_type is table of varchar2(20);
create table employee(
id number (4),name varchar2(10),sal number(6,2),
phone phone_type
)nested table phone store as phone_table;
-- 为嵌套表插入数据
insert into employee values(2,'scott',200,phone_type('2222','333333'));
--检索嵌套表累得数据
set serveroutput on
declare
phone_table phone_type;
begin
select phone into phone_table
from employee where id=1;
for i in 1..phone_table.count loop
dbms_output.put_line(phone_table(i));
end loop;
end;
-- 更新嵌套表列的数据
delcare
phone_table phone_type:=('44444','555555');
begin
update employee set phone=phone_table
where id=1;
end;
3) 变长数组
在使用varray 时必须指定最大个数,和数据类型,在使用其元素时必须进行初始化
type ename_table_type is varray(20) of emp.ename%type;
ename_table ename_table_type:=ename_table_type('1','2');
-- 在快中使用varray
declare
type ename_table_type is varray(20) of emp.ename%type;
ename_table ename_table_type:=ename_table_type('mary');
begin
select ename into ename_table(1) form emp
where empno=&no;
end;
--在表列中使用varray
create type phone type is varray(20) of varchar2(20);
create table employee(
id number(4),name varchar2(10),
sal number(6,2),phone phone_type);
3)记录表
记录表结合了记录和集合的优点
declare
type emp_table_type is table of emp%rowtype
index by binary_integer;
emp_table emp_table_type;
begin
select * from into emp_table(1) from emp
where empno=&no;
dbms_output.put_line(emp_table(1).ename);
end;
4)多维集合
1 多级varray
declare
--define 一维集合
type al_array_type is varray(10) of int;
--定义二维集合
type nal_varray_type is varray(10) of a1_varray_type;
--初始化二维集合
nvl nal_varray_type:=nal_varray_type(
a1_varray_type(1,2),
a1_varray_type(2,3)
)
beign
for i in 1..nal_varray_type.count loop
for j in 1..a1_array_type.count loop
dbms_out.putline(nvl(i)(j));
end loop;
end loop;
end;
2 使用多级嵌套表
table a1_table_type is table of int;
table nvl_table_type is table of a1_table_type;
nvl nvl_table_type:=nvl_table_type(
a1_table_type(1,2),
a1_table_type(2,3)
);
2 集合方法
1) exist
if ename_table.exists(1) then
ename_table(1):='scott';
2) count 返回当前集合变量中的元素总个数
ename_table.count
3) limit 返回集合元素的最大个数 只有varray 有
4)first and last
ename_table.first
ename_table.last
5) prior 和next
ename_table.prior(5); --返回元素5的前一个
ename_table.next(5); -- 后一个
6) extend
使用于varray 和 嵌套表。
extend add a null value
extend (n) add n null value
extend (n,i)add n i value
declare
type ename_table_type is varray(20) of varchar2(20);
ename_table ename_table_type;
begin
ename_table:=ename_table_type('mary');
ename_table.extend(5,1);
dbms_output.put_line(ename_table.count);
end;
7) trim
trim remove one element from the tail of the collection.
trim(n) remove n element from the tail of the colleciton.
8)delete
delete: delete all the elements
delete(n) :delete the nth elements
delete(m,n): delete the elements from m to n
3 集合赋值
1)将一个集合的数据赋值给另一个集合.clear the destination collectins and set the original collection
delcare
type name_varray_type is varray(4) of varchar2(10);
name_array1 name_varray_type;
name_array2 name_varray_type;
begin
name_array1:=name_varray_type('scott','smith');
name_array2:=name_array_type('a','b','c');
name_array1:=name_array2;
end;
type name_array1_type is varray(4) of varchar2(10);
type name_array2_type is varray(4) of varchar2(10);
name_array1 name_array1_type;
name_array2 name_array2_type;
具有相同的数据类型,单具有不同的集合类型不能构赋值
2) 给集合赋城null 值
可以使用delete 或 trim
也可以使用 空集合赋给目表集合
type name_varray_type is varray(4) of varchar2(10);
name_array name_varray_type;
name_empty name_varray_type;
name_array:=name_varray_type('1','2');
name_array:=name_empty;
3) 使用集合操作赋和比较集合都是10g 的内容,p176 先略过。
4 批量绑定
执行单词sql 操作能传递所有集合元素的数据。
1 forall 语句
用于insert update 和delete操作。在oracle9i 中forall 语句必须具有连续的元素
1) using forall on insert
declare
type id_table_type is table of number(6)
index by binary_integer;
type name_table_type is table of varchar2(2)
index by binary integer;
id_table id_table_type;
name_table name_table_type;
begin
for i in 1..10 loop
id_table(i):=i;
name_table(i):='Name'||to_char(i);
end loop;
forall i in 1..id_table.count
insert into demo values(id_table(i),name_table(i));
end;
2)using forall on using update
forall i in 1..id_table.count
upate demo set name:=name_table(i)
where id:=id_table(i);
3)using forall on using delete
forall i in 1..id_table.count
delete from demo where id:=id_table(i);
4) using forall on part of the collection
for i in1..10 loop
id_table(i):=i;
name_table(i):="name"||to_char(i);
end loop;
forall i in 8..10 l
insert into demo values(id_table(i),name_table(i));
2 bulk collect
is fit for select into ,fetch into and dml clause
1) using bulk collect
declares
type emp_table_type is table of emp%rowtype
index by binary_integer;
emp_table emp_table_type;
begin
select * bulk collect into emp_table
from emp where deptno=&no;
for i in 1..emp_tablee.count loop
dbms_output.put_line(emp_table(i).ename);
end loop;
2) 在dml 的返回字句使用bulk collect 字句
declare
type ename_table_type is table of emp.ename%type;
ename_table ename_table_type;
begin
deletee from emp where deptno=&no
returning ename bulk_collect into ename_table;
for i in 1..ename_table.count loop
dbms_output.put(ename_table(i));
end loop;
end;
end;
end;
1 subquery: is a select statement embedded in other sql statement.
.the subquery execute (inner query) once before the main query
.the result of the subquery is used by the main query.
2 pairwise comarison subquery
select * from employee
where (manager_id,department_id) in
(select manager_id,department_id
from employees
where employee_id in (178,174))
and employee_id not in (178,174);
nonpairwise comparison subquery
select employee_id,manager_id,department_id
from employee
where manager_id in
(select manager_id
from employees
where employee id in (174,141))
and department_id in
(select department_id
from employees
where employee_id in (174,141))
and employ_id not in (174,141);
)
3 using a subquery in the from clause
select a.last_name,a,salary,b.slaavg
from employees a ,(select department_id,
avg(salary) salavg
from employees
group by department_id) b
where a.department_id=b.department_id
and a.salary>b.salavg;
4 scalar subquery expressions
. a scalar subquery expression is a subquery that return exactly on column value from one row
. in oracle8i scalar subqueries can be used in condition and expression part and all clause.
1) sclaar subqueries in casse expression
select employee_id ,last_name,
(case
when department_id=
(select department_id from departments
where location_id=1800)
then 'canada'
else 'usa'
end) location
from employees
2)scalar subqueries in order by clasue
select employee_id,last_name
from employees e
order by (select department_name
from departments d
where e.department_id=d.department);
4 correlated subqueries
the wubquery references a column form a table in the parment query
select column1,solumn2....
from table1 outer
where column1 operator
(select column1,column2
from table2
where expr1=out.expr2);
e.g 1
select last_name,salary,department_id
from employees outer
where salary>
(select avg(salary)
from employees
where department_id=
outer.department_id);
)
e.g 2
display details of those employees who have switched jobs at lease twice
select e.employee_id,last_name,e.job_id
from employees e
where 2<=(select count(*)
from job_history
where employee_id=e.employee_id);
6 using the exists operator
. the exists operator tests for existencee of rows in the results set of the subquery
. if a subquery row value id found:
the search does not continue in the inner query
the condition is flagged true
.if a subquery row value is not fount
the condition is flagged fasle
the search continues in the inner query
e.g
find employees who have at least one person reporting to them
select employee_id,last_name,job_id,department_id
from employees outer
where exists (select count(*)
from employees
where manager_id=outer.employee_id);
not exist.
7 corelated update
use a correlated subquery to update rows in on table based on rows from another table
e.g
--denormalize the employees table by adding a column to store the department name
alter table employees
add(department_name varchar2(14));
--populate the table by using a correlated update
update employees e
set department_name=
(select department_name
from departments d
where e.departmentid=d.department);
8 correlated delete
delete test1 t1
where ster_id in(select ster_id form sales t2 where t.ster_id=t2.ster_id);
9 using the with clause ,you can use the same query block in a a select statement when it cocurs more than once within a complex query
the with clause retrieves the results of a query block and stores it in the user's the user's templary tablespace
the with clause improves performance.
e.g
with
dept_costs as(
select d.department_name,sum(e.salary) as dept_total
from employee e,departments d
where e,department_id=d.department_id
group by d.department_name),
avg_cost as(
select sum(dept_total)/count(*) as dept_avg
from dept_cost)
select *
from dept_costs
where dept_total>(select dept_avg
from afb_cost)
order by department_name;
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;
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
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;
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)
)
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'
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();
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;
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( );
}
本文阐述了怎么使用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结合使用,是一个非常强大的工具。
结论
存储过程可以帮助你在代码中分离逻辑,这基本上总是有益的。这个分离的好处有:
• 快速创建应用,使用和应用一起改变和改善的数据库模式。
• 数据库模式可以在以后改变而不影响Java对象,当我们完成应用后,可以重新设计更好的模式。
• 存储过程通过更好的SQL嵌入使得复杂的SQL更容易理解。
• 编写存储过程比在Java中编写嵌入的SQL拥有更好的工具--大部分编辑器都提供语法高亮!
• 存储过程可以在任何SQL命令行中测试,这使得调试更加容易。
并不是所有的数据库都支持存储过程,但是存在许多很棒的实现,包括免费/开源的和非免费的,所以移植并不是一个问题。Oracle、PostgreSQL和DB2都有类似的存储过程语言,并且有在线的社区很好地支持。
存储过程工具很多,有像TOAD或TORA这样的编辑器、调试器和IDE,提供了编写、维护PL/SQL或pl/pgsql的强大的环境。
存储过程确实增加了你的代码的开销,但是它们和大多数的应用服务器相比,开销小得多。如果你的代码复杂到需要使用DBMS,我建议整个采用存储过程的方式。
1 不是使用了spring ,hibernate 等企业级产品的框架,我们就是企业级产品了。不是我们采用了新瓶装旧酒的web 2.0 我们就走在技术的前沿了。我门所需要的是一个高性能的,健壮的 产品,是一个可以降低我们实施成本,一个可以树立我们企业品牌的产品。在这里我不得不对我们产品的所谓的架构们产品疑问,Archetectures,what are you doing?
2 在实现框架代码的时候,当你对采用那种实现方式犹豫不决的时,换个角度,想一想如果你是程序员,喜欢怎么这些框架。在实现框架的时候一定要考虑程序员是否能够理解你写框架的思路,除非万不得已不要用一些自以为很高明很巧妙,然而却很晦涩难懂的方法,那样的框架,程序员至少合格的程序员是不愿意使用的。我想程序员和编码工人最大的区别就是程序员不仅要知其然,还要知其所以然。
3 只有在不断实践中,才能激发你不断的求知欲。只有把学到的知识不断的应用道实践中,你才能在学习中得到满足。不要为了学习而学习(学院派,不好听点就是纸上谈兵),而是要从实际问题出发,在解决问题的过程中不断深入,不断总结,所以说,当你离开了编程的第一线,你将失去学习编程知识的欲望。当然如果你愿意,在别的领域还有更广阔的天空,但是请不要总是说自己原来编程怎么怎么,其实你已经被三振出局了。
4 想外行一样思考,想专家一样实践,一本书的名字,虽然书没有看过,但她的名子就已经非常有意思了。这岂不就是我们作需求,和作架构时的座右铭吗?既能象“外行”一样的站在客户的角度思考问题,又能象“专家”一样参与到整个产品的开发和实施当中,在实践中不断提高自我。然而,不幸的是许许多多的所谓的架构师,系统分析员们却正向着相反的方向迈进。“真正”的做到了,象“专家”一样思考,象“外行”一样实践,可悲呀可悲。
5设计做到什么样才叫做到位呢。我想只有真正的开发者才有权利发言。只有有它们才是设计的真正使用者和受害者。因为就我所知和所见,绝大多数设计都是设计者自己的游戏(当然,我可能是井底之蛙了没有见过什么好的设计),程序员所开发往往还是对着原形自己再进行一遍设计,且不说额外增加了多少工作量,浪费了多少时间,就工作质量而言,也是差强人意。毕竟大多数情况下,设计者或称为架构师的在技术方面的经验都更为丰富,对业务的理解也更为深入,另外由一个人进行设计在功能复用,和整体性能方面的考虑也更完整一些。但怎么做才能熊掌和鱼兼得呢?下面我发表一下我个人的看法:
1 代码就是最好的设计,这句话不是我说的,是 xp开发届 中的一位大牛说的。之所以在这里引用别人的观点,并不是自己是一个xp 的fans,也并不时完全赞同xp 的理论,我只是觉得这句话得太对了,对程序员来说什么设计比代码读起来更亲切呢?。其实设计无非是向开发所着传达设计者的思想,告诉开发者系统需要开什么个对象,具有什么属性和行为,它们之间的调用关系又如何。我们在设计文档中经常使用的方法就是有class 图,协作图,和顺序图对上面所提到的进行描述。然而结果呢,面对这大量的令人畏惧的抽象图表,开发者可选择的也只有是“重整江河待后生了”。想想,这样的设计和代码能够同步吗,这样的设计文档还有什么用呢?所以说与其是这样还不如把设计变成代码,如对象属性可以这直接在代码中体现,方法可以只定义接口,实现方式可以作为代码的注释,向写需求分析用例似的来一步一步说明程序是需要怎样调用。当客户要求设文档的时候,只需要提出javadoc就可以了,而其保证和代码同步。而开发者呢,在开发前需要阅读用例,了解需求,然后在设计者已经搭好的代码框架中进行开发就可以了。如果需要修改的话,不用在去设计文档中更改,只需要修改一下代码注释就可以了,(程序员是比较懒的,不怎么愿意写写文档的)。当然了,让懒惰的程序员能够自觉地写好文档也不是一件容易事,下面也许能给你提供一个好的方法
2 交差开发能够帮助完成最好的设计文档。
3 设计者在开发阶段还作什么呢?
待续
1Privilgeges
1) Database security:
--System security
--Data security
2)System privileges:Caining access to the database
3)Object privileges:manipulationg thee content of the database objects
4)Schemas:Collections of objects ,such as tables,views,and sequences
2System Privileges
. More than 100 privileges are available;
. The database administrator has high-levle system privileges for tasks such as:
creating new user,removing user,removing tables,backing up tables
3 Creating user
the dba creates users by using the create user statement
create user user
identified by password;
e.g create user object scott
identified by tiger;
SQL> create user testuser
2 identified by test;
User created
SQL> conn testuser/test@orcl2000
Not logged on
SQL> grant access session to testuser;
grant access session to testuser
Not logged on
SQL> conn digit_cc/digit_cc@orcl2000
Connected to Oracle9i Enterprise Edition Release 9.2.0.1.0
Connected as digit_cc
SQL> grant create session to testuser;
Grant succeeded
SQL> conn testuser/test@orcl2000;
Connected to Oracle9i Enterprise Edition Release 9.2.0.1.0
Connected as testuser
4 user System privileges
once a user is created,the dba can grant specific system privileges to a user
grant privilege[,privilege...]
to user [,user|role,public...];
DBA can grant a user specific system privileges
grant create session,create table,create sequence,create view to scott;
5 creating and granting privileges to role
' Create a role
create role manager;
.grant privileges to a role
grant create table,create view to manager
.Grant a role to user
grant manager to kochar;
SQL> create role testrole;
Role created
SQL> grant create table,create view,create sequence to testrole;
Grant succeeded
SQL> grant testrole to testuser;
6 change your password
you can change your password by using the alter user statement;
alter user scott
indetified by lion;
7 object privileges
object privileges vary from object to object
an owner has all the privilege to the object
an owner can give specific privilege on that owner object
grant select on auther to testuser;
grant select on outher to testuser with grant option -- testuser also can grant it to
other user;
grant update(department_name,location_id)
on departments
to scott,manager;
8 how to revoke object privileges
--you use the revoke statement to revoke privileges granted to other users
--privileges granted to other users through the with grant option clause are also revoked.
revoke privilege {[,privilege...]|all} on object
from {user[,user....]|role|public}
[cascade constraints]
revoke select on author from user;
9 Database Links
Database link allow user to access data in the remote database;
SQL> create database link kjw1
2 connect to digit_cc identified by digit_cc
3 using 'orcl2000';
Database link created
SQL> select * from digit_cc.table_action@kjw1;
链接到远程数据库
在一个分布式的环境里,数据库链接是定义到其它数据库的路径的一个重要方法,使得远程处理天衣无缝。
要获得数据库链接的更深奥的知识,查看Oracle8i SQL Reference(Oracle8i SQL参考)和Oracle8i Concepts (Oracle8i概念手册)。详细资料的另一个极好的来源是Oracle8i Distributed Database Systems(Oracle8i分布式数据库系统手册)。
今天许多运行Oracle的机构有不止一个Oracle数据库。有时不管原计划是否这样,一个数据库中的数据可能与另一数据库中的数据关联。出现这种情况时,你可以链接这两个数据库使得用户或应用程序可以访问所有数据,就好象它们在一个数据库中。当你这么做时,你就有了一个分布式数据库系统。
如何将两个数据库链接在一起呢?使用一个数据库链接来完成。数据库链接是定义一个数据库到另一个数据库的路径的对象。数据库链接允许你查询远程表及执行远程程序。在任何分布式环境里,数据库链接都是必要的。
简单案例
数据库链接的目的是定义一条到远程数据库的路径,使你可以通过在本地执行一条SQL语句来使用那个数据库中的表和其它的对象。例如,你在一个远程数据库上有一个称之为"geographic feature name"的表,而你想在已连接到你本地数据库的情况下访问那些数据。数据库链接正是你所需要的。在建立它之前,你必须搜集如下信息:
一个网络服务名称,你的本地数据库事例能够使用它来与远程事例相连接远程数据库上的有效用户名和口令网络服务名称是每一个数据库链接必需的。每一次你从客户机PC使用SQL*Plus连接到你的数据库时都要使用服务名称。在那些情况下,你提供给SQL*Plus的网络服务名称是通过在你的客户机上的nsnames.ora文件中查找它们来解析的。在数据库链接中使用的网络服务名称也是如此,除非是那些名字是使用驻留在服务器上的tnsnames.ora文件来解析。
在你定义数据库链接时指定的用户名和口令,用于建立与远程事例的连接。不需硬编码用户名和口令,建立数据库链接也是可能的甚至是值得选取的。既然这样,现在我们注意这个最直接的例子。
下列语句建立了一个数据库链接,它允许访问客户帐户,这个帐户是事先在GNIS数据库建好的:
CREATE DATABASE LINK GNIS
CONNECT TO GUEST IDENTIFIED BY WELCOME
USING 'GNIS';
链接名称GNIS紧随LINK关键字。当连接到远程事例时,CONNECT TO...IDENTIFIED子句指定UEST/WELCOME作为用户名和口令使用 。USING子句指定通过网络服务名称GNIS建立连接。使用这一链接,现在你可以在远程数据库上查询数据。例如:
SQL> SELECT GFN_FEATURE_NAME
2 FROM GNIS.FEATURE_NAMES@GNIS
3 WHERE GFN_FEATURE_TYPE='falls'
4 AND GFN_STATE_ABBR='MI'
5 AND GFN_COUNTY_NAME='Alger';
GFN_FEATURE_NAME
_________________
Alger Falls
Au Train Falls
Chapel Falls
Miners Falls
Mosquito Falls
Tannery Falls
..
在SELECT语句中@GNIS紧随表名称,说明GNIS.FEATURE_NAMES表是在远程数据库,应该通过GNIS链接访问,链接类型Oracle支持几种不同类型的链接。这些类型相互重叠,有时难以通过选项进行分类。当你建立数据库链接时,你需要从下面选取:
Public(公用)或Private (私有)链接
权限类: Fixed User(固定用户), Connected User(连接用户)或 Current User(当前用户)
Shared Link(共享链接)或 Not Shared Link(非共享链接)
每次创建数据库链接时,你要自觉不自觉地做这三种选择。
公用链接与私有链接相对比
公用数据库链接对所有的数据库用户开放访问权。前面显示的是私有数据库链接,它只对建立它的用户授权。公用数据库链接更为有用,因为它使你不必为每一个潜在用户创建单独的链接。为了建立一个公用数据库链接,使用如下显示的PUBLIC关键字:
CREATE PUBLIC DATABASE LINK GNIS
CONNECT TO GUEST IDENTIFIED BY WELCOME
USING 'GNIS';
即使这是一个公用链接,用户名仍旧固定。所有使用这个链接的用户都作为用户GUEST连接到远程数据库。
使用数据库链接访问远程表
图1 数据库链接GNIS,指明网络服务名称,链接PROD事例到GNIS事例中的FEATURE_NAMES表。
权限类
当你建立一个数据库链接时,关于你如何授权对远程数据库进行访问,有三种选择。这三种选择代表了数据库链接的另一种分类方法。这三种类别如下:
固定用户。为远程数据库链接指定用户名和口令,作为数据库链接定义的一部分。
连接用户。在不指定用户名和口令时创建的数据库链接。
当前用户。建立数据库链接并指定CURRENT_USER关键字。
固定用户数据库链接是指在创建链接时为远程数据库指定用户名和口令。这一链接不管什么时候使用,也无论谁使用,都使用相同的用户名和口令登陆到远程数据库。到目前为止你在本文中所看到的都是固定用户链接。
固定用户链接,尤其是公用固定用户链接的一个潜在问提是他们把远程系统上的同一帐户给了许多本地用户。从安全角度来说,如果所有的本地用户在远程系统上拥有同一个帐户,责任就要折中,这取决于用户的数量 。如果数据丢失,几乎不可能确定破坏是如何发生的。另一个潜在问题是公用固定用户链接将对远程数据库的访问权给了所有的本地数据库用户。
如果你不想在数据库链接中嵌入用户名和口令,Oracle提供给你另一个非常有用的选择。你可以建立一个连接用户链接。连接用户链接是这样的链接,它通过任一个正在使用该链接的本地数据库的用户的用户名和口令登陆到远程数据库。你可以通过简单地空出用户名和口令来建立一个连接用户链接。考虑如下定义:
CREATE PUBLIC DATABASE LINK GNIS
USING 'GNIS';
链接名是GNIS。它连接到远程数据库连接时使用的网络服务名称是GNIS,但是没有指定用户名和口令。当你在查询中使用这个链接时,它将向远程数据库发送你当前的用户名和口令。例如,如果你使用AHMAD/SECRET 登陆到你的本地数据库,那么AHMAD/SECRET将是你登陆到远程数据库时使用的用户名和口令。
为了使用一个连接用户链接,你必须在远程数据库上有一个帐号,了解这一点是很重要的。不但这样,而且你在两个数据库上应使用同样的用户和口令。如果本地登陆使用AHMAD/SECRET,那么登陆到远程数据库时也必须使用同样的用户名和口令。使用连接用户链接时,如果你的口令不同,你就无权登陆。
公用连接用户数据库链接尤其有用,因为你可以建立一个可被所有用户访问的链接,并且所有用户被分别使用他或她自己的用户名和口令授权。你获得责任方面的利益,没有将远程数据库向你的本地数据库上的每一位用户开放。代价是你必须在两个数据库上建立用户帐户,并且你必需确信口令保持一致。
当前用户链接通过使用CURRENT_USER关键字建立并且与连接用户链接相似。只有当使用Oracle Advanced Security Option(Oracle高级安全选项)时,你才能使用当前用户链接,这个链接只对授权使用X.509认证的用户有用。
共享链接
共享数据库链接是指该链接的多个用户可以共享同一个底层网络连接。例如,在有四位用户的MTS(多线程服务器)环境下,每一个共享服务器进程都将与远程服务器有一个物理链接,这四位用户共享这两个链接。
表面上,共享链接乍一听起来像是一件好事。在某些环境下的确如此,但是,当你考虑使用共享链接时,应当意识到这有许多局限性和警告:
如果你使用一个专用的服务器连接来连接到你的本地数据库,链接只能在你从那些连接中创建的多重会话间共享。 在MTS环境里,每一个共享服务器进程潜在地打开一个链接。所有的会话被同一共享服务器进程提供并且分享被那个进程打开的任意共享链接。因为在MTS环境里的一个共享服务器进程能够服务于许多用户连接,共享链接的使用可能导致打开的链接远多于所必须的链接。用SHARED关键字建立共享数据库链接。还必须使用AUTHENTICATED BY 子句在远程系统上指定一有效的用户名和口令。如下命令建立一个共享的、公用的、连接用户数据库链接:
CREATE SHARED PUBLIC DATABASE LINK GNIS
AUTHENTICATED BY DUMMY_USER IDENTIFIED BY SECRET
USING 'GNIS';
要获得创建链接和管理分布式系统的更多资料,请查阅Oracle Technology Network (http://otn.oracle.com/)。
使用AUTHENTICATED BY子句稍微有些困扰,但是由于实现共享链接的方式安全性决定它是必须的。这个例子中的用户名和口令DUMMY_USER/SECRET必须在远程系统上有效。然而,远程系统上使用的帐户仍就是连接用户的帐户。如果我以JEFF/SECRET登陆到我的本地数据库并使用我刚建好的共享链接,将会发生以下一系列事件:
为了打开链接,Oracle使用DUMMY_USER/SECRET向远程数据库授权。 然后,Oracle试图使用HMAD/SECRET使我登陆到远程数据库。共享链接的主要目的是减少两个数据库服务器之间的底层网络连接数量。它们最适合于MTS环境,在那你拥有大量的通过这一链接访问远程数据库的用户。观念上,你想让用户数量超过共享服务器进程的数量。那么你可以通过为每一共享服务器进程打开一个链接而不是每位用户打开一个链接的方法,节省资源。
查找关于数据库链接的资料
你可以从几个数据字典视图中获得建立好的数据库链接的资料。DBA_DB_LINKS视图为每一定义的链接返回一行。OWNER 列和DB_LINK列分别显示了这一链接的所有者及名称。对公用数据库链接,OWNER列将包含'PUBLIC'。如果你建立固定用户链接,用户名应在DBA_DB_LINKS视图的USERNAME列里,但是口令只能从SYS.LINK$视图中看到。默认情况下,只有具有SELECT ANY TABLE系统权限的DBA能够访问SYS.LINK$视图查看口令。你应该保护访问那个视图的权限。ALL_DB_LINKS 视图和 USER_DB_LINKS视图与 DBA_DB_LINKS视图相类似-它们分别显示了你能够访问的所有链接及你所拥有的全部链接。最后,V$DBLINK动态性能视图向你显示出任意给定时间你-当前用户,打开的全部数据库链接。
全局性的数据库名称
在分布式环境里,Oracle建议你的数据库链接名应与它们连接到的数据库的全局性名称相匹配。因此如果你正在连接到名称为GNIS.GENNICK.ORG的数据库,你应当将你的数据库链接命名为GNIS.GENNICK.ORG
为确定数据库的全局性名称,以SYSTEM登陆并查询GLOBAL_NAME视图:
SQL> SELECT * FROM GLOBAL_NAME;
GLOBAL_NAME
_______________
GNIS.GENNICK.ORG
由于历史的原因,默认情况下,全局性名称与数据库链接名称的之间的链接不是强制性的。不过,你可以通过设置GLOBAL_NAMES的初始化参数为TRUE来改变这一行为。例如:
SQL> SHOW PARAMETER GLOBAL_NAMES
NAME TYPE VALUE
________________________________________________________
global_names boolean TRUE
用于产生这个范例的事例要求你使用的数据库链接名,必须与目标数据库的全局性数据库名称相匹配。注意与一些Oracle文档中说的相反,关键是你的本地事例的GLOBAL_NAMES设置。如果你的本地事例中GLOBAL_NAMES=FALSE,你就能够使用数据库链接,而不用管它们是否与远程数据库的全局性名称相匹配。总的来说,如果你设置GLOBAL_NAMES=TRUE,你应该在你的所有事例中一律这么做。
1 sequence
1) automatically generatess unique numbers
is a sharable object
is typically used to create a primary key value
replaces applicaition code
speeds up the efficiency of accessing sequence
create sequence sequence
[increment by n]
[start with n]
[{maxvalue n |nomaxvalue}]
[{minvalue n |nominvalue}]
[{cycle|nocycle}]
[{cache n |nocache}]
create sequence dept_deptin_seq
increment by 10
start with 120
maxvalue 9999
nocache
nocycle
2) Confirming Sequences
verify your sequence values in the user_sequences data dictionary table
select sequence_name,min_value,max_value,increment_by,last_number
from user_sequences;
the last_number display the next available sequence number if nocache is specified
3)nextval and currval Pseudocolumns
--nextval return thee next available sequence value,it return a unique value every time
it si referenced,even for different ueer;
--currval obtains the current sequence value;
--nextval must be issued for that sequence before curval contains a value;
4) Using a Sequence
-- Caching sequence values in the memory give faster access to these values;
-- Gaps in sequence value can occur when
a rollback occurs
b the system crashes
c A sequence us used in another table;
5) alter sequence test increment by 10;
you can change all properties of the sequence except the start with .
6) remove sequence
drop sequence test;
2 index
1) how are indexes created
Automatically : a unique index is created automatically when you create primary key or
unique constraint in a table definition,
Manually: user can create nounique index on column to speed up access to the rows.
create index testindex on autoer(lanme);
2) When to Create an index
ypu should create an index if:
. a column contains a wide range of values
. a column contains a large number of null values
. one or more columns are frequently used together in where clause or a join condition;
. The table is large and most queries are expected to retrieve less than 2 to 4 percent
of the rows;
3) When not to create an index
this usually not worth creating an index if:
. the table is small
. The columns are not often used as a condition in the query.
. Most queries are expected to retrieve more than 2 to 4 percent of the rows in the
table
. the indexed columns are referenced as part of an expression.
4)Confirming indexes
. The user_indexes data dictionary view contains the name of the index and tis uniquess
. the user_ind_columns view contains the index name,the table name,and the column name.
select ic.index_name,ic_column_name,ic.column_position,ic_col_pos,ix.uniqueness
from user_indexed ix,user_ind_columns ic
where ic.index_name=ix.index_name
and ic.table_name='employees';
5)基于函数的索引
. a function-based index is an index based on expressions
. The index expression is built form table columns,constraints,SQL functions and user-
defined functions
create index testindex2
on autors (upper(au_fname));
select * from authors
where upper(au_fname) like 'B%';
6) remoe index
drop index index_name;
3 synonyms
Simplify access to objects by creating a synonym
. Ease referring to a table ownerd by anther user
. Shorten lengthy object names;
create [publi] synonym synonym for object;
1 pl/sql 集合 处理单列多行数据库,使用的类型为标量类型
1) 索引表
type ename_table_type is table of emp.ename%type
index by binary_integer;
ename_table ename_table_type;
begin
select ename into ename_table(-1) from emp
where empno=&no;
dbms_output.put_line('雇员名:'||ename_table(-1));
end;
set serveroutput no
declare
type area_table_type is table of number
index by varchar2(10);
rea_table area_table_type;
begin
area_table('beijing'):=1;
area_table('shanghai'):=2;
area_table('guangzhou'):=3;
dbms_output.put_line(area_table.first);
dbms_output.put_line(area_table.last);
end;
2) 嵌套表
索引表类型不能作为累得数据类型使用,但是嵌套表可以作为表类的数据类型使用。
当使用嵌套表元素时,必须先用其构造方法初始化其嵌套表:
a 在pl/sql 块中使用嵌套表
declare
type ename_table_type is table of emp.ename%type;
ename_table ename_table_type;
begin
ename_table:=eanme_table_type('2','2','3');
select ename into ename table(2) from emp where empno=&no;
dbms_ouput.put_line(ename_table(2));
end;
b 在表中使用嵌套表
create type phone_type is table of varchar2(20);
create table employee(
id number (4),name varchar2(10),sal number(6,2),
phone phone_type
)nested table phone store as phone_table;
-- 为嵌套表插入数据
insert into employee values(2,'scott',200,phone_type('2222','333333'));
--检索嵌套表累得数据
set erveroutput on
declare
phone_table phone_type;
begin
select phone into phone_table
from employee where id=1;
for i in 1..phone_table.count loop
dbms_output.put_line(phone_table(i));
end loop;
end;
-- 更新嵌套表列的数据
delcare
phone_table phone_type:=('44444','555555');
begin
update employee set phone=phone_table
where id=1;
end;
3) 变长数组
在使用varray 时必须指定最大个数,和数据类型,在使用其元素时必须进行初始化
type ename_table_type is varray(20) of emp.ename%type;
ename_table ename_table_type:=ename_table_type('1','2');
-- 在快中使用varray
declare
type ename_table_type is varray(20) of emp.ename%type;
ename_table ename_table_type:=ename_table_type('mary');
begin
select ename into ename_table(1) form emp
where empno=$no;
end;
--在表列中使用varray
create type phone type is varray(20) of varchar2(20);
create table employee(
id number(4),name varchar2(10),
sal number(6,2),phone phone_type);
3)记录表
记录表结合了记录和集合的优点
declare
type emp_table_type is table of emp%rowtype
index by binary_integer;
emp_table emp_table_type;
begin
select * from into emp_table(1) from emp
where empno=&no;
dbms_output.put_line(emp_table(1).ename);
end;
4)多维集合
1 多级varray
declare
--define 一维集合
type al_array_type is varray(10) of int;
--定义二维集合
type nal_varray_type is varray(10) of a1_varray_type;
--初始化二维集合
nvl nal_varray_type:=nal_varray_type(
a1_varray_type(1,2),
a1_varray_type(2,3)
)
beign
for i in 1..nal_varray_type.count loop
for j in 1..a1_array_type.count loop
dbms_out.putline(nvl(i)(j));
end loop;
end loop;
end;
2 使用多级嵌套表
table a1_table_type is table of int;
table nvl_table_type is table of a1_table_type;
nvl nvl_table_type:=nvl_table_type(
a1_table_type(1,2),
a1_table_type(2,3)
);
2 集合方法
1) exist
if ename_table.exists(1) then
ename_table(1):='scott';
2) count 返回当前集合变量中的元素总个数
ename_table.count
3) limit 返回集合元素的最大个数 只有varray 有
4)first and last
ename_table.first
ename_table.last
5) prior 和next
ename_table.prior(5); --返回元素5的前一个
ename_table.next(5); -- 后一个
6) extend
使用于varray 和 嵌套表。
extend add a null value
extend (n) add n null value
extend (n,i)add n i value
declare
type ename_table_type is varray(20) of varchar2(20);
ename_table ename_table_type;
begin
ename_table:=ename_table_type('mary');
ename_table.extend(5,1);
dbms_output.put_line(ename_table.count);
end;
7) trim
trim remove one element from the tail of the collection.
trim(n) remove n element from the tail of the colleciton.
8)delete
delete: delete all the elements
delete(n) :delete the nth elements
delete(m,n): delete the elements from m to n
3 集合赋值
1)将一个集合的数据赋值给另一个集合.clear the destination collectins and set the original collection
delcare
type name_varray_type is varray(4) of varchar2(10);
name_array1 name_varray_type;
name_array2 name_varray_type;
begin
name_array1:=name_varray_type('scott','smith');
name_array2:=name_array_type('a','b','c');
name_array1:=name_array2;
end;
type name_array1_type is varray(4) of varchar2(10);
type name_array2_type is varray(4) of varchar2(10);
name_array1 name_array1_type;
name_array2 name_array2_type;
具有相同的数据类型,单具有不同的集合类型不能构赋值
2) 给集合赋城null 值
可以使用delete 或 trim
也可以使用 空集合赋给目表集合
type name_varray_type is varray(4) of varchar2(10);
name_array name_varray_type;
name_empty name_varray_type;
name_array:=name_varray_type('1','2');
name_array:=name_empty;
3) 使用集合操作赋和比较集合都是10g 的内容,p176 先略过。
4 批量绑定
执行单词sql 操作能传递所有集合元素的数据。
1 forall 语句
用于insert update 和delete操作。在oracle9i 中forall 语句必须具有连续的元素
1) using forall on insert
declare
type id_table_type is table of number(6)
index by binary_integer;
type name_table_type is table of varchar2(2)
index by binary integer;
id_table id_table_type;
name_table name_table_type;
begin
for i in 1..10 loop
id_table(i):=i;
name_table(i):='Name'||to_char(i);
end loop;
forall i in 1..id_table.count
insert into demo demo values(id_table(i),name_table(i));
end;
2)using forall on using update
forall i in 1..id_table.count
upate demo set name:=name_table(i)
where id:=id_table(i);
3)using forall on using delete
forall i in 1..id_table.count
delete from demo where id:=id_table(i);
4) using forall on part of the collection
for i in1..10 loop
id_table(i):=i;
name_table(i):="name"||to_char(i);
end loop;
forall i in 8..10 l
insert into demo values(id_table(i),name_table(i));
2 bulk collect
is fit for select into ,fetch into and dml clause
1) using bulk collect
declares
type emp_table_type is table of emp%rowtype
index by binary_integer;
emp_table emp_table_type;
begin
select * bulk collect into emp_table
from emp where deptno=&no;
for i in 1..emp_tablee.count loop
dbms_output.put_line(emp_table(i).ename);
end loop;
2) 在dml 的返回字句使用bulk collect 字句
declare
type ename_table_type is table of emp.ename%type;
ename_table ename_table_type;
begin
deletee from emp where deptno=&no
returning ename bulk_collect into ename_table;
for i in 1..ename_table.count loop
dbms_output.put(ename_table(i));
end loop;
end;
end;
end;
1Why Use Views
to restrict data access
to make complex query easy
to provide data independence
to provide defferent view of the same data
2 Creating a View
1)create [or replace] [force|noforce] view view
as subquery
force : create view wether the referenced object existed or not
desc view_name;
2)create a view by using column aliases in the subquery
create view salv50
as select employee_idIO_NUMBER,last_name NAME,slaary*12 ANN_SALARY
from employees
where department_id=50;
3 Modigy a View
1) Modigy the emplvu80 view by using create or replace view clause.Add an alias for each
column name;
create or replace view empvu80
(id_number,name,sal,department_id)
as select employee_id,first_name||" "||last_name,salary.department_id
from employees
where department_id=80;
column aliases in the create view clause are listed in the same order as the columns in
the subquery
note : alter view_name is not a valid command.
4 Create a Complex View
Create a complex view that contains group functions to display values from two tables
create view dept_sum_vu
(name,minsal,maxsal,avgsal)
as
select d.department_name,min(e.salary),max(e.salary),avg(e.salary)
from employees e,departments d
where e.department_id=d.department_id
group by d.department_name;
5 Rules for performs DML operaton on a view
1) You can perform DML operation on simple views
2) You can not romove a row if the view contains the following:
--group functions
--a group by clause
--the distince keyword
-- rownum keyword
-- column defined by expressions
6 Using the with check option Clause
1) you can ensure that dml operatons performed on the view stay within the domain of the
view by using the with check option clause.
creaate view test1
as
select * from emp where qty>10;
with check option;
update testview1 set qty=10
where ster_id=6830;
--when you doing the following update operation
update testview1 set qty=5 where id=10;
-- an error will report
--you violate the where clause
2)Any attempt to change the department number for any row in the view fails because it
violates the with check option constraint
create or replace view empvu20
as
select * where department_id=20
with check option constriant empvu20_ck;
7 Denying DML Operations
1 You can ensure that no dml operations occur by adding the with read only option to your
view definition.
2)Any attempt to a DML on any row in the view resuls in an oralce server error.
8 remove veiw
drop view_name
9 inline view
1) an inline view is a subquery with an alias that you can use within a sql statement.
2) a named subquery in the from clause of the main query is an exqmple of an inline view
3) an inline view is not a schema object.
10 Top-N Analysis
1)Top_N querise ask for the n largest or smallest values of a column.
2)Both largest values and smallest values sets considered Top-N queries
select * from (select ster_id,qty from sales);
example
To display the top three earner names and salaries from the employees
select rownum as rank,last_name,salary
from (select last_anme,slary from employee
order by slary desc)
where rownum<=3;
1 pl/sql 集合 处理单列多行数据库,使用的类型为标量类型
1) 索引表
type ename_table_type is table of emp.ename%type
index by binary_integer;
ename_table ename_table_type;
begin
select ename into ename_table(-1) from emp
where empno=&no;
dbms_output.put_line('雇员名:'||ename_table(-1));
end;
set serveroutput no
declare
type area_table_type is table of number
index by varchar2(10);
rea_table area_table_type;
begin
area_table('beijing'):=1;
area_table('shanghai'):=2;
area_table('guangzhou'):=3;
dbms_output.put_line(area_table.first);
dbms_output.put_line(area_table.last);
end;
2) 嵌套表
索引表类型不能作为累得数据类型使用,但是嵌套表可以作为表类的数据类型使用。
当使用嵌套表元素时,必须先用其构造方法初始化其嵌套表:
a 在pl/sql 块中使用嵌套表
declare
type ename_table_type is table of emp.ename%type;
ename_table ename_table_type;
begin
ename_table:=eanme_table_type('2','2','3');
select ename into ename table(2) from emp where empno=&no;
dbms_ouput.put_line(ename_table(2));
end;
b 在表中使用嵌套表
create type phone_type is table of varchar2(20);
create table employee(
id number (4),name varchar2(10),sal number(6,2),
phone phone_type
)nested table phone store as phone_table;
-- 为嵌套表插入数据
insert into employee values(2,'scott',200,phone_type('2222','333333'));
--检索嵌套表累得数据
set erveroutput on
declare
phone_table phone_type;
begin
select phone into phone_table
from employee where id=1;
for i in 1..phone_table.count loop
dbms_output.put_line(phone_table(i));
end loop;
end;
-- 更新嵌套表列的数据
delcare
phone_table phone_type:=('44444','555555');
begin
update employee set phone=phone_table
where id=1;
end;
3) 变长数组
在使用varray 时必须指定最大个数,和数据类型,在使用其元素时必须进行初始化
type ename_table_type is varray(20) of emp.ename%type;
ename_table ename_table_type:=ename_table_type('1','2');
-- 在快中使用varray
declare
type ename_table_type is varray(20) of emp.ename%type;
ename_table ename_table_type:=ename_table_type('mary');
begin
select ename into ename_table(1) form emp
where empno=$no;
end;
--在表列中使用varray
create type phone type is varray(20) of varchar2(20);
create table employee(
id number(4),name varchar2(10),
sal number(6,2),phone phone_type);
3)记录表
记录表结合了记录和集合的优点
declare
type emp_table_type is table of emp%rowtype
index by binary_integer;
emp_table emp_table_type;
begin
select * from into emp_table(1) from emp
where empno=&no;
dbms_output.put_line(emp_table(1).ename);
end;
4)多维集合
1 多级varray
declare
--define 一维集合
type al_array_type is varray(10) of int;
--定义二维集合
type nal_varray_type is varray(10) of a1_varray_type;
--初始化二维集合
nvl nal_varray_type:=nal_varray_type(
a1_varray_type(1,2),
a1_varray_type(2,3)
)
beign
for i in 1..nal_varray_type.count loop
for j in 1..a1_array_type.count loop
dbms_out.putline(nvl(i)(j));
end loop;
end loop;
end;
2 使用多级嵌套表
table a1_table_type is table of int;
table nvl_table_type is table of a1_table_type;
nvl nvl_table_type:=nvl_table_type(
a1_table_type(1,2),
a1_table_type(2,3)
);
2 集合方法
1) exist
if ename_table.exists(1) then
ename_table(1):='scott';
2) count 返回当前集合变量中的元素总个数
ename_table.count
3) limit 返回集合元素的最大个数 只有varray 有
4)first and last
ename_table.first
ename_table.last
5) prior 和next
ename_table.prior(5); --返回元素5的前一个
ename_table.next(5); -- 后一个
6) extend
使用于varray 和 嵌套表。
extend add a null value
extend (n) add n null value
extend (n,i)add n i value
declare
type ename_table_type is varray(20) of varchar2(20);
ename_table ename_table_type;
begin
ename_table:=ename_table_type('mary');
ename_table.extend(5,1);
dbms_output.put_line(ename_table.count);
end;
7) trim
trim remove one element from the tail of the collection.
trim(n) remove n element from the tail of the colleciton.
8)delete
delete: delete all the elements
delete(n) :delete the nth elements
delete(m,n): delete the elements from m to n
3 集合赋值
1)将一个集合的数据赋值给另一个集合.clear the destination collectins and set the original
collection
delcare
type name_varray_type is varray(4) of varchar2(10);
name_array1 name_varray_type;
name_array2 name_varray_type;
begin
name_array1:=name_varray_type('scott','smith');
name_array2:=name_array_type('a','b','c');
name_array1:=name_array2;
end;
type name_array1_type is varray(4) of varchar2(10);
type name_array2_type is varray(4) of varchar2(10);
name_array1 name_array1_type;
name_array2 name_array2_type;
具有相同的数据类型,单具有不同的集合类型不能构赋值
2) 给集合赋城null 值
可以使用delete 或 trim
也可以使用 空集合赋给目表集合
type name_varray_type is varray(4) of varchar2(10);
name_array name_varray_type;
name_empty name_varray_type;
name_array:=name_varray_type('1','2');
name_array:=name_empty;
3) 使用集合操作赋和比较集合都是10g 的内容,p176 先略过。
4 批量绑定
执行单词sql 操作能传递所有集合元素的数据。
1 forall 语句
用于insert update 和delete操作。在oracle9i 中forall 语句必须具有连续的元素
1) using forall on insert
declare
type id_table_type is table of number(6)
index by binary_integer;
type name_table_type is table of varchar2(2)
index by binary integer;
id_table id_table_type;
name_table name_table_type;
begin
for i in 1..10 loop
id_table(i):=i;
name_table(i):='Name'||to_char(i);
end loop;
forall i in 1..id_table.count
insert into demo demo values(id_table(i),name_table(i));
end;
2)using forall on using update
forall i in 1..id_table.count
upate demo set name:=name_table(i)
where id:=id_table(i);
3)using forall on using delete
forall i in 1..id_table.count
delete from demo where id:=id_table(i);
4) using forall on part of the collection
for i in1..10 loop
id_table(i):=i;
name_table(i):="name"||to_char(i);
end loop;
forall i in 8..10 l
insert into demo values(id_table(i),name_table(i));
2 bulk collect
is fit for select into ,fetch into and dml clause
1) using bulk collect
declares
type emp_table_type is table of emp%rowtype
index by binary_integer;
emp_table emp_table_type;
begin
select * bulk collect into emp_table
from emp where deptno=&no;
for i in 1..emp_tablee.count loop
dbms_output.put_line(emp_table(i).ename);
end loop;
2) 在dml 的返回字句使用bulk collect 字句
declare
type ename_table_type is table of emp.ename%type;
ename_table ename_table_type;
begin
deletee from emp where deptno=&no
returning ename bulk_collect into ename_table;
for i in 1..ename_table.count loop
dbms_output.put(ename_table(i));
end loop;
end;
end;
end;
1 What are Constrains
1) Constrains enforce on the table level
2) Constrains the deletion of a table if there are dependencies
2 Constrain Guidelines
1) Name a constraint or the oracle generate a name by the sys_cn format
2) Create a constraint either
--At the same time as the table is created.or
--After the table has been created
3)Define a constraint at the column or table level
4)view constraint in the data dictionary
3 Crete a constraint
create table test2
(id int not null,-- column level
lname varchar(20),
fname varchar(20),
constraint uk_test2_1 unique(lname,fname))--table level
4 The not null Constraint
create table employees(
employee_id number(6),
last_name varchar2(25) not null --system named
hire_date DATE
constraint emp_hire_date not null --User named
5Foreign key
create table test3
(rid int,
name varchar(30),
constraint fk_test3_1 foreign key(rid) reference test2(id));
froeign key constraint keywords
foreign key :Define the column in thee child table at the table constrain level.
references :Identifies the table and column in the parent table.
on delete cascade: Delete the dependent rows in the child table when a row in the
parent table is deleted
on delete set null:Convert the dependent foreign key values to null when a row in the
parent table is deleted.
--parent table referenced table
--child table refernce other table
6 The check Constraint
Define a condition that each row must be satify
alter table test3
add constrain ch_test3 check(name like 's%')
7 Dropping a Constraint
1) Remove the manager constraint form the employee table
alter table test3
drop constriant test3_manager_fk
2) Remove the primary key constraint on the departments table and drop the associated
foreign key constraint on the employees.department_id column
alter table departments
drop primary key cascade
8 Disabling and enable Constraints
1)Execute the disable clause of the alter table statment to deactive an integrity
constraint
2)Apply the cascade option to disable dependent integrity constrints
alter table employees
disable constraint emp_emp_id_pl cascade
3) enabling Constraints
.Active an integrity constraint currently disabled in the table definition by using the
enable clause.
alter table employees
enable constraint emp_emp_id_pk;
a unique or a primary index is automatically created if you enable a unique key or a
primary key constraint
8 View Constraints
select constraint_name,constriant_type,serch_condition
from user_constraints
where table_name='employees'
9 view the columns associated with constraints
select constraint_name,column_name
from user_cons_columns
where table_name='employees'
OpenSessionInView
Created by
potian. Last edited by
admin 61 days ago. Viewed 181 times.
[edit]
[attach]
Hibernate的Lazy初始化1:n关系时,你必须保证是在同一个Session内部使用这个关系集合,不然Hiernate将抛出例外。
另外,你不愿意你的DAO测试代码每次都打开关系Session,因此,我们一般会采用OpenSessionInView模式。
OpenSessionInViewFilter解决Web应用程序的问题
如果程序是在正常的Web程序中运行,那么Spring的
OpenSessionInViewFilter能够解决问题,它:
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
SessionFactory sessionFactory = lookupSessionFactory();
logger.debug("Opening Hibernate Session in OpenSessionInViewFilter");
Session session = getSession(sessionFactory);
TransactionSynchronizationManager.bindResource(sessionFactory,
new SessionHolder(session));
try {
filterChain.doFilter(request, response);
}
finally {
TransactionSynchronizationManager.unbindResource(sessionFactory);
logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
closeSession(session, sessionFactory);
}
}
可以看到,这个Filter在request开始之前,把sessionFactory绑定到TransactionSynchronizationManager,和这个SessionHolder相关。这个意味着所有request执行过程中将使用这个session。而在请求结束后,将和这个sessionFactory对应的session解绑,并且关闭Session。
为什么绑定以后,就可以防止每次不会新开一个Session呢?看看HibernateDaoSupport的情况:
publicfinal void setSessionFactory(SessionFactory sessionFactory) {
this.hibernateTemplate = new HibernateTemplate(sessionFactory);
}
protectedfinal HibernateTemplate getHibernateTemplate() {
return hibernateTemplate;
}
我们的DAO将使用这个template进行操作:
publicabstract class BaseHibernateObjectDao
extends HibernateDaoSupport
implements BaseObjectDao {protected BaseEntityObject getByClassId(finallong id) {
BaseEntityObject obj =
(BaseEntityObject) getHibernateTemplate()
.execute(new HibernateCallback() {
publicObject doInHibernate(Session session)
throws HibernateException {
return session.get(getPersistentClass(),
newLong(id));
}
});
return obj;
}
public void save(BaseEntityObject entity) {
getHibernateTemplate().saveOrUpdate(entity);
}
public void remove(BaseEntityObject entity) {
try {
getHibernateTemplate().delete(entity);
} catch (Exception e) {
thrownew FlexEnterpriseDataAccessException(e);
}
}
public void refresh(final BaseEntityObject entity) {
getHibernateTemplate().execute(new HibernateCallback() {
publicObject doInHibernate(Session session)
throws HibernateException {
session.refresh(entity);
returnnull;
}
});
}
public void replicate(finalObject entity) {
getHibernateTemplate().execute(new HibernateCallback() {
publicObject doInHibernate(Session session)
throws HibernateException {
session.replicate(entity,
ReplicationMode.OVERWRITE);
returnnull;
}
});
}
而HibernateTemplate试图每次在execute之前去获得Session,执行完就力争关闭Session
publicObject execute(HibernateCallback action) throws DataAccessException {
Session session = (!this.allowCreate ?
SessionFactoryUtils.getSession(getSessionFactory(),
false) :
SessionFactoryUtils.getSession(getSessionFactory(),
getEntityInterceptor(),
getJdbcExceptionTranslator()));
boolean existingTransaction =
TransactionSynchronizationManager.hasResource(getSessionFactory());
if (!existingTransaction && getFlushMode() == FLUSH_NEVER) {
session.setFlushMode(FlushMode.NEVER);
}
try {
Object result = action.doInHibernate(session);
flushIfNecessary(session, existingTransaction);
return result;
}
catch (HibernateException ex) {
throw convertHibernateAccessException(ex);
}
catch (SQLException ex) {
throw convertJdbcAccessException(ex);
}
catch (RuntimeException ex) {
// callback code threw application exception
throw ex;
}
finally {
SessionFactoryUtils.closeSessionIfNecessary(
session, getSessionFactory());
}
}
而这个SessionFactoryUtils能否得到当前的session以及closeSessionIfNecessary是否真正关闭session,端取决于这个session是否用sessionHolder和这个sessionFactory在我们最开始提到的TransactionSynchronizationManager绑定。
publicstatic void closeSessionIfNecessary(Session session,
SessionFactory sessionFactory)
throws CleanupFailureDataAccessException {
if (session == null ||
TransactionSynchronizationManager.hasResource(sessionFactory)) {
return;
}
logger.debug("Closing Hibernate session");
try {
session.close();
}
catch (JDBCException ex) {
// SQLException underneath
thrownew CleanupFailureDataAccessException(
"Cannot close Hibernate session", ex.getSQLException());
}
catch (HibernateException ex) {
thrownew CleanupFailureDataAccessException(
"Cannot close Hibernate session", ex);
}
}
HibernateInterceptor和OpenSessionInViewInterceptor的问题
使用同样的方法,这两个Interceptor可以用来解决问题。但是关键的不同之处在于,它们的力度只能定义在DAO或业务方法上,而不是在我们的Test方法上,除非我们把它们应用到TestCase的方法上,但你不大可能为TestCase去定义一个接口,然后把Interceptor应用到这个接口的某些方法上。直接使用HibernateTransactionManager也是一样的。因此,如果我们有这样的测试:
Category parentCategory = new Category ();
parentCategory.setName("parent");
dao.save(parentCategory); Category childCategory = new Category();
childCategory.setName("child");
parentCategory.addChild(childCategory);
dao.save(childCategory);
Category savedParent = dao.getCategory("parent");
Category savedChild = (Category ) savedParent.getChildren().get(0);
assertEquals(savedChild, childCategory);
将意味着两件事情:
- 每次DAO执行都会启动一个session和关闭一个session
- 如果我们定义了一个lazy的关系,那么最后的Category savedChild = (Category ) savedParent.getChildren().get(0);将会让hibernate报错。
解决方案
一种方法是对TestCase应用Interceptor或者TransactionManager,但这个恐怕会造成很多麻烦。除非是使用增强方式的AOP.我前期采用这种方法(Aspectwerkz),在Eclipse里面也跑得含好。
另一种方法是在TestCase的setup和teardown里面实现和Filter完全一样的处理,其他的TestCase都从这个TestCase继承,这种方法是我目前所使用的。
Jolestar补充:openSessionInView的配置方法:
<filter>
<filter-name>opensession</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
<init-param>
<param-name>singleSession</param-name>
<param-value>false</param-value>
</init-param>
</filter>
1 Table in the Oracle Database
1) User Tables:
a Are a collection of tables created and maintained by the user
b Contain user information
2) Data Dictionary
a is a collection of table created and maintained by the Oracle Server
b Contain database information
2 Querying the Data Dictionary
1)see the names of the table owned by the user
select table_name from user_tables;
2) view distinct object types ownered by the user
select distinct object_type from user_object;
3) view tables ,view ,synonyms and sequences owned by the user
select * from user_catalog
3 Creating a Table by Ussing a Subquery Syntax
create table tt3
as
select * from authors
4 Teh alter table Statement
1) Add a new column
alter table tt2
add(fname varchar2(20) default 'unkonown',
address varchar2(30) null);
2)Modigying a Column's data type size and default value
alter table dept80
modigy (last_name varchr2(30))
A change to thee default value affects onlly subsequent insertion to the table
3) drop a column
alter table dept80
drop column job_id;
The set unseed Option
a you use the set unused optoin to mark one or more columns as unused
b you use the drop unused colimns options to remove the columns that are marked as
as unused
alter table tt2
set unused colun fnamel;
alter table table
drop unused columns
5 Dropping a Table
1) All data and structure in the table is deleted
2) Any pending transaction are committed
3) All indexes are dropped
4) You cannot roll back the drop table statement
6 Changing the Name of an Object
rename dept to detail_dept;
you must be the owner of the object
7 Truncate a Table
Remove all rows from the table
release the storage space used by that table
you cannot rollback row when using truncate
alternatly ,you can remove row by using delete statement
1 Data Manipulation Language
1) A DML statement is executed when you:
add new rows to a table
modify existing row in a table
remove existing rows from a table
2) A transaction consist a collection dml statements form a logic unit of work
2 Using Explicit Default Values
1) default with insert
insert into departments
values(200,'ddd',default)
2) default with update
update departments
set manager_id=default where department_id=10
3 The Merge Statement
1)Provide the ability to conditionaly update or insert data into database
2)Perform a update if the row exists and an insert if it is a new row
a Avoid update separatly
b increase performance and ease of use
c is useful in data warehousing application
example
merge into copy_emp c
using employees e
on (c.employee_id=e.employee_id)
when mathched then
update set
c.first_name=e.first_name
c.last_name=e.last_name
..............
c.department_id=e.department_id
when not matched then
insert values(e.employeeid,e.first_name,......e.department_id);
4 Database Transactions
1)Begin when the first dml statement is executed
2)end with one of the following events
a a commit or rollback statement is issued;
b a ddl or dcl statement execute (commit automatically)
c the user exist isqllplus
d the system crashes
3) advantage of commit and rollback statemnt
With commit and rollback statement ,you can
a ensure data consistence
b Preview data change before making change permant
c group logic relate operatons
5 State of The Data Before commit or rollback
1) the previous state of the data can be recovered
2) The current user can review the result of the dml operation by using the select statment
3) other user can not view the result of the dml
4) the affected was locked ,other user cannot change the data within the affecteed row
6 Read Consistency
1) Read consistency guarantees a consistent view of the data at all times
2) Changes made by one user do not confilict with changes made by another user
3) Read consistency ensures that on the same data
a Readers do not wait for writers
b Writers do not wait for readers
7Locking
1) Prevent destructive interaction between concurrent transactions
2) Reqire no user action
3) Automatically use the lowest level of restrictiveness
4) Are held for the duration of the transaction
5) Are of two types:explicit locking an implicit locking
8 Implicit Locking
1)Two lock modes
a Exclusive :Locks out other users
b Share: Allows other users to accesss
2)High level of data concurrency
a DML:Table share,row exclusive
b Queries: No locks required
c DDL:Protects object definitions
3)Locks held until commit or rollback
刚刚用sequence ,又忘了,呵呵,从网上找了一篇文章,写的不错,copy 在这里
1、Create Sequence
你首先要有CREATE SEQUENCE或者CREATE ANY SEQUENCE权限,
CREATE SEQUENCE emp_sequence
INCREMENT BY 1 -- 每次加几个
START WITH 1 -- 从1开始计数
NOMAXVALUE -- 不设置最大值
NOCYCLE -- 一直累加,不循环
CACHE 10;
一旦定义了emp_sequence,你就可以用CURRVAL,NEXTVAL
CURRVAL=返回 sequence的当前值
NEXTVAL=增加sequence的值,然后返回 sequence 值
比如:
emp_sequence.CURRVAL
emp_sequence.NEXTVAL
可以使用sequence的地方:
- 不包含子查询、snapshot、VIEW的 SELECT 语句
- INSERT语句的子查询中
- NSERT语句的VALUES中
- UPDATE 的 SET中
可以看如下例子:
INSERT INTO emp VALUES
(empseq.nextval, 'LEWIS', 'CLERK',7902, SYSDATE, 1200, NULL, 20);
SELECT empseq.currval FROM DUAL;
但是要注意的是:
- 第一次NEXTVAL返回的是初始值;随后的NEXTVAL会自动增加你定义的INCREMENT BY值,然后返回增加后的值。CURRVAL 总是返回当前SEQUENCE的值,但是在第一次NEXTVAL初始化之后才能使用CURRVAL,否则会出错。一次NEXTVAL会增加一次SEQUENCE的值,所以如果你在同一个语句里面使用多个NEXTVAL,其值就是不一样的。明白?
- 如果指定CACHE值,ORACLE就可以预先在内存里面放置一些sequence,这样存取的快些。cache里面的取完后,
oracle自动再取一组到cache。 使用cache或许会跳号, 比如数据库突然不正常down掉(shutdown abort),cache中的sequence就会丢失. 所以可以在create sequence的时候用nocache防止这种情况。
2、Alter Sequence
你或者是该sequence的owner,或者有ALTER ANY SEQUENCE 权限才能改动sequence. 可以alter除start至以外的所有sequence参数.如果想要改变start值,必须 drop sequence 再 re-create .
Alter sequence 的例子
ALTER SEQUENCE emp_sequence
INCREMENT BY 10
MAXVALUE 10000
CYCLE -- 到10000后从头开始
NOCACHE ;
影响Sequence的初始化参数:
SEQUENCE_CACHE_ENTRIES =设置能同时被cache的sequence数目。
可以很简单的Drop Sequence
DROP SEQUENCE order_seq;
1 Guidelines for Using Subqueries
a Enclose subqueries in parenttheses
b placce subqueries on the right side of the comparision condition
c the order by clause in the subquery is not needed
d using single-row operators with single-row subqueries and use multiple -row operator with multiple-row subqueries .
single-row subqueries can work as a expression,and muitiple-row subqueries can only be used with in all any ,i will talk it later
select last_name where job_idd=(select job_id
from employees
where imployee_id=141)
2 The HAVING CLause with Subqueries
a The Oracle server execute subqueries first
b The Oracle return result into the HAVING clause of the main query
select department_id,min(salary)
from employee
group by department_id
having min(salary)>
(select min(salary)
from employees
where department_id=50);
3 Multiple-Row Subqueries
a Return more than one row
Using mutiple-row comparsion operator
select employee_id
from employees
where salary<any
(select salary
from employees
where job_id='ddd')
select employee_id
from employees
where salary<all
(select salary
from employees
where job_id='ddd')
select emp.last_name
from employees emp
where emp.employee_id not in
(select mgr.manager_id
from employees mgr)
1 Jioning Tables Using Oracle Syntax
Using a join to query data form more than one table
select table1.column,table2,column
from table1,table2
where table1.column1=table2.column2 .
2 outjoin
1)You use an outer join to also see rows that do not meet the join condition
2)The Outer join operator is the plus sign(+)
a left join
select tabl1.column,table2,column
from table1,table2
where table1.column(+)=table2.column
b right join
select table1.column,table2.column
from table1,table2
wheretable1.coulmn=table2.column(+)
3) self join
select worker.last_name||'works for'||manager.last_name
from employees owrker,employees manager
where worker.manager_id=manager.employee_id;
3 Joining Tables Using SQL:1999 Syntax
Use a join to query data from more than one table
1) Creationg Cross Joins
a The cross join clause produces thee cross product of two tables
b This is the same as Cartesian product between the two tables
select last_name,department_name
from employees
ccross join departments
2) Creating Natual Joins
a The Natual join clause is bassed on all columns in the two tables that have the same name
b it select rows from the two tables that have the equal values in all matched columns
c if the columns having the same name and have the different data types in an error is returned.
select department_id,department_name,location_id,city
from departments
natual join locations
3) using clause
select e.employee_id,e.last_name
from employees e join departments d
using (department_id);
4) Creating joins with thee on clause
a The join condition for thee natual join is basically an equaljoin of all column with the same name.
b To specify arbitrary condition or specify columns to join, the on clause is userd
c The join condition is separated from other search conditions
d The on claus make code easy to understand.
select e.employee_id,e.last_name,e.department_id,
from employees e join departments d
on (e.department_id=d.department_id);
from employe
join departments d
on d.department_id=e.department_id
join locations l
on d.location_id=l.location_id
5) INNER Versus OuTER Joins
a In SQL:1999,the join of two tables returning only matched rows is an inner join
6) FULL OUTER JOIN
select e.last_name,e,department_id,d.department_name
from employees e
full outer join departments d
on (e.department_id=d.department_id);
1 "'
2 ||
3 isql*plus http://127.0.00.1/isqlplus
4 desc author
5 initcap('SQL Course')
INSERT('JellwWord','W') 6
LPAD (salary,10,'*') *****24000
RPAD (salary,10,'*') 24000*****
TRIM ('H' from 'HolloWorld') olloWord
substr('helloword',1,5) hello
substr('helloword',-1,5) oword
6 Number Functions
round(45.926,2) 45.93
round(45.926,-2) 0
round(55.926,-2) 100
trunc(45.926,2) 45.92
mod(1600,300) 100
7 data function
systdate
(sysdate-hire_date)/7 as weeks
months_between number of months between two dates
months_between ('01-sep-95','11,jan-94') 19.6774194
add_months add calendar months to date
add_months('11-JAN-94',6) '11-JUL-94'
next_day next day of the date specified
next_day('01-SEP-95','FRIDAY') '08-SEP-95'
last_day last day of the month
last_day('01-feb-95') '28-feb-95'
round round date
assume sysdate='25-jul-95'
round(sysdate,'month') 01-aug-95
round(sysdate,'year') 01-JAN-96
trunc truncate date
trunc(sysdate,'month') 01-Jul-95
trunc(sysdate,'month') 01-JAN-95
8 Conversion Functions
1) implicit data typ conversion
varchar2 or char ---number
varchar2 or char ---date
numbeer ---varchar2
date ---varchar2
2) to_char(date,'format')
format:
YYYY Full year in numbers
YEAR Year spelled out
MM Two-digit value for month
MONTH Full name of the month
MON THree-letter abbreviation of the month
DY Three-letter abbreviation of the day of the week
DAY Full name of the day of hte week
DD Numberic day of the month
HH24:MI:SS AM 15:45:32:PM
DD "of" MONTH 12 of october
3) to_char function with number
TO_CAHR(number,'format_model')
These are some of the format elements you can use with the to_char function to display number as a character.
9 Reqresents a number
0 Forces a zero to be displayed
$ Places a flationg dollar sign
L Uses the floating local currency symbol
. Prints a decimal point
, Print a thousand director
select to_char(qtym,"$999.99")
4) Using t_number and to _date functions
a converting a character string to a number format using to_number function
to_number(char,"format")l
b converting a character string to a date format
to_date(char,"format")
5 Nesting Functions
.Single-row function can be nested to many level
.Nested function can be evaluated from deepest level
6General Function
These function work with any data type and pertain to using nulls
nvl(expr1,expr2);
nvl2(expr1,expr2,expr3)
nullif(expr1,expr2)
coalesce(expr1,expr2,,,,exprn)
1) nvl function
convert a null to an actual function
a Data type can be used are data character and number
b Data types must match
(set wrap off
set line 1000
)
2)Using the COALESCE Function
a The advantage of the coalesce function over nal function is that coalesce function can take multiple alternative value
b If the first value is not null, it return that expression,otherwise,it does a coalesce of remaining expressions
6 Conditional Expressions
a Provide the use of if-then-else logic
b use two methods: case expression decode function
select last_name,job_id,salary,
case job_id when 'it' then 1*salary
when 'manager' then 1.2*salary
else salary end;
from employee.
select last_namek,job_id,salary,
decode(job_id,'it' ,1*salary,
'manager',1.2*salary,
salary)
from employees
1 What Are Group Functions
Group functions operatee on sets of rows to give one result per group
1)agg,count,max,min,stddev,sum,variance
select avg(salary),max(salary),min(salary),sum(salary)
from employees
where job_id like '%REP%'
select count(*) from
select count(address) from authors
count the valid count of the address (exclude the null value)
2) Using theDISTINCT Keyword
count(distinct expr) return thee number of the distinct non-null value of the expr
select count(distincee department_id) from employees
3)Group functions and null values
group functions ignore null values in the clumn
4) Using thee NVL Function with Group Functions
The nul function force group funtion to include null values
select avg(nvl(commission_pct,0)) from employees
2 Creating Groups of Data
1)
a Divide rows in a table into smaller groups by using the group by clause
b All coulmns in the select list that are not in group function must be in the group by clause
select department_id,avg(salary)
from employees
group by department_id;
2) Grouping by More Than One Column
3) Ilegal Queries Using Group Functions
a You cannot use thee where clause to restrict groups
b You use thee having clause to restrict groups
c you cannot use group functions in the where clause
4)Excluding Group Resdults:The Having Clause
Use the HAVING clause to restrict groups
a Rows are grouped
b The group functions is applied
c Groups matcching the Having clause are display
select department_id,max(salary)
from employees
group by department_id
having max(salary)>10000
5) Nesting Group function
select max(avg(salary))
from employees
group by department_id;
1 Keyboardd Basics
1) Ignoring the Keyboard
Your programm does not need to act on every keyboard message it received,Window handle many keyboard message function itself.
2)Who's Got thefocus
Though the keyboard is shared by all the window in the application ,The DispatchMessage send the message to the window procedure associated the window which message is intended.
The window that receives a particular keyboard event is the window has the input foucs.
Sometime no window has input foucs,this is the case if all your programs have been minmized,window continue send keyboard to the active window ,but it is send in the deffert form from sending to the input foucs.
A window procedure can be determine when its window has the input focus by trapping WM_SETFOCUS and WM_KILLFOCUS.
3) Queues and Synchronization
As the user presses and releases key on keyborad,Windows and keyboard device driver translate the hardware scan code into formatted message.Howerver the messages are not palced on the application queue right away,Instean Windows store these message in a system message queue .The System message queue is a single message maintained by windows specifically for the prelimary storage of user input from keyboard and the mouse. Window will take the next message from the system message queue and place it on the application message queue only when a window application has finished proecssing the previous user input message.
4) Keystorkes and Character
The message that an application receives from windows about keyboard events distingush between keystrokes and characters.
for instance The keysokes has only one key labbed 'A' ,and the character may be 'a' or 'ctr-a' etc.
2 Keystroke Message
1)Wirtual key Codes
The virtual key code is stored in the wParam parameter of WM_KEYDOWN,WM_KEYUP,the code identifies the key being pressed or release.
2)lParam Information
the wParam message parameter contain virtual key code and the lparam message parameter contains other information in understanding the keystoke.
3) Shift States
iState = GetKeyState (VK_SHIFT) ;
iState variable will be negative if the Shift key is donw
iState = GetKeyState (VK_CAPITAL) ;
4)Using Keystroke Messages
5)
case WM_KEYDOWN:
switch (wParam)
{
case VK_HOME:
SendMessage (hwnd, WM_VSCROLL, SB_TOP, 0) ;
break ;
case VK_END:
SendMessage (hwnd, WM_VSCROLL, SB_BOTTOM, 0) ;
break ;
case VK_PRIOR:
SendMessage (hwnd, WM_VSCROLL, SB_PAGEUP, 0) ;
break ;
3 Character Messages
Message Key or Code
WM_KEYDOWN Virtual key code for `A' (0x41)
WM_CHAR Character code for `a' (0x61)
WM_KEYUP Virtual key code for `A' (0x41)
Message Key or Code
WM_KEYDOWN Virtual key code VK_SHIFT (0x10)
WM_KEYDOWN Virtual key code for `A' (0x41)
WM_CHAR Character code for `A' (0x41)
WM_KEYUP Virtual key code for `A' (0x41)
WM_KEYUP Virtual key code VK_SHIFT (0x10)
Key Character Code Duplicated by ANSI C Escape
Backspace 0x08 Ctrl-H \b
Tab 0x09 Ctrl-I \t
Ctrl-Enter 0x0A Ctrl-J \n
Enter 0x0D Ctrl-M \r
Esc 0x1B Ctrl-[
case WM_CHAR:
[other program lines]
switch (wParam)
{
case `\b': // backspace
[other program line
break ;
case `\t': // tab
[other program lines]
break ;
case `\n': // linefeed
[other program lines]
break ;
case `\r': // carriage return
[other program lines]
break ;
default: // character codes
[other program lines]
break ;
}
return 0 ;
1 An Architectural Overview
1)Getting a good feel for messages is an import part of learning how to write programs for windows.
Windows send a message to your porgram means that Windows calls a function in your program .The parameter of this function describe the message that is being send.The function in your program is know as Window Procedure.
Windows send a message to window by calling window procedure ,The window procedure do some processing based on the message and return control to Windows.
More precisely , a Window is always createdd based on a "window class".The window class identifies the window procedure that precesses messages to the windows.The use of window class allow mutiple window to be based the same window class and hence use the same window procedure.
2) Requsteriing the Window Class
typedef struct
{
UINT style ;
WNDPROC lpfnWndProc ;
int cbClsExtra ;
int cbWndExtra ;
HINSTANCE hInstance ;
HICON hIcon ;
HCURSOR hCursor ;
HBRUSH hbrBackground ;
LPCTSTR lpszMenuName ;
LPCTSTR lpszClassName ;
}
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
2)Creating the Window
Window class define the general Characteristics of the a window.If you want to create window based on the same window class,you can use CreateWindwo which allow you to specify more detail imformation about the window.
hwnd = CreateWindow (szAppName, // window class name
TEXT ("The Hello Program"), // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL) ; // creation parameters
3)Displaying the window
When thee CreateWindow function return ,windows create a window internal.What it means is that windows allocate a block memory to store the imformation about the window.If you want to show that ,you should call
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
4) The Message Loop
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
typedef struct tagMSG
{
HWND hwnd ;
UINT message ;// message identifier
WPARAM wParam ;
LPARAM lParam ;
DWORD time ; // the time the message is placed on the message queen
POINT pt ; // the mouse coordiante
}
typedef struct tagPOINT
{
LONG x ;
LONG y ;
}
POINT, * PPOINT;
the message filed of message retrived from the message queen is anyting except WM_QUITm ,GetMessage return a nonzero value
wM_QUIT cause GetMessage reuturn 0.
TranslateMessage (&msg) ;
passing the msg struct back to window for some keysboard translation
DispatchMessage (&msg) ;
pass the msessageback to window .Windwo then send the message to the appropriate window procedure for processing.After window
procedure processing the message ,it return control to the windows,which is still in serving the Dispatchmessage
5) The Window Procedure
a The window procedure determined the how the window display on the client area and how the window respose to user input
b LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam),the four parameter is idential to the first four filed of the message struct.
6) Processing the Message
switch (iMsg)
{
case WM_CREATE :
[process WM_CREATE message]
return 0 ;
case WM_PAINT :
[process WM_PAINT message]
return 0 ;
case WM_DESTROY :
[process WM_DESTROY message]
return 0 ;
}
return DefWindowProc (hwnd, iMsg, wParam, lParam) ;
when a window procedure process the message ,it should return 0;
7) The WM_PAINT Message
WU_PAINT message is extremely import in window.it inform a program when part or all of the window 's client area are invalid and must be redraw or repaint.
WM_PAINT processing almost always begins with a call to BeginPaint:
hdc = BeginPaint (hwnd, &ps) ; //return a handle to device context
and ends with a call to EndPaint:
EndPaint (hwnd, &ps) ;
8)The WM_DESTROY Message
PostQuitMessage (0) ;
WNDCLASS, * PWNDCLASS ;
#include <windows.h>
/* the same as long _stdcall WndPro(long,unsign int,unsign int ,long)*/
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
/*int _stdcall WinMain(long hInstance,long hPrevInstance,char * szComdLine,int iCmdShow)*/
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("HelloWin") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
/*
all window createe based on this window class will completely repaint whenever horizational window sizd and vertial
window size change.
*/
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ; // set the window procedure for the window class
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ; // the handle of this program
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, // window class name
TEXT ("The Hello Program"), // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL) ; // creation parameters
ShowWindow (hwnd, iCmdShow) ;// iCmdShow determine how the window is to be initially displayed on the screen.
UpdateWindow (hwnd) ; // cause the client area to paint
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc ;
PAINTSTRUCT ps ;
RECT rect ;
switch (message)
{
case WM_CREATE:
PlaySound (TEXT ("hellowin.wav"), NULL, SND_FILENAME | SND_ASYNC) ;
return 0 ;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;//return a handle to device context
GetClientRect (hwnd, &rect) ;// set the struct rect with the dimensions of the client area
DrawText (hdc, TEXT ("Hello, Windows 98!"), -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_DESTROY:
PostQuitMessage (0) ;// insert a WM_QIUT in the message queue.
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
2 The Window Programming Hurdles
1)Queue and noqueue message
queue message are post the message queue and the noqueue message send to the window procdure directly.
1 Understand Transaction
1) Introduce Spring's transaction manager
a JDBC transactions
<bean id="transactionManager" class="org.springframework.jdbc.
datasource.DataSourceTransactionManager">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
b Hibernate transactions
<bean id="transactionManager" class="org.springframework.
orm.hibernate.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
2 Programing transaction in Spring
One approach to adding transaction to your code is to programmly add transactional boundary using transiationTemplate class.
Programming is good when you want complete control over transactional boundary.but you have to use spring specific class.In most case ,your tansactional needs will not require such precise control over transactional boundaries.That is why you will typically choolse to declare transaction support
public void enrollStudentInCourse() {
transactionTemplate.execute(
new TransactionCallback() {
public Object doInTransaction(TransactionStatus ts) {
try {
// do stuff Runs within doInTransaction()
} catch (Exception e) {
ts.setRollbackOnly(); //Calls setRollbackOnly() to roll Calls setRollbackOnly() //to roll back
}
return null; //If successful, transaction is committed
}
}
);
}
<bean id="transactionTemplate" class="org.springframework.
transaction.support.TransactionTemplate">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
</bean>
<bean id="courseService"
class="com.springinaction.training.service.CourseServiceImpl">
<property name=" transactionTemplate">
<ref bean=" transactionTemplate"/>
</property>
</bean>
3 Declaring transactions
Spring's support for declarative transaction management is implementedd through Spirng's AOP framework.
<bean id="courseService" class="org.springframework.transaction.
interceptor.TransactionProxyFactoryBean">
<property name="proxyInterfaces">
<list>
<value>
com.springinaction.training.service.CourseService
</value>
</list>
</property>
<property name="target">
<ref bean="courseServiceTarget"/> //Bean being proxied
</property>
<property name="transactionManager">
<ref bean="transactionManager"/> //Transaction manager
</property>
<property name="transactionAttributeSource">
<ref bean="attributeSource"/> //Transaction attribute source
</property>
</bean>
1) Understanding transaction attributes
In Spring transaction attribute is a description of how transaction policies should be
applied to a methods
a Propagation behavior
Propagation behavior What it means
PROPAGATION_MANDATORY indicate that the method must run within a transaction.If no transaction is in progress
an exception will be thrown
PROPAGATION_NESTED
PROPAGATION_NEVER indicate that the method can not run withi a transaction. if a transaction exist an exception will be thrown.
PROPAGATIOM_NOT_SUPPORT Indicates that the method should not run within a transaction. If an existing transaction is in progress, it will be suspended for the
duration of the method.
PROPAGATION_REQUIRED indicate that the current method must run within a transaction.if an existing transaction is in progress,the ,method will run with the transaction
otherwise a new transaction will be started
PROPAGATION_REQUIRENEW indicates that the current must run within its own
transaction.A new transaction is started and an existing transaction will be suspend
PROPAGATION_SUPPORT indicate the current mehtod does not require a transaction.but may run if on is already in progress
b Isolation levels
Isolation level What it means
ISOLATION_DEFAULT Using the defaul isolation level of the underlying database
ISOLATION_READ_UNCOMMITTED Allows you read change that have not yet been commit
May result in dirty read,phantom read,nonrepeatable read
ISOLATION_READ_COMMITTED Allows reads from concurrent transactions that have
bean committed.Dirty read are prevent.but platform and norepeatable reads may still occur.
ISOLATIOM_REPEATABLE_READ Multiple read the same field will yield the same result ,unless changed by the transaction itself.Dirty reads ,nonrepeatable are all prevented
phantom may still occur
ISOLATION_SERIALIZABLE This fully ACID-compliant isolation level ensusme that dirty read,unrepeatable read ,phantom read are all prevented.And this is the most slowest isolation
since it is typically accomplished by doing full table lock on the tables in the transaction.
c Read-Only
If a transaction performs only read operation against the underlying datastore.when a transaction begin ,it only make sense to declare a transaction as read only on mehtods with
propagation behavior which start a new transaction.
Furthermore ,if you are Hibernate as persistence mechanism,declaring a transaction as read only will reult in Hibernate flush mode being set to FLUST_NEVER.this tell hibernate to avoid synchroniztion of objects with database.
d Transaction timeout
Suppose that your transaction becomes unexpectedly long-running transaction.Because transaction may invole locks on the underlying database.Instead of waiting it out ,you can delcare a transaction to automaitically roll back.
because timeout clock begin ticking when a transaction start. it only make sense to declare a transaction timeout on methods with propagation behavior that start a new transaction.
2) Declaring a simple transaction policy
<bean id="myTransactionAttribute"
class="org.springframework.transaction.interceptor.
DefaultTransactionAttribute">
<property name="propagationBehaviorName">
<value>PROPAGATION_REQUIRES_NEW</value>
</property>
<property name="isolationLevelName">
<value>ISOLATION_REPEATABLE_READ</value>
</property>
</bean>
<bean id="transactionAttributeSource"
class="org.springframework.transaction.interceptor.
MatchAlwaysTransactionAttributeSource">
<property name="transactionAttribute">
<ref bean="myTransactionAttribute"/>
</property>
</bean>
4 Declaring transactions by method name
1) Using NameMatchTransactionAttributeSource
The properties property of NameMatchTransactionAttributeSource maps mehtod to a transaction property descriptor. the property descriptor takes the following form:
Propagation,isolation,readOnly,-Exception,+Exception
<bean id="transactionAttributeSource"
class="org.springframework.transaction.interceptor.
NameMatchTransactionAttributeSource">
<property name="properties">
<props>
<prop key="enrollStudentInCourse">
PROPAGATION_REQUIRES_NEW
</prop>
</props>
</property>
</bean>
2) Specifying the transaction Isolation level
<bean id="transactionAttributeSource"
class="org.springframework.transaction.interceptor.
NameMatchTransactionAttributeSource">
<property name="properties">
<props>
<prop key="enrollStudentInCourse">
PROPAGATION_REQUIRES_NEW,ISOLATION_REPEATABLE_READ
</prop>
</props>
</property>
</bean>
3) Using real-only transaction
<bean id="transactionAttributeSource"
class="org.springframework.transaction.interceptor.
NameMatchTransactionAttributeSource">
<property name="properties">
<props>
<prop key="getCompletedCourses">
PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ,readOnly
</prop>
</props>
</property>
</bean>
4)Specifying rollback rules
You can sepcify that a transaction be rollback on specify checked exception
<bean id="transactionAttributeSource"
class="org.springframework.transaction.interceptor.
NameMatchTransactionAttributeSource">
<property name="properties">
<props>
<prop key="enrollStudentInCourse">
PROPAGATION_REQUIRES_NEW,ISOLATION_REPEATABLE_READ,
-CourseException
</prop>
</props>
</property>
</bean>
Exception can be marked as negative(-) or postive(+)
Negative exception will trigger the roll back if the exception (or sublclass of it) is thrown.Postive exception on the other hand indicate that the transacton should be commit
even if the exception is thrown
5)Using wildcard matches
<bean id="transactionAttributeSource"
class="org.springframework.transaction.interceptor.
NameMatchTransactionAttributeSource">
<property name="properties">
<props>
<prop key="get*">
PROPAGATION_SUPPORTS
</prop>
</props>
</property>
</bean>
6 Short-cut name match transaction
<bean id="courseService" class="org.springframework.transaction.
interceptor.TransactionProxyFactoryBean">
<property name="transactionProperties">
<props>
<prop key="enrollStudentInCourse">
PROPAGATION_REQUIRES_NEW
</prop>
</props>
</property>
</bean>
一 Unicode 简介
1 Unicode 是ASCII 扩展,从传统的7位,扩展位16 位,可以显示世界上所有语言
ASCII 码
0- 1- 2- 3- 4- 5- 6- 7-
-0 NUL DLE SP 0 @ P ` p
-1 SOH DC1 ! 1 A Q a q
-2 STX DC2 " 2 B R b r
-3 ETX DC3 # 3 C S c s
-4 EOT DC4 $ 4 D T d t
-5 ENQ NAK % 5 E U e u
-6 ACK SYN & 6 F V f v
-7 BEL ETB ' 7 G W g w
-8 BS CAN ( 8 H X h x
-9 HT EM ) 9 I Y I y
-A LF SUB * : J Z j z
-B VT ESC + ; K [ k {
-C FF FS , < L \ l |
-D CR GS - = M ] m }
-E SO RS . > N ^ n ~
-F SI US / ? O _ o DEL
2 双位字符集
DBCS:double-byte character set,最初的128个代码是ASCII,较高的128个代码中的某些总是跟随著第
二个位元组。这两个位元组一起(称作首位元组和跟随位元组)定义一个字元。
3 Unicode 解决方案
Unicode是统一的16位元系统,也DBCS 这样的同时含有一位和两位的字符集不同,Unicode 可以表示
65536 个字符。
Unicode 的缺点是,Unicode 使用的空间是ASCII 的两倍
二 宽字符和c
1 char
char c='A';
变量c 用一个字节来存储,用16 进制表示位0x41
char * p;
32 位系统,一次指针变量需要用4个字节表示
char * p="Hello!";
字符串占用7个字节 其中 6个用于保存字符串,1个用于保存中止符号0
char [10]
占用10个字节
char a[]="Hello!";
占用 7个字节
2 宽字节
typedef unsigned short whcar_t which is define in the window.h
与unsign short 一样 为16 字节,两个字节
wchar_t c='A' 0x0041
wchar_t *p=L"Hello!" 指针占用 4个字节 而 字符串占用 14 个字节
3 宽字元程序库函数
char * pc = "Hello!" ;
iLength = strlen (pc) ;
wchar_t * pw = L"Hello!" ;
iLength = wcslen (pw) ;
4 维护单一原始码
Microsoft Visual C++包含的TCHAR.H
如果定义了名为_UNICODE的识别字,并且程式中包含了TCHAR.H表头档案,那么_tcslen就定义为wcslen
#define _tcslen wcslen
如果没有定义UNICODE,则_tcslen定义为strlen:
#define _tcslen strlen
如果定义了 _UNICODE识别字,那么TCHAR就是wchar_t:
typedef wchar_t TCHAR ;
否则,TCHAR就是char:
typedef char TCHAR ;
如果没有定义_UNICODE识别字
#define __T(x) x
#define _T(x) __T(x)
#define _TEXT(x) __T(x)
三 宽字节和windows
1 window 头文件中的类型
typedef char CHAR ;
typedef wchar_t WCHAR ;
typedef CHAR * PCHAR, * LPCH, * PCH, * NPSTR, * LPSTR, * PSTR ;
typedef CONST CHAR * LPCCH, * PCCH, * LPCSTR, * PCSTR ;
typedef WCHAR * PWCHAR, * LPWCH, * PWCH, * NWPSTR, * LPWSTR, * PWSTR ;
typedef CONST WCHAR * LPCWCH, * PCWCH, * LPCWSTR, * PCWSTR ;
#ifdef UNICODE
typedef WCHAR TCHAR, * PTCHAR ;
typedef LPWSTR LPTCH, PTCH, PTSTR, LPTSTR ;
typedef LPCWSTR LPCTSTR ;
#else
typedef char TCHAR, * PTCHAR ;
typedef LPSTR LPTCH, PTCH, PTSTR, LPTSTR ;
typedef LPCSTR LPCTSTR ;
#endif
2 Windows 函数调用
#ifdef UNICODE
#define MessageBox MessageBoxW
#else
#define MessageBox MessageBoxA
#endif
3 Windows 的字符函数
ILength = lstrlen (pString) ;
pString = lstrcpy (pString1, pString2) ;
pString = lstrcpyn (pString1, pString2, iCount) ;
pString = lstrcat (pString1, pString2) ;
iComp = lstrcmp (pString1, pString2) ;
iComp = lstrcmpi (pString1, pString2) ;
4 在windows 使用printf
windows 并不支持printf 但是可以使用sprintf
int printf (const char * szFormat, ...) ;
printf ("The sum of %i and %i is %i", 5, 3, 5+3) ;
int sprintf (char * szBuffer, const char * szFormat, ...) ;
char szBuffer [100] ;
sprintf (szBuffer, "The sum of %i and %i is %i", 5, 3, 5+3) ;
puts (szBuffer) ;
一 Spring DAO philosophy
1 Understanding Spring's DataAccesssException
Spring's DAO frameworks donot throw teechnology-specific exceptions such as SQLException
or HibernateeExcepiton.Instead ,all exceptions thrown are subclasses of DataAccessException
2 You are not forced to handle DataAccessExceptions
DataAccessException is a RuntimeException,so it si an unchecked exception.Since these are quite often unrecoverable,you are not forced to handle these exception.
Instead ,you can catch the exception if recovery is possible.since DataAccessException is not only a RuntimeException,but it subclasses Spring's NestedRuntimeException. This menas that the root Exception is alwarys via NestedRuntimeException's getCause() method.
3 Work with DataSources
a getting a Datasource from JNDI
<bean id="dataSource"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/myDatasource</value>
</property>
</bean>
b Creating a Datasource connection pool
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driver">
<value>${db.driver}</value>
</property>
<property name="url">
<value>${db.url}</value>
</property>
<property name="username">
<value>${db.username}</value>
</property>
<property name="password">
<value>${db.password}</value>
</property>
</bean>
c Using a DataSource while testing
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
4 Consistent DAO support
Spring template class handle the invariant part of data access-controling the trancsaction
manage resource,handling exception .Implementation of callback interface define what is specific to your application--creating statement,binding parameter and marshalling result set.
Spring separates the fixed an vaiant parts of data access process into tow distince classes:
template and callbacks.Template manage the fixed parts of the process while callback are where you fill in the implement details;
one the top of template-callback desing ,spring framework provide a support class which your own data access subclass it. And the support class already have a property for holding a template.
二 Integerating Hibernate with Spring
1 Managing Hibernate resources
you will keep a single instance of SessionFactory throughtout your application
<bean id="sessionFactory"class="org.springframework.
orm.hibernate.LocalSessionFactoryBean">
<bean id="sessionFactory" class="org.springframework.
orm.hibernate.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
you also want to manager how hibernate is configured
<bean id="sessionFactory" class="org.springframework.
orm.hibernate.LocalSessionFactoryBean">
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">net.sf.hibernate.
dialect.MySQLDialect</prop>
</props>
</property>
…
</bean>
and the last thing is whick map files is read
<bean id="sessionFactory" class="org.springframework.
orm.hibernate.LocalSessionFactoryBean">
<property name="mappingResources">
<list>
<value>Student.hbm.xml</value>
<value>Course.hbm.xml</value>
…
</list>
</property>
…
</bean>
Now you have fully configured your sessionfactory ,so we need do create an object which we
will access hibernate. As we know, we will use a template class
<bean id="hibernateTemplate"
class="org.springframework.orm.hibernate.HibernateTemplate">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<bean id="courseDao" class="com.springinaction.
training.dao.hibernate.CourseDaoHibernate">
<property name="hibernateTemplate">
<ref bean="hibernateTemplate"/>
</property>
</bean>
2 Accessing Hibernate through HibernatTemplate
The template-callback mechanism in Hibernatee is pretty simple.There is the HibernatTmpplate and one callback interface
public Student getStudent(final Integer id) {
return (Student) hibernateTemplate.execute(
new HibernateCallback() {
public Object doInHibernate(Session session)
throws HibernateException {
return session.load(Student.class, id);
}
});
The HibernateTemplate class provides some convience methods that implicit create a HibernateCallback instance:
(Student) hibernateTemplate.load(Student.class, id);
hibernateTemplate.update(student);
hibernateTemplate.find("from Student student " +
"where student.lastName = ?",
lastName, Hibernate.STRING);
3 Subclassing HibernateDaoSupport
public class StudentDaoHibernate extends HibernateDaoSupport
implements StudentDao {
…
}
getHibernateTemplate()
getSession()
1 hibernate 一级缓存
Session
evict(Object o) 从缓存中清除指定的持久化对象
clear() 清除缓存中所有对象
2 批量更新于批量删除
1) 批量更新
Iterator customers=session.find("from Customer c where c.age>0");
while(customers.hasNext()){
Customer customer=(Customer)customers.next();
customer.setAge(customer.getAge()+1);
}
tx.commit();
session.close();
缺点:内存中加载了大量数据
执行了多次update 语句
改进
Iterator customers=session.find("from Customer c where c.age>0");
while(customers.hasNext()){
Customer customer=(Customer)customers.next();
customer.setAge(customer.getAge()+1);
session.flush();
session.evict(customer);
}
tx.commit();
session.close();
遗留问题
执行了多次update 语句
采用jdbc api 进行调用
Connection con=session.connection();
PrepareStatement stmt=con.prepareStatement("update customers set age=age+1 where age>0");
stmt.executeUpdate();
tx.commit();
另外,也可以调用底层的存储过程进行批量更新
create or replace procedure batchUpdateCustomer(p_age,in number) as
begin
update customer set age=age+1 where age>p_age;
end;
tx=session.beginTransaction();
Connection con=session.connection();
CallableStatement cstmt=con.prepareCall(batchUpdateCustomer);
cstmt.setInt(1,0);
cstmt.eqecuteUpdate();
tx.commit();
2) 批量数据的删除
session.delete("from Customer c where c.age>0");
实际调用的过程
session * from Customer where age>0;
在把所有数据加载到内存之后执行多条delete 语句
delete from customer where id=i;
.......................
改进办法采用jdbc api 进行批量数据的删除
tx=session.beginTransaction();
Connection con=session.connection();
con.execute("delete from customers where age>0");
tx.commit();
Hibernate java sql oracle
integer or int int or Integer INTEGER
long long or Long BIGINT
short short or Short SMALLINT
byte byte or Byte TINYINT
float float or Float FLOAT
double double or Double DOUBLE
big_decimal java.math.BigDecimal NUMBERBIC
character char java.lang.Character CHAR(1)
String
string String VARCHAR
boolean boolean or Boolean BIT
date java.util.Date DATE
java.sql.Date
time Date or java.sql.time TIME
timestamp Date or java.sql.Timestamp TIMESTAMP
binary byte[] blog blog
text String clob clog
serializable blog blog
clob java.sql.clob clob clob
blob java.sql.blob blog blob
1 动态连接
Windows 运作机制的核心是一个称作动态连接的概念
#include <windows.h>
int WINAPI WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
MessageBox (NULL, TEXT ("Hello, Windows 98!"), TEXT ("HelloMsg"), 0);
return 0 ;
}
1) #include <windows.h>包含其它的头文件
2) 程序入口
int WINAPI WinMain ( HINSTANCE hInstance,HINSTANCE hPrevInstance,
PSTR szCmdLine,int iCmdShow)
a #define WINAPI __stdcall 指定一个呼叫约定,包括如何生产机器码,参数如何入栈
b HINSTANCE hInstance 执行体代号,唯一标识该程序
c HINSTANCE hPrevInstance 已经不采用
d PSTR szCmdLine 参数列表
e int iCmdShow 显示方式
3) MessageBox 函数
MessageBox (NULL, TEXT ("Hello, Windows 98!"), TEXT ("HelloMsg"), 0);
参数1 窗体代号
参数2 主题显示文字
参数3 标题显示文字
参数4 按钮,0 为确认 使用C语言的OR(|)操作符号将上面显示的一个常数与代表内定按钮的常数组合:
#define MB_OK 0x00000000L
#define MB_OKCANCEL 0x00000001L
#define MB_ABORTRETRYIGNORE 0x00000002L
#define MB_YESNOCANCEL 0x00000003L
#define MB_YESNO 0x00000004L
#define MB_RETRYCANCEL
#define MB_DEFBUTTON1 0x00000000L
#define MB_DEFBUTTON2 0x00000100L
#define MB_DEFBUTTON3 0x00000200L
#define MB_DEFBUTTON4
图示的外观
#define MB_ICONHAND 0x00000010L
#define MB_ICONQUESTION 0x00000020L
#define MB_ICONEXCLAMATION 0x00000030L
#define MB_ICONASTERISK
#define MB_ICONWARNING MB_ICONEXCLAMATION
#define MB_ICONERROR MB_ICONHAND
#define MB_ICONINFORMATION MB_ICONASTERISK
#define MB_ICONSTOP
2 c 语言编译过程 c--compile -- .obj ---linking---- .exe
一 文件
1 c 标准文件驱动器,可以支持两种文件类型,二进制文件,和文本文件。c 标准文件是在头文件
stdio.h 中声明。
标准文件类型通过指针来进行存储 FILE * fp;
2 c++ 流式文件类 fstream,ifstream 和ofstream,分别对应读写,读和写,并支持文本和二进制文
件。
3 非缓冲文件
二 文件对话框组件
1 OpenDialog 两种.TXT and .PAS 两种类型的过滤器。
1) Filter OpenDaalog1->Filter="Text files{*.txt}|*.TXT|Pascal files{*.pas}|*.PAS";
同一个过滤器中,还可以有多种文件后缀
OpenDialog1->Filter="Pascal files|*.PAS;*.DPK;*.DPR";
2) FilterIndex 设置对话框一打开时选中的文件过滤。数值从1开始计算。
3) InitialDir 设置对话框打开时定位的目录。
4) Options
OpenPictureDialog1->Options.Clear();
OeenPictureDialog1->Options<<ofFileMustExist<<ofHideReadOnly<<ofNoChangeDir;
5) Title 设置对话框标题中显示的内容。
2 SaveDialog 组建可以选择并保存文件
3 OpenPictureDialog 可以选择并打开图形文件。
4 SavePictureDialog 可以选择并保存图形文件。
三 Win3。1 相关组件
FileListBox,DirectoryListBox,DriveCombox,FilterComboBox
四 常用文件管理函数
1 文件函数常用函数
将一个文件从记录盘上删除,如果不存在或无法删除。则返回False。
extern PACKAGE bool __fastcall DeleteFile(const AnsiString FileName);
void __fastcall TFORM1::ButtonClick(TObject *Sender)
{
char buffer[256];
GetWindowsDirectory(buffer,sizeof(buffer));//获取Windows 系统目录
AnsiString asFileName=FileSearch(Edit1->Text,GetCurrentDir()+AnsiString(";")
+AnsiString(buffer));//在当前目录下和windows系统}//目录下查询文件。
if(asFileName.IsEmty()) ShowMessage(AnsiString("Couldn't Found")+Edit1->Text1);
2 FileSeek
extern PACKAGE int __fastcall FileSeek(int Handle, int Offset, int Origin);
extern PACKAGE __int64 __fastcall FileSeek(int Handle, const __int64 Offset, int Origin);
Description
Use FileSeek to reposition the read/write point in a file that was opened with FileOpen or
FileCreate. Handle is the file handle that was returned by FileOpen or FileCreate.
Offset specifies the number of bytes from Origin where the file pointer should be
positioned. Origin is a code with three possible values, denoting the beginning of the file,
the end of the file, and the current position of the file pointer.
Origin Action
0 The file pointer is positioned Offset bytes from the beginning of the file.
1 The file pointer is positioned Offset bytes from its current position.
2 The file pointer is positioned Offset bytes from the end of the file.
If FileSeek is successful, it returns the new position of the file pointer; otherwise, it
returns -1.
void __fastcall TForm1::Button1Click(TObject *Sender)
{
int iFileHandle;
int iFileLength;
int iBytesRead;
char *pszBuffer;
if (OpenDialog1->Execute())
{
try
{
iFileHandle = FileOpen(OpenDialog1->FileName, fmOpenRead);
iFileLength = FileSeek(iFileHandle,0,2);
FileSeek(iFileHandle,0,0);
pszBuffer = newchar[iFileLength+1];
iBytesRead = FileRead(iFileHandle, pszBuffer, iFileLength);
FileClose(iFileHandle);
for (int i=0;i<iBytesRead;i++)
{
StringGrid1->RowCount += 1;
StringGrid1->Cells[1][i+1] = pszBuffer[i];
StringGrid1->Cells[2][i+1] = IntToStr((int)pszBuffer[i]);
}
delete [] pszBuffer;
}
catch(...)
{
Application->MessageBox("Can't perform one of the following file operations: Open,
Seek, Read, Close.", "File Error", IDOK);
}
}
}
3FileExists
if(FileExist(SaveDialog1->FileName))
{
RenameFile(SaveDialog1->File,SaveDialog1->FileName+".bak");
}
iFileHandle=fileCreate(SaveSialog1->FileName);
for(int i=0;i<Memo2->Lines->String[i].length())
{
FileWrite(iFileHandle,Memo2->Lines->String[i].c_str(),length);
}
FileClose(iFileHandle);
4 FileGetAttrs
FileGetAttr returns the attributes of the file as a string of bits. This value is the same
as the Attr field of a TSearchRec struct. Check for individual attributes with code such as
the following:
int Attrs = FileGetAttr("MyFile.sys");
if x(Attrs & faHidden)
FileSetAttr("MyFile.sys", Attrs & !faHidden);
A return value of -1 indicates that an error occurred.
5 FileSetAttrs
FileSetAttr sets the file attributes of the file given by FileName to the value given by
Attr. The value of Attr is formed by combining the appropriate file attribute constants, as
in the following:
FileSetAttr("MyFile.sys", faReadOnly | faSysFile);
FileSetAttr returns zero if the function was successful. Otherwise the return value is an
error code.
三 目录操作常用函数
1 CreateDir
#include <Filectrl.hpp>
void __fastcall TForm1::Button1Click(TObject *Sender)
{
if (!DirectoryExists("c:\\temp"))
{
if (!CreateDir("C:\\temp"))
throw Exception("Cannot create c:\\temp directory.");
}
}
2 ForceDirectories
ForceDirectories creates a new directory as specified in Dir, which must be a fully-
qualified path name. If the directories given in the path do not yet exist, ForceDirectories
attempts to create them.
ForceDirectories returns true if it successfully creates all necessary directories, false
if it could not create a needed directory.
Important
Do not call ForceDirectories with an empty string. Doing so causes ForceDirectories to
throw an exception.
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Dir = "C:\Apps\Sales\Local";
if (ForceDirectories(Dir))
Label1->Caption = Dir + " was created";
}
3 GetCurrentDir
获取当前的目录完整的路径名
4 RemoveDir
删除一个存在的目录,目录必须为空
5 SetCurrentDir设置系统的当前目录
6 SelectDirectory
extern PACKAGE bool __fastcall SelectDirectory(constAnsiString Caption, const WideString
Root, AnsiString &Directory);
Call SelectDirectory to let the user enter a directory name.
Use the first syntax to display the Windows directory browser. The Caption parameter
specifies a caption for the dialog. The Root parameter specifies the root directory from
which to browse. The selected directory is returned as the Directory parameter. When using
this syntax,
SelectDirectory does not change the value of the current directory.
extern PACKAGE bool __fastcall SelectDirectory(AnsiString &Directory, TSelectDirOpts
Options, int HelpCtx);
enum TSelectDirOpt { sdAllowCreate, sdPerformCreate, sdPrompt };
typedef Set<TSelectDirOpt, sdAllowCreate, sdPrompt> TSelectDirOpts;
sdAllowCreate An edit box allows the user to type in the name of a directory that
does not exist. This option does not create a directory: the
application
must read the name of the selected directory and create it i
f desired.
sdPerformCreate Used only in combination with sdAllowCreate. If the user enters a
directory
name that does not exist, the directory selection dialog creates it.
sdPrompt Used only in combination with sdAllowCreate. Displays a message box
that informs the user when the entered directory does not exist
and asks if the directory should be created.
If the user chooses OK, the directory is created
if the option set includes sdPerformCreate.
If the option set does not include sdPerformCreate,
the directory is not created:
the application must read the directory name and create
#include <FileCtrl.hpp>
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Dir = "C:\\Program Files\\MyApp";
if (SelectDirectory(Dir, TSelectDirOpts() << sdAllowCreate << sdPerformCreate <<
sdPrompt,1000))
Label1->Caption = Dir;
}
三 驱动器常用函数
1 DiskFree 指定驱动器中剩余空间的字节数
2 DiskSize 驱动器容量
四文件名常用函数
1 ChangeFileExt
2 ExtractFileDir
3 ExtractFileDriver
4 ExtractFileExt
5 ExtractFileName
6 ExtractFilePath
7 ExtractRelativePath
实例
1
1
L a b e l 1 目录列表( & D ) : FocusControl: DirectoryListBox1
D i r e c t o r y L i s t B o x 1 D i r L a b e l : L a b e l 6 ;
FileList: FileListBox1
L a b e l 2 文件列表( & S ) : FocusControl: FileListBox1
F i l e L i s t B o x 1 FileEdit: Edit1
L a b e l 3 驱动器( & R ) : FocusControl: DriveComboBox1
D r i v e C o m b o B o x 1 DirList: DirectoryListBox1
L a b e l 4 文件类型( & F ) : FocusControl: FilterComboBox1
F i l t e r C o m b o B o x 1 FileList: FileListBox1
Filter: 所有文件 ( * . * ) | * . * |文本文件( * . t x t ) | * . t x t
L a b e l 5 路径名:
L a b e l 6 C : \ S a m p l e s \ S 0 6 B
L a b e l 7 文件名( & N ) : FocusControl: Edit1
E d i t 1
B u t t o n 1 文件长度( & L ) . . . Te x t : * . *
#include<stdio.h>
void __fastcall TForm1::Button1Click(TObject *Sender)
{
FILE* fp;
AnsiString FileFullName;
long size;
AnsiString PropertyMes;
FileFullName=Label2->Caption+"\\"+Edit1->Text;
if(FileExists(FileFullName))
{
fp=fopen(FileFullName.c_str(),"rt");
if(fp!=NULL)
{
fseek(fp,0L,SEEK_END);
size=ftell(fp);//get the length of file
PropertyMes="file is total"+IntToStr(size)+"bytes.";
MessageDlg(PropertyMes,mtInformation,TMsgDlgButtons() << mbOK, 0);
}else
{
MessageDlg(PropertyMes,mtWarning,TMsgDlgButtons() << mbOK, 0);
}
fclose(fp);
}
}
2 获取驱动器类型信息
UINT GetDriveType(
LPCTSTR lpRootPathName //获取根目录的路径名称
)
表6-5 函数G e t D r i v e Ty p e的返回值及其含义
数 值 含 义
0 无法检测驱动器的类型
1 根目录不存在
D R I V E _ R E M O VA B L E 可移动驱动器
D R I V E _ F I X E D 不可移动驱动器
D R I V E _ R E M O T E 网络驱动器
D R I V E _ C D R O M C D - R O M驱动器
D R I V E _ R A M D I S K 虚拟驱动器
Result=GetDriveType(Edit2->Text.c_str());
3 操作ini 文件
动态连接库(Dynamic link library),是一些编译过的可以执行的代码模块,后缀为.dll
1 DLL的基本理论
在使用普通函数库时,可以在程序连接时将库中的代码拷贝到执行文件中,这时静态链接,在多个同样程序执行时,体统保留了许多
代码副本,造成了内存资源的浪费。在使用dll时,不必将dll链接到程序中,而是在应用程序运行时动态的装载dll,装载dll被映射
到进程的地址空间中。同时,使用dll 并不时将库代码拷贝,只是在程序中记录了函数的入口点和接口。
2 DLL 的优点
1) 节省系统资源
2) 不仅可以包括可执行代码,还可以包括数据和各种资源
3)支持多语言
4)升级可以仅仅覆盖dll 文件
5)dll 独立编程语言,c++builder 中的dll vc 也可以使用
3导入导出匹配
DLL函数一般有两种函数,内部函数(internal)和导出函数(export).在实际情况下,许多DLL 调用了其他DLL里面的函数,因此
DLL可以同时有导入和导出函数。
DLL 包含有一个导出函数表,可以通过函数的符号化的名字和称为序号的正书来识别这些函数,函数表中包含了函数在dll内部的
地址。在动态链接进程好建立一张表,把客户的调用与dll里的函数的地址连接起来。
double dbValue(value);//内部函数
double dbValue(value);//内部函数
extern"c" _declspec(dllexpoert) double changeValue(double,bool);//外部函数
double dblValue(double value)
{
return value*vlaue;
}
double changeValue(double value,bool whichOp)
{
return whichOp?doublValue(value):halfValue(value);
}
如果我们希望dll可以用于其他语言或不同版本的c++ 需要在声明导出函数的时候加上extern "C."
4 隐式的链接和显示的链接
隐式链接(前面所讲)在创建dll 的时候,链接器产生一个lib 文件把拿获了dll中的导出符号和序号
显示链接调用Win32 的LoadLibrary 函数,使用完后,调用 FreeLibrary.
5 查找dll
依次顺序为包含exe 的目录,进程的当前目录,Windows 目录,path 环境变量里列出的目录。
6 创建动态链接库
(如何查看dll 文件的定义)
7 导出函数:extern "C" __declspec(dllexport) ExportType FunctionName(Parameter)
extern "C" __declspec(dllimport) __stdcall void CreateFromFunct();
extern "C" __declspec(dllexport) __stdcall void CreateFromFunct();//导出函数
导出类:class __declspec(dllexport) ExportType ClassName{...}
class __declspec(dllexport) __stdcall MyDllClass { //导出类
public:
MyDllClass();
void CreateAForm();
TDllFrm* DllMyForm;
};
__declspec(dllimport) class __stdcall MyDllClass {
public:
MyDllClass();
void CreateAForm();
TDllFrm* DllMyForm;
};
静态调用,build 生成dll 文件和lib 文件,并把lib 文件导入到工程中
void __fastcall TForm1::Button1Click(TObject *Sender)
{ // 导出类实现,导出类只能使用静态方式调用
DllClass = new MyDllClass();
DllClass->CreateAForm();
}
void __fastcall TForm1::Button2Click(TObject *Sender)
{ // 导出函数实现
CreateFromFunct();
}
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
delete DllClass;
}
动态调用
class TForm1 : public TForm
{
...
private: // User declarations
void (__stdcall *CreateFromFunct)();
...
}
HINSTANCE DLLInst = NULL;
void __fastcall TForm1::Button2Click(TObject *Sender)
{
if( NULL == DLLInst ) DLLInst = LoadLibrary("DLL.dll"); //上面的 Dll
if (DLLInst) {
CreateFromFunct = (void (__stdcall*)()) GetProcAddress(DLLInst,
"CreateFromFunct");
if (CreateFromFunct) CreateFromFunct();
else ShowMessage("Could not obtain function pointer");
}
else ShowMessage("Could not load DLL.dll");
}
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
if ( DLLInst ) FreeLibrary (DLLInst);
}
8 bcb 调用vc 编写的DLL
1) 名字分解
1. 名字分解:
没有名字分解的函数
TestFunction1 // __cdecl calling convention
@TestFunction2 // __fastcall calling convention
TESTFUNCTION3 // __pascal calling convention
TestFunction4 // __stdcall calling convention
有名字分解的函数
@TestFunction1$QV // __cdecl calling convention
@TestFunction2$qv // __fastcall calling convention
TESTFUNCTION3$qqrv // __apscal calling convention
@TestFunction4$qqrv // __stdcall calling convention
使用 extern "C" 不会分解函数名
2)
__cdecl 缺省
是 Borland C++ 的缺省的 C 格式命名约定,它在标识符前加一下划线,以保留
它原来所有的全程标识符。参数按最右边参数优先的原则传递给栈,然后清栈。
extaern "C" bool __cdecl TestFunction();
在 def 文件中显示为
TestFunction @1
注释: @1 表示函数的顺序数,将在“使用别名”时使用。
__pascal Pascal格式
这时函数名全部变成大写,第一个参数先压栈,然后清栈。
TESTFUNCTION @1 //def file
__stdcall 标准调用
最后一个参数先压栈,然后清栈。
TestFunction @1 //def file
__fastcall 把参数传递给寄存器
第一个参数先压栈,然后清栈。
@TestFunction @1 //def file
3)
3. 解决调用约定:
Microsoft 与 Borland 的 __stdcall 之间的区别是命名方式。 Borland 采用
__stdcall 的方式去掉了名字起前的下划线。 Microsoft 则是在前加上下划线,在
后加上 @ ,再后跟为栈保留的字节数。字节数取决于参数在栈所占的空间。每一个
参数都舍入为 4 的倍数加起来。这种 Miocrosoft 的 DLL 与系统的 DLL 不一样。
4 查看dll 的调用接口tdump -ee MyDll.dll >1.txt (查看 1.txt 文件即可)
5 编辑c++ builder build 为一个可以直接调用的 .exe 。 点击project option 中linker 标签 去掉user dynamic RTL 选项 和package 中 去掉builder with runtime package 选项.
6 调用代参数的vl 编写的dll 调用的实例。
int (__cdecl *fun)(char*,char*,char*);
HINSTANCE DLLInst = NULL;
void __fastcall TForm1::Button1Click(TObject *Sender)
{
if( NULL == DLLInst )
{
DLLInst = LoadLibrary("HollyIVRCard.dll");
}
if(DLLInst)
{
fun=(int (__cdecl*)(char*,char*,char*))GetProcAddress(DLLInst,"hTrade");
if(fun)
{
cardid=Edit1->Text.c_str();
num=Edit2->Text.c_str();
ShowMessage(fun(cardid,num,res));
//cout<<cardid<<endl;
//cout<<num<<endl;
}
} else{
ShowMessage("load dll fail");
}
ShowMessage(AnsiString(res));
}
Containing your beans
Tere i sno single Spring container.Spring actually comes with two distince types of containers:Bean factories and Application
contexts.Beyong there two basic types of contains .Srping come with sereral implementss of BeanFacotory and ApplicationContext.
1 introducing the BeanFactory
There are several implementations of BeanFactory in Spring .But the most userful one is XmlBeanFactory,whick loads
its bean based on the definitions contained in an xml file.
Creat a XmlBeanFactory BeanFactory factory=new XMLBeanFactory(new FileInputStream("beans.xml"));
But at that time ,the BeanFactory does not initialize the bean ,it is loaded lazliy.
Get the Bean :MyBean myBean=(MyBean)factory.getBean("myBean");
When getBean() is called ,the factory will instantiate the bean and being setting the bean using dependency injection.
2 Working with an application context
an ApplicationContextis prefered over a BeanFactory in nearly all application ,the only time you might consider using a BeanFactory
are in circumtance where resource s are scarce.
Amony the many implements of ApplicationContext are three that are commonly used:
ClassPathXmlApplicationContext,FileSystemXmpApplicationContext,XmlWebApplicationContext.
ApplicationContext context=new ClassPathXmlApplicationContext("foo.xml");
wiring the beans
<beans>
<bean id="foo" class="com.springinaction.Foo" />
</beans>
Prototyping vs.singleton
By default ,all Spring beans are singletons.When the container dispenses a bean it will always give the exact same instance of the
In this case ,you would want to define a prototype bean .Defining a prototype means that instead of defining a single bean.
<bean id="foo" class="com.springinaction.Foo" single/>on="false" />
Initialization and destruction
<bean id="foo" class="com.springinaction.Foo" init-method="setup" destory-method="teardown">
Injectiong dependencies via setter method
<bean id="foo" class="com.srpinginaction.Foo" >
<property name="name">Foo McFoo</value>
</bean>
Referencing other beans
<bean id="foo" class="com.springinaction.Foo">
<property name="bar" >
<ref bean="bar" />
</property>
</bean>
<bean id="bar" colass="com.srpinginaction.Bar" />
Inner beans
<bean id="courseService"
class="com.CourseWericeImpl">
<property nanme="studentService">
<bean
class="com....." />
</property>
</bean>
Wiring collections
1Wiring lists and arrays java.util.List
<property name="barList">
<list>
<value>bar1</value>
<ref bean="bar2"/>
</lsit>
</property>
2 Wiring set java.tuil.Set
<property name="barSet">
<set>
<value>bar1</value>
<ref bean="bar2" />
</set>
</property>
3 Wiring maps java.util.Map
<property name="barMap">
<ebtry key="key1">
<value>bar1</value>
</property>
4 Wiring propertyies
<property name="barProps">
<props>
<prop key="key1">bar1</prop>
<prop key="key2">bar2</prop>
</props>
</property>
5 Setting null values
<property name="foo"><null/><property>
injecting dependencies via constructor
<id="foo" class="com.springinaction.Foo">
<constructor-arg>
<value>42<value>( <ref bean="bar">)
</constructor-arg>
<bean id="foo" class="com.springinaction.Foo">
<constructor-arg>
<value>http://www.manning.com</value>
</constructor-arg>
<constructor-arg>
<value>http://www.manning.com</value>
</constructor-arg>
</bean>
代码会生锈吗?这真是一个很奇怪的问题,代码怎么会生锈呢?但是现在的许多软件企业,却总认为代码放久了就会发霉,会生锈,因此每次发布的新版本总抛弃了原来所有的代码从头来过。这种做法真的可取吗?我们且不说这么做要浪费多少人力物力(反正公司有的是钱 really?但为什么工资只开这么一点点,配的电脑也这么烂),就仅仅从新版本的质量来讲,也不见得尽如人意。谁能够保证新版本的核心人员与原来版本是同一批人,那么又怎么来保证原来的“经验积累”能够在新版本中发挥作用。另外,老版本的代码多是经过项目实践来检验的,它们身上可能带着修复bug后,留下的伤疤,但是至少它已经痊愈
了,他已经成为了一名经历过战场洗礼的战士。而新版本呢,好比是在军校学习的学生,它们可进行了更为先进的战略战术的学习(一些更先进的技术)但是,遗憾的是他们从来没有在战场上真枪实弹的打过仗,(在项目中许多新技术的应用往往是程序员边学边用的,当然,这也是软件行业的一个特点)因此能否成为合格的战士还需要经过实战(项目)的考验,而不仅仅是考试(测试人员)的成绩。如果我们把一些战斗经验丰富的老战士,进一步培训(对老版本进行修复,重构)我想他们的战斗力可能会远远超过这些新兵?
但是为什么这么多的企业,都会不约而同的选择重新编写代码呢,我想很可能是那些程序员在作怪(呵呵,不好意思我也是一个程序员,在这里只是就事论事 不敢含有任何贬低咱程序员的意思)。程序员总是不停的在抱怨,原来的代码事如何如何的乱,几页的代码竟然没有任何注释,许许多多的代码我竟然不知道做什么用的,让我修改,我还不如重写一遍呢?这是发生在程序员修改别人写的代码时,时常会发的牢骚。 原来的代码真的真么糟吗,其实并不尽然。那写你看起来一团糟的代码,也许就是修改某个
bug 时留下的伤疤,如果从头写一段新的代码,谁能保证你的代码没有原来那bug呢?其实我们可以采用很多重构的方法来解决,如设计模式的开闭原则,就可以很好的规避这一类问题。
因此我认为,一个企业不要总是频繁的发布新版本,只有可以明确的指出现有版本已经满足不了市场的需求了,我们才需要重新规划。我们需要明确,我们当前最需要做的是对现有版本修修补补,使之不断完善,不断健壮。君不见,网景的netscape 和borland 的dbasde就是前车之鉴吗?
注:网景的netscape 因新版本重写代码,整整用了3年的时间,其市场份额从80% 降到了20%
borland 从些Arago(dbase的前身) 也把市场白白的让给了 access
现在各行各业都兴采用什么,矩阵管理的方式,号称可以提高效率,但是在软件行业一定适用吗?
据说,微软采取的就是这种矩阵管理的方式,每一个项目由技术人员,项目经理,测试人员三个
部门的人员组成。其中,项目经理负责项目的协调。看起来,是人尽其用,每个人只需完成它分内的工作
即可,但是在一个项目中,涉及到大量的沟通(正式的和非正式的,内部的和外部的),和协调。如果项目组成员仅仅完成自己分内的工作,而把剩下的工作全部交给项目经理去完成,那么工作效率之低就可想而知了。这理涉及到一个问题,如何提高项目组成员的工作主动性,主动去完成自己分外的,但是自己最合适的工作呢?当然可以提高员工的工资,但是人的欲望是没有止境的,长到多少合适呢,在说公司能够承受多少呢?
可见,涨工资不是解决问题的根本方法。因此我们需要想一些别的办法。
在矩阵管理的模式下,由于每个人不隶属于任何的项目,只隶属于自己的部门。因此,在项目经理
与组员进行沟通时,也仿佛在与其他部门进行交互一样,存在这推诿,敷衍等等许多问题。如何解决这
个问题呢,那就是让每个项目组成员都要与这个项目荣辱与共。这恰恰就是矩阵管理存在的最大问题。
在矩阵管理中,当项目组成员完成一步份工作后,可能就会撤出这个项目,因此这个组员也不会全
身心的投入项目的开发,因为它还要想着下一个项目。项目经理常常挂在嘴边的一句话,我的项目
怎么怎么样了(先不管这样说会让其它项目组成员心里怎么想),但是很少有项目组成员会说我的项目。。。。,这是为什么呢。因为不管嘴里怎么说,项目组成员在内心深处就没有把他当作自己的项目
他只需要完成自己的工作就可以了,没有必要作一些额外的工作,不在其位,不谋其政吗?这里所提到的
是矩阵管理存在的一些共性的问题,对软软件小组进行矩阵管理存在的问题更大了。众所周知,软件开发
是一种创造性的工作,其工作主动性所产生的作用更远远大于其它行业。在《人件》认为软件工程的管理
其实就是对人的管理,一切管理都要以人为核心。但是某些领导,往往忽视了这一点,把软件人员当作一种可以重复利用的资源,结果吃亏的将会是项目本身。
也许大家会说了,你是不当家不知柴米贵,不作领导你不知领导的难处,在这里发发牢骚谁都会,如果你是领导,你会怎么办呢?
当然了,作为非领导的我,只是从我的角度讲了一下我对这个问题的看法,另外我也不只是在这里
夸夸其谈,我呢,在下面也阐述一下,如果是我,我会如何管理,希望某个领导看到后也也考虑考虑。
1 软件小组依然存在,但是其作用已经发生的变化。首先软件小组对已经进入项目的小组成员不能
进行工作的安排。只能对在项目之外的软件人员进行工作安排。其次,软件小组需要担付起对新入职的
软件人员进行培训的工作,不能把培训大量的工作放到真实项目中,这样必然会降低项目的质量。再次
软件小组,对项目中一些通用的问题集中解决,对项目中的疑难问题提供技术支持。另外软件小组还需要
对小组成员代码的质量进行走查,提高软件小组的成员的技能。当然作为软件小组成员的行政单位,软件小组成员的考核还是要有软件小组主导的。
2 软件人员,尽能的参与项目真个生命周期,项目紧张人紧张,项目不紧张人员可以稍微放松,或及时进行充电。忽略了软件人员的对不断学习的需求,是当前软件管理的一大弊病。(可能有些上岗上线了,但这对调动软件人员的积极性和保持相对稳定的团队有这意想不到的作用)
3 项目经理,需要对软件开发的特点,和软件人员的管理有所了解,建议读一读《人件》这本书。当然
提高项目经理本身的软件素养才能根本解决问题,建议软件项目的项目经理一定要具备较强的开发能力和较为丰富的开发经验,公司不要心疼一点点工资,它可以给公司带来的效益要远远高于此。
4 项目经理不要说,“我的项目”,应该改成“我们的项目”,让项目组的每个成员由一种归属感。
作为一个项目组成员,我们需要的是一种经历风雨见彩虹的成功感,而不是一种机械的忙碌的工作。
5 最后,也是每一个软件人员都十分关心的问题,什么时候给我们换一个快点的机器呀。一个好一点的机器
比可能比更高一点的工资更具备吸引力,对公司来讲也是更划算的。(效率和人员流动上,呵呵)
1 写出用户级的需求用例。在现在的需求调研中,更多的是把客户提出的需求用流程图的方式表达。但是
在给客户讲解的时候效果不是很好,主要存在以下问题:
1)流程图不适合描述分支很多的流程。分支过多,将导致流程图十分复杂,不具有可读性。
2)流程图的受众比较少。在实际的业务业务调研中,面对的用户往往是系统的使用者,而不是作为
技术人员的维护和开发者,由于不具备相关技术背景,因此这些人在阅读流程图的时候,往往觉的眼花缭乱,更不要说提什么修改建议了。这将会使很多本应在需求调研阶段发现的问题,遗留到了用户正式使用的时候,由此带来的损失不可估量。
3)由于流程图是一个粗线条的流程描述,因此许多客户提出的细节问题,需要以另外的方式进行记录
这可能会导致在设计阶段遗漏掉。如 系统使用这在使用时的心态,等等
2 采用用例和流程的结合形式来描述客户的需求,原因如下:
1)由于用例采用自然语言描述,所以任何人可以轻松的进行阅读。
2)在一定格式的辅助下,用例描述不必受流程分支多少的约束。
3)采用自然语言描述,可以详细的描述处用户的使用细节,这些细节可能会对这个项目的开发起着
决定作用。
4)加入流程图,让具有相关背景知识的人迅速的了整个流程的全貌。如果分支不是很多流程图
还是可以画的十分简洁易懂的。
5)好的用例对后期的设计,开发,测试都是很有帮助的。甚至可以直接作为客户的培训素材
3 如何写用例
1)写用例需要结合用例图,用例图可以让用例的读者了解整个系统提供的功能,和与其他系统的关系。 这样可以使读者的在阅读用例时,在一个限定的范围内思考问题。
2)用例的格式大体上可以分为前提条件,主成功用例,扩展。当然,作者可以丰富用例的格式,这里
仅仅是一个最简单的框架。
3)由于是在需要阶段的用例,因此用例尽量用轻松的语调来写用例。你甚至可以把用例当作一片散文来写。这里需要注意的是,在写用户级用例的时候需要把系统当作一个黑盒,不要去描述系统内部是如何工作的
此时作者一定要以一个客户的角度来考虑问题,来描述系统。
4)用例可以也可以想写函数是的写一些通用性比较强的模块,以便其他用例可以复用。如用户身份验证模块。
5)在写用户级的用例时候,对用户使用系统的细节需要描述,如使用者的心态。这可能决定着用户易用度的设计。
6)在写用例的时候一定需要用完整的主谓宾来写。及谁,在做什么
4 用例描述仅仅是对用户需求一个梳理的过程,我们还需分析出其中的主要实体,和他们的关系,在分析
的过程中可能会对产生新的疑惑,可以和客户及时沟通。当然在设计的过程中,也可以继续和客户沟通
但是,客户方不一定能够随时协调到合适人员,这将导致项目的推后。因此,在集中讨论期间
多做一些分析,乃至设计(原型的设计),可以大大减少后期的工作了量,提高客户满意度。用例,分析,和原型 可以是在需求期间一个小的迭代周期。
5 在讨论需求的时候,最好是以集中会议的形式进行,参会者应为 相关领导,系统将来的实际使用者
,技术把关人员。为什么者样作,和如何利用其中的微妙关系,需要大家自己去体会,去琢磨。呵呵
用了几年java 了,突然想学习c++ ,昨天用了一天的时间疯狂的学习了一天c++ 基础知识,发现感觉还不错,不过精验告诉我,学编程语言一定要实践,在这里指记录了一些学习中的点滴。
1 const 与volatile 的用法
1 const
#include<conio.h>
#include<iostream.h>
//行参数指向const 类型变量的指针
void display_c(cons int * pi)
{
cout<<"display_c:"<<*pi<<endl;
}
//行参为普通类型变量的指针
void display(int *pi)
{
cout<<"display_c:"<<*pi<<endl;
}
//const 类型变量
const int i1=1;
//error i1=3;
//const 类型变量的指针
int i2=2;
const int * pi2=&i2;
//error *pi2=3
// const 指针
int * const pi3=&i3;
*pi3=5;
// error *pi3=&i4 可以赋予不同的值,但是不可一指向不同的变量
//指向const 内容的const 指针
const int * cosnt pi5=&i5;
2 sizeof 返回某个便赖宁嘎或数据类型的长度
3 引用
1 引用变量
int i=1;
int & r_i=i;
5 名空间
1 namespace
namespace car
{
int model;
int length;
int width;
}
namespace plane
{
int model;
namespace size
{
int lenth;
int width;
}
}
namespace car //添加名空间的成员
{
char * name;
}
namespqce c=car; //定义别名
int Time //外不变量属于全局名空间
car::length=3;
plane::size::length=70;
int Time=1996;
::Time=1997;
2 using
void main()
{
using namespace car;
length;
using namespace phane;
model;
}
6 new 与delete 运算符
double * pd; // define pointer variable
pd=new double; // allocate memory
if(pd!=null)
{
...
delete pd; // free memory
}
double1=null
* pds=new double[100];
if(pds)
{
....
delete[] pds;
}
如果是使用new 进行内存空间分配没有成功,则返回空指针null
释放一个数组分配的内存是,常常采用带[]的形式
7 void 指针 它指向一个地址值,但是不说名数据类型,可以使用void 指针创建一个通用的函数,在使用
的时候将指针类型转化成相应的具体类型。
void ShowHex(void *pv,int siae)
{
....
((unsigned char *)pv)[i]
}
void main()
{
void *pv=null;
unsigned char c1=0x12;
pv=&c1;
ShowHex(pv,sizeof(c1));
}
9 typeid 运算符 用来求得变量或队形爱女嘎的数据类型,返回一个type_info 类型的对象,通过该对象
可以获取数据类型的名称
include<typeinfo.h>
int i;
const type_info &t0=typeid(i);
t0.name();
10 函数
1 模板函数
template<class T> T min(R &x,Tv&y)
{
return x<y?x:y;
}
2 指向函数的指针
int max(int x,int y)
{
...
}
int min(int x,int y)
{
...
}
int (* m_pfunction)(int,int);
void main()
{
m_pfunction=max;
(*m_pfunction)(2,3);
m_pfunction=min;
(*m_pfunction)(2,3);
}
11 类与对象
1 构在函数和析构函数
#include <iostream.h>
#include <string.h>
#include <conio.h>
class Book
{
private:
char * pBookName;
public:
int PageNum;
public:
Book(char * pBN=NULL);
~ B o o k ( v o i d ) ;
void SetBookName(char * pBN);
int GetBookName(char * pBN,unsigned int MaxSize);
} ;
Book:Book(char *PBN)
{
cout<<"构造函数"<<endl;
pBookName=null;
if(oBN!=null)
{
pBookName=new char[strlen(pBN)+1];
if(pBookName!=null)
strcyp(pBookName,pBN);
}
}
Book::~Book()
{
delete[] pBookName;
}
void Book::SetBookName(char * pBN)
{
if(pBookName!=null)
delete[] pBookName;
pBookName=new char[strlen(pBN)+1];
if(pBookName!=null)
strcyp(pBookName,pBN);
}
int Book::GetBookName(char * pBN,unsigned intmaxSize)
{
if((pBookName!=null))&&(MaxSize>strlen(pBookName))
{
strcpy(pBN,pBookName);
retrun strlen(strlen(pBookName));
}
}
// 使用
Book b1;
b1.SetBookName("test");
Book b2(test1);
2 对象的引用参数传递
void Add(Book b)
void AddRef(Book & b);
3 静态成员变量 是一个公共变量
在初始化 的时候利用作用运算符:: 对私有类型的静态成员变量可以向公有类型的静态成变量一样赋值
但不能直接引用
3 const 类型成员函数与mutable
class CDate
{
public:
int year;
mutable int month;
CDate(int y=2000,int m=1)
{
year=y;
month=m;
};
int BetMonth() const ;//read only
void SetMonth(int m);// write only
}
void CDate::SetMonth(int m)
{
month=m;
}
void main()
{
CDate d1;
}
在const 类型的成员函数定义中,不可一直接或简介的修改普通类型的成员变量
如果象修改const 类型对象的成员函数,可以使用关键字mutable 对该成员变量进行修改
5 对象的初始化与初始化行
将参数类表中的数值赋予成员变量时,不仅可以在构造函数的函数体中进行,以阿宽衣在初始化行中进行
在初始化处惊醒初始化的情况有:
1 分层类的构在函数可以调用它的任何一个子对象的构造函数
2 对常量const 类型的成员变量的初始化必须在初始化行上
3 对于引用类型的成员变量的初始化必须在初始化行上
class CPoint
{
public:
int x,y;
CPoint(int ax=0,int ay=0)
{
x=ax;
y=ay;
}
};
class CRect
{
private:
CPoint low_right;
CPoint up_left;
public:
int & CenterX;
const int CenterY;
CRect(int x1,int y1,int x2,int y2,int &x3,int y3)
:up_left(x1,y1),low_right(x2,y2),CenterX(x3),CenterY(y3)
{
}
};
void main()
{
int cx=5;
int cy=6;
CRect r1(1,2,3,4,cx,cy);
}
6 拷贝构造函数
拷贝构造函数与普通构造函数的差别在与棋参数类表,参数列表中有一个对象,该对象的数据类型是
本类的一个引用,而且一般情况下,该对象还应该是一个const 类型的对象。
如果在类的定义是不是显示的定义一个拷贝函数,则编译器会自动的定义一个拷贝构造函数
class CPoint
{
public:
int x,y;
CPoint(int m_x=0,ubt m_y=0); // default constructor
cPoint(const CPoint &c); //copy consrucotr
};
CPoint::CPoint(int m_x,int m_y)
{
}
CPoint::CPoint(const CPoint &c)
{
x=c.y;
y=c.x;
}
void main()
{
CPoint c1(1,2); //invoke default constructor
CPoint c2-c1; // invoke copy constructor
}
7 template class
template<class t,int Size>class Array // template class
{
private:
T arr[Size];
int CurSize;
public:
Array(T * date,int n)
{
CurSize=n<Size?n;Size;
for(int i=0;i<CurSize;i++)
{
Arr[i]=data[i];
}
}
}
void main()
{
int i1[10]={1,2,3,4,5,6,7,8,9};
Array<int,6>array_i1(i1,i0);
}
1 友员类和友员函数
#include <iostream.h>
#include<string.h>
#include<conio.h>
class SoftWareEngineer; //先对SoftwareEngineer 类进行显示说明一下
class Computer // 定义Computer 类
{
private:
int Price;
public:
Computer(int p){Price=p};
friend class SoftwareEngineer; //将友员类载这里声明
frined void Judge(Computer &c,SoftwareEngineer & s) //友员函数
};
class SoftwareEngineer
{
int Salary;
char Name[20];
public:
SoftwareEngineer(int s,char *n //构造函数)
{
Salary=s;
strcpy(Name,n);
}
int GetComputerPrice(Computer &c){return c.Price} //访问Computer 的思友变量
friend void Judge(Computer &c,SoftwareEngineer & s) //友员函数
};
//判断一个软件工程师是否可以用一个月的薪水买的器一台电脑
void Judge(Computer &c,SoftwareEngineer &s) //桥友员函数
{
if(c.Price>s.Salary)
cout<<"软件工程师"<<s.Name<<"的一个月薪水买不起一台电脑"<<endl;
else
cout<<"软件工程师"<<s.Name<<"的一月薪水买的起一台电脑"<<endl;
}
void main()
{
Computer c1(100);
SoftwareEngineer s1(120,"user1");
Judge(c1,s1);
SiftwareEngineer s2(80,"user2")
Judge(c1,s2);
getch();
}
2运算符重载
#include<iostream.h>
#include<conio.h>
#include<iomanip.h>
class TValue{
private:
int value;
public:
TValue(int i){value=i}
//成员函数重载运算符
TValue operator!();
TValue operator+(TValue & rv);
// 友员函数重载运算符
friend ostream & operator<<{ostream & os,TValue & rv};
}
TValue Tvalue::operator!()
{
return TValue(!value);
}
TValue TValue:operator+(TValue& rv)
{
return TValue(value+rv.value);
}
ostream & operator<<(ostream & os,TValue rv)
{
os<<setw(5)<<rv.value;
return os;
}
void main()
{
TValue v1(3),v2(5);
cout<<
}
3 类的派生和继承
1class Box{
public:
int width,height;
void SetWidth(int w){width=w};
void SetWidth(int h){height=h;};
};
class TColorBox::public Box{
public:
int color;
void SetColor(int c){color=c;};
};
void main(){
TColorBox cb;
cb.SetColor(255); //声明非继承类的对象
cb.SetWidth(100);//声明继承类的对象
cb.SetHeight(100); //声明继承类的对象
}
2 不能被继承的成员
构造函数,析构函数,用户定义的新操作符,用户定义的赋值操作,友员关系
3 构造函数,析构函数的调用顺序
class A{
int a,b,c;
public:
A(int x,int y,int z)
{
a=x;
b=y;
c=z;
}
};
class B{
int d;
public :
B(int xx):A(xx,xx+1,xx+2)(d=xx);//内联构造函数
B(int x,int y,int z,int xx);//非内联构造函数
B:B(int x,int y,int z,int xx):A(x,y,z)
{
d=xx;
}
}
实例
class Currency
{
poublic:
double par_value;
Currency(){per_value=0.0;}
Currency(double d){per_value=d;}
Currency(Currency &rc){par_value=rc.par_value;}
Currency & operator={Currency & c}
{
par_valuc=c.par_value;
return * this;
}
Currency & operator+(Currency & c)
{
par_value+=c.par_value;
return *this;
}
}
//人民币
class RMB:public Currency
{
public:
RMB():Currency(){};//调用派生类的构造函数前,需要调用器基类的工造函数
RMB(double d):Currency(d){};
RMB(Currency& c):Currency(c){};
RMB(RMB& rmb):Currency(rnb){};
friend ostream& operator<<{ostream& os,RMB& rnb};//派生类的附加功能
};
ostream& operator<<{ostream& os, RMB& rmb} //output 运算符不能是一个类的成员函数
{
os<<"¥"<<setiosflags(ios::shwopoint|ios:fixed)<<setprecision(2)rmb.par_value;
return os;
}
void main()
{
RMB r_income(5000);
RMB r_balance;
r_balance=r_income=r_expense;
cout<<"income"<<r_income<<endl;
}
4 将iostream 运算符重载
1)ostream & operator<< (ostream &os,const Triangular & ths)
{
os<<"("<<rhs.beg_pos()<<","<<rhs.length()<<")";
rhs.display(rhs.length(),rhs.beg_pos(),os);
}
ouutput 运算符不能够设计成member function
2)istream& operator>>(istream &is,Triangular &rhs)
{
char ch1,ch2;
int bp,len;
//输入 ch1='(',bp=3,ch3=',' len=6
is>>ch1>>bp>>ch2>>len;
rhs.beg_pos(bp);
rhs.length(len);
rhs.next_reset();
return is;
}
Triangular tris;
cin>>tri2
4 虚基类
载继承关系中,同一基类被继承多次,不仅会引器歧异,而起可能浪费空间
class A
{
public:
int value;
};
class B:public virtual A(); //虚基类 编译器只产生一个基类版本。如果不定义为virtual 编译器不知到调用那个value 了,当然
class C:public virtual A();// 也可以return B::value;
class D:public b.public c
{
public
int GetValue(){return value;}
};
void main()
{
D dd;
dd.GetValue();
}
5 多态形,和虚函数
class TFirst
{
public virtual void Display();
};
void TFirst::Display()
{
cout<<"first "
}
class TSecond:public TFirst
{
public:
virtual void Display();
};
void TSecond::Display()
{
cout<<"second"
}
void Display(TRist * pFirst)
{
pFisrt=>Display();
}
void main()
{
TFirst * pFirst=new TFirst;
TSecond * pSecond=new TSecond;
pFirst->Display();
pSecond->Display();
Display(pFirst);
Display(pSecond);
delet pfirst ;
delet pSecond;
getch();
}
c++ builder 中的集合的
1 集合的概念基本
Set<type,minval,maxval>
Set<char,'A','C'> s1
tydefef Set(char,1,255) UPPERCASet;
UPPERCASESet s1;
s1<<'A'<<'B'<<'C';
sysset.h 直接包含载vcl.h 中
2 集合的操作
#include<iostream>
#include<system.hpp>
#include<conio.h>
using namespace std;
typedef Set<char,'B','Z'> UpperSet;
typedef Set<char,'a','z'> LoverSet;
typeder Set<char,'a','j'> HalfLowerSet;
void set_example()
{
LowerSet ae,ae2,ac,de;
UpperSet AE,AE2,AC,DE;
HalfLowerSet aj;
}
异常处理
1 c++ 的异常处理
#include <iostream.h>
#include <conio.h>
class Crange
{
public:
int index;
CRange(int i){index=i;}
}
class CString
{
char a[100];
int len;
public:
CString(char * s)
{
Len=strlen(s);
strcpy(a,s);
}
char & operator[](int i)
{
if(i>0 && i<len) return a[i];
else throw CRange(i);
}
void DisplayNoCatch(CString & s)
{
int j;
for(j=0lj<20;j++)
cout<<s[j]<<""endl;;
}
int DisplayHasCatch(CString & s)
{
try{
DisplayNoCatch(s);
}catch(CRange r)
{
cerr<<r.index<<endl;
}
return 99;
}
}
2 多路捕捉
#include<iostream.h>
#include<conio.h>
void MultiException()
{
int i;
double d;
int no;
cout<<"(>0 and <5)";
cin>>no;
tyr
{
switch(no)
{
case 1;
throw 123;
break;
case 2:
throw i;
break;
case 3:
throw d;
break;
case 4:
throw "Error";
break;
default:
cout<<"error";
}
}
catch(int ie)
{
cout<<"int"<<endl;
}
catch(double de)
{
cout<<"double"<<endl;
}
catch(char* se)
{
cout<<"char"<<endl;
}
}
3 bcb中的异常类
1)却省vcl 异常处理 无try catch 自动处理
int i=4,j=0;k;
k=i/k;
//下一句永远不会执行
ShowMessage(k);
2) 引发vcl 异常类
try{
}
catch(Exception &e)
{
ShowMessage(e.,Message);
}
不能引发如int double 等简单类型的异常
3) c++ 异常处理
try
{
throw 2222;
}
catch(int ErrorCode)
{
ShowMessage(ErrorCode);
}
}
4 单一捕捉异常
try{
k=10/0;
}catch(EDivByZero & E)
{
MessageDlg()
}
5 捕捉所有异常
try
{
}catch(...) or(EExternalException &E)
现在公司招来的员工中,总是招进一些“空降兵”式的项目经理,这些项目经理不管它以前有什么
样的经验,仅仅就项目实施来说,他们有太多的不知道了。在我心目中,一个项目经理不仅仅具备一定
的沟通技巧还需要具备较强的技术修养和背景。
不否认,项目中的沟通是可以解决项目中的一些问题,但是说服客户是需要“以理服人”,因为客户
不是傻子,他们需要了解为什么这项功能不能实现,为什么这项功能需要推后实现,在我的经验中,项目
中没有什么是客户提出问题,而仅仅通过项目经理的沟通就可以解决的。解决的方式往往是项目经理“无可奈何”的向客户保证××××我们一定完成。恶梦开始了,软件人员有需要不停的加班来满足客户那些毫无理由的需求了。
我认为项目经理在客户的和项目组员眼中应该是一个技术高手的形象,只要这样他所作的决定才具有一定的说服力,所安排的工作才具备一定的合理性。而不是那些一行代码没有些过,而仅仅花一些钱考一些什么pmp 之类的认证的人。由于缺乏客户的信任,将导致客户绕过项目经理,直接找技术人员去解决问题,这将导致项目的逐渐失控。
现在公司不知是怎么想的,招聘只是考虑有没有意愿,有没有pmp而不是从实际是否具备的能力。在项目中也不知多少是由于他们的无知造成工期的延误,一点点问题,都要到处协调人去解决,很小的一个问题一来一去不知要耽误多少时间,消耗多少资源。最后还颇为感慨的说,作项目经理太累了。其实这不是太累了,这是因为技术素养太低造成的。IT行业所具有的特点是高手和庸才 之间生产力的差距不仅仅是几倍而是几十倍,甚至是上百倍。
不具备软件开发背景的项目经理工作进度的安排仅仅是一个漂亮的project 图表,不具备任何实际意义。由于没有亲身经历过开发,他不可能了解软件开发的全过程,不可能对项目进度有比较深入的控制。而是靠pmp 中过程控制的方式管理软件的开发,这几乎成了软件项目开发一济致命毒药。因此软件项目的延期甚至失败则变成了必然。
另外 没有作过软件人员的项目经理,在软件人员的管理方面存在也存在问题。不了解技术人员所想
的是什么,更不可能真正调动起技术人员的积极性。他们所做的仅仅是不停的催促软件人员开发,其实这也不能怪他,因为在他的眼里,整个软件开发是一个黑盒,他之所以急躁,是因为他觉的不可控。
嗨 不说了,说了这么多,只不过是对外行人管内行人的一点点感慨。趁这自己还在软件开发这个阶段,多学习,多总结,为成为自己心目中的软件的项目经理而努力。
1 Standard Template Library (STL)主要有两种组件构成,一时容器container 另一种组件是 操作
这些容器类的泛型算法
1 vector and list 是序列是容器
2 map 是一对keyvalue 组合 3 set 其中仅含有key 我们对它惊醒查询操作。主要是判断某之是否存在其中。
2 指针的算术运算
当数组被传递给函数,仅有第一个元素的地址会被传递
template <typename elemType>
elemType * find(const elemType *array,int size,const elemType &value)
{
if(!array||size<1)
return 0;
for(int i=0;i<size;i++)
{
if(array[i]==value)
return &array[i];
}
/*
for(int i=0;i<size;i++,array++)
{
if(*array==value)
return array;
}
*/
return 0;
}
template <typename elemType>
elemType * find(const elemType *first,const elemType *last,const elemType &value)
{
if(!fist||!last)
return 0;
for(;first!=last;first++)
if(*first==value)
return first;
return 0;
}
由于vector 和array 相同,
array[2] equals *(array+2) 2 指两个elemType 单位
由于vector 和array 相同,都是以一块赖宁许内存存储所有元素,所以我们可以使用和array 一样的处理处理
方式
vector<string> svec
find(&vec[],&svec[vec.size()].serch_value);
3 了解Iterator
1 template<typename elemType>
void display(const vector<elemType>&vec,ostream &os)
{
vector<elemType>::const_iterator iter=vec.begin();
vector<elemType>::const_iterator end_it=vec.end();
for(;iter !=end_it;++iter)
{
os<<"ite3r"<<endl;
}
}
2 find
template<typename IteratorTypes,typename elemType>
IteratorType
find(IteratorType first,IteratorType last,count elemType &values)
{
for(;first!=last;++first)
if(value==*first)
return first;
}
return last;
const int siz3=9;
int ia[size]={1,2,3,4,5,6,7,8,9};
vector<int> vec=(ia,ia+size);
list<int> list=(ia,ia+size);
int *pia=find(ia,ia+size,3);
if(pia!=ia+size)
//find...;
vector<int>::iterator it;
it=find(vec.begin(),vec.end,1024);
if(it!=vec.end())
//find...
list<int>::iterator it;
it=find(list.first().list.end,4);
4 所有容器的共同操作
equality(==),assignment(=),empty(),size(),clear()
begin() 返回一个iterator,只向容器的第一个元素
end() 返回一个iterator,只向容器的最后 一个元素
5 使用序列容器
1 vector 和list 是两个最主要的序列式容器 vector 式一块连续的内存。取数据效率较高,但是存数据
但是如果在任意位置插入或删除数据,效率就比较低。(但是在最后一位添加和删除数据效率都比较高)
2 list 系以双向连接来存储内存,可以任意执行前进或后退操作,可以在任意位置安插或删除数据。
3 deque 以连续的内存存储元素,但是deque 在最前端元素的安插和删除操作更有效,末端相同
4 #include<vector>
#include<list>
#include<deque>
5 产生空的容器
list<string> slist;
vector<int> ivec;
6 产生特定大小的容器,每个元素都以千默认的值作为初值
list<int> ilist(1024);
vector<string> svec(32);
7产生特定大小的容器,并为每个软速制定初值
vector<int> ivec(10,-1)
list<string> slist(16,'unassigned');
8 int ia[9]={1,2,3,4,5,6,7,8,9};
vector<int> fib(ia,ia+8);
9 根据某个容器产生新容器,复制软来容器的元素,作为新容器的初值
list<string> slist;
list<string> slist2<slist>
10 push_back(),pob_back() 在容器末尾进行安插和删除操作。在deque和list可以用push_front
和pop_front 在最前面天加和删除操作。
11 fornt() 和back()可以取回最前和最后的值
12 iterator insert(iterator position,elemType value)将value 安插于position 之前,返回一个iterator
指向被安插的元素
list<int>ilist;
list<int>:: it=ilist.begin();
while(it!=ilist.end())
if(*it>=ival)
{
ilist.inert(it,ival);
break;
}
if(it==ilist.end())
ilist.pushi_back(ival);
1 java 类型, hibernate 类型 sql
java .lang.String string varchar
java.lang.String text Text
int int INT
char character char(1)
boolean boolean bit
byte[] binary blob
java.sql.Date date Date
java.sql.Timestamp timestamp Timestamp (载数据库中如果插入为null,数据库系统自动插入为当前值)
2 表述层--》业务逻辑层-》hibernate-》database
3
Configuration config=new Configuration();
config.add(Customer.class);
sessionFactory=conf.buildSessionFactory();
Session session=sessionFactory.openSession();
Transaction tx;
try{
tx=session.beginTransaction();
tx.commit();
}catch(Exception e){
if(tx!=null){
tx.rollback();
}
}finally{
session.close();
}
4 数据库存取blob 对象
1
InputStream in=this.getClass().getResourceAsStream("photo.gif");
byte[] buffer=new byte[in.available()]'
in.read(buffer);
customer.setImage(buffer);
2 byte[] buffer=customer.get.getImage();
File OutputStream fout=new fileOutStream("photo.gif");
fout.write(buffer);
fout.close();
1 class 的定义,一般来说分为两部分,其中一个是所谓的头文件,用来声明class 所提供的各种操作行为
另一个是文件,程序代码文件,用来包含这些行为的实现内容。预使用class 不许在程序中含入其头文件
2 using namespace std
3 template class 机制使程序员直到使用template class 时才决定真正的数据类别。先使用一个代名,
稍后才绑定至实际的数据类别
4 Arrays 要定义array 我们必须指定array 的元素类型,名称,并指定其尺度的大小
array 的尺度必须是个常量表达式
const int seq_size=18;
int pell_seql seq_size=1;
5 vector 必须首先含如vector 的头文件。在角括号中指定其元素类型,其尺度则写作小括号内,不一定
是常量表达式
#include<vector>
vector<int> pell_seq(seq_size);
6 初始化数组和vector
1 初始化数组
int elem_seq[seq_size]={1,2,3,4} ;
int elem_swq[]={1,2,3,4};由编译其根据初始值自动算出array 的值
2 初始化vector
1) vector<int> elem_seq(seq_size);
elem_seq[0]=1;
elem_seq[1]=2;
.....
elem_seq[[17]==22;
2) 利用一个以初始化的array
int elem_val[seq_size]={1,2,3,4}
vector<int>elem_seq(elem_val,elem_val+seq_size); 其中elem_val 为内存地址
7 array 和 vector 的使用
vector 知道自己的大小,而array 不知道
for(int i=0;i<elem_seq.size();i++){
cout<<elem_seq[[i]<<'';
}
8指针 指针为程序引入了一层间接性,我们可以操作指针(代表某特定内存地址),而不再直接操控对象。
指针主要形成两件事,可以增加程序本身的弹性,但同时也增加了直接操控对象时所没有的复杂度
1 int ival=1024
int *p=&ival; 其中*p 指int型对象的地址
2 指针所具有的双重性,既可以让我们操控指针内含的内存地址,也可以让我们操作指针所指定的对象值
pi 指定pi所含有的内存地址
*pi 核定ival的值
3 指针的提领(dereference)
如果pi 寻址到某个对象,则执行提领操作,如果pi 不指定任何对象,提领会导致未知的执行结果
一个为只想任何对象的指针,其内含地址为0,我们称为null,任何指针都可以被初始话,或是令值为0
if(pi&&...)
只有pi含一个非0值时,其结果为true
vector<int> *pv=0;
const int seq_cnt=6;
vector<int> *seq_addres[seq_cnt]={
&fibonacci,&lucas,&pell...
};
一个指针数组,容量为seq_cnt,每个指针都指向vector<int>
4 #include<cstdlib>
rand(seed) 返回一个介于0和seed 之间的随机数
5 对象指针
if(!fibonacci.empty()&&....){
pv.empty()..
}
9 文件写
对文件的读写,首先的含入fstream
#include<fstream>
1 ofstream outfile("seq_data.txt"); 如果文件不存在,产生一个文件,如果文件已经存在,这个文件
被开启作为输出只用,但是源文件中的数据会输调
2 ofstream outfile("seq_data.txt",ios_base::app) 追加模式
3 oufile 为false 表示文件未开启成功
10 文件读
ifstream 将文件名传人,如果文件未能开启成功,ifstream 对象被核定为false ,如果成功,为true
ifstream infile("seq_data.txt");
int num_tries=0;
int num_cor=0;
if(!infile){
//由于某种原因,文件无法开启
}
else
{
string name;
int nt;
int nc;
while(infile>>name)
{
// 一旦读到到文件尾,infile 尾false
// infile>>name>>nt>>nc ,把文件 anna 24 19 分别读到name,nt,nc 中
infile>>nt>>nc;
if(name==usr_name)
{
//find hime
count<<"Welcome back,"<<usr_name
<<"\nYour current score is" <<nc
<<" out of " <<nt<<"\nGood Luck"!\n";
num_tries=nt;
num_cor=nc;
}
}
11 同时读写同一个文件
fstream iofile("seq_data.txt",ios_base::in|ios_base::app);
if(!iofile)
...
else
{
iofile.seekg(0); 将文件重新定位的文件的最末端
}
12
#include<iostream>
#include<string>
using namespace std;
//---------------------------------------------------------------------------
#pragma argsused
int main()
{
string username;
cout<<"Please enter your name:";
cin>>username;
switch(username.size()){
case 0:
cout<<"with no name";
break;
case 1:
cout<<"with one character";
break;
default:
cout<<"hollo ,"<<username<<endl;
break;
}
return 0;
}
13
#include<iostream>
#include<vector>
#include<string>
using namespace std;
//---------------------------------------------------------------------------
int main()
{
vector<int> ivec;
string str;
int val;
while(cin>>val){
ivec.push_back(val);
}
int sum=0;
for(int i=0;i<ivec.size();i++){
sum+=ivec[i];
}
int average=sum/ivec.size();
cout<<"sum of "<<ivec.size()
<<"elements "<<sum
<<"average "<<average<<endl;
return 0;
}
14
//---------------------------------------------------------------------------
#include<iostream>
#include<vector>
#include<string>
using namespace std;
//---------------------------------------------------------------------------
int main()
{
const int array_size=120;
int la[array_size];
int ival,icnt=0;
while(cin>>ival&&icnt<array_size){
la[icnt++]=ival;
}
int sum=0;
for(int i=0;i<array_size;i++){
sum+=la[i];
}
int average=sum/array_size;
cout<<array_size
<<"\n"<<sum
<<"\n"<<average<<endl;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#include<iostream>
#include<vector>
#include<string>
#include<fstream>
#include<algorithm>
using namespace std;
//---------------------------------------------------------------------------
int main()
{
ifstream in_file ("D:\inputfile.txt");
ofstream out_file("D:\outputfile.txt");
if(!in_file){
cerr<<"unable to open the inputfile" ;
}
if(! out_file){
cerr<<"unable to open the outputfile" ;
}
string word;
vector<string> text;
while(in_file>>word)
{
text.push_back(word);
}
cout<<"unsort file";
for(int i=0;i<text.size();++i)
{
cout<<text[i]<<" "<<endl;
}
cout<<"sort file";
sort(text.begin(),text.end());// sort the vector
for(int i=0;i<text.size();++i)
{
out_file<<text[i]<<" "<<endl;
}
}
1 条件分之语句
1 简单条件判断
declare
v_sal number(6,2);
begin
select sal into v_sal from emp
where lower(ename)=lower('&&name');
if v_sal<2000 then
update emp set sal=v_val+200
where lower(ename)=lower('&name');
end if;
end;
2 二重条件分支
if v_comm<>0 then
.....
else
........
end if;
3 多重条件分支
IF THEN
ELSIF THEN
ELSIF THEN
ELSE
END IF;
2 case 语句
1 在case 语句中使用单一选择符进行等值比较
declare
v_deptno emp.deptno%type
begin
v_deptno:=&no;
case v_deptno
when 10 then
update emp...
when 20 then
update ......
else
dems_out.put_line('不存在该部门');
end case;
end;
2 在case 语句中使用多种比较条件
declare
v_sal emp.sal%type
v_ename emp.ename%type
begin
select ename ,sal into vv_ename,v_sal
from emp where empno=&no;
case
when v_sal<1000 then
update emp set ...
when v_sal<2000 then
end case;
3 循环语句
1 基本循环
declare
i INT:=1;
begin
loop
insert into temp valuse(1);
exit when i=10;
i:=i+1;
end loop;
end;
2 while 循环
while i<=10 loop
insert into tem valuse(i);
i:=i+1;
end loop;
3for 循环
for i in reverse 1..10 loop
insert into temp values(1);
end loop;
4 顺序控制语句
1 goto
goto label_name;
loop
...
goto end_loop;
<<end loop>>
dbms_output
2 null 语句不会执行任何操作,并且会直接将控制传递道下一条语句
if v_sal<3000 then
update emp set .....
else
null;
end if;
在pl/sql 中只能直接嵌入sql,dml,以及事务控制语句,而不能嵌入ddl语句如create。。和dcl 语句如grant
1 检索单行数据
1 使用游标变量接受数据
declare
v_ename emp.ename%type
v_sal emp.sal%type
begin
select ename,sal into v_ename,v_sal
from emp
2 使用记录变量接受数据
declare
type emp_record_type is record(
ename emp.ename%type,sal emp.sal%type
);
emp_record emp_record_type;
begin
select ename,sal into emp_record
from emp
3 嵌入 select 语句注意的事项:语句必须返回一条数据,且只能返回一条数据,否则回触发例外,或显示错误
1) no_data_found
2) too_many_rows
2 操纵数据
1 插入数据
1) 使用values子句插入数据
declare
v_deptno dept.deptno%type
v_dname dept.dname%type
v_deptno:=&no
v_dname:=&name;
insert into dept(deptno,dname)
values(v_deptno,v_danme);
2)使用子查询插入数据
declare
v_deptno emp.deptno%type:=no;
begin
insert into employee
select * from emp where deptno=v_deptno
3 更新数据
1)使用表达时更新列值
declare
v_deptno dept.deptno%type:=&no;
v_loc dept.loe%type:='&loc';
begin
update dept set loc=v_loc
where deptno=v.deptno;
end;
2) 使用子查询更新列值
declare
v_ename emp.ename%type:='&name';
begin
update emp set(sal,comm)=
(select sal ,comm from emp where ename=v_ename)
where job=(select job from emp where ename=v_ename);
3 sql 游标
1 sql%isopen 用于确定sql 游标是否已经打开。当在pl/sql 块中执行select into ,update 以及delete 语句
时oracle 会隐含的打开游标,并且在语句执行完之后会隐含的关闭游标。
2 sql/%found 用于确定sql 语句执行是否成功。
declare
v_deptno emp.deptno%type:=$no;
begin
update emp set sal=sal*1.1
where deptno=v_deptno;
if sql%found then
dbma_output.put_line('语句执行成功');
else
dbms_output.put_line('not success')
end if
end
3 sql%notfound
4 sql%rowcount 用于返回sql 语句所作用的总计行数
4
1字符函数
1 ascII(char) 返回字符串首字符的ascII 码
2 chr(n) 将asccII 转化成字符
3 v_chr varchar2(10)
begin
v_char:=chr(56);
dbms_output.put_line('ascII 码 为'||v_chr);
end;
4 concat 该函数用于连接字符串,其作用余连接操作符|| 完全相同
5 initcap(char) 用于将字符串中的每个字符大写
6instr(char1,char2) 该函数用于取得子串在字符串中的位置 select instr('morning','n') from ,,,
7 length(char)
8 lower(char)
9 lpda(char1,n,char2) 该函数用于在字符串char1的左端填充字符串char2 ,直至字符串总长的为n,
v_lpas:=lpad('aaa',10,'*');---*******aaa
10 ltrim 去掉字符串char1 左端所包含的热乎字符
select ltirm('morning','m') from dual
11 replace('缺省值为10','缺省','默认')--默认值为10
12 rpad rpad('aaa',10,'*')--aaa*******
13 rtirm
14 substr v_sub:=substr('morning',1,3)
15 upper
2 数值处理函数
1 abs(),floor(),round(),power(),sort(),....
3 日期时间函数
1 add_months(d,n) 返回特定日期时间d 之后,的n个月所对应的日期
v_date:=add_months(sysdate,-14)
2 current_date select current_date from dual
3 current_timestamp
4 dbtimesone
5 extract 从日期时间中取得所需要的特定数据
select extract(year from sysdate) year from dual
6 months_between(d1,d2) 返回日期d1 和d2 之间相差的月数
7 next_day(d,char)
4 转换函数
1 to_char()
2 to_date()
5 集合函数
6 其它单行函数
7 分组函数
1 检索日期
1 select birthday from ...使用的是日期的默认格式
2 使用YYYY-MM_DD 格式 select to_char(birthday,'YYYY-MM-DD') from ..
2 处理null值
1 使用nvl函数处理null值:nvl 函数用于将null 转变为实际值,其语法格式为nvl(exp1,exp2),如果exp1是null 则反会exp2,否则返回exp1
select nvl(comm,0) as salary from
2 使用nvl2 处理null :nvl2(exp1,exp2,exp3),如果exp1 是null 返回exp3,否则返回exp3,exp2 ,和exp3 不可以是long,并需要和exp1匹配
3 连接字符:select eanme||'is a '|| job as "employee detail" form emp
4 在where 中使用 日期值
select * from hiredate>to_date('1982-01-01','YYYY-MM-DD')
5 在where 子句中使用like
select * from ename like 'S%' select * from ename like '__A%' select * from ename like '%a_%' 字符a为转义符
6 插入数据
insert into emp(empno ,ename,job,hiredate)values(1234,'mary','clerk',to_datee('1983-02-02','YYYY-MM-DD'))
insert into dept values(50,'train','boston')
7 使用子查询插入数据
1 使用子查询
insert into employee (empno,ename,sal,deptno,form emp where deptno=20);
2 使用查询执行直接转载
insert /*+append*/ into employee (empno,ename,sal,deptno)
select ..............(大批量数据直接转载时速度更快一些)
8使用多表插入数据
1 使用all 操作符执行夺标插入
insert all
when deptno=10 then into dept10
when deptno=20 then into dept20
when job='clerk' then into clerk
else into other
select * from emp;
2 使用first 操作符执行多表插入L:如果数据已经满足先前条件,并且已经被插入到某表,那么
该行数据在后续插入中将不会被再次使用。即不会出现既插入到dept10 中又插入到 clerk 中的
情况
insert first
when deptno=10 then into dept10
when deptno=20 then into dept20
when job='clerk' then into clerk
else into other
select * from emp
9 更新数据
1 update emp set job default where cname='scott' 如果存在默认使用默认,否则使用null
2 使用子查询更新数据,可以减少网络开销
update emp set (job,sal,comm)= (select job,sal,comm from emp where ename='cmith')
where ename='scott'
3 复制数据 update employee set deptno=7788 where job=(select job form emp where empno=7788)
10 删除数据
1 delete 使用delete 的时候只删去数据,而不会释放空间,可以回退
2 truncate table emp 不仅删除数据,而起回释放空间,不可一回退
11 使用事务控制语句
1 提交事务 commit
2 回退事务
1 回退部分事务:savepoint a
rollback a
2 回退全部事务 rollback
3 只读事务,只允许运行查询操作。可重复读 set transaction read only
4 顺序事务 set transaction isolation level serializable
12 分组函数,作用于多行,一般情况下于group by 字句结合使用,在使用分组函数时,如果忽略了 groub by 则汇总所有的行
select max(sal),min(sal) from emp
select avg(sal),sum(sal) from emp
select count(*) form emp
select count(emp) from emp
13 使用group by and having
1 select deptno,avg(sal),max(sal) from emp group by deptno
2 select deptno ,avg(sal),max(sal) from emp group by deptno having avg(sal)<2000
分组函数只能出现在选择列表,having 和order 中
当选择表包含有列表达式,和分组函数,那么这些列表和表达式必须出现在group by 字句中
3 rollup 和cube 中 产生横向纵向 的统计结果
在使用rollup操作符时,在生成原有统计结果的基础,还会生成横向小计结果,在使用cube 操作
符时,在软有rollup 统计结果的基础,还会生成纵向小计结果
select deptno,job,avg(sal) from emp group by rollup(deptnojob);
select deptno,job,avg(sal) from emp group by cube(deptnojob);
14 连接查询
在使用连接查询时,必须在where 子句中指定有效的连接条件。如果不指定连接条件,或者指定无效的连接条件
那么会导致生成笛卡尔乘积。
1 select e.name,esal, from emp e,dept d where e.deptno=d.deptno;
2 自然连接:在同一张表之间连接查询
select manager.ename form emp manager,emp worker
where manager.empno=worker.mgr and worker.ename='blanke'
3 内连接由于返回满足连接条件的记录,而外连接则是内连接的扩展,还会返回不满足的连接条件的记录
4 左外连接: 不仅返回满足条件的所有记录,而且还会返回不满足连接条件的连接符左表的其它行
select a.name,b,ename from adpt a left join emp b on a.deptno=b.deptno
5 右外连接 right join
6 完全外连接 不仅返回满足条件的所有行,而且还会返回不满足连接条件的所有其它行
select a.dname,b,ename from dept a full join emp b on a.deptno=b.deptno
15 子查询
1 单行子查询 返回一行数据的子查询语句
select ename,sal,deptno form emp where deptno=(select deptno from emp where ename='scott')
2 多行子查询,返回多行子查询
1) 使用in操作符
select ename ,job,sal,deptno from emp where job in
(select distince job from emp where deptno='10')
2)在多行子查询中使用all操作符
select ename,sal,deptno from emp where sal>all(select sal from emp where deptno='30')
3)在多行子查询中使用any操作符 任何一个结果即可
select ename,sal,deptno from em where sal>any(select sal from emp where deptno='30')
3 多列子查询
select ename,job,sal,deptno from emp where (deptno,job)=(select deptno,job from emp where ename='smith')
1) 成对比较示例
select ename,sal,comm,deptno from emp where (sal,nvl(cpmm.-1)) in (select sal,nvl(comm,-1) from emp where deptno='30')
2) 非成对比较
select ename,sal.comm,deptno from emp where sal_in(select sal from emp where deptno='30')
and nvl(comm,-1) in (select nvl) in (select nvl(comm,-1) from emp where deptno=30)
4 相关子查询
SELECT ENAME,JOB.SAL,DEPTNO FROM EMP FROM EXISTS(SELECT l FROM DEPT WHERE.......)
16 在dml 中使用子查询
1)在insert 中使用
insert into employee(id,name,title,salary)
select ename,job,sal from emp
2)update emp sset (sal,comm)=
(select sal,comm fromm emp where ename='smtp')
where job=(select job from emp where ename='smith')
17 在ddl
1 在create table 语句中使用子查询
create table new_emp(id,name,sql,jog,deptno) as
select empno,ename,sal,job,deptno from emp
18 合并查询
1) union 自动去掉集合中重复的行,定对第一列结果排序
select ename,sal,job from emp where sal>2500
union
select ename,sal,job from emp where job='manager'
2) union all 不会取消重复值
3)intersect 取两个结果继的交集
4) ninus 取两个结果结的差集
19 其它复杂查询
1 层次查询
1 oracle universal installer(OUI)
used to install,upgrade,or remove software components and create a database
./runInstaller(unix)
Non-interactive installation using response files
./runInstaller -responsefile myrewpfile -silent(用指定的安装文件)
2 OracleDatabase Configuration Assistant(DBCA)
creaste a database ,configure database options ,delete a database,manage template
3 Database Administrator Users
Sys is the owner of the database data dictionary
System is the owner of additional internal tables and views used by oracle tools
4 Local DataBase Administrator
create os user id
create os group ora dba,ora fox dba
ora_oper,ora_fox_oper
add os user id to ora_dba,group
edit sqlnet file: slqnet.authentication_services=(nts)
you can login in database
conn / as sysdba
5 User Password File Authentication(由于数据库还没有启动,需要利用数据库外面的如文件系统,或口令文件来管理具有特出权限的用户)
1 create the password file using the password
orapwd file='d:\oracle\ora90\database\pwd<sid>.ora' password=admin1 entries=10;
conn sys/admin1 as sysdba
2 set remote_login_passwordfile to exclusice
1 orapwd
2 edit inti parameter file remote_login_passwordfile to exclusive
3 grant system to kang (最多只能授权orapwd 中 entries参数指定用户用户数,具有此特出权限)
revoke sysdba form kong
select * from V$pwfile_users(查看有多少用户具有特出权限)
6 sql/plus
sqlplus /nolog sqlplusw /nolog
set autocommmit on
set linesize 1000
7 Oracle Enterprise Manager Architecture
Oracle Management Server,repository ,agent ,oracle server
oracle 独立登陆,虽然能够联机oracle ,但是很多管理更能不能操作,如backup 等
8 oem console
central launching point for all applications
can be run in thin mode(web) or as a fat client
can bu launched either standalone or through oracle management server
1 An oracle server consists of an oracle instance ans oracle database
2 startup nomount (allocate physical memory)
alter database mount (control file)
alter database open (data file and log file)
3 instance memory strusture
background process
database--data file
log file
control file
4 an oracle instance
is a means to access an oracle database
alwary opens one and only one database
consists of memory and process structures
5 show sga
select * from v$bgprocess;
select * from where v$bgprocess where paddr<>'00'列出必须的后台进程
6 connection to an oracle instance consists of establishing a user connection and creating a session
user process server process
7 an oracle database is collection that is treated as a unti
consist s of thress file types data file control file log file
8 the physical structure of an oracle database is determined by the orpertion system file
that provide the actual
select * from v$controlfile(列出所有控制文件)
select * from v$datafile (列出说数据文件)
53
select * from v$logfile (列出所有日志文件)
9memory structure
oracle menory structure consists of two menory areas known as
sga and pga(程序全局区2)
10 The SGA consists of several menory structures:
shared pool
Database buffer cache
redo log buffer
there are two optional menory structure than can be configured within the SGA
large pool
java pool
11 SGA
show parameter shared (列出系统全局区的参数设置)
show parameter db_cache(列出系统数据库缓存参数设置)
SGA is dynamic an d sized using SGA_MAX_SIZE,调整各个部分值的总合不能超过SGA_MAX_SIZE
alter session set nls_lanage=american
alter system set db_cache_size=64m
12 Share Pool
Share pool is used to store the most recently executed SQL statement s and the the most recently
used data definitions
it consists of two key performance related memory structure
-library cache
-Data dictionary cache
it sized by the parameter share_pool_size
alter system set share_pool_size=64
13 libray cache
The libray cache stores information about the most recently used sql and pl/sql statement
1)Enable the shreing of commonly used statments
is managed by ta least recently used LRU
2)consists of two structures
shared sql area
Shared Pl/SQL area
3)Has its size determined by the shared pool sizing
14 Data Dictionary Cache
The data dictionary cache is a collection of the most recently used definitions in the database
15 Database Buffer Cache
1)The database buffer cache stores copies of data blocks that have been retrieved form the data files
2)it enable great performace gains when you obtain and update data
3)it is managered through a LRU
4)DB_BLOCK_SIZE determines the primary block size
5)show parameter db (列出db 中所有的参数)
6)Consists of indepent sub-cache
db_cache_size
db_keep_cache_size
db_recycle_cache_size
7)Database buffer cache can by dynamically resize to grow or shrink using alter system
alter system set db_cache_xiae=96m
8)DB_CACHE_ADVICE can be set gater statistics for predictin different cache size behavior
alter system set db_cache_advice=on ?
16 The redo log buffer
The redo log buffer cache records all changes made to the database data block
1)its primary perpose is recovery
2)change record within are called redo entries
3)redo entries contain information to reconstruct or redo changes
4)size is defined by log_buffer
17 large Pool
the loarge pool is an optional area of memory in the SGA
1)it relivere the burden placed on the shared pool
2)this configured memory area is used for sesion memory(UGA) ,
i/o slavers and backup and restore operation
3) the large pool does not use an LRU list
show parameter log_buffer
18 Process Structure
Oracle takes advantage of various types of
processes:
1) User process :Started at the time a database user requests connection to the oracle server
2) Serer process connects to the oracle instance and is started when a user establishes a session
3) background process available when an oracle instance is started
19 user process
A suer process is a program that requests interaction with the oracle server
1)it must first establish a connection
2) it does not interact directly with the oracle
20 Server Process
Aserver process is a program that directly interacts with the oracle server
1)it fulfills call generate and returns results
2) can bi dedicated or shared server
21 DBWn write s when checkpoint, dirty buffers threshold reach, no free buffer,timeout ,tablespaxe
offline,tablespacee read only ,table drop or turncate,tablspace begin backup
22 LGWR write
at commit,went one third full,when threre is 1mb of redo ,every 3 seconds ,before DBWn writes
24 System Moritor,PMON
25 Checkpoint
Responsible for signalling DBWn at checkpoints
Updating datafile header with checkpoint information
26 Archiver ARCn
optional background process automaticall archives online redo logs when ARCHIVELOG mode is set
Preserves the record of all changes made to database
27 Lpgoca; Structure
The logical structure of the oracle architecture dictates how the physical space of a database is to be
sued
A hierarchy seists in this structure that consists of tablespaces ,segments ,extents and blocks
为什么兴趣小组没有什么报酬,但 却比大多数商业公司的团队更有效。为什么open source 在软件行业中成为了一只推动发展的生力军。这是因为参与者都具有相当的热情和爱好,只根据能力和状态的不同去分配任务,则会让一切变得简单。这一切都取决于一个根本的原因--人。软件项目的管理根本是人的管理而不是过程管理。
在商业软件项目中,完成项目的时间应该是安排的程序员制定的,而不是项目经理或者其它人。完成高质量的任务的并不是将任务分配下去,而是自己自己抢这去做。因为每个程序员都渴望成功,这个成功可以是贡献,也可以是分享。当软件项目有机的切割成不同的任务时,每个任务最适合的人员就是那些有兴趣,有决心把它做到最好。
在工业时代,我们需要管理的是工人的四肢;科技时代,我们需要管理的是程序员的敏捷头脑和激发一切的主管能动性。软件凝聚的是程序的智慧,而不是程序员的汗水。
一个项目团队,就像是一个临时家庭,作为一个团队的管理者,你是知道团队中每个人的生日,你是否知道团队中每个人的上班路线,你是否知道团队中每一个人的爱好。越来越的团队开始用兄弟连的的例子去描述一个团队。一个团队的核心是每个团队成员而不是管理者。
1 用plsql 连接 plsql cyts_cc/cyts_cc@cyts
2 sqlplusw 打开oracle sql*plus 界面。
3 plsql 中commond window 实现了sql*plus 的所有功能。
4 programmer window 和 test windown 实现了编程和调试的功能。
5 pl/sql 的结构
create or replace procedure test
declare
c_name varchar(5);
begin
select name into c_name from emp where id=@no;
dbms output.put_line('客户名称:'||c_name);
exception
when no_data_found then
dbms_output.put_line('请输入正确雇员号!');
end test;
输入no得值
6 匿名块/命名块
命名块主要是为了在嵌套结构是区分层次
<<outter>>
declare
c_name varchar(5);
begin
<<inner>>
begin
....
end;
select name into c_name from emp where id=@no;
dbms output.put_line('客户名称:'||c_name);
exception
when no_data_found then
dbms_output.put_line('请输入正确雇员号!');
end test;
7 调用 存储过程
exec pro_name
call pro_name
8 调用函数
call anual_income into income
9 保用于逻辑作合相关的过程和函数,包括包头,和包体,在包头中只定义存储过程or函数,在包体中
定义实现。
10 标量变量
varchar2(n)max 4000 char(n) max 2000 number(p,s) p 总的位长,s 小数电后面的位长
date ,timestamp,long(类似于varchar) max 32760,long raw 二进制 32760
binary_fload 和 binary_double oralce 10g 用于高精度计算高速计算。
11 定义标量变量
c_max_value constant number(3,2):=5.5
constant,default,not null,:=
12 %type
13 复合变量
1 pl/sql 记录 类似于高级语言中的结构
type emp_record_type is record(
name emp.ename%type
salary emp.sal%type);
emp_record emp_record_type;
2 pl/sql 表,类似于高级语言中的数组,单其下标可以为负,且元素个数没有上下限。
declare
type ename_table_type is table of emp.ename%type
index by binary_integger;
ename_table ename_table_type;
select ename into ename_table(-1) from emp where &enomo='1118'
3 嵌套表结构还有些看不懂,先放下,以后在看
14 参照变量
参照变量是指由于存放指针的变量。通过石油参量变量可以使用相同的对象。
1 ref cursor
当显示游标时,需要在定义显示游标时制定响应的select语句,当使用游标变量时,在定义是不需
指定select 语句,而是在游标指定select 语句
declare
type c1 is ref cursor
emp_cursor c1
...............
begin
ipen emp_cursor for select ename,sal from emp where deptno=10;
loop
fetch emp_sursor into v_ename,v_sal;
exit when emp_cursor%not found
...........
end loop;
close emp_sursor;
2 ref obj_type
可以引用对象类型
create or replace type home_type as object(
street varchar2(50),city varchar2(20),
owner varchar(10)
);
create table homes of home_type;
insert into homes values('222','3333');
create table person(
id number(6) primary key,
name varchar2(10),
addr ref home_type
);
inert into person select 1,'22',ref(p) from homes p where p.owner='22'
14 lob 变量
lob 分为内部lob(clob,blob,nclob ) 和外部lob(bfile),内部lob 存在数据库内,支持事务。外部
lob 存在外部,不支持事务