oracle返回记录集与VB程序的内存泄露,弱水三千,biti_rainy等高手帮帮忙!!!

penitent 2002-07-26 05:54:37
--pkgRemote包的定义

TYPE t_CurGetCandListImg IS REF CURSOR ;

--pkgRemote包体的过程
/***********************************************************************
* PROCEDURE: sp_Get_CandidateImg
* DESCRIPTION: get Candidate imgae data
* PARAMETERS:
iRemote_ID_I IN VARCHAR2 (1) 远程编号
iResponseID IN NUMBER (2) 消息编号
* RETURNED:
io_cursor IN OUT t_CurGetCandListImg 返回的记录集
***********************************************************************/
PROCEDURE sp_Get_CandidateImg(iRemote_ID_I IN VARCHAR2,
iResponseID IN NUMBER,
io_cursor IN OUT t_CurGetCandListImg)
IS
v_Check NUMBER;
v_cursor t_CurGetCandListImg;
CURSOR cur_Check IS
SELECT ResponseID
FROM T_MResponse
WHERE Remote_ID_I = iRemote_ID_I
AND ResponseTYPE = gnMRCandidateImgTYPE
AND ResponseID = iResponseID;
BEGIN
--检查是否有需要处理的数据,如果没有,返回一个空的记录集
OPEN cur_Check;
FETCH cur_Check INTO v_Check;
IF (cur_Check%NOTFOUND) OR (cur_Check%NOTFOUND IS NULL) THEN
CLOSE cur_Check;
OPEN v_cursor FOR
SELECT * FROM T_CandidateImg
WHERE 1 = 0 ;
io_cursor := v_cursor;
RETURN;
END IF;
--如果有需要处理的数据,则返回需要处理的数据(一个记录集)
OPEN v_cursor FOR
SELECT * FROM T_CandidateImg
WHERE ResponseID = iResponseID;
io_cursor := v_cursor;
EXCEPTION
WHEN OTHERS THEN
CLOSE cur_Check;
END sp_Get_CandidateImg;


//以下是VB程序代码,执行该过程,作用是从远程数据库中获取数据(存取过程),保存到本地数据库
Public Function fReceiveCandImage(ByVal RemoteID As String, ByVal ResponseID As Long, ocKeyNo As String, oiFingerNo As Integer) As Boolean
Dim rsR As ADODB.Recordset
Dim Rs As ADODB.Recordset
Dim sWhere As String
Dim sErr As String
Dim cmdR As ADODB.Command
Dim Pram As ADODB.Parameter
Dim Result As Integer
Dim gImage() As Byte
Dim sKeyNo As String
Dim ImageLen As Long
'//写日志
sLog conINFO_Msg, "开始接收候补图象信息, ResponseID = " & ResponseID
On Error GoTo fReceiveCandImageErr
'//执行以上过程
Set cmdR = New ADODB.Command
With cmdR
.CommandText = "{call pkgRemote.sp_Get_CandidateImg(?,?,{resultset 0, io_cursor})}"
.CommandType = adCmdText 'adCmdText
Set Pram = .CreateParameter("iRemote_ID_I", adBSTR, adParamInput, , RemoteID)
.Parameters.Append Pram
Set Pram = .CreateParameter("iResponseID", adInteger, adParamInput, , ResponseID)
.Parameters.Append Pram
End With
'//得到记录集
Set rsR = fCenterCmdExecute(cmdR)
'//如果没有记录集,过程执行不成功
If rsR Is Nothing Then
sLog conERROR_Msg, "读取远程remote数据库发生错误"
fReceiveCandImage = False
GoTo fReceiveCandImageErr
End If
'//如果记录集为空,没有取到数据
If rsR.EOF Then
sLog conERROR_Msg, "没有该图象供接收:ResponseID = " & ResponseID
fReceiveCandImage = False
GoTo fReceiveCandImageExit
End If
'//如果记录集不为空,分析数据
sKeyNo = rsR!KeyNo
Select Case fGetKeyNoType(sKeyNo)
Case conKeyTypeIndex_TP
sWhere = "keyno='" & sKeyNo & "' and fingerno=" & rsR!FingerNo
Case conKeyTypeIndex_LP
sWhere = "keyno='" & sKeyNo & "'"
Case Else
sWhere = "keyno='" & sKeyNo & "'"
End Select
sErr = ""
Set Rs = CommFunc.fGetUpdatedRS(TBL_VERTPCANDIMAGE, sWhere, sErr)
If sErr <> "" Then
sLog conERROR_Msg, "读取数据库错误:" & sErr
fReceiveCandImage = False
GoTo fReceiveCandImageExit
End If
ImageLen = rsR!fpimagelen
If Not (ImageLen > 0) Then
sLog conERROR_Msg, "图象长度信息错误:ImageLen = " & ImageLen
fReceiveCandImage = False
GoTo fReceiveCandImageExit
End If
If IsNull(rsR!FPImage) Then
sLog conERROR_Msg, "接收到图象为空:ResponseID = " & ResponseID
fReceiveCandImage = False
GoTo fReceiveCandImageExit
End If
ReDim gImage(ImageLen - 1) As Byte
gImage = rsR.Fields("fpImage").GetChunk(ImageLen)
'//如果分析数据没有问题,写入本地表
If Rs.EOF Then Rs.AddNew
Rs!ResponseID = rsR!ResponseID
Rs!JobNo = rsR!JobNo
Rs!CardType = rsR!CardType
Rs!KeyNo = rsR!KeyNo
Rs!FingerNo = rsR!FingerNo
Rs!FingerGet = Left(rsR!FingerGet, 1)
Rs!ErrorMsg = rsR!ErrorMsg
Rs!FPImageX = rsR!FPImageX
Rs!FPImagey = rsR!FPImagey
Rs!fpimagelen = ImageLen
Rs!FPImage = gImage
Rs.Update

ocKeyNo = rsR!KeyNo
oiFingerNo = rsR!FingerNo
'//函数执行成功,数据获取成功
fReceiveCandImage = True
sLog conINFO_Msg, "接收候补图像结束"
fReceiveCandImageExit:
If Rs.Status = adStateOpen Then Rs.Close
Set Rs = Nothing
If rsR.Status = adStateOpen Then rsR.Close
Set rsR = Nothing
If Not (cmdR Is Nothing) Then Set cmdR = Nothing
On Error GoTo 0
Exit Function
fReceiveCandImageErr:
sLog conERROR_Msg, "接收候补图像失败:" & Err.Description
fReceiveCandImage = False
GoTo fReceiveCandImageExit
End Function


-------------------------
说明:操作系统NT,数据库oracle 805,连接方式,VB+ADO2.6+数据库直连
其中,连接与打开记录集的语句是包含在dll中的。
rsR是通过远程存取过程返回的,打开方式为adOpenStatic,锁方式为adLockReadOnly
RS是直接打开的本地记录集,打开方式为adOpenDynamic,锁方式为adLockOptimistic

以上函数被定时执行(10秒),检查远程数据库是否有自己的图象数据,如果有,则取回来。
但是,在执行和测试过程中,发现在这里有很严重的内存泄露,每次泄露的内存大小就是我取的数据的大小
(因为是图象,含有long raw类型,一般为30K左右,10秒泄露30k,太严重了)。
如果我的rsR不是通过存取过程返回,而是直接连接到远程数据库,直接打开,就不会泄露。

为什么,vb的错???oracle的错???还是我的程序错???
btw,最近csdn怎么啦,登录都登录不上来???

...全文
86 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
121111 2002-07-30
  • 打赏
  • 举报
回复
用JOB也好啊。
penitent 2002-07-30
  • 打赏
  • 举报
回复
: biti_rainy(biti_rainy)
这个问题,就我的认为,不一定是VB的问题,我现在正在想办法在v c++上去测试,只是我今天还没有找到在c++上调用返回记录集的存取过程的执行方法,不是返回记录集的我会执行,但返回记录集的存取过程我在c++上还真不会执行。

我想,这个内存的申请而不释放,有可能是oracle客户端或是ADO,而不是vb,用什么语言无所谓的,而且,vb我还很少见过内存泄露的。
KingSunSha 2002-07-30
  • 打赏
  • 举报
回复
我也没有好的建议。

如果这个程序不需要用户的干预的话,那何不直接用pl/sql写,然后用sqlplus批命令方式来执行呢?这样绝对不会有内存泄漏的问题:)
penitent 2002-07-30
  • 打赏
  • 举报
回复
用job肯定不行,因为不止一个过程需要执行,执行的参数也没有办法传递进来。

用pl/sql写的话也存在一个问题,有些参数是需要从程序中获取的,如读取文件、访问本地数据库得到的参数等等,我怎么传递给sqlplus批命令。

这还不是最麻烦的,最麻烦的是我在pl/sql块中,怎么把大于32K的long raw类型的数据从远程转移到本地数据库。

呵呵,既然有问题,那还不是我的问题,我就放心了,现在就是找解决办法。
办法是可以找到的,我现在唯一想明白的是,这是oracle的错,还是vb的错

biti_rainy 2002-07-29
  • 打赏
  • 举报
回复
我只能看看热闹了 :)
真是不好意思
vb我没有用过,根本不会 :(
penitent 2002-07-29
  • 打赏
  • 举报
回复
当初我来的时候,这些存取过程、程序都不是我写的,存在很大的不合理性。要我写,我就不写这种两层结构体系了,他们写的差不多了,我也就不改写了,平常就是维护和查找错误,这个内存的泄露,是发现了好久,但最后才发现在这里泄露的。
penitent 2002-07-29
  • 打赏
  • 举报
回复
因为我的这个程序是个网络传输程序,最好要求无人看管,它在正常情况下是每10秒运行一次,现在下发了的版本,内存占用可高达300M,然后程序就死了,如果这样泄露,我们的程序就没有办法工作了。
这是哪里的原因???
KingSunSha 2002-07-29
  • 打赏
  • 举报
回复
好像是这样的,我运行了500次,结果内存占用增加了35兆,不过关掉了vb应用程序以后内存就恢复正常了。
penitent 2002-07-29
  • 打赏
  • 举报
回复
我用的就是windows NT server pack6和windows 2000 server server pack2下做的测试,数据库是oracle 805 server(我不知道与数据库版本有关系没有)。
vb6(没有打补丁的那种,难道与这个有关系???),我决定打上vb的补丁后再看看。
--------------------
测试需要写在循环里,你在程序中单步调式一下记录集打开是否成功,也就是说,是否有较大的数据被打开,不停的打开记录集,关闭记录集就可以了。
不需要其它的内存检查,在window 任务管理器就可以明显看到,内存使用一直往上加,一直加到几百兆,直到机器死掉。
如果你的内存释放的话,那内存的使用应当是一升一降才对,也就是说,用存取过程打开记录集时,内存往上涨记录集的大小,记录集关闭的时候,内存释放。内存使用数复原。
我们这里的情况是,内存只往上涨,不恢复。
KingSunSha 2002-07-29
  • 打赏
  • 举报
回复
我自己建了两个很简单的表,只有几个关键列,做了一下测试,但是我这边没法观察到内存泄漏的问题(我对windows下的编程了解甚浅),你能指点一下用什么工具可以检查吗?
系统环境:WINDOWS XP PRO,VB6+SP5,ORACLE 8.17 AIX VERSION
KingSunSha 2002-07-29
  • 打赏
  • 举报
回复
我简化了一下过程:少用了一个cursor,一个ref cusor。应该比原来的好一些,当然还没有测试过内存泄漏的问题。

/***********************************************************************
* PROCEDURE: sp_Get_CandidateImg
* DESCRIPTION: get Candidate imgae data
* PARAMETERS:
iRemote_ID_I IN VARCHAR2 (1) 远程编号
iResponseID IN NUMBER (2) 消息编号
* RETURNED:
io_cursor IN OUT t_CurGetCandListImg 返回的记录集
***********************************************************************/
PROCEDURE sp_Get_CandidateImg
(iRemote_ID_I IN VARCHAR2,
iResponseID IN NUMBER,
ora_status OUT VARCHAR2,
--该参数用来返回执行状态,那样就不需要通过判断rs来检查执行结果是否正确
io_cursor IN OUT t_CurGetCandListImg
) IS
v_Check NUMBER;
BEGIN

--检查是否有需要处理的数据
SELECT COUNT(*) INTO V_CHECK
FROM T_MResponse
WHERE Remote_ID_I = iRemote_ID_I
AND ResponseTYPE = gnMRCandidateImgTYPE
AND ResponseID = iResponseID;

IF NOT V_CHECK > 0 THEN --如果没有,返回一个空的记录集
OPEN io_cursor FOR
SELECT * FROM T_CandidateImg
WHERE 1 = 0 ;
ora_status := 'NOT FOUND';
ELSE --如果有需要处理的数据,则返回需要处理的数据(一个记录集)
OPEN io_cursor FOR
SELECT * FROM T_CandidateImg
WHERE ResponseID = iResponseID;
ora_status := 'SUCCESS';
END IF;


EXCEPTION
WHEN OTHERS THEN
ora_status := SQLERRM;
END sp_Get_CandidateImg;
penitent 2002-07-29
  • 打赏
  • 举报
回复
谢谢 KingSunSha(弱水三千) :
我给你原表的创建语句:
-- Create table
create table T_CANDIDATEIMG
(
RESPONSEID NUMBER(9) not null,
JOBNO NUMBER(10),
CARDTYPE NUMBER(1),
KEYNO VARCHAR2(30) not null,
FINGERNO NUMBER(2) not null,
FINGERGET CHAR(1),
ERRORMSG VARCHAR2(255),
FPIMAGE LONG RAW,
FPIMAGEX NUMBER(4),
FPIMAGEY NUMBER(4),
FPIMAGELEN NUMBER(6),
CONSTRAINT PK_CANDIDATEIMG_RESPONSEID PRIMARY KEY (RESPONSEID))
pctfree 10 pctused 40
initrans 1 maxtrans 255
storage
( initial 2048K next 2048K
minextents 1 maxextents 500
pctincrease 0);
其中的测试数据,我是用pl/sql develper另外添加上去的,特别是long raw是用pl/sql develper导入的一个32k以上的文件。你也可以生成一条类似的记录。
过程你可以修改一下
PROCEDURE sp_Get_CandidateImg(iRemote_ID_I IN VARCHAR2,
iResponseID IN NUMBER,
io_cursor IN OUT t_CurGetCandListImg)
IS
BEGIN
--如果有需要处理的数据,则返回需要处理的数据(一个记录集)
OPEN v_cursor FOR
SELECT * FROM T_CandidateImg
WHERE ResponseID = iResponseID;
io_cursor := v_cursor;
EXCEPTION
WHEN OTHERS THEN
raise;
END sp_Get_CandidateImg;
和上面相比,去掉数据检查部分,vb程序就可以用改写后的函数,写日志你就可以不必写了。
KingSunSha 2002-07-29
  • 打赏
  • 举报
回复
能给出相关表的结构吗?我想做一下测试
penitent 2002-07-29
  • 打赏
  • 举报
回复
这是msdn中有关返回记录集和vb调用存取过程的办法,虽然对于我来说,不实用,但是他却没有说返回记录集,是不是oracle返回记录集本身有问题(bug),而只是大家没有发现罢了。

DROP TABLE person;

CREATE TABLE person
(ssn NUMBER(9) PRIMARY KEY,
fname VARCHAR2(15),
lname VARCHAR2(20));

INSERT INTO person VALUES(555662222,'Sam','Goodwin');

INSERT INTO person VALUES(555882222,'Kent','Clark');

INSERT INTO person VALUES(666223333,'Jane','Doe');

COMMIT;
/
Create the following package on your Oracle server:

CREATE OR REPLACE PACKAGE packperson
AS
TYPE tssn is TABLE of NUMBER(10)
INDEX BY BINARY_INTEGER;
TYPE tfname is TABLE of VARCHAR2(15)
INDEX BY BINARY_INTEGER;
TYPE tlname is TABLE of VARCHAR2(20)
INDEX BY BINARY_INTEGER;

PROCEDURE allperson
(ssn OUT tssn,
fname OUT tfname,
lname OUT tlname);
PROCEDURE oneperson
(onessn IN NUMBER,
ssn OUT tssn,
fname OUT tfname,
lname OUT tlname);
END packperson;
/
Create the following package body on your Oracle server:

CREATE OR REPLACE PACKAGE BODY packperson
AS

PROCEDURE allperson
(ssn OUT tssn,
fname OUT tfname,
lname OUT tlname)
IS
CURSOR person_cur IS
SELECT ssn, fname, lname
FROM person;

percount NUMBER DEFAULT 1;

BEGIN
FOR singleperson IN person_cur
LOOP
ssn(percount) := singleperson.ssn;
fname(percount) := singleperson.fname;
lname(percount) := singleperson.lname;
percount := percount + 1;
END LOOP;
END;

PROCEDURE oneperson
(onessn IN NUMBER,
ssn OUT tssn,
fname OUT tfname,
lname OUT tlname)
IS
CURSOR person_cur IS
SELECT ssn, fname, lname
FROM person
WHERE ssn = onessn;

percount NUMBER DEFAULT 1;

BEGIN
FOR singleperson IN person_cur
LOOP
ssn(percount) := singleperson.ssn;
fname(percount) := singleperson.fname;
lname(percount) := singleperson.lname;
percount := percount + 1;
END LOOP;
END;
END;
/
Open a new project in Visual Basic 5.0 or 6.0 Enterprise edition. Form1 is created by default.


Place the following controls on the form:
Control Name Text/Caption
-----------------------------------------
Button cmdGetEveryone Get Everyone
Button cmdGetOne Get One
From the Tools menu, select the Options item. Click the "Default Full Module View" option and then click OK. This will allow you to view all of the code for this project.

Paste the following code into your code window:

Option Explicit
Dim Cn As ADODB.Connection
Dim CPw1 As ADODB.Command
Dim CPw2 As ADODB.Command
Dim Rs As ADODB.Recordset
Dim Conn As String
Dim QSQL As String
Dim inputssn As Long

Private Sub cmdGetEveryone_Click()

Set Rs.Source = CPw1

Rs.Open

While Not Rs.EOF
MsgBox "Person data: " & Rs(0) & ", " & Rs(1) & ", " & Rs(2)
Rs.MoveNext
Wend

Rs.Close

End Sub

Private Sub cmdGetOne_Click()

Set Rs.Source = CPw2

inputssn = InputBox("Enter the SSN you wish to retrieve:")

CPw2(0) = inputssn

Rs.Open

MsgBox "Person data: " & Rs(0) & ", " & Rs(1) & ", " & Rs(2)

Rs.Close

End Sub

Private Sub Form_Load()

'Replace <User ID>, <Password>, and <Server> with the
'appropriate parameters.
Conn = "UID=*****;PWD=*****;driver=" _
& "{Microsoft ODBC for Oracle};SERVER=dseOracle;"

Set Cn = New ADODB.Connection
With Cn
.ConnectionString = Conn
.CursorLocation = adUseClient
.Open
End With

QSQL = "{call packperson.allperson({resultset 9, ssn, fname, " _
& "lname})}"

Set CPw1 = New ADODB.Command
With CPw1
Set .ActiveConnection = Cn
.CommandText = QSQL
.CommandType = adCmdText
End With

QSQL = "{call packperson.oneperson(?,{resultset 2, ssn, fname, " _
& "lname})}"

Set CPw2 = New ADODB.Command
With CPw2
Set .ActiveConnection = Cn
.CommandText = QSQL
.CommandType = adCmdText
.Parameters.Append .CreateParameter(, adInteger, adParamInput)
End With

Set Rs = New ADODB.Recordset
With Rs
.CursorType = adOpenStatic
.LockType = adLockReadOnly
End With

End Sub

Private Sub Form_Unload(Cancel As Integer)

Cn.Close
Set Cn = Nothing
Set CPw1 = Nothing
Set CPw2 = Nothing
Set Rs = Nothing

End Sub
Go to the Project menu item and select References. Select the "Microsoft Active Data Objects 2.x Library."

Run the project. When you click on the "Get Everyone" button, it executes this query:

QSQL = "{call packperson.allperson({resultset 9, ssn, fname, "_
& "lname})}"

-------------------------
在最后,他们也是执行存取过程,返回一个记录集,这个和我的没有什么区别,区别在于他们使用的是表类型,但怎么返回大于32的字段(如long raw),msdn上没有说,我也不知道
penitent 2002-07-29
  • 打赏
  • 举报
回复
我查遍了msdn(2001,2002),都没有找到原因,
用ado2.7还是一个样。

在msdn的示例代码中,他们返回记录集是用的表类型,然后用光标加一个循环返回回来的,其他的和我的一样。但是我不能那样写,我的表中有long raw类型,如果那样写,大于32k的long raw则没有办法返回回来。我只有返回一个记录集,但是一旦返回记录集,就内存泄露。

测试结果表明:
1、过程返回记录集,泄露
2、直接打开记录集,不泄露
3、过程中定义一个行类型,通过光标返回一行(但long raw需要小于32k),不泄露。
这说明,就是返回记录集的问题

penitent 2002-07-29
  • 打赏
  • 举报
回复
: KingSunSha(弱水三千) ,我想这个问题与oracle有关,你是否可以测试一下,因为我这几天一直都在测试,测试结果表明,只要是用oracle的返回记录集,内存就泄露,我不说fCenterCmdExecute,我把程序写成以下还是泄露。

Public Function fReceiveCandImage(ByVal RemoteID As String, ByVal ResponseID As Long, ocKeyNo As String, oiFingerNo As Integer) As Boolean
Dim rsR As New ADODB.Recordset
Dim cmdR As ADODB.Command
Dim Pram As ADODB.Parameter
'//写日志
Call WriteToSendLog("开始接收候补图象信息, ResponseID = " & ResponseID)
On Error GoTo fReceiveCandImageErr
'//执行以上过程
Set cmdR = New ADODB.Command
With cmdR
.CommandText = "{call pkgRemote.sp_Get_CandidateImg(?,?,{resultset 0, io_cursor})}"
.CommandType = adCmdText 'adCmdText
Set Pram = .CreateParameter("iRemote_ID_I", adBSTR, adParamInput, , RemoteID)
.Parameters.Append Pram
Set Pram = .CreateParameter("iResponseID", adInteger, adParamInput, , ResponseID)
.Parameters.Append Pram
End With
'//得到记录集
rsR.CursorType = adOpenStatic
rsR.LockType = adLockReadOnly
Set cmdR.ActiveConnection = CNRemote 'CNRemote是一个ADO的连接
Set rsR.Source = cmdR
'set fExecuteOneCommand = cmdR.Execute '这是另一种执行方式,也泄露
rsR.Open
'//如果没有记录集,过程执行不成功
If rsR Is Nothing Then
Call WriteToSendLog("读取远程remote数据库发生错误")
fReceiveCandImage = False
GoTo fReceiveCandImageErr
End If
'//如果记录集为空,没有取到数据
If rsR.EOF Then
Call WriteToSendLog("没有该图象供接收:ResponseID = " & ResponseID)
fReceiveCandImage = False
GoTo fReceiveCandImageExit
End If
'//函数执行成功,数据获取成功
fReceiveCandImage = True
Call WriteToSendLog("接收候补图像结束")
fReceiveCandImageExit:
If rsR.Status = adStateOpen Then rsR.Close
Set rsR = Nothing
If Not (cmdR Is Nothing) Then Set cmdR = Nothing
On Error GoTo 0
Exit Function
fReceiveCandImageErr:
Call WriteToSendLog("接收候补图像失败:" & Err.Description)
fReceiveCandImage = False
GoTo fReceiveCandImageExit
End Function
----------------------------------
你可以仔细看一下以上改写过后的函数,rsR 是在函数内部定义的记录集,直接调用存取过程返回记录集(没有通过别的函数)。
以上函数仅仅是通过存取过程返回记录集,但是就泄露。如果我的rsR 不是通过存取过程返回,而是在程序中直接打开(用rsR.open "select * from table"),它就不泄露,为什么???
我很奇怪,也很烦,找不到原因,我的记录集中有long raw的字段,与这个有关系吗?
KingSunSha 2002-07-28
  • 打赏
  • 举报
回复
没法做测试,不过感觉上应该是rs对象的问题。我写过很多类似的东西,都没法发现过问题。。。

你再检查一下fCenterCmdExecute函数
penitent 2002-07-26
  • 打赏
  • 举报
回复
也就是说,以上的
rsR是直接调用远程存取过程返回的一个记录集,
打开方式为adOpenStatic,锁方式为adLockReadOnly
RS是通过CommFunc.dll打开的本地记录集,
打开方式为adOpenDynamic,锁方式为adLockOptimistic
但这个地方泄露的是rsR
以上的Set rsR = fCenterCmdExecute(cmdR)中
fCenterCmdExecute是个函数,私有的,定义就是记录集,所以返回也就是记录集,这个函数主要打开数据库,执行存取过程,返回记录集


17,377

社区成员

发帖
与我相关
我的任务
社区描述
Oracle 基础和管理
社区管理员
  • 基础和管理社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧