项目中有使用xml传递大数据量的写入IT模型,因为之前的测试场景都是单一表的写入测试,有的表数据在初期使用量少,所以有可能导致没有使用xml进行数据的传递与使用模型进行写入的测试。如果这些隐藏的问题发现越晚,对之前历史数据的清理以及重发消息的同步数据工作量就更大。所以有必要填充一份完整的传递数据的xml,然后验证IT模型中所有表数据写入的正确性。
这个需求的前提是,这个IT模式中有维护一份数据库字段映射xml字段的映射表,这里面最重要的其实就是所有表的数据动态查询与取值,为了模型的简化,我们直接取 Oracle数据库自带的 表 User_Tab_Columns作为我们字段的映射表。
GitHub地址:点我
简单查询效果明显,可以不要写任何sql,java层面使用Map承接数据,可以直接转入VO中。该项目启发性大于实用性
只能用于简单的单表查询,复杂查询有点鸡肋,所以整体上属于启发性Demo,如果各位有类似简单的查询可以使用,可扩展性差
可以根据这种方式实现插入,更新,删除操作,更新操作会比这个略显复杂,同时也是另外一种启发方式解放无聊的增删改查把
只要在数据库中有新建表和字段,改表中就会存储对应字段名称和字段数据类型信息,注意我们建立的emp表的hireDate字段类型为Date,在后面的包中,我们会对日期进行统一格式化处理
SELECT column_name ,lower(column_name),data_type FROM User_Tab_Columns WHERE table_name = upper('emp' )
访问表emp数据:
http://localhost:10001/curDynamicSql/findByDynamicSqlGetReturn/emp
访问表operator数据:
http://localhost:10001/curDynamicSql/findByDynamicSqlGetReturn/operator
create or replace
package pkg_querySql
as
type cursorRef is ref cursor;
procedure querySqls(p_table VARCHAR2,cursor_ref out cursorRef);
end pkg_querySql;
包头中定义了一个过程,入参是 要查询的表名 p_table , cursor_ref是定义的一个游标,存储查询表的数据,可以是多条既存储 List
create or replace
package body pkg_querySql
is
procedure querySqls(p_table VARCHAR2,cursor_ref out cursorRef)
AS
v_column VARCHAR2(50); --存储待拼接的数据库字段名
v_mappName VARCHAR2 (50); --存储映射xml字段的名称
v_dataType VARCHAR2 (50); --存储该字段数据库字段类型
v_sqlStmt VARCHAR2(5000); --存储拼接的临时查询sql
BEGIN
OPEN cursor_ref FOR --打开动态游标
'SELECT column_name ,lower(column_name),data_type from User_Tab_Columns WHERE table_name = upper(''' ||p_table || ''' )';
LOOP
FETCH cursor_ref INTO v_column, v_mappName,v_dataType ; --循环提取游标数据
EXIT WHEN cursor_ref%NOTFOUND; --没有数据时退出循环
IF v_dataType = 'DATE' THEN --如果是日期格式
v_column := 'to_char(' || v_column || ',''YYYY-MM-DD HH24:MI:SS'')';
END IF;
IF v_sqlStmt IS NULL THEN --动态拼接sql
v_sqlStmt := v_column || ' AS "' || v_mappName || '" ';
ELSE
v_sqlStmt := v_sqlStmt || ' ,' || v_column || ' AS "' || v_mappName || '" ';
END IF;
END LOOP;
CLOSE cursor_ref; --关闭游标变量
v_sqlStmt := 'SELECT '|| v_sqlStmt || ' FROM ' || p_table;
DBMS_OUTPUT.PUT_LINE ('查询sql:' || v_sqlStmt);
open cursor_ref for --打开动态游标存储查询数据
v_sqlStmt;
EXCEPTION
WHEN OTHERS THEN
IF cursor_ref%FOUND THEN --如果出现异常,游标变量未关闭
CLOSE cursor_ref; --关闭游标
END IF;
DBMS_OUTPUT.PUT_LINE ('ERROR: ' ||
SUBSTR(SQLERRM, 1, 200));
end querySqls;
end pkg_querySql;
1. 'SELECT column_name ,lower(column_name),data_type from User_Tab_Columns WHERE table_name = upper(''' ||p_table || ''' )';
通过p_table 传入需要查询的表查询User_Tab_Columns 中的映射字段
2. FETCH cursor_ref INTO v_column, v_mappName,v_dataType ; --循环提取游标数据
一次移动一个游标位置,将一个游标中的三个数据一次性装入后面的三个定义字段中
3. IF v_dataType = 'DATE' THEN --如果是日期格式
v_column := 'to_char(' || v_column || ',''YYYY-MM-DD HH24:MI:SS'')';
END IF;
如果是日期Date格式,进行统一 To_char格式转型
4. v_sqlStmt := v_sqlStmt || ' ,' || v_column || ' AS "' || v_mappName || '" ';
动态拼接sql,同时对于映射字段前后加 " 双引号,防止返回Map时字段强制大写
5. open cursor_ref for --打开动态游标存储查询数据
v_sqlStmt;
打开动态游标存储查询数据
CREATE TABLE emp(
empno NUMBER(4) CONSTRAINT PK_EMP PRIMARY KEY,
ename VARCHAR2(10),
job VARCHAR2(15),
mgr NUMBER(4),
hiredate DATE,
sal NUMBER(7,2),
comm NUMBER(7,2),
deptno NUMBER(2) CONSTRAINT FK_DEPTNO REFERENCES DEPT
);
INSERT INTO emp VALUES(7369,'SMITH','CLERK',7902,to_date('17-12-1980','dd-mm-yyyy'),800,NULL,20);
INSERT INTO emp VALUES(7499,'ALLEN','SALESMAN',7698,to_date('20-2-1981','dd-mm-yyyy'),1600,300,30);
INSERT INTO emp VALUES(7521,'WARD','SALESMAN',7698,to_date('22-2-1981','dd-mm-yyyy'),1250,500,30);
INSERT INTO emp VALUES(7566,'JONES','MANAGER',7839,to_date('2-4-1981','dd-mm-yyyy'),2975,NULL,20);
INSERT INTO emp VALUES(7654,'MARTIN','SALESMAN',7698,to_date('28-9-1981','dd-mm-yyyy'),1250,1400,30);
INSERT INTO emp VALUES(7698,'BLAKE','MANAGER',7839,to_date('1-5-1981','dd-mm-yyyy'),2850,NULL,30);
INSERT INTO emp VALUES(7782,'CLARK','MANAGER',7839,to_date('9-6-1981','dd-mm-yyyy'),2450,NULL,10);
INSERT INTO emp VALUES(7788,'SCOTT','ANALYST',7566,to_date('19-4-87','dd-mm-yyyy'),3000,NULL,20);
INSERT INTO emp VALUES(7839,'KING','PRESIDENT',NULL,to_date('17-11-1981','dd-mm-yyyy'),5000,NULL,10);
INSERT INTO emp VALUES(7844,'TURNER','SALESMAN',7698,to_date('8-9-1981','dd-mm-yyyy'),1500,0,30);
INSERT INTO emp VALUES(7876,'ADAMS','CLERK',7788,to_date('23-5-87','dd-mm-yyyy'),1100,NULL,20);
INSERT INTO emp VALUES(7900,'JAMES','CLERK',7698,to_date('3-12-1981','dd-mm-yyyy'),950,NULL,30);
INSERT INTO emp VALUES(7902,'FORD','ANALYST',7566,to_date('3-12-1981','dd-mm-yyyy'),3000,NULL,20);
INSERT INTO emp VALUES(7934,'MILLER','CLERK',7782,to_date('23-1-1982','dd-mm-yyyy'),1300,NULL,10);
----------------operator----------------
CREATE TABLE operator(
ID NUMBER(4),
dates VARCHAR2(10),
equpment varchar2(10),
operators varchar2(10)
)
INSERT INTO OPERATOR VALUES(1,'301', 'd', 'jemy');
insert into operator values( 2,'302', 'b', 'tony');
insert into operator values( 3,'303', 'c', 'jemy');
insert into operator values( 4,'304', 'a', 'tony');
insert into operator values( 5,'305', 'c', 'jemy');
INSERT INTO OPERATOR VALUES( 6,'306', 'a', 'jemy');
INSERT INTO OPERATOR VALUES( 7,'307', 'a', 'tom' );
declare
return_cursor pkg_querySql.cursorRef; --定义接收返回数据集的变量
tableName varchar2(20) := 'operator' ; --定义接收table的变量
id varchar2(20); --定义接收id的变量
dates varchar2(50); --定义接收name的变量
equpment varchar2(20); --定义接收id的变量
operators varchar2(50); --定义接收name的变量
begin
pkg_querySql.querySqls(tableName,return_cursor); --调用包中的存储过程返回游标引用
loop fetch return_cursor into id,dates,equpment,operators; --循环获取游标中每一行的数据
exit when return_cursor%notfound; --游标结束时退出
dbms_output.put_line('id:'||id||' dates:'||dates || ' equpment:'||equpment||' operators:'||operators); --将获取到的值打印出来
end loop; --循环结束
close return_cursor; --关闭游标
end;
package com.mon.project.model.dynamicSQL.dao;
import org.springframework.stereotype.Repository;
import java.util.Map;
@Repository
public interface DynamicSqlDao {
public void findByDynamicSql(Map seachMap);
}
package com.mon.project.model.dynamicSQL.controller;
import com.mon.project.model.dynamicSQL.dao.DynamicSqlDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.*;
@RestController
@RequestMapping("/curDynamicSql")
public class CurDynamicSqlContorller {
private static final Logger logger = LoggerFactory.getLogger(CurDynamicSqlContorller.class);
@Autowired
DynamicSqlDao dynamicSqlDao;
@RequestMapping(value = "/findByDynamicSqlGetReturn/{tableName}",method = RequestMethod.GET)
public List
在Map中传入tableName和接受参数return_cursor,从而实现Mybatis对存储过程的调用
CREATE ROLE toad_plsql_debug NOT IDENTIFIED;–新建角色
GRANT DEBUG ANY PROCEDURE TO toad_plsql_debug; --为角色赋值子程序调试权限
GRANT EXECUTE ON SYS.dbms_debug_jdwp TO toad_plsql_debug; --为角色分配调试包权限
GRANT DEBUG CONNECT SESSION TO toad_plsql_debug; --为角色分配调试会话权限
grant toad_plsql_debug to system; --让system具有角色权限
最后一句-让system具有角色权限,有的不是这个账户登录的,改成你对应登录账户即可
如果下面控制台没有打印查询结果可以执行以下语句
set serveroutput on;
SELECT object_type,object_name FROM user_objects WHERE object_type IN ('PACKAGE','PAKAGE BODY')
--查看某一个包的代码
select line,text from user_source where name = 'PKG_ALEN'
--删除无用包
drop package pkg_querySql
GitHub地址:点我
本文中的知识学习来自 Oracle PL/SQL 从入门到精通,有兴趣的同学可以买这本书来看看