Oracle数据库通过定义TYPE及Member对象来实现日志信息的分级管理

简介:

调用路径:

存储过程-》调用函数初始化TYPE里变量-》存储过程调用具体级别的日志操作-》调用TYPES实现体TYPE BOBIES里的具体Member实现体-》调用公用的Member成员存储过程写入syslog表。

 

代码样例展示:

1、存储过程

 
  1. create or replace procedure sp_message_hisorderdata_create( 
  2.        p_l_date  HsCrmType.LDate%TYPE, 
  3.        p_vc_customer hscrmtype.vc50%type) IS 
  4.  
  5.    v_l_date                              HsCrmType.LDate%Type; 
  6.    v_l_currentdate                       HsCrmType.LDate%Type; 
  7.    v_vc_customer                         hscrmtype.vc50%type; 
  8.    v_l_count                             HsCrmType.LInt%Type; 
  9.    v_l_total                             HsCrmType.LInt%Type; 
  10.  
  11.    v_vc_open_value                       HsCrmType.VC255%Type; 
  12.    v_vc_open_value_temp                  HsCrmType.VC255%Type; 
  13.    v_vc_customer_no                      HsCrmType.VC20%Type; 
  14.    vc_product_no                         HsCrmType.CKind%Type; 
  15.    vc_product_temp                       HsCrmType.CKind%Type; 
  16.    v_vc_prefix                           HsCrmType.CKind%Type; 
  17.  
  18.    v_vc_temp1                            HsCrmType.VC255%Type; 
  19.    v_vc_temp2                            HsCrmType.VC255%Type; 
  20.    v_vc_temp3                            HsCrmType.VC255%Type; 
  21.    v_vc_temp4                            HsCrmType.VC255%TYPE; 
  22.  
  23.    V_L_SPEAK_NO                          HsCrmType.LInt%Type; 
  24.  
  25.   l_tyLog  ty_logManager := ty_logManager('system','003'); 
  26. begin 
  27.   l_tyLog.up_Enter('sp_message_hisorderdata_create开始'); 
  28.   v_vc_temp1 := chr(1)||' '||chr(1)||' '||chr(1)||' '||chr(1)||' '
  29.   v_vc_temp2 := chr(1)||' '||chr(1)||' '||chr(1)||' '
  30.   v_vc_temp3 := chr(1)||' '||chr(1)||' '
  31.   v_vc_temp4 := chr(1)||' '
  32.  
  33.   --zhoudy 2013-01-30 添加初始化赋值 
  34.   v_vc_open_value := ''
  35.  
  36.   v_l_total  := 0; 
  37. V_L_SPEAK_NO := 0; 
  38.   v_l_date := nvl(p_l_date,0); 
  39.   v_vc_customer := nvl(p_vc_customer,' '); 
  40.   if v_l_date = 0  then 
  41.     v_l_date := to_number(to_char(SYSDATE-1,'YYYYMMDD')); 
  42.   end if; 
  43.  
  44.   FOR r IN (SELECT a.vc_customer_no 
  45.                     ,a.l_product_no 
  46.                     ,'3' AS c_sourcetype 
  47.                     ,a.l_de_begin_date AS l_de_begin_date 
  48.                     ,a.l_de_end_date AS l_de_end_date 
  49.                     ,(SELECT WMSYS.WM_CONCAT(b.vc_open_value) FROM hscrm_dbo.orderinfo b 
  50.                              WHERE b.vc_customer_no=a.vc_customer_no 
  51.                              AND b.l_product_no=a.l_product_no 
  52.                              and b.l_product_no < 20000) AS vc_open_value 
  53.                     ,'1' AS c_processtype 
  54.             FROM hscrm_dbo.speakforrelation a 
  55.                  WHERE  --a.l_create_date <= v_l_date 
  56.                  --a.l_create_date <= 20101026 
  57.                  --and 
  58.                  a.l_product_no < 20000 
  59.                  --and a.l_create_date <= 20101024 
  60.                  --and (a.vc_customer_no = v_vc_customer or v_vc_customer = ' ') 
  61.                  --and a.l_product_no=11003 
  62.                  GROUP BY vc_customer_no,l_product_no,l_de_begin_date,l_de_end_date 
  63.   ) 
  64.   LOOP 
  65.  
  66.     v_vc_prefix := substr(r.vc_customer_no,1,3); 
  67.     if v_vc_prefix = 'CRM' then 
  68.       v_vc_customer_no := substr(r.vc_customer_no,4); 
  69.       v_vc_open_value_temp := r.vc_open_value; 
  70.       vc_product_temp := substr(to_char(r.l_product_no),1,1); 
  71.       if vc_product_temp = '1' then 
  72.         v_l_total := v_l_total + 1; 
  73.         vc_product_no := substr(to_char(r.l_product_no),2); 
  74.  
  75.         SELECT COUNT(*) INTO v_l_count FROM hscrm_dbo.smsserviceparam WHERE vc_smsno = to_char(r.l_product_no); 
  76.  
  77.         CASE 
  78.           WHEN v_l_count = 0 THEN 
  79.             v_vc_open_value := ''
  80.           WHEN v_l_count = 1 THEN 
  81.             v_vc_open_value := REPLACE(r.vc_open_value,v_vc_temp1); 
  82.           WHEN v_l_count = 2 THEN 
  83.             v_vc_open_value := REPLACE(r.vc_open_value,v_vc_temp2); 
  84.           WHEN v_l_count = 3 THEN 
  85.             v_vc_open_value := REPLACE(r.vc_open_value,v_vc_temp3); 
  86.           WHEN v_l_count = 4 THEN 
  87.             v_vc_open_value := REPLACE(r.vc_open_value,v_vc_temp4); 
  88.             --zhoudy 20130131 
  89.           ELSE 
  90.             v_vc_open_value := REPLACE(r.vc_open_value,v_vc_temp4); 
  91.         END CASE
  92.  
  93.         v_vc_open_value := REGEXP_REPLACE(v_vc_open_value,' '); 
  94.         v_vc_open_value := REPLACE(v_vc_open_value,',',chr(1)); 
  95. --V_L_SPEAK_NO := r.L_SPEAK_NO; 
  96.         INSERT INTO THJZX_DZGX_IN_HIS2(KHH,CPBH,DZLY,DZSJ,DQSJ,DZLX,CS,CJRQ) 
  97.                VALUES(v_vc_customer_no 
  98.                      ,vc_product_no 
  99.                      ,r.c_sourcetype 
  100.                      ,r.l_de_begin_date 
  101.                      ,r.l_de_end_date 
  102.                      ,r.c_processtype 
  103.                      ,v_vc_open_value 
  104.                      ,v_l_date); 
  105.       end if; 
  106.     end if; 
  107.  
  108.     COMMIT
  109.   END LOOP; 
  110.   commit
  111.   l_tyLog.up_Leave('sp_message_hisorderdata_create处理结束,成功生成数'||v_l_total); 
  112.  
  113.   exception 
  114.        when others then 
  115.            rollback
  116.            l_tyLog.up_Error('sp_message_orderdata_create error:'||v_vc_customer_no||':'||V_L_SPEAK_NO||':'||v_l_date||':'||vc_product_no||':'|| v_vc_open_value||':'||SQLCODE); 
  117. end sp_message_hisorderdata_create; 

片段解析:

初始化log的定义,其实现在type的内部;

 
  1. l_tyLog  ty_logManager := ty_logManager('system','003');  

调用log具体子过程

 
  1. l_tyLog.up_Error('sp_message_orderdata_create error:'||v_vc_customer_no||':'||V_L_SPEAK_NO||':'||v_l_date||':'||vc_product_no||':'|| v_vc_open_value||':'||SQLCODE); 
 
  1. l_tyLog.up_Leave('sp_message_hisorderdata_create处理结束,成功生成数'||v_l_total); 

2、TYPE定义

 上面初始化时调用的TY_LOGMANAGER是TYPE构造函数是的,整个TYPE的定义如下,注意其中的Member成员定义。

 
  1. CREATE OR REPLACE TYPE "TY_LOGMANAGER"                                                                          AS OBJECT 
  2. /* 
  3.   * $Header: $ 
  4.   * 
  5.   * 
  6.   *  Overview:  日志管理器,封装LOG,规范化LOG的输出 
  7.                 实现了“多个Session的区别、性能问题定位、错误堆栈信息”, 
  8.                 设有LogLevel开关 
  9.   * 
  10.   *  NOTES:  NULL 
  11.   *--系统支持的LOG基本设置 
  12.   *C_LOG_DEBUG CONSTANT NUMBER(1) := 1; 
  13.   *C_LOG_INFO  CONSTANT NUMBER(1) := 2; 
  14.   *C_LOG_WARN  CONSTANT NUMBER(1) := 3; 
  15.   *C_LOG_ERROR CONSTANT NUMBER(1) := 4; 
  16.   *--当前系统LOG的设置 
  17.   *C_CURR_LOG_LEVEL CONSTANT NUMBER(1) := C_LOG_DEBUG; 
  18.   *C_CURR_PER_LEVEL CONSTANT NUMBER(10) := 1000; --单位(百分之一秒)除以100即为秒数 
  19.   */ 
  20.  
  21. ---成员属性 
  22. -- 对象生成的时间 
  23.   C_CURR_LOG_LEVEL  NUMBER, 
  24.   C_CURR_PER_LEVEL  NUMBER, 
  25.   m_nStartTime      NUMBER, 
  26.   m_nSessionID      CHAR(20), 
  27.   m_varTerminal     VARCHAR2(16), 
  28.   m_varBusinessCode CHAR(100), 
  29.   m_chOperator      CHAR(20), 
  30.  
  31. ---成员函数 
  32. -- 构造函数 
  33.   CONSTRUCTOR FUNCTION ty_logManager 
  34.   ( 
  35.     i_Operator        IN CHAR DEFAULT NULL
  36.     i_varBusinessCode IN VARCHAR2 DEFAULT NULL 
  37.   ) RETURN SELF AS RESULT, 
  38.  
  39. -- 函数入口输出重要信息 
  40.   MEMBER PROCEDURE up_Enter(i_varMsg IN VARCHAR2 DEFAULT NULL), 
  41.  
  42. -- 正常调用SP结束 
  43.   MEMBER PROCEDURE up_Leave(i_varMsg IN VARCHAR2 DEFAULT NULL), 
  44.  
  45. -- 输出up_Debug信息到日志表 
  46.   MEMBER PROCEDURE up_Debug(i_LogDesc IN VARCHAR2), 
  47.  
  48. -- 输出up_Info信息到日志表 
  49.   MEMBER PROCEDURE up_Info(i_LogDesc IN VARCHAR2), 
  50.  
  51. -- 输出up_Warning信息到日志表 
  52.   MEMBER PROCEDURE up_Warning(i_LogDesc IN VARCHAR2), 
  53.  
  54. -- 输出up_Error信息到日志表 
  55.   MEMBER PROCEDURE up_Error(i_LogDesc IN VARCHAR2), 
  56.  
  57. -- 往T_LOG中插入记录 
  58.   MEMBER PROCEDURE up_InsertLog 
  59.   ( 
  60.     i_LOGID        IN NUMBER, 
  61.     i_LOGDATE      IN CHAR
  62.     i_LOGTIME      IN CHAR
  63.     i_LogLevel     IN CHAR
  64.     i_ELAPSETIME   IN NUMBER, 
  65.     i_SESSIONID    IN CHAR
  66.     i_TERMINAL     IN CHAR
  67.     i_Operator     IN CHAR
  68.     i_LOGDESC      IN VARCHAR2 
  69.   ) 

3、TYPE BOBY定义

 上面的TYPE体中定义了各个级别的Log处理Member子过程,其具体实现则在TYPE BODY中进行,源码如下:

注意其实现中的公用过程的定义。

 
  1. CREATE OR REPLACE TYPE BODY ty_logManager IS 
  2.  
  3.   /************************************************************************* 
  4.   【函数功能】构造LOG对象,记录开始此对象生成的开始时间,并记录日志 
  5.   【使用情况】构造函数,对象定义时自动调用 
  6.   【参数说明】i_varBusinessCode IN VARCHAR2,一般传入调用的SP程序名或者业务对应的代号 
  7.   【异常处理】出错时,处理所有异常,不抛出异常 
  8.    *************************************************************************/ 
  9.   CONSTRUCTOR FUNCTION ty_logManager 
  10.   ( 
  11.     i_Operator        IN CHAR DEFAULT NULL
  12.     i_varBusinessCode IN VARCHAR2 DEFAULT NULL 
  13.   ) RETURN SELF AS RESULT IS 
  14.   BEGIN 
  15.     m_nStartTime      := dbms_utility.get_time; 
  16.     m_nSessionID      := userenv('sessionid'); 
  17.     m_varTerminal     := userenv('terminal'); 
  18.     m_varBusinessCode := i_varBusinessCode; 
  19.     m_chOperator    := i_Operator; 
  20.  
  21.     RETURN
  22.   EXCEPTION 
  23.     WHEN OTHERS THEN 
  24.       NULL
  25.   END
  26.  
  27.   /************************************************************************* 
  28.   【函数功能】 调用SP接口的入口,记录重要参数信息 
  29.   【注意事项】一般在SP结束时调用 
  30.   【参数说明】i_SPName IN VARCHAR2,一般传入调用的SP程序名 
  31.   【异常处理】出错时,处理所有异常,不抛出异常 
  32.    *************************************************************************/ 
  33.   MEMBER PROCEDURE up_Enter(i_varMsg IN VARCHAR2 DEFAULT NULLIS 
  34.   BEGIN 
  35.     up_Info(i_varMsg || ',Enter.'); 
  36.   EXCEPTION 
  37.     WHEN OTHERS THEN 
  38.       NULL
  39.   END
  40.  
  41.   /************************************************************************* 
  42.   【函数功能】正常调用SP结束,记录时间统计信息 
  43.   【异常处理】出错时,处理所有异常,不抛出异常 
  44.    *************************************************************************/ 
  45.   MEMBER PROCEDURE up_Leave(i_varMsg IN VARCHAR2 DEFAULT NULLIS 
  46.   BEGIN 
  47.     up_Info(i_varMsg || ',Leave.'); 
  48.   EXCEPTION 
  49.     WHEN OTHERS THEN 
  50.       NULL
  51.   END
  52.  
  53.   /************************************************************************* 
  54.   【函数功能】输出up_Debug信息到日志表 T_LOG 
  55.   【注意事项】注意参数的长度和数据库一致 
  56.   【异常处理】出错时,处理所有异常,不抛出异常。 
  57.    *************************************************************************/ 
  58.   MEMBER PROCEDURE up_Debug(i_LogDesc IN VARCHAR2) IS 
  59.     PRAGMA AUTONOMOUS_TRANSACTION; 
  60.  
  61.     l_date CHAR(8); 
  62.     l_time CHAR(8); 
  63.  
  64.     l_LogID NUMBER(10); 
  65.   BEGIN 
  66.     SELECT to_char(SYSDATE, 'yyyymmdd'), 
  67.            to_char(SYSDATE, 'hh24miss'), 
  68.            seq_syslog.NEXTVAL 
  69.       INTO l_date, l_time, l_LogID 
  70.       FROM dual; 
  71.  
  72.     up_InsertLog(l_LogID, 
  73.                  l_date, 
  74.                  l_time, 
  75.  
  76.                  '1',--Debug 
  77.                  (dbms_utility.get_time - m_nStartTime), 
  78.                  m_nSessionID, 
  79.                  m_varTerminal, 
  80.                  m_chOperator, 
  81.                  i_LOGDESC); 
  82.     COMMIT
  83.   EXCEPTION 
  84.     WHEN OTHERS THEN 
  85.       ROLLBACK
  86.   END
  87.  
  88.   /************************************************************************* 
  89.   【函数功能】输出up_Info信息到日志表 T_LOG 
  90.   【注意事项】注意参数的长度和数据库一致 
  91.   【异常处理】出错时,处理所有异常,不抛出异常 
  92.    *************************************************************************/ 
  93.   MEMBER PROCEDURE up_Info(i_LogDesc IN VARCHAR2) IS 
  94.     PRAGMA AUTONOMOUS_TRANSACTION; 
  95.  
  96.     l_date  CHAR(8); 
  97.     l_time  CHAR(8); 
  98.     l_LogID NUMBER(10); 
  99.   BEGIN 
  100.     SELECT to_char(SYSDATE, 'yyyymmdd'), 
  101.            to_char(SYSDATE, 'hh24miss'), 
  102.            seq_syslog.NEXTVAL 
  103.       INTO l_date, l_time, l_LogID 
  104.       FROM dual; 
  105.  
  106.     up_InsertLog(l_LogID, 
  107.                  l_date, 
  108.                  l_time, 
  109.  
  110.                  '2',--Info 
  111.                  (dbms_utility.get_time - m_nStartTime), 
  112.                  m_nSessionID, 
  113.                  m_varTerminal, 
  114.                  m_chOperator, 
  115.                  i_LOGDESC); 
  116.     COMMIT
  117.   EXCEPTION 
  118.     WHEN OTHERS THEN 
  119.       ROLLBACK
  120.   END
  121.  
  122.   /************************************************************************* 
  123.   【函数功能】输出up_Warning信息到日志表 T_LOG 
  124.   【注意事项】注意参数的长度和数据库一致 
  125.   【异常处理】出错时,处理所有异常,不抛出异常 
  126.    *************************************************************************/ 
  127.   MEMBER PROCEDURE up_Warning(i_LogDesc IN VARCHAR2) IS 
  128.     PRAGMA AUTONOMOUS_TRANSACTION; 
  129.  
  130.     l_date CHAR(8); 
  131.     l_time CHAR(8); 
  132.  
  133.     l_LogID NUMBER(10); 
  134.   BEGIN 
  135.     SELECT to_char(SYSDATE, 'yyyymmdd'), 
  136.            to_char(SYSDATE, 'hh24miss'), 
  137.            seq_syslog.NEXTVAL 
  138.       INTO l_date, l_time, l_LogID 
  139.       FROM dual; 
  140.  
  141.     up_InsertLog(l_LogID, 
  142.                  l_date, 
  143.                  l_time, 
  144.  
  145.                  '3',--Warn 
  146.                  (dbms_utility.get_time - m_nStartTime), 
  147.                  m_nSessionID, 
  148.                  m_varTerminal, 
  149.                  m_chOperator, 
  150.                  i_LOGDESC); 
  151.     COMMIT
  152.   EXCEPTION 
  153.     WHEN OTHERS THEN 
  154.       ROLLBACK
  155.  
  156.   END
  157.  
  158.   /************************************************************************* 
  159.   【函数功能】输出up_Error信息到日志表 T_LOG 
  160.   【注意事项】注意参数的长度和数据库一致 
  161.   【异常处理】出错时,处理所有异常,不抛出异常 
  162.    *************************************************************************/ 
  163.   MEMBER PROCEDURE up_Error(i_LogDesc IN VARCHAR2) IS 
  164.     PRAGMA AUTONOMOUS_TRANSACTION; 
  165.  
  166.     l_date CHAR(8); 
  167.     l_time CHAR(8); 
  168.  
  169.     l_LogID NUMBER(10); 
  170.   BEGIN 
  171.     SELECT to_char(SYSDATE, 'yyyymmdd'), 
  172.            to_char(SYSDATE, 'hh24miss'), 
  173.            seq_syslog.NEXTVAL 
  174.       INTO l_date, l_time, l_LogID 
  175.       FROM dual; 
  176.  
  177.     up_InsertLog(l_LogID, 
  178.                  l_date, 
  179.                  l_time, 
  180.                  '4',--Error 
  181.                  (dbms_utility.get_time - m_nStartTime), 
  182.                  m_nSessionID, 
  183.                  m_varTerminal, 
  184.                  m_chOperator, 
  185.                  i_LOGDESC || CHR(10) || 
  186.                  DBMS_UTILITY.FORMAT_Error_BACKTRACE); 
  187.     COMMIT
  188.   EXCEPTION 
  189.     WHEN OTHERS THEN 
  190.       ROLLBACK
  191.  
  192.   END
  193.  
  194.   /************************************************************************* 
  195.   【函数功能】往日志表T_LOG中插入一条记录 
  196.   【使用情况】建议外部不要直接调用 
  197.   【异常处理】出错时,不处理任何异常 
  198.    *************************************************************************/ 
  199.   MEMBER PROCEDURE up_InsertLog 
  200.   ( 
  201.     i_LOGID        IN NUMBER, 
  202.     i_LOGDATE      IN CHAR
  203.     i_LOGTIME      IN CHAR
  204.     i_LogLevel     IN CHAR
  205.     i_ELAPSETIME   IN NUMBER, 
  206.     i_SESSIONID    IN CHAR
  207.     i_TERMINAL     IN CHAR
  208.     i_Operator     IN CHAR
  209.     i_LOGDESC      IN VARCHAR2 
  210.   ) IS 
  211.   BEGIN 
  212.     C_CURR_LOG_LEVEL := to_number(sp_message_sysparameters_get(0,5029));--1 
  213.     C_CURR_PER_LEVEL := to_number(sp_message_sysparameters_get(0,5030));--1000 
  214.     IF C_CURR_LOG_LEVEL <= i_LogLevel 
  215.        OR C_CURR_PER_LEVEL <= i_ELAPSETIME THEN 
  216.       INSERT INTO syslog 
  217.         (l_serial_no 
  218.         ,l_date 
  219.         ,l_time 
  220.         ,c_loglevel 
  221.         ,l_elapsetime 
  222.         ,vc_sessionid 
  223.         ,vc_terminal 
  224.         ,vc_businesscode 
  225.         ,vc_operator_no 
  226.         ,vc_logdesc) 
  227.       VALUES 
  228.         (i_LOGID, 
  229.          i_LOGDATE, 
  230.          i_LOGTIME, 
  231.          i_LogLevel, 
  232.          i_ELAPSETIME, 
  233.          i_SESSIONID, 
  234.          i_TERMINAL, 
  235.          m_varBUSINESSCODE, 
  236.          i_Operator, 
  237.          i_LOGDESC); 
  238.     END IF; 
  239.   END
  240. END

 

4、日志截图展示

 可见上面初始化时候的类型为“system”,vc_logdesc字段则记录了我们在调用地方记录日志的文本提示信息,如操作的记录id、产品id、以及报错信息、ora0000等的方便我们排查的信息。

数据

文章小结

由上面可以看到通过层层封装,最终我们的日志信息是写入了syslog表进行了统一管理,并通过TYPE定义了各个级别的日志写入柄对外提供各个级别日志的信息写入。

 




     本文转自danni505 51CTO博客,原文链接:http://blog.51cto.com/danni505/1130084,如需转载请自行联系原作者




相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
7天前
|
SQL Oracle 关系型数据库
【Oracle】玩转Oracle数据库(一):装上去,飞起来!
【Oracle】玩转Oracle数据库(一):装上去,飞起来!
43 7
|
24天前
|
Oracle 关系型数据库 数据库
Oracle数据库基本概念理解(3)
Oracle数据库基本概念理解(3)
17 2
|
7天前
|
SQL Oracle 关系型数据库
【Oracle】玩转Oracle数据库(七):RMAN恢复管理器
【Oracle】玩转Oracle数据库(七):RMAN恢复管理器
32 5
|
7天前
|
存储 SQL Oracle
【Oracle】玩转Oracle数据库(二):体系结构、存储结构与各类参数
【Oracle】玩转Oracle数据库(二):体系结构、存储结构与各类参数
32 7
|
15天前
|
SQL 数据可视化 关系型数据库
轻松入门MySQL:深入探究MySQL的ER模型,数据库设计的利器与挑战(22)
轻松入门MySQL:深入探究MySQL的ER模型,数据库设计的利器与挑战(22)
|
15天前
|
存储 关系型数据库 MySQL
轻松入门MySQL:数据库设计之范式规范,优化企业管理系统效率(21)
轻松入门MySQL:数据库设计之范式规范,优化企业管理系统效率(21)
|
15天前
|
关系型数据库 MySQL 数据库
轻松入门MySQL:精准查询,巧用WHERE与HAVING,数据库查询如虎添翼(7)
轻松入门MySQL:精准查询,巧用WHERE与HAVING,数据库查询如虎添翼(7)
|
17天前
|
存储 关系型数据库 MySQL
数据库字符编码MySQL中使用UTF-8还是UTFB4
数据库字符编码MySQL中使用UTF-8还是UTFB4
20 0
|
20天前
|
SQL 关系型数据库 MySQL
【MySQL技术专题】「问题实战系列」深入探索和分析MySQL数据库的数据备份和恢复实战开发指南(8.0版本升级篇)
【MySQL技术专题】「问题实战系列」深入探索和分析MySQL数据库的数据备份和恢复实战开发指南(8.0版本升级篇)
93 0
|
11天前
|
存储 关系型数据库 MySQL
MySQL基础入门:数据库操作全攻略
MySQL基础入门:数据库操作全攻略
44 0

推荐镜像

更多