LOB 流与定位器 (★★)
#open-sql #lobs #database
LOB 类型
| LOB 类型 |
ABAP 类型 |
数据库类型 |
内容 |
| 二进制 LOB |
xstring |
BLOB |
二进制数据(图像、PDF 等) |
| 字符 LOB |
string |
CLOB |
文本数据(文档、XML 等) |
访问方法比较
| 方法 |
传输方式 |
内存 |
使用场景 |
| 普通(直接) |
完整 LOB 到 ABAP |
高(完整内容在内存中) |
小 LOB,需要全部内容 |
| 流 |
顺序读/写 |
低(逐块处理) |
大 LOB,顺序处理 |
| 定位器 |
元数据 + 子序列 |
很低 |
检查长度、提取部分、在数据库端复制 |
普通访问(完整传输)
1 2 3 4 5
| " 完整传输 - 将整个 LOB 加载到内存 SELECT document_content INTO lv_string " 类型 STRING = 完整 CLOB 传输 FROM documents WHERE doc_id = '001'.
|
流(NW 7.0 EhP2+)
无需完整传输的顺序读/写。
读取器类
| 类 |
用途 |
CL_ABAP_DB_C_READER |
读取 CLOB(字符) |
CL_ABAP_DB_X_READER |
读取 BLOB(二进制) |
CL_ABAP_DB_C_WRITER |
写入 CLOB |
CL_ABAP_DB_X_WRITER |
写入 BLOB(二进制) |
流方法
| 方法 |
用途 |
DATA_AVAILABLE() |
检查是否有更多数据可读 |
READ(length) |
读取指定长度的下一块 |
SKIP(length) |
跳过字节/字符 |
CLOSE() |
关闭流并释放资源 |
IS_CLOSED() |
检查流是否已关闭 |
流读取示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| DATA: lo_reader TYPE REF TO cl_abap_db_c_reader.
SELECT document_content INTO lo_reader " 流对象而非字符串 FROM documents WHERE doc_id = '001'.
WHILE lo_reader->data_available( ) = abap_true. lv_chunk = lo_reader->read( 1000 ). " 每次读取 1000 字符 " 处理 lv_chunk ENDWHILE.
lo_reader->close( ). ENDSELECT.
|
流写入示例
1 2 3 4 5 6 7
| DATA: lo_writer TYPE REF TO cl_abap_db_x_writer.
INSERT INTO documents VALUES ( '002', lo_writer ).
lo_writer->write( lv_data_chunk1 ). lo_writer->write( lv_data_chunk2 ). lo_writer->close( ).
|
定位器
无需完整传输即可访问 LOB 元数据和子序列。可以在数据库端复制 LOB 而无需传输到应用服务器。
定位器类
| 类 |
用途 |
CL_ABAP_DB_C_LOCATOR |
字符 LOB 定位器 |
CL_ABAP_DB_X_LOCATOR |
二进制 LOB 定位器 |
定位器方法
| 方法 |
用途 |
GET_LENGTH() |
获取 LOB 长度而不传输 |
FIND(substring) |
在 LOB 中搜索 |
GET_SUBSTRING(offset, length) |
提取 LOB 的一部分 |
CLOSE() |
释放定位器 |
定位器示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| DATA: lo_locator TYPE REF TO cl_abap_db_c_locator.
SELECT document_content INTO lo_locator FROM documents WHERE doc_id = '001'.
lv_length = lo_locator->get_length( ). " 无数据传输 lv_pos = lo_locator->find( 'IMPORTANT' ). " 在数据库端搜索 lv_excerpt = lo_locator->get_substring( " 仅传输这部分 offset = lv_pos - 50 length = 100 ).
lo_locator->close( ). ENDSELECT.
|
流和定位器的缺点
| 缺点 |
详情 |
| 更高的数据库资源消耗 |
数据库保持游标/锁打开 |
| 数据库依赖性 |
并非所有数据库原生支持 |
| 复杂性 |
比简单 SELECT 代码更多 |
| 限制 |
16 个流,每个 LUW 1000 个 LOB 句柄 |
流 vs 定位器
| 特性 |
流 |
定位器 |
| 访问模式 |
仅顺序 |
随机访问 |
| 读取分块 |
是(READ(length)) |
是(GET_SUBSTRING) |
| 写入 |
是(写入器类) |
否 |
| 搜索 |
否 |
是(FIND) |
| 获取长度 |
否 |
是(GET_LENGTH) |
| 数据库端复制 |
否 |
是 |
| 最大打开数 |
16 |
与流合计 1000 |
考试/测试模式
| 关键词 / 短语 |
答案 |
| “最大打开流数” |
每个会话 16 个 |
| “每个 LUW 最大 LOB 句柄” |
1000 个(流 + 定位器合计) |
| “BLOB 读取的流类” |
CL_ABAP_DB_X_READER |
| “CLOB 写入的流类” |
CL_ABAP_DB_C_WRITER |
| “定位器相比流的优势” |
随机访问、搜索、获取长度、数据库端复制 |
| “普通访问的缺点” |
完整传输到内存(高消耗) |
| “DATA_AVAILABLE 方法” |
检查流中是否有更多数据可用 |
| “定位器上的 GET_LENGTH” |
返回长度而不传输 LOB 内容 |
相关笔记