CD263 ABAP语言新特点 What is new in ABAP in NW 7.0, EhP2? Jean Guo Zhong Ba Tao Xu ©2010 SAP AG. All rights reserved. / Page 2 Disclaimer This presentation outlines our general product direction and should not be relied on in making a purchase decision. This presentation is not subject to your license agreement or any other agreement with SAP. SAP has no obligation to pursue any course of business outlined in this presentation or to develop or release any functionality mentioned in this presentation. This presentation and SAP's strategy and possible future developments are subject to change and may be changed by SAP at any time for any reason without notice. This document is provided without a warranty of any kind, either express or implied, including but not limited to, the implied warranties of merchantability, fitness for a particular purpose, or non-infringement. SAP assumes no responsibility for errors or omissions in this document, except if such damages were caused by SAP intentionally or grossly negligent. ©2010 SAP AG. All rights reserved. / Page 3 课程安排 1. 表达式 2. 内表 3. 基于类的异常处理 4. 十进制浮点数 5. 使用Locator和数据流读写数据库 6. Boxed 组件 ©2010 SAP AG. All rights reserved. / Page 4 运算表达式只能由COMPUTE命令完成 算术表达式(数字计算) 二进制表达式(位计算) 控制逻辑中只能使用纯逻辑表达式 表达式–现状 tmp1= n / i. tmp2= ME->meth( tmp1 ) * i. IF tmp2= n. EXIT. ENDIF. 过多的辅助变量给编程造成困难 一些内建方法(如strlen, lines)只能使用在非常特定的操作数位置,用途 很有限 ©2010 SAP AG. All rights reserved. / Page 5 新的运算表达式类型:字符串表达式 支持运算表达式的地方: 逻辑表达式当中 IMPORTING参数中 ABAP语句中各种类型的操作数位置 扩展之后的表达式–主要功能 在方法调用时允许嵌套及链式调用 扩展内建方法集(如字符串处理内建方法) 通过内建方法的调用使编程更加紧凑高效 IF ME->meth( n / i ) * i = n. EXIT. ENDIF. 运算表达式作为方法实参 运算表达式作为逻辑表达式一个 操作数 ©2010 SAP AG. All rights reserved. / Page 6 在逻辑表达式中使用计算表达式 CHECK sy-index > i + 1. WHILE x1 BIT-AND x2 BYTE-CO xs1 BIT-OR xs2. 位运算 LOOP AT tab INTO wa WHERE c BETWEEN n – 10 AND n + 10. 在比较语句中的运算 IF sy-tabix MOD 10 = 0. ULINE. ENDIF. 算术运算 IF int / ( 4 * int ) = 0. 整型运算→ true IF flt / ( 4 * flt ) = 0. 浮点型运算→ false ©2010 SAP AG. All rights reserved. / Page 7 在IMPORTING参数中使用运算表达式 o->m( abs( i * 2 ) + 1 ). 不指定参数名 cl=>m( p1 = i + 1 p2 = 2 ** j ). 指定参数名 o->m( pX10 = BIT-NOT x1 pXStr = x1 BIT-OR x2 ). 任意二进制类型参数均接受二进制运算表达 式 cl=>m( pInt = 12 / 10 pDec = 12 / 10 ). 任意数字类型的参数均接受算术运算表达式 形参的类型决定运算类型(pInt1, pDec 1.2) CREATE OBJECT o EXPORTING p = i + 1 . 调用构造函数构建实例时的 参数 RAISE EXCEPTION TYPE lcx EXPORTING p = i + 1 . 实例化异常时的参数 o->m( cl=>m( p1 = o->i~m( 7 ) ) ). 将方法调用作为参数 ©2010 SAP AG. All rights reserved. / Page 8 其他ABAP语句中的运算表达式(输入操作数) READ TABLE itab INDEX lines( itab ) … APPEND LINES OF oref->tab( ) FROM i + 1 TO n – 1 TO t. DO strlen( txt ) – 1 TIMES. 数字类型的输入操作数 MOVE-CORRESPONDING o->struct( ) TO x. 在使用通用类型输入操作数的 位置使用方法调用 也可用于WAIT,SET BIT,GET BIT,SHIFT,FIND,REPLACE,… 也可用于其他使用内表操作索引的语句如LOOP,INSERT,DELETE,… 也可用于其他使用通用类型输入操作数的语句(主要是字符类型操作语句)如 CLEAR, FIND, REPLACE,… 也可用于其他使用工作区/表的内表操作语句如LOOP, INSERT, DELETE, READ, MODIFY,… ©2010 SAP AG. All rights reserved. / Page 9 链式方法调用 cl=>get_instance( )->cleanup( ). 链式方法调用 IF oref->m1( )->intf~m2( )->a > 1. 以链式调用访问实例的成员变 量 CASE cl=>m1( )->obj->m2( ) . 以链式调用访问实例的成员方 法 ©2010 SAP AG. All rights reserved. / Page 10 扩展之后的表达式应用–不足 lcl=>cm_ii( 1 + abs( lcl=>factory2( f_in1 = lcl=>factory0( )->m_lif( )->im_lif( )->im_ii( i ) f_in2 = lcl=>cm_ii( 2 ** i ) - 3 )->m_ii( lcl=>factory1( f_in = j + 4 )->m_lif_i( lcl=>cm_ii( 5 ) )->im_ii( 6 ) ) ) ). ©2010 SAP AG. All rights reserved. / Page 11 扩展之后的表达式应用–不足 不支持编译器优化,如 公共子表达式消去 循环不变式提取 编程人员应合理使用中间变量以使程序更清晰 ABAP变得容易混淆 但ABAP调试器可以支持复杂表达式 可以显示方法返回值 可以显示中间运算结果 px_width=px_width+ col->get_layout()->width * units->to_px_width(col->get_layout()->width_unit). ©2010 SAP AG. All rights reserved. / Page 12 字符串表达式 新的运算表达式: 字符串表达式 串连 txt1 && txt2 字符串模板 |…Text…{ expression format = …}…Text…| 字符串表达式 用于方便地创建格式化的文本(如xml) 同算术表达式和二进制表达式一样可以用于很多位置 可用于替换大量的: WRITE TO语句及相应的辅助变量 CONCATENATE语句 新的内建方法 用于字符串处理:23个 用于非字符串处理:8个 用于字符串断言:4个 ©2010 SAP AG. All rights reserved. / Page 13 DATA txt TYPE string. CONCATENATE txt1 txt2 INTO txt. CONDENSE txt. txt = condense( txt1 && txt2 ). 字符串连接 连接操作符 txt1 && txt2 替换CONCATENATE语句以及相应的辅助变量 ©2010 SAP AG. All rights reserved. / Page 14 字符串模板 字符串模板能够将表达式与文本字符结合起来 |…Text…{expression format = …}…Text…| 文本字符 内嵌表达式 格式选项 文本字符 do 20 times. prog1 = |REP{ sy-index - 1 }TEST|. prog2 = |/{ nspace }/REP{ sy-index - 1 zero = no }TEST|. prog3 = |/{ nspace }/REP{ sy-index - 1 align = right pad = '0' width = 2 }TEST|. enddo. 字符串模板以| 作为开始和结束 ©2010 SAP AG. All rights reserved. / Page 15 字符串模板的特点 字符串模板 允许将动态及静态文本相结合 可使用字符转换,格式化以及字符串连接 支持控制字符(如“\n” 可以新起一行) 不能跨越多行(需要使用„&‟ 来连接多行) 可用于替换WRITE TO 语句及辅助变量 对于技术性文本(如code/xml/html) 进行了优化 不支持语言相关的模板 s = |Hello, \n| & |today is { sy-datum date = iso } \n| & |now is { sy-uzeit time = iso }|. ©2010 SAP AG. All rights reserved. / Page 16 字符串模板中的内嵌表达式 内嵌表达式 以„{„ 和„}‟ 作为开始和结束 表达式结果会被转换为字符串 格式选项可用于定义字符串格式 在内嵌表达式中使用的换行没有意义 s = |<line index=“{ sy-tabix }” | & |kind=“{ o->get_kind( ) }”>|. s = |timestamp=“{ sy-datum date = iso }T| & |{ sy-uzeit time = iso }”|. 格式选项 ©2010 SAP AG. All rights reserved. / Page 17 常用格式选项 可用于所有类型 width [integer number] 总输出宽度 align {left|right|center} 对齐方式(默认为左对齐) pad [character] 填充字符 case {raw|upper|lower} 大小写 ©2010 SAP AG. All rights reserved. / Page 18 可用于数字类型的格式选项 可用于数字类型 sign {left|leftplus|leftspace| right|rightplus|rightspace} 正负号位置(默认左侧) exponent [integer number] 指数 decimals [integer number] 小数位数 zero {yes|no} 消零处理 number {raw|user|environment} 小数格式(默认raw) style CL_ABAP_FORMAT中的常量 浮点数格式 currency 数据库表TCURC中的值 货币代码 ©2010 SAP AG. All rights reserved. / Page 19 可用于日期时间类型的格式选项 可用于日期和时间 date raw (“20080906”) user 使用自定义设置 iso (“2008-09-06”) environment 使用区域设置 日期格式 (默认为raw) time raw “182504” user 使用自定义设置 iso “18:25:04” environment 使用区域设置 时间格式 (默认为raw) timestamp space 日期时间 user 使用自定义设置 iso 日期„T‟ 时间 environment 使用区域设置 时间戳格式 timezone 数据库表TTZZ-TZONE中的值 时区 ©2010 SAP AG. All rights reserved. / Page 20 7.0 EhP2之前的字符串处理 ABAP命令集, 如: CONCATENATE SPLIT CONDENSE FIND SUBSTRING | REGEX REPLACE SUBSTRING | REGEX 逻辑操作符集, 如: CS, NS CA, NA CP, NP 内建方法集, 如: strlen( ... ) charlen( ... ) 字符串子串操作: ... text+off(len) ... ©2010 SAP AG. All rights reserved. / Page 21 字符串操作可在表达式中直接使用 新的字符串操作内建方法 text= 'Product description: Superdooper smartphone'. desc= to_upper( condense( substring_after( val = textsub = `description:` occ = 1 len = 18 ) ) ). text= `... use product no. &prod-id& (&prod-desc&).`. LOOPAT replacementsASSIGNING <repl>. text = replace( val = text sub = '&' && <repl>-repl && '&' with = <repl>-content ). ENDLOOP. 结果:"SUPERDOOPER SMART" 结果:"... use product no. XY007 (SUPERDOOPER SMART)." 'prod-id‘ `XY007` 'prod-desc‘ desc 参数替换= ©2010 SAP AG. All rights reserved. / Page 22 返回值为字符串的方法(1) 提取子串 substring( val = s [off = i1] [len = i2] ) substring_after( val = s (sub|regex) = s1 [occ = i1] [len = i2] ) substring_from( val = s (sub|regex) = s1 [occ = i1] [len = i2] ) substring_before( val = s (sub|regex) = s1 [occ = i1] [len = i2] ) substring_to( val = s (sub|regex) = s1 [occ = i1] [len = i2] ) segment( val = s index = i [sep = s1] ) match( val = text regex = regex [case = case] [occ = occ] ) 字符串移位 shift_left( [val =] s [places = i1 | circular = i2 | sub = s1] ) shift_right( [val=] s [places = i1 | circular = i2 | sub = s1] ) ©2010 SAP AG. All rights reserved. / Page 23 返回值为字符串的方法(2) 字符串转化 replace( val = s (sub|regex) = s1 with = s2 [occ = i1] [case = c] ) insert( val = s sub = s1 [off = i] ) repeat( val = s occ = i ) condense( [val =] s [del = s1] [from = s2] [to = c] ) reverse( [val =] s ) escape( val = s format = f ) translate( val = s from = s1 to = s2 ) to_upper([val =] s ) to_lower([val =] s ) to_mixed( [val =] s [sep = c1] [case = c2] [min = i] ) from_mixed( [val =] s [sep = c1] [case = c2] [min = i] ) ©2010 SAP AG. All rights reserved. / Page 24 返回值为字符串的方法(3) oref->meth( boolc( …condition… ) ). if …condition… . temp_flag = 'X'. else. temp_flag = ' '. endif. oref->meth( temp_flag ). 连接内表各行 concat_lines_of( [table =] t [sep = s] ) 将内表<t> 各行以<s>为分隔符连接 布尔运算 boolc( logical-expression) 如逻辑表达式为真,返回„X‟ 否则返回„ ‟ boolx( bit = i bool = logical-expression) 返回值为一个Byte, 如果逻辑表达式结果为真, 则此Byte第i位置1,否则置0 ©2010 SAP AG. All rights reserved. / Page 25 可在逻辑表达式中直接使用字符串内建方法 新的用于字符串描述的内建方法 IF not matches( val = email regex = `\w+(\.\w+)*@(\w+\.)+(\w{2,4})` ). * Email format is not valid … 如果email格式合法,则match方法返回真值 text= `... use product no. XY007 (SUPERDOOPER SMART).`. IF find( val = text sub = 'XY'case= abap_true occ = 1 off = 10 len = 20 ) <> -1. * Substring found … find方法给出子串’XY‘在text中从11位到31位的位移量 如果找不到子串,则返回-1 ©2010 SAP AG. All rights reserved. / Page 26 字符串描述方法 搜索子串(返回所找到位置的位移量) find( val= s (sub|regex) = s1 [off = i1] [len = i2] [occ= i3] [case = c] ) find_end( val = s (sub|regex) = s1 [off = i1] [len = i2] [occ = i3] [case = c] ) find_any_of( val= s sub = s1 [off = i1] [len = i2] [occ= i3] ) find_any_not_of( val = s sub = s1 [off = i1] [len = i2] [occ = i3] ) 子串计数(返回所找到的子串数量) count( val = s (sub|regex) = s1 [off = i1] [len = i2] [occ = i3] [case = c] ) count_any_of( val = s sub = s1 [off = i1] [len = i2] [occ = i3] ) count_any_not_of( val = s sub = s1 [off = i1] [len = i2] [occ = i3] ) 字符串相似度(返回两个字符串的LevenshteinDistance值) distance( val1 = s1 val2 = s2 [max = i] ) ©2010 SAP AG. All rights reserved. / Page 27 字符串断言方法 包含子串或字符 contains( val = s (sub|start|end|regex) = s1 [off = i1] [len = i2] [occ = i3] [case = c] ) contains_any_of( val = s (sub|start|end) = s1 [off = i1] [len = i2] [occ = i3]) contains_any_not_of( val = s (sub|start|end) = s1 [off = i1] [len = i2] [occ = i3] ) 匹配正则表达式 matches( val = text regex = regex [case = case] [off = off] [len = len] ) ©2010 SAP AG. All rights reserved. / Page 28 总结–扩展后的表达式 扩展了表达式的用途 支持了更多的操作数位置,特别是一些内表相关的ABAP语句 与面向对象无缝集成(嵌套调用,链式调用) 字符串表达式 简单实用 可以像算术表达式一样直观地使用 丰富的格式选项 丰富的内建方法 想了解更多? 运行ABAP report程序:DEMO_EXPRESSIONS 查看ABAP在线文档 Demo 演示& 练习 ©2010 SAP AG. All rights reserved. / Page 30 课程安排 1. 表达式 2. 内表 3. 基于类的异常处理 4. 十进制浮点数 5. 使用Locator和数据流读写数据库 6. Boxed 组件 ©2010 SAP AG. All rights reserved. / Page 31 为什么在内表中使用次键(Secondary Keys)? 有键值的内表的优点(自4.0起支持) 对哈希表的键值快速访问,时间复杂度:O(1) Time Table Size Hashed ©2010 SAP AG. All rights reserved. / Page 32 为什么在内表中使用次键(Secondary Keys)? 有键值的内表的优点(自4.0起支持) 对哈希表的键值快速访问,时间复杂度:O(1) 对排序表的键值快速访问,时间复杂度:O(log n) 对排序表的部分连续快速处理(LOOP … WHERE 优 化) Time Table Size Hashed Sorted ©2010 SAP AG. All rights reserved. / Page 33 为什么在内表中使用次键(Secondary Keys)? 有键值的内表的优点(自4.0起支持) 对哈希表的键值快速访问,时间复杂度:O(1) 对排序表的键值快速访问,时间复杂度:O(log n) 对排序表的部分连续快速处理(LOOP … WHERE 优 化) 非主键访问 缓慢的性能,时间复杂度:O(n) 可能会导致整体性能问题 需要由手工实现的次键访问来进行性能优化,而 这种手工实现很容易出错 提供像数据库表一样的次键 在添加次键的同时保留兼容性 (不会自动隐式使用次键) 编译器提示正确用法 Time Table Size Hashed Sorted Standard 实际应用中的低性 能 数据量小的情 况下性能不错 ©2010 SAP AG. All rights reserved. / Page 34 内表的属性 LH 0400 4.167 A380-800 SQ 0866 1.625 A340-600 UA 0007 2.572 767-200 CARRID CONNID DISTANCE PLANETYPE 行类型: t_flight 主键 QF 0005 1.000 747-400 索引访问 4 次键访问 A340-600 次键: plane 唯一性检查 AA 0017 2.572 737-800 主键访问 UA 0007 LH 0400 6.162 A340-600 data flights type sorted table of t_flight with unique key carrid connid with non-unique sorted key plane components planetype. ©2010 SAP AG. All rights reserved. / Page 35 定义次键 次键是内表类型定义的一部分,即静态定义 但在一些ABAP语句中(如READ, LOOP, …)次键以及组件可以动态指定 次键定义必须完整, 也就是说如下属性必须全部指定 定义次键名称(Keyname) , 系统保留字: PRIMARY_KEY,LOOP_KEY 访问类型(Access kind): HASHED或SORTED 唯一性(Uniqueness): UNIQUE或NON-UNIQUE,哈希值必须唯一(UNIQUE) 组件(Key components): 可以使用自定义的组件列表或者使用TABLE_LINE 最多支持15个次键 DATA <Well-known table definition> WITH KEY COMPONENTS <Uniqueness> <Access Kind> <Components> <Keyname> ©2010 SAP AG. All rights reserved. / Page 36 非唯一性次键vs. 唯一性次键 非唯一性(排序)次键 懒惰索引更新(Lazy index update), 即:索引在被用到之前不会自动更新 如果没有使用该索引,则不会消耗相应的内存空间 因此,非常适合用于调整既有程序 唯一性次键 唯一性是一个语义上的约束, 也就是对于违反约束的原子操作(INSERT, MOVE, SELECT, …)即刻做出反应(异常/运行时错误) ©2010 SAP AG. All rights reserved. / Page 37 定义次键–实例 ©2010 SAP AG. All rights reserved. / Page 38 定义次键–ABAP字典 ABAP 字典 (SE11) 新的标签项 „Secondary Key“ 最多支持15个次键 ©2010 SAP AG. All rights reserved. / Page 39 数据库表中的次键vs. 内表中的次键 数据库表 优化器判定选择哪一个键 一般情况下,结果集可按任意次序返回, 次序由SELECT语义决定 内表 定义好的内表条目次序 标准表/哈希表:插入次序 排序表:插入位置 无法采用基于优化器的判定 因此,需要显式指定要使用哪一个键 ©2010 SAP AG. All rights reserved. / Page 40 在有次键的内表上INSERT ABAP在内表插入语句(INSERT, SELECT … INTO, MOVE, …)中并没有针对次键的语 法扩展 由应用次键带来的性能提升是以适度增加内存消耗和键值更新为代价的: 主键立即更新 如果一个键值已经存在,则在向排序表和哈希表插入一条重复数据时并不更新主键 (但语句返回值会置为非0) 在批量重复插入时会产生运行时错误 唯一性次键也会立即更新 如果一个键值已经存在,则在向排序表和哈希表插入一条重复数据时会抛出可捕获的异常 在批量重复插入时会产生运行时错误 非唯一性次键采用懒惰更新(lazy update) 只有当用该次键访问内表时,这些键才会被更新 在使用该键之前没有额外的内存开销(除一些基本的程序管理开销) 要避免使用不必要的次键 ©2010 SAP AG. All rights reserved. / Page 41 在有次键的内表上READ 新的语法扩展… USING KEY KeyName… 新的语法扩展… KeyNameCOMPONENTS …针对WITH从句 在WITH从句中的次键组件须注意恰当使用 对唯一性键值所有组件都必须指定 对非唯一性键值必须指定其引导部分 ©2010 SAP AG. All rights reserved. / Page 42 在有次键的内表上LOOP 新的语法扩展… USING KEY KeyName… 新的语法扩展… USING KEY KeyName…针对WHERE从句 在WHERE条件中指定次键的组件: comp 1 = val 1 AND … AND comp n = val n 在WHERE从句中的次键组件须注意恰当使用(同READ WITH) 其他的非键值组件可以由AND进行连接 ©2010 SAP AG. All rights reserved. / Page 43 其他支持次键的ABAP语句 新的语法扩展… USING KEY KeyName…针对DELETE和MODIFY ©2010 SAP AG. All rights reserved. / Page 44 主动键值保护 主键:写保护 排序表和哈希表的键组件是受到写保护的,不允许通过指针或引用更改键组件的值 次键: 在针对一个指定次键的loop当中,相关的键组件均被写保护 在嵌套loop中, 所有主键及当前使用的相关次键的组件均被写保护 技术上讲,这需要在所有写操作时对键组件进行监控 当前没有使用的键的组件将会被覆盖(索引更新延迟进行) 否则,如果所有次键的所有组件均处于写保护状态,则在向内表添加新的键值的时候会产生 不兼容的后果 ©2010 SAP AG. All rights reserved. / Page 45 可应用次键的业务场景 适合使用次键的业务场景 超大表 在最初表创建之后,没有或只有少量的表更新操作 程序管理开销主要集中在创建表的阶段 在使用次键之后性能提升显著 使用唯一性次键的特殊应用场景 需要重视数据完整性(唯一性)的程序 小型内表 以下情况不应使用次键 小型内表(少于50条记录),系统开销和内存消耗另其得不偿失 内表经常性地需要更新 ©2010 SAP AG. All rights reserved. / Page 46 总结–内表次键 次键可以非常容易地与已有程序进行集成或在新程序当中应用以提高程序性能 ABAP定义了一些语法扩展(USING KEY, COMPONENTS)以使用次键 ABAP语法检查会对冗余及性能进行提示 通过添加次键,既有程序的性能可以有效地提高,并且这些改动是上下兼容的 懒惰更新(lazy update)及延迟更新处理提供了强大的增量处理能力 ©2010 SAP AG. All rights reserved. / Page 47 data: condition typestring. * construct condition string dynamically condition = |{ cname1 } >= { start } and | & |{ cname2 } <= { start } + { delta }|. * evaluateloopcondition completely at runtime loop at <itgeneric> assigning <line> where (condition). … endloop. 另一些不同的情况… LOOP AT <itab> with dynamic WHERE condition 动态工作 区 动态WHERE 条 件 通用内表 如对数据库表操作的读取中所用到的动态WHERE条件一样, 这里我们需要: ABAP提供了非常广泛的通用及动态编程技术,但是有一个功能之前并未提供: ©2010 SAP AG. All rights reserved. / Page 48 支持动态WHERE条件的LOOP语句 动态WHERE条件与静态WHERE条件遵循同样的规则: 操作符左边的操作数必须是内表行的一个组件 操作符右边的操作数在LOOP到某一条记录时判定 动态WHERE条件也可用于以下语句: MODIFY ... WHERE DELETE ... WHERE (规则同上) ©2010 SAP AG. All rights reserved. / Page 49 data: condition typestring. * construct condition dynamically condition = |comp1 cp { val1} and | & |not comp2 < { val2 } or | & |comp3 = { val3} equiv comp4 = { val4}|. loop at <itgeneric> assigning <line> where (condition). … endloop. 动态WHERE条件的构造 一个合法的条件构造如下: 所有类型的算术和字 符串操作 布尔操作符: and, or, not, equiv ©2010 SAP AG. All rights reserved. / Page 50 错误处理 如果使用了不正确的WHERE条件,程序会在运行时抛出 CX_SY_ITAB_DYN_LOOP异常: data: condition type string, excptype ref to cx_sy_itab_dyn_loop. * construct condition dynamically condition = |comp1 = { val1} ant | & |comp2 = { val2}|. try. loopat <itgeneric> assigning <line> where (condition). ... endloop. catch cx_sy_itab_dyn_loop intoexcp. " error handling endtry. 条件不能正常解析: unknown operator ant ©2010 SAP AG. All rights reserved. / Page 51 总结–动态WHERE条件 动态WHERE条件可以使用以下结构条件: 方法调用和成员变量 运算表达式 预定义方法 数据引用 动态WHERE支持次键 性能表现: 为避免内部类型转换问题,组件部分和值部分应使用相同数据类型. 如果在WHERE条件当中恰当地使用了内表的键(排序键的第一个组件, 哈希键的所有 组件),则该WHERE条件可以被优化 作为一个内部优化,ABAP使用了缓存使得表的静态信息可以重用 Demo 演示& 练习 ©2010 SAP AG. All rights reserved. / Page 53 课程安排 1. 表达式 2. 内表 3. 基于类的异常处理 4. 十进制浮点数 5. 使用Locator和数据流读写数据库 6. Boxed 组件 ©2010 SAP AG. All rights reserved. / Page 54 基于类的异常处理的几条原则 将软件看成是(分层的)服务的集合 服务发生错误时: 没有程序上下文,并且可能无法纠正错误 因此,只能发出错误标志,并且给出部分额外的错误信息 中止程序并且把控制流交给合适的能够处理这种特殊情况的处理程序 RAISE EXCEPTION TYPE CX_ORDER_LOCKED EXPORTING TEXTID = … 静态地通知调用者可能要处理的异常 METHODS readOrder … RASING CX_ORDER_LOCKED. 将普通代码和错误处理程序分开: 分开定义异常处理程序 TRY. order = readOrder( orderId ). CATCH CX_ORDER_LOCKED into excpobj. “ handle locked order situation ENDTRY. 异常处理程序可以: 停止操作 继续操作, e.g. restart the service from the beginning RETRY ©2010 SAP AG. All rights reserved. / Page 55 异常处理的例子 METHOD a. TRY. b( ). CATCH cx. … ENDTRY. ENDMETHOD. METHOD b. TRY. c( ). CLEANUP. … ENDTRY. ENDMETHOD. METHOD c. … RAISE EXCEPTION TYPE cx. … ENDMETHOD. c b a b a a 堆栈 代码 1 2 3 4 1 2 4 cx的异常处理程序在方法a的执行上下文中调用! 3 ©2010 SAP AG. All rights reserved. / Page 56 标准异常处理的局限 以下几种情况下很难使用典型的异常 处理大量数据: 子任务中的异常不能够终止整个任务 收集错误: 捕获异常的方法必须捕获所有的错误 纠正错误后重新启动: 继续正常的后续程序 错误已经纠正(比如通过用户的交互) 找到一个基于当前上下文的临时解决方案 解决方案 简单重试服务 不自动终止服务 从技术角度:不可以立刻退栈 可恢复的异常 抛出的异常必须是定义为“可恢复”的 异常处理程序能决定是终止服务还是恢复服务 服务必须是预定义为“可恢复”的 分层的架构:所有的层都必须预定义为可传递“可恢复”的异常 ©2010 SAP AG. All rights reserved. / Page 57 在异常处理程序中使用RETRY 一种可能的处理异常的办法就是重试... TRY. CATCH cx_sy_file_access_error. ENDTRY. OPEN DATASET file FOR OUTPUT IN BINARY MODE. TRANSFER xbuffer TO file. CLOSE DATASET file. WRITE: 'Buffer successfully written'. IF ui->ask_for_retry( msg = 'No memory stick in port' ) IS NOT INITIAL. RETRY. ELSE. WRITE: ‘Could not write buffer’. ENDIF. 将控制交给定义当 前异常处理程序的 TRY模块 ©2010 SAP AG. All rights reserved. / Page 58 可保留上下文的异常处理程序: CATCH BEFORE UNWIND 恢复服务的前提: 必须保留上下文 异常发生时不立即退栈 没有执行CLEANUP的程序块 新的CATCH 子句: 异常发生时,退栈动作和CLEANUP程序块的执行将被推迟,直到异常处理程序执行 完成 因此,调用异常处理程序的时候需要保留原程序执行的上下文 原程序的堆栈还包括所有有效的局部变量 和在TRY…ENDTRY 里使用普通CATCH一样,使用相同的语法检查规则 TRY. … CATCH BEFORE UNWINDcx_file_too_large INTO ex. msg = … ENDTRY. ©2010 SAP AG. All rights reserved. / Page 59 使用Catch Before Unwind的异常处理 METHOD a. TRY. b( ). CATCH BEFORE UNWIND cx. ... ENDTRY. ENDMETHOD. METHOD b. TRY. c( ). CLEANUP. ... ENDTRY. ENDMETHOD. METHOD c. ... RAISE EXCEPTION TYPE cx. ... ENDMETHOD. c b a b a a 堆栈 代码 1 2 1 2 ©2010 SAP AG. All rights reserved. / Page 60 使用Catch Before Unwind的异常处理 METHOD a. TRY. b( ). CATCH BEFORE UNWIND cx. ... ENDTRY. ENDMETHOD. METHOD b. TRY. c( ). CLEANUP. ... ENDTRY. ENDMETHOD. METHOD c. ... RAISE EXCEPTION TYPE cx. ... ENDMETHOD. c b a b a a c b a 1 2 3 1 2 3 堆栈 代码 ©2010 SAP AG. All rights reserved. / Page 61 使用Catch Before Unwind的异常处理 METHOD a. TRY. b( ). CATCH BEFORE UNWIND cx. ... ENDTRY. ENDMETHOD. METHOD b. TRY. c( ). CLEANUP. ... ENDTRY. ENDMETHOD. METHOD c. ... RAISE EXCEPTION TYPE cx. ... ENDMETHOD. c b a b a a c b a 1 2 3 4 5 1 2 3 4 5 堆栈 代码 ©2010 SAP AG. All rights reserved. / Page 62 可恢复的异常 抛出可恢复的异常: RAISE RESUMABLE EXCEPTION TYPE cx [ EXPORTING … ] RAISE RESUMABLE EXCEPTION object 和RAISE EXCEPTION一样的语法规则 抛异常的原程序需允许重启(恢复) Statement might or might not return 定义为可恢复的处理程序: RESUME 语法检查: 只可用在定义在CATCH BEFORE UNWIND里的处理程序 不可恢复的异常使用RESUME会抛运行时错误(no-check exception CX_SY_ILLEGAL_HANDLER with text id NOT_RESUMABLE) 检查异常是否可恢复: ABAP_BOOL类型的属性IS_RESUMABLE 如果控制流离开原处理程序而没有执行RESUME , 那么认为处理程序选择了“终止”,即执 行退栈动作 检查一个异常是否是可恢复的: IS_RESUMABLE 这是异常根类CX_ROOT的成员变量, ABAP_BOOL类型, 只读 ©2010 SAP AG. All rights reserved. / Page 63 向上传递可恢复的异常 让使用者知道可能发生的可恢复的异常: RAISING cx_1 | RESUMABLE(cx_1) … cx_n| RESUMABLE(cx_n) 此子句可用于methods, function modules 和forms 的定义 CX_STATIC_CHECK 和CX_DYNAMIC_CHECK 类型的异常可向上传递, CX_NO_CHECK 不允许向上传递 如果可恢复的异常没有在RAISING语句中的RESUMABLE关键字后列出,将会被作 为普通(不可恢复)的异常抛出 RESUMABLE(cx) 的含义为:当前异常可以被当作可恢复异常抛出,但不是强制的。 在se24中的定义如图: ©2010 SAP AG. All rights reserved. / Page 64 使用Resume的异常处理 METHOD a. TRY. b( ). CATCH BEFORE UNWIND cx. RESUME. ENDTRY. ENDMETHOD. METHOD b. TRY. c( ). CLEANUP. ... ENDTRY. ENDMETHOD. METHOD c. ... RAISE RESUMABLE EXCEPTION TYPE cx. ... ENDMETHOD. c b a b a a 1 2 1 2 堆栈 代码 ©2010 SAP AG. All rights reserved. / Page 65 使用Resume的异常处理 METHOD a. TRY. b( ). CATCH BEFORE UNWIND cx. RESUME. ENDTRY. ENDMETHOD. METHOD b. TRY. c( ). CLEANUP. ... ENDTRY. ENDMETHOD. METHOD c. ... RAISE RESUMABLE EXCEPTION TYPE cx. ... ENDMETHOD. c b a b a a c b a 1 2 3 1 2 3 堆栈 代码 ©2010 SAP AG. All rights reserved. / Page 66 使用Resume的异常处理 METHOD a. TRY. b( ). CATCH BEFORE UNWIND cx. RESUME. ENDTRY. ENDMETHOD. METHOD b. TRY. c( ). CLEANUP. ... ENDTRY. ENDMETHOD. METHOD c. ... RAISE RESUMABLE EXCEPTION TYPE cx. ... ENDMETHOD. c b a b a a c b a 1 2 3 1 2 3 4 4 堆栈 代码 ©2010 SAP AG. All rights reserved. / Page 67 总结– 基于类的异常的新特性 RETRY –有点小用 CATCH BEFORE UNWIND 本身自有的作用(用于检查堆栈,比如debug的时候) 是使用可恢复的异常的前提 可恢复的异常的三要素 RAISE RESUMABLE EXCEPTION: service must allow resumption, and …RAISING(…): intermediate procedure must allow resumption, and RESUME: exception handler must choose resumption 使用可恢复异常可以避免容易引起问题的异常处理方式,比如: 使用标志位决定忽略错误,或者使用内表记录错误信息 使用如logging的方式记录错误 使用事件(event )报告错误 Demo 演示& 练习 ©2010 SAP AG. All rights reserved. / Page 69 课程安排 1. 表达式 2. 内表 3. 基于类的异常处理 4. 十进制浮点数 5. 使用Locator和数据流读写数据库 6. Boxed 组件 ©2010 SAP AG. All rights reserved. / Page 70 二进制浮点数小数的问题(F) ABAP Type F Kernel (C/C++) Type double 输入 用F 类型表示 (显示16位小数) 保留小数点后2 位数(四舍五入) 期望值 0.805 8.0500000000000005E-01 0.81 0.81 0.815 8.1499999999999995E-01 0.81 0.82 4.805 4.8049999999999997E+00 4.80 4.81 4.815 4.8150000000000004E+00 4.82 4.82 以2为底的小数如0.5, 0.25, 0.125, … 及其和可以被精确表示。 大多以10为底的小数不可以被精确表示。 ©2010 SAP AG. All rights reserved. / Page 71 ABAP P 类型: 定点小数(BCD 数字) 例子: 毫升和桶的相互转换 使用6位小数: 1500.000000 ml 0.009435 bbl. 1500.045128 ml 5 位小数不精确 使用最大14位小数: 1500.00000000000000 ml 0.00943471615138 bbl. 1500.00000000071672 ml 依旧有5位小数不精确 定点小数的问题(P) 1 桶= 42 加仑= 9702立方英寸= 158.987295 升 ©2010 SAP AG. All rights reserved. / Page 72 ABAP中新的小数浮点类型 基本类型: DECFLOAT 此类型的实现使用了IBM‟s decNumber库。 IBM 提供硬件支持。 没有硬件的特殊支持,此类型的性能和类型P相近。 此类型需要数据库提供商实现。 类型 大小 十进制数位数 最小幂指 数 最大幂指 数 DECFLOAT16 8 Bytes 16 -383 384 DECFLOAT34 16 Bytes 34 -6143 6144 ©2010 SAP AG. All rights reserved. / Page 73 可用十进制浮点数的服务 DDIC, 可以和UNIT 和CUKY 类型配套使用. 序列化(CALL TRANSFORMATION) RFC / ALV / Web DynproABAP ©2010 SAP AG. All rights reserved. / Page 74 如何在数据库中存储Decfloat类型 DF16_RAW / DF34_RAW SAP-proprietary format 序列化,SAP专有格式 DB AppServer DECFLOAT16 / DECFLOAT34 IEEE format 数据库尚不支持新的IEEE 754-2008 类型. 有三个可能解决方案(DDIC types). DF16_DEC / DF34_DEC Fixed-point decimal format 使 用定点小数存储 DECFLOAT16 / DECFLOAT34 IEEE format, NOT YET AVAILABLE 直接使用新标准数据类型尚不可行 ©2010 SAP AG. All rights reserved. / Page 75 如何在数据库中存储Decfloat类型 --使用DF16_RAW / DF34_RAW 将Decfloat16/Decfloat34 映射到RAW 类型 SAP专有格式 支持保留所有取值范围 在DB中: 可以排序,可以比较 在DB中: 可以作为键值数据类型 不能保留Scale信息,尾部0会被删除 不支持数据库大量数据集合处理: select sum(..) update tab set col= col+ val ©2010 SAP AG. All rights reserved. / Page 76 如何在数据库中存储Decfloat类型 --使用DF16_DEC / DF34_DEC 将Decfloat16/Decfloat34 映射到DEC 类型 (定点小数), 因此需要指定长度和小数位数 在DB中:可以作为键值数据类型(包括缓冲区中的表) 支持数据库大量数据集合处理 select sum(..) update tab set col= col+ val 不支持写入DB时对value range和value的约去 可能导致写入时推迟溢出发生 在where子句里使用有问题: 10.00 <= 9.995 可能导致溢出 不保留尾数0 ©2010 SAP AG. All rights reserved. / Page 77 Round –约去方法 新的内建方法round 指定需要保留的小数尾数: round( val = my_value dec = my_dec ). 指定需要保留的十进制位数: round( val = my_value prec= my_prec ). dec和prec不可以同时指定. 使用round 则意味着是使用类型DECFLOAT34 进行运算的. ©2010 SAP AG. All rights reserved. / Page 78 Rescale –精确度调整方法 例程 输出 df = '12.3'. df = rescale( val = df dec = 3 ). 12.300 df = '12.3005'. df = rescale( val = df dec = 3 ). 12.301 df = '12.3005'. df = rescale( val = df dec = 3 mode = cl_abap_math=>round_half_even ). 12.300 df = '-2.3005'. df = rescale( val = df dec = 3 ). -2.301 df = '1.25005E-2'. df = rescale( val = df dec = 3 ). 0.013 新的内置function rescale rescale function 可以约去尾数,也可以添加尾数0。 roundfunction 只可以约去尾数。 如果计算结果超出34个数字,rescale 将会抛异常 cx_sy_operation_failure ©2010 SAP AG. All rights reserved. / Page 79 输入的转换 读取decfloat类型的值(WRITE TO 的反向操作): DATA: df TYPE DECFLOAT34, ex TYPE REF TO cx_abap_decfloat_parse_err. TRY. cl_abap_decfloat=>read_decfloat34( EXPORTING string = `-1,234,567.89` IMPORTING value = df ). CATCH cx_abap_decfloat_parse_err INTO ex. MESSAGE ex TYPE 'E'. ENDTRY. Note: 读出数字的字符串格式由用户的设置决定 ©2010 SAP AG. All rights reserved. / Page 80 计算的精确度 COMPUTE 语句的新附加关键字EXACT 诸如+, -*, / 的运算符和诸如SQRT的内建方法在处理十进制浮点小数时几乎肯定会做约去操作: 误差范围最多为0.5ULP(unit in the last place) 相对误差最多为5E-34 大多数情况下,约去操作是悄悄进行的。 The EXACT 关键字使得用户可以侦查到一个语句是否可以被精确运算,约去操作是否是必须的。 当语句不可以被精确运算,将抛出异常: TRY. COMPUTE EXACT result = 3 * ( 1 / 3 ). ... CATCH cx_sy_conversion_rounding INTO exception. ... result = exception->value. ENDTRY. 0.9999999999999999999999999999999999 ©2010 SAP AG. All rights reserved. / Page 81 性能 类型decfloat的性能和类型P 的性能相近 其实现基于IBM的decNumber库。 IBM Power 6 processor has hardware support. 类型F 由硬件支持,但是F <-> P 和F <-> C/String 的类型转换非常消耗资 源。 ©2010 SAP AG. All rights reserved. / Page 82 ABAP数字类型的使用贴士 1. 类型I 适用于整数。如果类型I的取值范围不够,可以使用不带小数位的类型P 。如果还不 够,可以使用十进制浮点小数。 2. 类型P 适用于小数数位固定的小数。如果取值范围不够,可以使用十进制浮点小数。 3. 类型DECFLOAT16 和DECFLOAT34 适用于小数数位不固定的小数或者取值范围很大的数字。类型decfloat16 使用的内 存较少,但是运行时间和类型decfloat34 差不多。对于数据库访问,根据需要选择类 型DFn_RAW或者类型DFn_DEC。 4. 类型F 仅仅适用于对精度要求不高,并且对性能有很高要求的算法。 ©2010 SAP AG. All rights reserved. / Page 83 总结 Decfloat数据类型 新的内建方法round和rescale 使用cl_abap_decfloat 对输入进行转换 使用由类cl_abap_math提供的辅助方法 Decfloats可以用于 Web DynproABAP Classic Dynpro ALV 数据库中的Decfloat 条件允许的情况下可以使用DF16_RAW / DF34_RAW (比如没有大数据量的数据库访问) 有大数据量的数据库访问时,使用DF16_DEC / DF34_DEC (使用此类型,取值范围会比较小) Demo 演示& 练习 ©2010 SAP AG. All rights reserved. / Page 85 课程安排 1. 表达式 2. 内表 3. 基于类的异常处理 4. 十进制浮点数 5. 使用Locator和数据流读写数据库 6. Boxed 组件 ©2010 SAP AG. All rights reserved. / Page 86 动机 以前的Open SQL for ABAP支持LOB列 DATA: my_string TYPE STRING. SELECT SINGLE content FROM dbtable_xxl INTO my_string WHERE id = 1. 数据库对LOB提供更好的支持:Locators & Streams ©2010 SAP AG. All rights reserved. / Page 87 Locators –概念 Locator = 指向LOB列的值 好处:避免或者减少实例化 SELECT语句创建 INSERT、UPDATE和MODIFY语句使用 在一个DB事务结束的时候所有的Locator都会自动结束 ©2010 SAP AG. All rights reserved. / Page 88 读取一个LOB值 1. 创建一个locator DATA: my_locator TYPE REF TO cl_abap_db_c_locator. SELECT SINGLE content FROM dbtable_xxl INTO my_locator WHERE key = 1. 2. 在UPDATE SET语句中使用这个locator UPDATE dbtable_xxl SET content = my_locator WHERE key = 111. Locators –例子I ©2010 SAP AG. All rights reserved. / Page 89 Locators –例子II Locator的方法: GET_LENGTH, FIND, GET_SUBSTRING, CLOSE DATA: clob_lng TYPE abap_msize, search_str TYPE string VALUE 'Read from here', found_pos TYPE abap_msize, result_str TYPE string. * Get length of the CLOB value clob_lng = my_locator->get_length( ). * Find start position of substring found_pos = my_locator->find( pattern = search_str ). * Read substring of CLOB value result_str = my_locator->get_substring( offset = found_pos length = clob_lng – found_pos ). * Close locator (and free associated DB resources) my_locator->close( ). ©2010 SAP AG. All rights reserved. / Page 90 Streams –概念 两个:Reader和writer Streams可以处理序列化数据 数据可以根据需要部分读写 由包含Streams的SQL语句产生的底层数据库操作,将会在所有 Streams被显性关闭后才会结束 一定要尽快的关闭Streams! ©2010 SAP AG. All rights reserved. / Page 91 Streams –例子I 从数据库到文件系统传输数据 使用一个reader stream将一个LOB列的内容写到一个文件中去 DATA: my_reader TYPE REF TO cl_abap_db_x_reader, my_size TYPE I VALUE 1024. * Create reader object SELECT SINGLE picture FROM lob_table INTO my_reader WHERE KEY = 1. * Open file OPEN DATASET 'my_file' FOR OUTPUT IN BINARY MODE. * Transfer data WHILE my_reader->data_available( ) = ABAP_TRUE. TRANSFER my_reader->read( my_size ) TO 'my_file'. ENDWHILE. * Close stream my_reader->close( ). ©2010 SAP AG. All rights reserved. / Page 92 Streams –例子II 从文件系统向数据库传输数据 使用一个writer stream将一个文件写进一个LOB列 DATA: my_writer TYPE REF TO cl_abap_db_x_writer, length TYPE I. container TYPE X LENGTH 1024. * Open file OPEN DATASET 'my_file' FOR INPUT IN BINARY MODE. * Create writer stream UPDATE lob_table SET picture = my_writer WHERE key= 1. * Transfer data DO. READ DATASET 'my_file' INTO container ACTUAL LENGTH length. IF SY_SUBRC <> 0. EXIT. ENDIF. my_writer->write( container ). ENDDO. my_writer->write( container(length) ). * Close stream my_writer->close( ). COMMIT WORK. ©2010 SAP AG. All rights reserved. / Page 93 如果数据库表有许多LOB列,那么定义一个包含Streams和Locators的工作区域是非常费 力的 LOBHANDLE结构体 TYPES wa_type TYPE lob_struct LOCATOR FOR COLUMNS lob1 lob2 READER FOR COLUMNS lob3 lob4 lob5. WRITER和READER不能同时使用 可以给数据库表和视图使用 根据ABAP数据字典里的原表的描述,是可以生成相应的LOB HANDLE结 构体 STRING和RAWSTRING列可以更改成locators、readers或者writers. 当ABAP数据字典里的原表的定义变化被激活的时候,LOB HANDLE结构 体会自动更新 ©2010 SAP AG. All rights reserved. / Page 94 PK: Locators vsDB Streams 用例 Locators Database Streams 读取 搜索 序列化处理 读取子字符串 读取整个内容 降低内存 ©2010 SAP AG. All rights reserved. / Page 95 总结 只有一个数据库服务器 充分利用数据库表的缓存和索引 通过跟踪SQL语句来检查他们的使用 尽量坚持以下规则: 减少Round Trips的次数 通过好的索引来提高搜索命中率 尽量使用精确查找 降低传输数据量 降低数据库负载 Demo 演示& 练习 ©2010 SAP AG. All rights reserved. / Page 97 课程安排 1. 表达式 2. 内表 3. 基于类的异常处理 4. 十进制浮点数 5. 使用Locator和数据流读写数据库 6. Boxed 组件 ©2010 SAP AG. All rights reserved. / Page 98 动机 问题: 内存浪费在 填充稀疏结构 具有相同值的子结构 结构的大小限制在512K 需求: 为相同值子结构和空的子结构进行内存优化 解决方案: 分开存储子结构 按需分配内存 ©2010 SAP AG. All rights reserved. / Page 99 例子 安全协议结构: Security Officer: Date: Incidents: If Yes: Room: Time: Description: Paul Safe Sep. 4 th 2008 Yes 12 A 5 8:45 pm Window not closed ABAP里面的结构: TYPES: BEGIN OF security_struc, officer TYPE C LENGTH 30, date TYPE D, incidents TYPE ABAP_BOOL, room TYPE C LENGTH 10, time TYPE T, descr TYPE C LENGTH 200, END OF security_struc. ©2010 SAP AG. All rights reserved. / Page 100 结构体的内存分布 TYPES: BEGIN OF security_struc, officer TYPE C LENGTH 30, date TYPE D, incidents TYPE ABAP_BOOL, room TYPE C LENGTH 10, time TYPE T, descr TYPE C LENGTH 200, END OF security_struc. Officer D Room T Incidents Descr 通常没有用到 (if incidents = abap_false) 每条记录存在216个空字符! ©2010 SAP AG. All rights reserved. / Page 101 想法:通过数据引用来访问子结构 TYPES: BEGIN OF security_struc, officer TYPE C LENGTH 30, date TYPE D, incidents TYPE ABAP_BOOL, details TYPE REF TO detail_struc, END OF security_struc. Officer D Room Incidents 每条记录只有一个空的数据引用! TYPES: BEGIN OF detail_struc, room TYPE C LENGTH 10, time TYPE T, descr TYPE C LENGTH 200, END OF detail_struc. T Descr ©2010 SAP AG. All rights reserved. / Page 102 数据引用中的字段不能成为内表的主键: ... TYPE SORTED TABLE OF security_struc WITH UNIQUE KEY details->time. 笨重的数据引用操作: IF security_entry-details IS INITIAL. CREATE DATA security_entry-details. ENDIF. ASSIGN security_entry-details->* TO <details>. 垃圾收集器处理无用的数据对象(不是立即清除) 带数据引用的数据结构不能在RFC里面使用,也不能在EXPORT功能里面使用 数据引用的缺点 语法错误 TYPES: BEGIN OF security_struc, officer TYPE C LENGTH 30, date TYPE D, incidents TYPE ABAP_BOOL, details TYPE REF TO detail_struc, END OF security_struc. TYPES: BEGIN OF detail_struc, room TYPE C LENGTH 10, time TYPE T, descr TYPE C LENGTH 200, END OF detail_struc. ©2010 SAP AG. All rights reserved. / Page 103 解决方案:Boxed 组件 Officer D Room Incidents 每条记录只有一个空的数据引用! T Descr TYPES: BEGIN OF security_struc, officer TYPE C LENGTH 30, date TYPE D, incidents TYPE ABAP_BOOL, details TYPE detail_struc BOXED, END OF security_struc. TYPES: BEGIN OF detail_struc, room TYPE C LENGTH 10, time TYPE T, descr TYPE C LENGTH 200, END OF detail_struc. ©2010 SAP AG. All rights reserved. / Page 104 结构体中Boxed 组件的定义 TYPES: BEGIN OF my_struct, ... boxed_component TYPE structure_type BOXED, ... END OF my_struct. 必须是在TYPES语法里面定义 Boxed类型必须是结构体的一部分、 或者类的成员变量或者静态成员变 量的一部分 只有结构类型可用声明成为 BOXED ©2010 SAP AG. All rights reserved. / Page 105 类中Boxed 组件的定义 CLASS lcl_my_classDEFINITION. PUBLIC SECTION. CLASS DATA: boxed_class_attribute TYPE structure_type BOXED. DATA: boxed_instance_attribute TYPE structure_type BOXED. ENDCLASS. Boxed类型必须是结构体的一部分、 或者类的成员变量或者静态成员变 量的一部分 只有结构类型可用声名为BOXED ©2010 SAP AG. All rights reserved. / Page 106 访问Boxed 组件 Boxed Components可以象普通的结构一样访问: sec-details-time = sy-uzeit. lcl_security=>details-room = ’12 A 5’. Boxed Components可以提供类似普通结构一样有语义的值: lcl_security=>details-room = ’12 A 5’. sec-details = lcl_security=>details. lcl_security=>details-room = ’24 C 3’. sec-details-roomstill contains ’12 A 5’ Boxed组件可以做为内表的主键 Boxed组件可以在EXPORT功能和RFC中使用(必须使用basXML) TYPES: BEGIN OF security_struc, ... details TYPE detail_struc BOXED, END OF security_struc. DATA sec TYPE security_struc. CLASS lcl_security DEFINITION, PUBLIC SECTION. CLASS-DATA: details TYPE detail_struc BOXED. ENDCLASS. ©2010 SAP AG. All rights reserved. / Page 110 Boxed结构的内容 读取类型时初始化记录 内存分配 不会分配内存给boxed结构的语句: 读: time = sec-details-time. 引用根节点结构: ASSIGN sec TO <fs>. GET REFERENCE OF sec TO ref. 会分配内存给boxed结构的语句: 写: sec-details-time = sy-uzeit. 引用boxed结构: ASSIGN sec-details TO <fs>. GET REFERENCE OF sec-details TO ref. 参数传递: obj->meth( CHANGING details = sec-details ). 初始化boxed 引 用 根结构 Boxed 引用 根结构 初始化box: 已分配的box: ©2010 SAP AG. All rights reserved. / Page 111 总结 如下情况不要使用boxed组件: 结构中某一字段使用频率很高 该结构长度小于100个Byte 根结构被数据库表重用 如下情况请使用boxed组件: 结构中的字段通常不被使用,比如: 存储下列情形的详细信息的时候 –出错的时候 –在给定某些可选参数的时候 为某些很少使用的信息做缓存的时候 为某个特定请求而使用的时候 结构长度大于100个Byte Demo DEMO& EXERCISE 演示& 练习