编程基础
Java开发基础
语言基础
浅克隆和深克隆
Shallow Clone
被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。即浅克隆仅仅复制所拷贝的对象,而不复制它所引用的对象。
Deep Clone
被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深克隆把要复制的对象所引用的对象复制了一遍。
数据库
SQL 基础
增删改查
- INSERT ```sql / 全部字段INSERT / INSERT INTO 表名称 VALUES(值1,值2,…)
/ 部分字段INSERT / INSERT INTO 表名称 (列1,列2,…) VALUES (值1,值2,…)
> 注意:值一定要与字段顺序对应,字符串用引号包含,注意空格,字段名不要引号2. SELECT2. UPDATE```sql/* 单字段UPDATE */UPDATE 表名称 SET 列名称 = 新值 WHERE 条件/* 多字段UPDATE */UPDATE 表名称 SET 列1 = 新值1, 列2 = 新值2,... WHERE 条件
UPDATE 之前可以先 SELECT 确认一下数据是否是自己需要修改的数据
- DELETE
/* 单行删除 */DELETE FROM 表名称 WHERE 条件/* 多行删除 */DELETE FROM 表名称 WHERE 条件
下面举例说明:
DELETE FROM movies WHERE id = 2 /* 删除 id = 2 的一行数据 */DELETE FROM movies WHERE id > 2 /* 删除 id > 2 的所有数据 */
和 UPDATE 一样,操作会对数据进行修改,可以先 SELECT 确认一下是否是自己需要删除的数据
基础语法
排序
ORDER BY
可以添加后缀 ASC(升序排列)、DESC(降序排列),默认为ASC。
表达式
事实上我们在使用SQL语句的过程中也可以使用表达式来指定属性进行一定的计算或者处理,如有一个col_name是出生日期,现在要求SQL返回当前的年龄,这里就可以使用一个表达式来计算时间。表达式可以对数字运算、字符串运算也可以在表达式中只使用常量而不使用col_name。
/* 表达式举例说明 */SELECT partice_speed / 2.0 AS half_partice_speed /* 微粒速度除以2.0 */FROM physics_dataWHERE ABS(particle_position) * 10.0 > 500 /* 条件要求该属性绝对值乘以10.0大于500 */
每一个数据库都有一套函数提供给用户使用,包含常见的数字、字符串、时间等的处理。下面是几个常见的统计函数:
| 函数 | 描述 |
|---|---|
| COUNT(*) | 统计数据行数 |
| COUNT(column) | 统计column非null的行数 |
| MIN(column) | 找到column最小的一行 |
| MAX(column) | 找到column最大的一行 |
| AVG(column) | 对column所有行取平均值 |
| SUM(column) | 对column所有行求和 |
别名
我们在使用表达式的时候可能会出现很长的表达式,这时候语句的可读性就会下降,我们可以使用AS关键字来取一个别名。别名不仅可以用在表达式上也可以用在普通的属性列甚至是表上。
/* 别名 */SELECT column1 AS particle_speed /* 取别名,column1的别名为particle_speed */from physics_data
分组
分组语法可以按照某个col_name对数据进行分组,如对公司支出按照年份或者部门进行分组查询。
GROUP BY分组结果的条数就是分组数量。
/* 数据分组统计每栋办公室按人数排名,不要统计无办公室的雇员 */SELECT COUNT(*), /* 统计办公室总人数 */building /* 办公室名 */FROM employeesWHERE building IS NOT nullGROUP BY buildingORDER BY SUM(building) DESC
查询顺序
如下是一个完整的SELECT查询语句
SELECT DISTINCT column,AGG_FUNC(column_or_expression),…FROM mytableJOIN another_tableON mytable.column = another_table.columnWHERE constraint_expressionGROUP BY columnHAVING constraint_expressionORDER BY column ASC/DESCLIMIT count OFFSET COUNT;
其中各种语法的顺序需要严格按照规定来编写
- FROM 和 JOINs
FROM 和 JOINs 会在第一个执行,确定整体的数据范围。如果要JOIN不同表,则会生成一个临时表来用于进行下面的过程,总之第一步可以简单理解为确定一个数据源表(含临时表)。 - WHERE
确定了数据来源之后 WHERE 语句就在这个数据源中按照要求来进行数据的筛选,丢弃不符合要求的数据行。AS 别名不能在这个阶段使用,因为可能别名还是一个没有执行的表达式。 - GROUP BY
对数据进行分组、统计,并将结果集缩小为分数组,其他的数据在分组后丢弃 - HAVING
分组之后 HAVING 会对结果集进行筛选。AS别名不能在此阶段使用 - SELECT
确定结果之后,SELECT 用来对结果进行简单筛选或者计算,决定要输出什么数据 - DISTINCT
如果有数据行重复,DISTINCT 负责去除重复内容 - ORDER BY
确定了结果集之后,ORDER BY 对结果进行排序。因为 SELECT 中的表达式已经执行,因此可以使用 AS 别名 - LIMIT / OFFSET
最后 LIMIT 和 OFFSET 从排序的结果中截取部分数据
常用函数
NVL 空值判断函数
- NVL (表达式A, 表达式B)
如果表达式 A 为空值,NVL 返回值为表达式 B 的值,否则返回表达式 A 的值。该函数的目的是把空值转换为一个实际的值。表达式的值可以是数字型、字符型和日期型,但是表达式 A 和 B 的数据类型必须是同一种。 - NVL2(表达式A,表达式B,表达式C)
如果表达式 A 为空,则返回表达式 C 的值;如果表达式 A 不为空则返回表达式 B 的值。
存储过程(DB2)
没有学习的必要,这里作者是因为项目中确实需要用到这东西才去学了,目前已经很少会有公司用这种东西。数据库一般只用来存储数据,减少数据库的负担。存储过程调试修改起来费劲,并且后期难以拓展,不适用于现在的互联网项目。
应用示例
- 将一个表中的数据复制插入到另一张表里
```sql
CREATE PROCEDURE aaa()—存储过程可以设定输入参数和输出参数
LANGUAGE SQL—DB2可以用多种语言编写存储过程,这里用的是纯SQL
BEGIN—开始
DECLARE vID smallint;—定义变量,和Oracle一样 DECLARE 变量名 变量的数据类型;
FOR V AS SELECT BRND_CD FROM TMP_BRND_CD—for循环 tmp_brnd_cd预先创建好
END FOR;—循环体结束 END —存储过程结束DO--循环体开始SET vID=BRND_CD;--对vID赋值,db2可以用set赋值,也可以用values赋值,这里可以写成values(BRND_CD) into vIDINSERT INTO WWM_FORINSERT_TEST VALUES(vID);--往wwm_forinsert_test表中插入数据
— 执行存储过程 CALL aaa()
<a name="0b680046"></a>### 语法参数说明- **procedure-name**<br />存储过程的名字- **{IN | OUT | INOUT parameter-name data-type}**- **IN** 传入参数;- **OUT** 输出参数;- **INOUT** 输入输出参数;- **data-type** 参数类型,可以接收SQL类型和创建的表- **SPECIFIC specific-name**<br />唯一的特定名称(别名),可以用存储过程名代替,这个特定名称用于drop存储过程,或者给存储过程添加注释用,但不能调用存储过程。如果不指定,数据库会自动生成一个yymmddhhmmsshhn时间戳的名字。- **DYNAMIC RESULT SETS integer**<br />指定存储过程返回结果的最大数量。存储过程虽然没有return语句,但是可以返回结果集- **CONTAINS SQL, READS SQL DATA, MODIFIES SQL DATA**<br />指定存储过程中的SQL访问级别- **CONTAINS SQL** 表示存储过程可以执行中,既不可以读取SQL数据,也不可以修改SQL数据- **READS SQL DATA** 表示存储过程可以执行中读取SQL数据,但不可以修改数据- **MODIFIES SQL DATA** 表示存储过程中可以执行任何SQL语句- **DETERMINISTIC or NOT DETERMINISTIC** 表示存储过程时动态的或者非动态的。动态的返回值是不确定的,非动态的每次返回值是相同的- **CALLED ON NULL INPUT** 表示调用存储过程而不管任何输入参数是否为NULL,并且任何的 OUT 或者 INOUT 参数可以返回一个 NULL 或者非空值。检验参数是否为 NULL 是在过程中进行的- **INHERIT SPECIAL REGISTERS** 表示继承专用寄存器- **OLD SAVEPOINT LEVEL or NEW SAVEPOINT LEVEL** 建立存储点,OLD SAVEPOINT LEVEL 是默认的存储点- **LANGUAGE SQL** 指定程序的主体是用SQL语言- **EXTERNAL ACTION or NO EXTERNAL ACTION** 表示存储过程是否执行一些改变数据库状态的活动,而不通过数据库管理器管。默认是 EXTERNAL ACTION,如果指定为 NO EXTERNAL ACTION ,则数据库会确定最优化方案- **PARAMETER CCSID** 指定所有输出字符串数据的编码,默认为UNICODE 编码数据库为PARAMETER CCSID UNICODE,其他数据库默认为 PARAMETER CCSID 3 ASCII- **SQL-procedure-body** 存储过程的主体- **AUTONOMOUS** 声明为自治事务<a name="b7f5c477"></a>### 游标定义游标```sqlDECLARE 游标名 CURSOR FOR SELECT 语句
示例:
DECLARE mycurl CURSORFOR SELECT e.empno, e.lastname, e.jobFROM employee e, department dWHERE e.workdept = d.deptnoAND deptname = 'PLANTING';
在 SQL 过程中,游标除了迭代结果集中的行,还可以将结果集返回给调用程序或其他过程
- WITHOUT RETURN / WITH RETURN 选项指定游标的结果表是否作为从一个过程中返回的结果集
- WITH RETURN TO CALLER 选项指定将来自游标的结果集返回给调用者,后者可以是另一个过程或一个客户机应用程序
- WITH RETURN TO CLIENT 将来自游标的结果集返回给客户机应用程序,绕过任何中间的嵌套过程
- WITH HOLD 如果没有加 WITH HOLD,在 Commit 和 RollBack 时游标将会被关闭。
-- 下面是游标声明的几个例子DECLARE c1 CURSOR FOR SELECT * FROM staff;-- (DECLARE 关键字, c1游标名称, CURSOR是必须有的,指通过c1的游标来操作staff里所有的数据)-- 最常用的最普通的DECLARE c1 CURSOR WITH HOLD FOR SELECT * FROM staff;DECLARE c1 CURSOR WITH RETURN TO CALLER FOR SELECT * FROM staff;DECLARE c1 CURSOR WITH RETURN TO CLIENT FOR SELECT * FROM staff;
若要从一个过程中返回结果集,需要:
- 创建一个过程,创建时指定 DYNAMIC RESULT SETS 子句中声明存储过程将要返回结果集的数量
- 声明游标,声明时指定 WITH RETURN 子句
打开该游标,并使之保持 open 状态,如果关闭该游标,则结果集将不能返回调用者应用程序
-- 返回一个结果集的游标的声明CREATE PROCEDURE emp_from_dept()DYNAMIC RESULT SETS 1 -- 返回的结果集超出定义的数量会返回一个警告P1: BEGINDECLARE c_emp_dept CURSOR WITH RETURNFOR SELECT empno, lastname, job, salary, commFROM employeeWHERE workdept = 'E21';OPEN c_emp_dept;END P1
条件判断
if 语句
IF years_of_serv > 30 THENSET gl_sal_increase = 15000;ELSEIF years_of_serv > 20 THENSET gl_sal_increase = 12000;ELSESET gl_sal_increase = 10000;END IF;
CASE 语句
- simple CASE 语句用于根据一个字面值进入某个逻辑
- searched CASE 语句用于根据一个表达式的值进入某个逻辑 ```sql — 使用 searched CASE 语句的存储过程 CREATE PROCEDURE sal_increase_lim1 (empid CHAR(6)) BEGIN DECLARE years_of_serv INT DEFAULT 0; DECLARE v_incr_rate DEC(9,2) DEFAULT 0.0;
SELECT YEAR(CURRENT DATE) - YEAR(hiredate)
INTO years_of_servFROM empl1WHERE empno = empid;
CASE
WHEN years_of_serv > 30 THENSET v_incr_rate = 0.08;WHEN years_of_serv > 20 THENSET v_incr_rate = 0.07;WHEN years_of_serv > 10 THENSET v_incr_rate = 0.05;ELSESET v_incr_rate = 0.04;
END CASE;
UPDATE empl1
SET salary = salary + salary * v_incr_rate
WHERE empno = empid; END ```
循环
LOOP 循环
CREATE PROCEDURE LEAVE_LOOP (DEPTIN char(3), OUT p_counter INTEGER)L1: BEGINDECLARE v_at_end, v_counter INTEGER DEFAULT 0;DECLARE v_lastname VARCHAR(15);DECLARE v_birthd, v_hired DATE;DECLARE c1 CURSORFOR SELECT lastname, hiredate, birthdate FROM employeeWHERE WORKDEPT = deptin;DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_at_end = 1;OPEN c1;FETCH_LOOP: LOOPFETCH c1 INTO v_lastname, v_hired, v_birthd;IF v_at_end <> 0 THEN -- LOOP UNTIL LAST ROW OF the CURSORLEAVE FETCH_LOOP;END IF;SET v_counter = v_counter + 1;INSERT INTO PEPORT_INFO_DEPTvalues(v_lastname, v_hired, v_birthd);END LOOP FETCH_LOOP;SET p_counter = v_counter;END L1
WHILE 循环
CREATE PROCEDURE DEPT_REPT (DEPTIN CHAR(3), OUT p_counter INTEGER)P1: BEGINDECLARE v_at_end, v_counter integer DEFAULT 0;DECLARE v_lastname VARCHAR(15);DECLARE v_birthd, v_hired DATE;DECLARE c1 CURSORFOR SELECT lastname, hiredate, birthdate FROM employeeWHERE WORKDEPT = deptin;DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_at_end = 1;OPEN c1;FETCH c1 INTO v_lastname, v_hired, v_birthd;WHILE (v_at_end = 0)DOINSERT INTO REPORT_INFO_DEPTvalues(v_lastname, v_hired, v_birthd);SET v_counter = v_counter + 1;FETCH c1 INTO v_lastname, v_hired, v_birthd;END WHILE;SET p_counter = v_counter;END P1
FOR 循环
-- FOR 循环CREATE PROCEDURE DEPT_REPT1 (DEPTIN CHAR(3), OUT p_counter INT)P1: BEGINDECLARE v_counter INT DEFAULT 0;FOR dept_loop ASSELECT lastname, hiredate, birthdate FROM employeeWHERE WORKDEPT = deptinDOINSERT INTO REPORT_INFO_DEPT VALUES(dept_loop.lastname, dept_loop.hiredate, dept_loop.birthdate);SET v_counter = v_counter + 1;END FOR;SET p_counter = v_counter;END P1
REPEAT 循环
临时表空间
要使用临时表必须要创建一个表空间,默认为没有。
-- 创建一个临时表空间CREATE USER TEMPORARY TABLESPACE usertemp1managed BY SYSTEM USING ('usertemp1')
可以使用 **DECLARE GLOBAL TEMPORARY TABLE** 语句来定义临时表,DB2的临时表是基于会话的,且在会话之间是隔离的。当会话结束时,临时表的数据会被删除,临时表被隐式卸下。对临时表的定义不会 **SYSCAT.TABLES** 中出现。
/** NOT LOGGED 不记录事务日志*/DECLARE GLOBAL TEMPORARY TABLE gbl_tempLIKE empltab1ON COMMIT DELETE ROWSNOT logged IN usr_tbsp/*** 方法1:* ON COMMIT DELETE ROWS 在提交的时候清空数据,默认属性*/DECLARE GLOBAL TEMPORARY TABLE 表名(-- 参数列表NAME VARCHAR(10), -- 姓名DEPT SMALLINT, -- 部门SALARY DEC(7, 2) -- 工资)ON COMMIT DELETE ROWS;/*** 方法2:* 1. ON COMMIT PRESERVE ROWS 一直到会话结束* 2. LIKE 引用表名 INCLUDING COLUMN DEFAULTS WITH REPLACE 字段和类型引用其他表*/DECLARE GLOBAL TEMPORARY TABLE 表名LIKE 引用表名 INCLUDING COLUMN DEFAULTSWITH REPLACEON COMMIT PRESERVE ROWS;/*** 方法3:* DEFINITION ONLY WITH REPLACE 程序结束后自动删除该临时表*/DECLARE GLOBAL TEMPORARY TABLE 表名 AS(SELECT * FROM staff WHERE <condition>)DEFINITION ONLY WITH REPLACE;
- 用户定义临时表不支持
- LOB 类型的列(或基于 LOB 的单值类型列)
- 用户定义类型列
- LONG VARCHAR 列
- 使用表空间 ```sql CONNECT TO SAMPLE@ — Declare a teporary table from CLP — 创建表空间 DECLARE GLOBAL TEMPORARY TABLE temp_employee LIKE employee ON COMMIT PRESERVE ROWS@
— create a procedure which references the temporary table CREATE PROCEDURE p1 RESULT SETS 1
BEGIN — 声明游标 DECLARE cur CURSOR WITH HOLD WITH RETURN TO CLIENT FOR SELECT empno, firstname, lastname FROM SESSION.temp_employee FETCH FIRST 5 ROWS ONLY;
OPEN cur;
END @
— Now from the CLP (an application) — INSERT into the temp table INSERT INTO SESSION.temp_employee SELECT * FROM EMPLOYEE@
— CALL the procedure, which returns an open cursor back to the — CLP, proving that the temp table data was received. CALL p1@
在上面的例子中,创建 CLP 连接后声明了一个临时表。然后创建了引用临时表的过程 p1。这里要注意的关键是,即使在过程体中没有声明临时表,该过程也被成功创建。<a name="e449cf10"></a>### 异常处理begin 前声明异常 **DECLARE handler-type HANDLER FOR SQLEXCEPTION \ SQLWARNING | NOT FOUND** 为异常类型,handler-type 处理类型有以下几种:- UNDO 在处理器执行之前,DB2会回滚存储过程中执行的 SQL 操作。在处理器操作完成之后,存储过程会终止,并将控制返回给调用者- EXIT 在处理器操作完成之后,存储过程会终止,并将控制返回给调用者- CONTINUE 在处理器完成之后,会继续执行产生这个异常语句之后的下一条语句```sqlDECLARE CONTINUE HANDLER FOR not_found, SQLEXCEPTIONSET at_end = 1;DECLARE CONTINUE HANDLER FOR trunc BEGINSET truncated = 1;SET msg = 'message';END;
需要注意的问题:
- DB2 存储过程会在 SQL 执行完成后,将返回信息赋值给 SQLCODE 和 SQLSTATE。 这两个DB2 内置变量在使用前需要定义
- 定义 UNDO 类型的异常处理,在定义后面可以跟上操作语句
UNDO 类型的异常处理,必须是处理原子操作的 SQL 块,DB2 默认不是原子操作的。在 BEGIN 跟上 ATOMIC 即可 ```sql CREATE OR REPLACE PROCEDURE TEST ( IN num INTEGER, OUT P_ERRORCODE VARCHAR(256), — SQL 返回信息码 OUT P_ERRORCODE VARCHAR(1024)) — SQL 返回信息 BEGIN ATOMIC
DECLARE SQLCODE INTEGER DEFAULT 0; DECLARE SQLSTATE CHAR(5) DEFAULT ‘00000’; — 定义一个 UNDO 类型的异常处理 DECLARE UNDO HANDLER FOR SQLEXCEPTION SET P_ERRORCODE = to_char(sqlcode), P_ERRORCODE = ‘处理失败’;
UPDATE userinfo t SET t.usercode = ‘000000000003’ WHERE t.usercode = ‘000000000002’; UPDATE userinfo t SET t.usercode = ‘00000000000100’ WHERE t.usercode = ‘000000000001’; — 这里会因 usercode 字段超长出现异常
SET P_ERRORCODE = to_char(abs(SQLCODE)); SET P_ERRORDESC = ‘处理成功’;
END; ```
网络
Cookie 和 Session
| cookie | session |
|---|---|
| 保存在客户端 | 保存在服务器端 |
| 不够安全,用户就可以进行修改 | 用户无法修改,较为安全 |
| 保存数据的数量以及大小有限制 | 能够保存大量的数据 |
| 只能保存ASCII 字符串 | 可以存取任意类型的数据 |
要点:
- cookie 是实际存在的东西,而 session 可以理解为是一种抽象概念,是用于记录用户的状态、行为等的上下文。
- session 使用一个 sessionID 来标识用户,一般会将这个 sessionID 存在 cookie 里。可以使用 cookie 也可以使用其他来实现,如在 url 中传递 sessionID。
