Data Masking安装和使用指南

1. Data masking 简介

软件开发的最后阶段,是需要尽量真实的数据来作为基础测试软件的一系列功能。尤其是企业信息化系统,ERP、BI、EPM等这些大型系统实施或开发的时候,对于基础数据的要求很严格,很多时候都是直接克隆生产环境的数据来进行软件系统的测试,但是随之而来的影响却是深远的,生产数据中,首先它是一个真实的数据,透过数据基本上掌握了整个企业的资料。其次,在这当中包含很多敏感数据,不光是敏感数据,而且还是真实的敏感数据。如果在测试环境中发生了信息泄露问题,那么对于企业数据安全将造成致命的后果。

ORACLRE在OEM 10g之后提供Data Masking pack组件,解决从生产环境的数据向测试环境(或者开发环境)导入时可能会产生的数据内容安全问题,data masking特点是:按照指定的规则进行数据转换,可以通过规则控制最终生成的数据格式;维护数据表间的引用关系;通过EM图形界面来定义Data Masking,容易理解和使用。流程如下图所示:

2. 安装Data Masking Pack组件

OEM10g版本是10.2.0.4,提供了新6个pack功能,Data Masking Pack就是其中之一。因此,要使用安装,升级至最新的版本。使用Grid Control+OEM方便得使用管理Data Masking。

注:使用Data Masking的前提条件,安装Grid Control,升级OEM10g到10.2.0.4版本。

安装Grid Control软件。

下载介质:

从oracle官方网站下载gc_102011_linux.zip,补丁包GridControl_10.2.0.4_LINUX.zip

 

具体安装步骤详见文档:Oracle Grid Control 10.2.0.4 for Linux 安装和配置指南

3.    通过Grid Control使用Data Masking

1.     进入管理界面

使用SYSMAN用户登录 Oracle Enterprise Manger 10g(Grid Control)。

进入Grid Control主界面后,点击“Targets

进入Targets管理界面,点击“Database”

选择要进行管理的数据库,如图,进入“emrep”(数据库名)进行配置。

进入要管理的数据库之后,点击“Administration”。

进入管理界面后,看见Data Masking pack组件选项,点击“Definition”进入Data Masking进行管理与配置。

2.     定义/配置Data Masking

1.      添加一个定义
  1. 1.      选择需要mask的数据库,点击“Mask”,进入配置界面

  1. 2.      选择要mask的表,以及对应的列,并对格式进行定义。

  1. 3.      选择列转换规则(Array List,Fixed Number,Fixed string等转化规则,根据实际需求选择)

注:对定义TT用户的Mask表的列选择“随机字符串”转化规则

注:指定随机字符串的长度

2.      生成列转化规则脚本

脚本的内容为:

set echo off

set feedback off

set serveroutput on

set pagesize 0

spool /u02/app/oragrid/OracleHomes/db10g/dbs/masking14.log

-- Script Header Section

-- ==============================================

-- functions and procedures

CREATE OR REPLACE PROCEDURE mgmt$mask_sendMsg (msg IN VARCHAR2) IS

msg1 VARCHAR2(1020);

len INTEGER := length(msg);

i INTEGER := 1;

BEGIN

dbms_output.enable (1000000);

LOOP

msg1 := SUBSTR (msg, i, 255);

dbms_output.put_line (msg1);

len := len - 255;

i := i + 255;

EXIT WHEN len <= 0;

END LOOP;

END mgmt$mask_sendMsg;

/

CREATE OR REPLACE PROCEDURE mgmt$mask_errorExit (msg IN VARCHAR2) IS

BEGIN

mgmt$mask_sendMsg (msg);

mgmt$mask_sendMsg ('errorExit!');

END mgmt$mask_errorExit;

/

CREATE OR REPLACE PROCEDURE mgmt$mask_errorExitOraError (msg IN VARCHAR2, errMsg IN VARCHAR2) IS

BEGIN

mgmt$mask_sendMsg (msg);

mgmt$mask_sendMsg (errMsg);

mgmt$mask_sendMsg ('errorExitOraError!');

END mgmt$mask_errorExitOraError;

/

CREATE OR REPLACE PROCEDURE mgmt$mask_checkDBAPrivs (user_name IN VARCHAR2)

AUTHID CURRENT_USER IS

granted_role REAL := 0;

BEGIN

EXECUTE IMMEDIATE 'SELECT 1 FROM SYS.DBA_ROLE_PRIVS WHERE GRANTED_ROLE = ''DBA'' AND GRANTEE = (SELECT USER FROM DUAL)'

INTO granted_role;

EXCEPTION

WHEN NO_DATA_FOUND THEN

mgmt$mask_sendMsg ( 'WARNING checking privileges... User Name: ' || user_name);

mgmt$mask_sendMsg ( 'User does not have DBA privs. ' );

mgmt$mask_sendMsg ( 'The script will fail if it tries to perform operations for which the user lacks the appropriate privilege. ' );

END mgmt$mask_checkDBAPrivs;

/

CREATE OR REPLACE PROCEDURE mgmt$mask_setUpJobTable (script_id IN INTEGER, job_table IN VARCHAR2, step_num OUT INTEGER)

AUTHID CURRENT_USER IS

ctsql_text VARCHAR2(200) := 'CREATE TABLE ' || job_table || '(SCRIPT_ID NUMBER, LAST_STEP NUMBER, unique (SCRIPT_ID))';

itsql_text VARCHAR2(200) := 'INSERT INTO ' || job_table || ' (SCRIPT_ID, LAST_STEP) values (:1, :2)';

stsql_text VARCHAR2(200) := 'SELECT last_step FROM ' || job_table || ' WHERE script_id = :1';

TYPE CurTyp IS REF CURSOR;  -- define weak REF CURSOR type

stsql_cur CurTyp;  -- declare cursor variable

BEGIN

step_num := 0;

BEGIN

EXECUTE IMMEDIATE ctsql_text;

EXCEPTION

WHEN OTHERS THEN

NULL;

END;

BEGIN

OPEN stsql_cur FOR  -- open cursor variable

stsql_text USING  script_id;

FETCH stsql_cur INTO step_num;

IF stsql_cur%FOUND THEN

NULL;

ELSE

EXECUTE IMMEDIATE itsql_text USING script_id, step_num;

COMMIT;

step_num := 1;

END IF;

CLOSE stsql_cur;

EXCEPTION

WHEN OTHERS THEN

mgmt$mask_errorExit ('ERROR selecting or inserting from table: ' || job_table);

return;

END;

return;

EXCEPTION

WHEN OTHERS THEN

mgmt$mask_errorExit ('ERROR accessing table: ' || job_table);

return;

END mgmt$mask_setUpJobTable;

/

CREATE OR REPLACE PROCEDURE mgmt$mask_deleteJobTableEntry(script_id IN INTEGER, job_table IN VARCHAR2, step_num IN INTEGER, highest_step IN INTEGER)

AUTHID CURRENT_USER IS

delete_text VARCHAR2(200) := 'DELETE FROM ' || job_table || ' WHERE SCRIPT_ID = :1';

BEGIN

IF step_num <= highest_step THEN

return;

END IF;

BEGIN

EXECUTE IMMEDIATE delete_text USING script_id;

IF SQL%NOTFOUND THEN

mgmt$mask_errorExit ('ERROR deleting entry from table: ' || job_table);

return;

END IF;

EXCEPTION

WHEN OTHERS THEN

mgmt$mask_errorExit ('ERROR deleting entry from table: ' || job_table);

return;

END;

COMMIT;

END mgmt$mask_deleteJobTableEntry;

/

CREATE OR REPLACE PROCEDURE mgmt$mask_setStep (script_id IN INTEGER, job_table IN VARCHAR2, step_num IN INTEGER)

AUTHID CURRENT_USER IS

update_text VARCHAR2(200) := 'UPDATE ' || job_table || ' SET last_step = :1 WHERE script_id = :2';

BEGIN

-- update job table

EXECUTE IMMEDIATE update_text USING step_num, script_id;

IF SQL%NOTFOUND THEN

mgmt$mask_sendMsg ('NOTFOUND EXCEPTION of sql_text: ' || update_text);

mgmt$mask_errorExit ('ERROR accessing table: ' || job_table);

return;

END IF;

COMMIT;

EXCEPTION

WHEN OTHERS THEN

mgmt$mask_errorExit ('ERROR accessing table: ' || job_table);

return;

END mgmt$mask_setStep;

/

CREATE OR REPLACE FUNCTION mgmt$mask_randomencode (i_input VARCHAR2, pad_length NUMBER) RETURN VARCHAR2

AUTHID CURRENT_USER IS

TYPE charmap IS TABLE OF VARCHAR2(1) INDEX BY BINARY_INTEGER;

l_input NUMBER;

l_mod NUMBER;

l_retCode VARCHAR2(100);

l_map charmap;

l_base number := 25;

BEGIN

if (i_input is null) then

return lpad('a',pad_length,'a');

end if;

l_map(0)  := 'a';

l_map(1)  := 'b';

l_map(2)  := 'c';

l_map(3)  := 'd';

l_map(4)  := 'e';

l_map(5)  := 'f';

l_map(6)  := 'g';

l_map(7)  := 'h';

l_map(8)  := 'i';

l_map(9)  := 'j';

l_map(10) := 'k';

l_map(11) := 'l';

l_map(12) := 'm';

l_map(13) := 'n';

l_map(14) := 'o';

l_map(15) := 'p';

l_map(16) := 'q';

l_map(17) := 'r';

l_map(18) := 's';

l_map(19) := 't';

l_map(20) := 'u';

l_map(21) := 'v';

l_map(22) := 'w';

l_map(23) := 'x';

l_map(24) := 'y';

l_map(25) := 'z';

l_input := i_input;

l_retCode := '';

LOOP

-- skip 'a' for padding

l_mod := l_input mod l_base + 1;

l_retCode := l_map(l_mod) || l_retCode ;

IF (l_input >= l_base) THEN

l_input := round(l_input / l_base);

ELSE

l_input := 0;

END IF;

-- dbms_output.put_line('left ' || l_input || ' mod ' || l_mod );

EXIT WHEN l_input = 0;

END LOOP;

return lpad(l_retCode, pad_length, 'a');

END ;

/

create or replace type mgmt$mask_array_list as table of varchar2(128)

/

CREATE OR REPLACE PROCEDURE mgmt$step_1_14(script_id IN INTEGER, job_table IN VARCHAR2, step_num IN OUT INTEGER)

AUTHID CURRENT_USER IS

sqlerr_msg VARCHAR2(100);

BEGIN

IF step_num <> 1 THEN

return;

END IF;

mgmt$mask_setStep (14, 'MGMT$MASK_CHECKPOINT', step_num);

step_num := step_num + 1;

BEGIN

mgmt$mask_sendMsg ('declare

adj number:=0;

begin

select length(count(distinct NAME)) into adj from "TT"."MASK";

adj := greatest(adj - 1, 0);

execute immediate ''create table MGMT_DM_TT_15 (orig_val, new_val) NOLOGGING as

select s.orig_val,

CAST(lpad(lower(dbms_random.string(''''l'''', trunc(dbms_random.value(1, 7 - least(7, greatest(''||adj||'' - 0, 0)))))), 7 - least(7, greatest(''||adj||'' - 0, 0)),''''a'''')

|| mgmt$mask_randomencode(nvl(substr(s.new_num, 1, 1 + least(7, greatest(''||adj||'' - 0, 0))), ''''0''''),1 + least(7, greatest(''||adj||'' - 0, 0)))

AS VARCHAR2(10)) new_val

from (select rownum rn

, orig_val

, lpad(rownum - 1, ''||adj||'' + 1, 0) new_num

from (select distinct NAME orig_val from "TT"."MASK"

order by dbms_random.value)) s

where 1=1

'';

DBMS_STATS.GATHER_TABLE_STATS(NULL, ''"MGMT_DM_TT_15"'', estimate_percent=>DBMS_STATS.AUTO_SAMPLE_SIZE, degree=>DBMS_STATS.DEFAULT_DEGREE);

end;

');

EXECUTE IMMEDIATE 'declare

adj number:=0;

begin

select length(count(distinct NAME)) into adj from "TT"."MASK";

adj := greatest(adj - 1, 0);

execute immediate ''create table MGMT_DM_TT_15 (orig_val, new_val) NOLOGGING as

select s.orig_val,

CAST(lpad(lower(dbms_random.string(''''l'''', trunc(dbms_random.value(1, 7 - least(7, greatest(''||adj||'' - 0, 0)))))), 7 - least(7, greatest(''||adj||'' - 0, 0)),''''a'''')

|| mgmt$mask_randomencode(nvl(substr(s.new_num, 1, 1 + least(7, greatest(''||adj||'' - 0, 0))), ''''0''''),1 + least(7, greatest(''||adj||'' - 0, 0)))

AS VARCHAR2(10)) new_val

from (select rownum rn

, orig_val

, lpad(rownum - 1, ''||adj||'' + 1, 0) new_num

from (select distinct NAME orig_val from "TT"."MASK"

order by dbms_random.value)) s

where 1=1

'';

DBMS_STATS.GATHER_TABLE_STATS(NULL, ''"MGMT_DM_TT_15"'', estimate_percent=>DBMS_STATS.AUTO_SAMPLE_SIZE, degree=>DBMS_STATS.DEFAULT_DEGREE);

end;

';

EXCEPTION

WHEN OTHERS THEN

sqlerr_msg := SUBSTR(SQLERRM, 1, 100);

mgmt$mask_errorExitOraError('ERROR executing steps ',  sqlerr_msg);

step_num := -1;

return;

END;

END mgmt$step_1_14;

/

CREATE OR REPLACE PROCEDURE mgmt$step_2_14(script_id IN INTEGER, job_table IN VARCHAR2, step_num IN OUT INTEGER)

AUTHID CURRENT_USER IS

sqlerr_msg VARCHAR2(100);

BEGIN

IF step_num <> 2 THEN

return;

END IF;

mgmt$mask_setStep (14, 'MGMT$MASK_CHECKPOINT', step_num);

step_num := step_num + 1;

BEGIN

mgmt$mask_sendMsg ('ALTER TABLE "TT"."MASK" RENAME TO "MASK$DMASK"');

EXECUTE IMMEDIATE 'ALTER TABLE "TT"."MASK" RENAME TO "MASK$DMASK"';

EXCEPTION

WHEN OTHERS THEN

sqlerr_msg := SUBSTR(SQLERRM, 1, 100);

mgmt$mask_errorExitOraError('ERROR executing steps ',  sqlerr_msg);

step_num := -1;

return;

END;

END mgmt$step_2_14;

/

CREATE OR REPLACE PROCEDURE mgmt$step_3_14(script_id IN INTEGER, job_table IN VARCHAR2, step_num IN OUT INTEGER)

AUTHID CURRENT_USER IS

sqlerr_msg VARCHAR2(100);

BEGIN

IF step_num <> 3 THEN

return;

END IF;

mgmt$mask_setStep (14, 'MGMT$MASK_CHECKPOINT', step_num);

step_num := step_num + 1;

BEGIN

mgmt$mask_sendMsg ('CREATE TABLE "TT"."MASK"  TABLESPACE "USERS" PCTFREE 10 INITRANS 1 MAXTRANS 255 STORAGE  ( INITIAL 64K BUFFER_POOL DEFAULT)  NOLOGGING AS SELECT s."ID", c0m15.NEW_VAL "NAME" FROM "TT"."MASK$DMASK" s , MGMT_DM_TT_15 c0m15 WHERE s."NAME" = c0m15.ORIG_VAL(+) ');

EXECUTE IMMEDIATE 'CREATE TABLE "TT"."MASK"  TABLESPACE "USERS" PCTFREE 10 INITRANS 1 MAXTRANS 255 STORAGE  ( INITIAL 64K BUFFER_POOL DEFAULT)  NOLOGGING AS SELECT s."ID", c0m15.NEW_VAL "NAME" FROM "TT"."MASK$DMASK" s , MGMT_DM_TT_15 c0m15 WHERE s."NAME" = c0m15.ORIG_VAL(+) ';

EXCEPTION

WHEN OTHERS THEN

sqlerr_msg := SUBSTR(SQLERRM, 1, 100);

mgmt$mask_errorExitOraError('ERROR executing steps ',  sqlerr_msg);

step_num := -1;

return;

END;

END mgmt$step_3_14;

/

CREATE OR REPLACE PROCEDURE mgmt$step_4_14(script_id IN INTEGER, job_table IN VARCHAR2, step_num IN OUT INTEGER)

AUTHID CURRENT_USER IS

sqlerr_msg VARCHAR2(100);

BEGIN

IF step_num <> 4 THEN

return;

END IF;

mgmt$mask_setStep (14, 'MGMT$MASK_CHECKPOINT', step_num);

step_num := step_num + 1;

BEGIN

mgmt$mask_sendMsg ('ALTER TABLE "TT"."MASK" LOGGING ');

EXECUTE IMMEDIATE 'ALTER TABLE "TT"."MASK" LOGGING ';

EXCEPTION

WHEN OTHERS THEN

sqlerr_msg := SUBSTR(SQLERRM, 1, 100);

mgmt$mask_errorExitOraError('ERROR executing steps ',  sqlerr_msg);

step_num := -1;

return;

END;

END mgmt$step_4_14;

/

CREATE OR REPLACE PROCEDURE mgmt$step_5_14(script_id IN INTEGER, job_table IN VARCHAR2, step_num IN OUT INTEGER)

AUTHID CURRENT_USER IS

sqlerr_msg VARCHAR2(100);

BEGIN

IF step_num <> 5 THEN

return;

END IF;

mgmt$mask_setStep (14, 'MGMT$MASK_CHECKPOINT', step_num);

step_num := step_num + 1;

BEGIN

mgmt$mask_sendMsg ('DROP TABLE "TT"."MASK$DMASK" PURGE');

EXECUTE IMMEDIATE 'DROP TABLE "TT"."MASK$DMASK" PURGE';

EXCEPTION

WHEN OTHERS THEN

sqlerr_msg := SUBSTR(SQLERRM, 1, 100);

mgmt$mask_errorExitOraError('ERROR executing steps ',  sqlerr_msg);

step_num := -1;

return;

END;

END mgmt$step_5_14;

/

CREATE OR REPLACE PROCEDURE mgmt$step_6_14(script_id IN INTEGER, job_table IN VARCHAR2, step_num IN OUT INTEGER)

AUTHID CURRENT_USER IS

sqlerr_msg VARCHAR2(100);

BEGIN

IF step_num <> 6 THEN

return;

END IF;

mgmt$mask_setStep (14, 'MGMT$MASK_CHECKPOINT', step_num);

step_num := step_num + 1;

BEGIN

mgmt$mask_sendMsg ('BEGIN DBMS_STATS.GATHER_TABLE_STATS(''"TT"'', ''"MASK"'', estimate_percent=>DBMS_STATS.AUTO_SAMPLE_SIZE, cascade=>TRUE); END;');

EXECUTE IMMEDIATE 'BEGIN DBMS_STATS.GATHER_TABLE_STATS(''"TT"'', ''"MASK"'', estimate_percent=>DBMS_STATS.AUTO_SAMPLE_SIZE, cascade=>TRUE); END;';

EXCEPTION

WHEN OTHERS THEN

sqlerr_msg := SUBSTR(SQLERRM, 1, 100);

mgmt$mask_errorExitOraError('ERROR executing steps ',  sqlerr_msg);

step_num := -1;

return;

END;

END mgmt$step_6_14;

/

CREATE OR REPLACE PROCEDURE mgmt$mask_cleanup_14 (script_id IN INTEGER, job_table IN VARCHAR2, step_num IN INTEGER, highest_step IN INTEGER)

AUTHID CURRENT_USER IS

BEGIN

IF step_num <= highest_step THEN

return;

END IF;

mgmt$mask_sendMsg ('Starting cleanup of recovery tables');

mgmt$mask_deleteJobTableEntry(script_id, job_table, step_num, highest_step);

mgmt$mask_sendMsg ('Completed cleanup of recovery tables');

END mgmt$mask_cleanup_14;

/

CREATE OR REPLACE PROCEDURE mgmt$mask_commentheader_14 IS

BEGIN

mgmt$mask_sendMsg ('--   Target database:         emrep');

mgmt$mask_sendMsg ('--   Script generated at:    24-MAR-2012   23:52');

END mgmt$mask_commentheader_14;

/

-- Script Execution Controller

-- ==============================================

variable step_num number;

exec mgmt$mask_commentheader_14;

exec mgmt$mask_sendMsg ('Starting Data Masking');

exec mgmt$mask_sendMsg ('Executing as user: ' || 'system');

exec mgmt$mask_checkDBAPrivs ('system');

exec mgmt$mask_setupJobTable (14, 'MGMT$MASK_CHECKPOINT', :step_num);

exec mgmt$step_1_14(14, 'MGMT$MASK_CHECKPOINT', :step_num);

exec mgmt$step_2_14(14, 'MGMT$MASK_CHECKPOINT', :step_num);

exec mgmt$step_3_14(14, 'MGMT$MASK_CHECKPOINT', :step_num);

exec mgmt$step_4_14(14, 'MGMT$MASK_CHECKPOINT', :step_num);

exec mgmt$step_5_14(14, 'MGMT$MASK_CHECKPOINT', :step_num);

exec mgmt$step_6_14(14, 'MGMT$MASK_CHECKPOINT', :step_num);

exec mgmt$mask_sendMsg ('Completed Data Masking. Starting cleanup phase.');

exec mgmt$mask_cleanup_14 (14, 'MGMT$MASK_CHECKPOINT', :step_num, 6);

exec mgmt$mask_sendMsg ('Starting cleanup of generated procedures');

DROP PROCEDURE mgmt$step_1_14;

DROP PROCEDURE mgmt$step_2_14;

DROP PROCEDURE mgmt$step_3_14;

DROP PROCEDURE mgmt$step_4_14;

DROP PROCEDURE mgmt$step_5_14;

DROP PROCEDURE mgmt$step_6_14;

DROP PROCEDURE mgmt$mask_cleanup_14;

DROP PROCEDURE mgmt$mask_commentheader_14;

DROP TABLE MGMT_DM_TT_15;

exec mgmt$mask_sendMsg ('Completed cleanup of generated procedures');

exec mgmt$mask_sendMsg ('Script execution complete');

spool off

set pagesize 24

set serveroutput off

set feedback on

set echo on

3.      生成排程计划

排程有两种运行方式:立即执行和指定时间执行。

3.     数据格式转化

查看数据库中TT用户的mask表的原数据。

执行Job之后:

查看执行之后mask表的数据:

前后结果进行对比之后发现,mask表里面的name列数据发生变化,Data Masking就是通过生成脚本的方式将原有敏感数据,进行处理保证机密资料不被外泄,同时也满足开发者能获得和生产库相近的资料。

转载于:https://www.cnblogs.com/buffercache/p/10836553.html

Data Masking安装和使用指南相关推荐

  1. APC UPS网络管理卡 (AP9606/9617/9618/9619)的快速安装及配置指南

    APC UPS网络管理卡 (AP9606/9617/9618/9619)的快速安装及配置指南 本文说明如何配置APC UPS网络管理卡所需的基本网络参数 在正确使用网络管理卡之前,必须对其基本参数进行 ...

  2. keras安装与配置指南_Keras-快速指南

    keras安装与配置指南 Keras-快速指南 (Keras - Quick Guide) Keras-简介 (Keras - Introduction ) Deep learning is one ...

  3. Oracle Grid Control 11g for linux安装和配置指南

    2019独角兽企业重金招聘Python工程师标准>>> Oracle Grid Control 11g for linux安装和配置指南 原创 candon123 2010-07-1 ...

  4. 学习笔记:Windows 下Keras安装和配置指南

    目录: 目录: Windows下Keras安装和配置指南 Keras 框架搭建 安装 本系列参考官方文档官方文档 这就是keras可以参考前篇:这就是keras 学习笔记 Keras:一些基本概念 一 ...

  5. Anaconda安装和使用指南教程:环境管理、包管理、离线安装第三方包

    本文介绍anaconda的安装,和使用anaconda对Python进行环境管理. Anaconda安装和使用指南教程 1 概述 2 安装 3 环境管理 3.1 检查conda 3.2 创建环境 3. ...

  6. Azure SQL Database (23) Azure SQL Database Dynamic Data Masking动态数据掩码

    <Windows Azure Platform 系列文章目录> 我们在使用关系型数据的时候,有时候希望: - 管理员admin,可以查看到所有的数据 - 普通用户,某些敏感字段,比如信用卡 ...

  7. Mentor PADS 9.5下载安装及破解指南

    Pads,是一款用于设计.模拟电子线路及设计电路板的电脑软件,原由Innoveda公司开发,其后改名为PowerPCB,在2002年4月Innoveda被Mentor Graphics收购,近年再次改 ...

  8. P6 EPPM 16.1 安装和配置指南 1

    安装和配置指南 下一topiccontents 这些指南解释如何安装和配置数据库服务器,和P6 EPPM,模块:他们还提供在P6 EPPM能够解决所有模块的概述. 标准指南帮助您配置和部署应用程序向导 ...

  9. 请检查virtualboxapi是否正确安装_MBR膜组件安装施工方案指南

    在水处理系统建设时,往往要考虑到MBR膜组件安装施工方面的问题,而且很多公司对于MBR膜组件安装不够了解,在MBR膜分离池施工时没注意到后续安装问题,导致后面安装选型受限. MBR膜安装施工前的注意事 ...

最新文章

  1. mysql脚本下载_Mysql备份脚本
  2. NOIP2018 赛前集训总结反思
  3. C语言 内存分配 地址 指针 数组 参数 解析
  4. 【51Nod - 1001 】 数组中和等于K的数对 (排序+ 尺取)
  5. python爬pdf的曲线_科学网—Python爬PDF - 胡鹏程的博文
  6. 【maven】idea左侧External Libraries里,没有Maven的依赖包 代码飘红
  7. CentOS部署SpringBoot项目(二)
  8. document.all用法
  9. python网站开发实例 flask_Python Web开发之——构建基于Flask框架的web后端项目
  10. linux 下的下载管理工具
  11. Leetcode之机器人大冒险
  12. freeswitch呼叫中心之百度MRCP语音合成识别环境搭建
  13. 科目二倒车入库学车技巧_学车必看_保过。
  14. 网络是怎样连接的?从浏览器输入URL开始
  15. 2020-11-20
  16. vue中注释里@xxx是什么意思呢???
  17. 三招教你降低电脑屏幕蓝光对眼睛的危害
  18. Unity5.1 新的网络引擎UNET(十五) Networking 引用--中
  19. BootStrap初学者怎么使用?
  20. 图森计划裁员25%/ 特斯拉被曝将冻结招聘/ 天才黑客Geohot从推特辞职…今日更多新鲜事在此...

热门文章

  1. 简明扼要阐述synchronized和lock的区别
  2. 抖音一般多久能上热门 视频修改MD5工具
  3. Mongodb分组查询
  4. logo免费在线设计,给自己的logo寻找灵感
  5. 在Java中构建响应式微服务系统——第三章 构建响应式微服务
  6. LeetCode 544. 输出比赛匹配对(NBA季后赛对阵图)
  7. 【Android开发】wifi开关与wifi连接(密码连接)
  8. 解决chrome浏览器一打开就弹出hao123问题
  9. 01-基于C++的简易技能系统实现
  10. 机械祭天法力无边:练习3.5:编写一段程序从标准输入中读入多个字符串并将它们连接在一起,输出连接成的大字符串。然后修改上述程序,用空格把输入的多个字符串分隔开来。