本篇文章来自南大通用GBase技术社区,更多精彩内容请访问 https://www.gbase.cn/community
在数字化转型的征途上,数据库的每一次迁移都是对企业技术架构的一次深刻革新。当企业从DB2迈向南大通用GBase 8s,不仅是数据的简单搬迁,更是应用逻辑、开发环境和数据库操作的全面适配与升级。本文将深入探讨DB2至南大通用GBase 8s应用迁移的各个关键环节,为您提供一份详尽的迁移指南和实用技巧。
1、SQL迁移的微妙差异
临时表的转换
在GBase 8s中,我们可以创建临时表来处理应用中的临时数据,并且临时表数据存储在临时表空间中。系统表不记录临时表的字典信息,从数据库系统表中查询不到临时表的任何相关信息。可以在临时表上创建索引。临时表的作用域为session,当session结束(应用程序断开数据库)、数据库实例关闭或者系统异常关闭后重新启动时临时表由数据库系统自动进行删除。
可以使用SELECT INTO TEMP和CREATE TEMP TABLE两种语法方式创建临时表,较为常用的语法示例为:
Select * from table_name into temp temp_name ;
而DB2的临时表分DGTT和CGTT两种,DGTT和CGTT之间的主要差异在于CGTT的定义是持久存储在DB2目录下的,CGTT在会话中创建并且在会话终止后仍然将持久保存,而DGTT在创建后仅在用户会话期间保存。DGTT可以对应转换到GBase 8s的临时表,但CGTT实际是相当于批量处理数据的工作区。
2、SPL(存储过程语言)的迁移策略
1)SPL概览与迁移
GBase 8s的存储过程和方法都可以看做是UDR(user-defined routines),一个UDR可以使用SPL或是其他外部语言,例如C或JAVA。存储过程就是一个不返回值的程序。SPL语句只能在存储过程中使用,SPL程序以可执行的格式被解析,优化,存储在系统目录表中。
GBase 8s的存储过程支持输入,输出和输入输出参数,并且可以用在SQL语句中任何可以使用表达式的地方。
- 变量定义和赋值:DEFINE, LET
- 流程控制
分支控制:IF
循环控制:FOR,FOREACH,WHILE
EXIT, CONTINUE
函数调用与返回:CALL, SYSTEM ,RETURN
- 错误处理和调试:TRACE, ON EXCEPTION, RAISE EXCEPTION
2)存储过程大小及参数的限制
GBase 8s的存储过程大小限制在64K左右。DB2大于64K的存储过程,在移植时,可以改写成多个小的、互相关联的存储过程,通过传递和返回参数值来交互信息。
GBase 8s的存储过程参数上限是341个,使用JAVA编写的UDR也适用这个限制,C语言编写的UDR最多支持102个参数。Java编写的UDR中DECIMAL数据类型的参数不能超过9个。C语言编写的UDR中如果返回不透明数据类型的值,必须在C宿主变量的定义中指定opaque_type。
3)动态SQL的限制
GBase 8s在存储过程中支持动态SQL。
动态SQL是指可以在运行期间根据用户提供的信息动态地构建和执行的SQL语句。许多数据库应用程序在设计和验证阶段需要动态SQL功能来验证不完全确定的SQL。
EXECUTE IMMEDIATE语句
EXECUTE IMMEDIATE使程序在执行过程中动态执行单个SQL语句变得更加简单。
动态SQL示例
CREATE PROCEDURE create_tab (table_name CHAR(128), column_list CHAR(512))
DEFINE l_crtstmt CHAR(1024);
LET l_crtstmt = "CREATE TABLE " || table_name ||"("|| column_list || " )";
EXECUTE IMMEDIATE l_crtstmt;
END PROCEDURE;
EXECUTE PROCEDURE create_tab ("tmp_cust","cust_num INTEGER,cust_fname CHAR(30)");
3、函数的迁移与适配
1)数字类、字符类函数的迁移
GBase 8s支持一系列的数字和字符类函数,但在函数行为上与DB2存在差异。
名称 | 描述 |
ceil(number) | 查找大于等于number值的整数。 |
floor(number) | 查找小于等于number值的整数。 |
power(number, power) | 与GBase 8s的pow()相同。 |
LENGTH,DB2的LENGTH函数GBase 8s的LENGTH函数在CHAR类型的输出上有不同之处。DB2函数返回的数值包括字符末尾的空格,但GBase 8s函数返回值不包括空格。
ltrim(string1 [, string2]) 从前端截断string1。
示例:
SELECT LTRIM(’Hellohello world!’, ’Hello’) FROM mytab;
输出 hello world!
rtrim(string1 [, string2]) 从后端截断string1。
示例:
SELECT RTRIM(’good night... *!#?theend ’, ’ theend!*#?’) AS closing FROM mytab;
输出 good night...
DB2特有函数
一些DB2特有的字符类函数,GBase 8s并不支持,如SOUNDEX, TRANSLATE.
2)日期类函数的适配
日期类函数在两种数据库中的行为也有所不同。GBase 8s提供的round和trunc函数用于日期时间的四舍五入和截断,而add_months、last_day和next_day等函数则用于日期的计算和处理。
Round/Trunc
round(date/datetime [, fmt])
trunc(date/datetime [,fmt])
Fmt:
YEAR
MONTH
DD (day of the month)
DAY (day of the week)
HH (hour)
MI (minute)
extent(‘2014-2’,year to second)+12*interval(1) hour to hour
Round | Trunc |
datetime year to fraction(5) column, col_dt: 2014-12-07 14:30:12.12300 > select round(col_dt, 'YEAR') from mytab (expression) 2015-01-01 00:00 > select round(col_dt, 'MI') from mytab (expression) 2014-12-07 14:30 | datetime year to fraction(5) column, col_dt: 2014-12-07 14:30:12.12300 > select trunc(col_dt, 'YEAR') from mytab (expression) 2014-01-01 00:00 > select trunc(col_dt, 'MI') from mytab (expression) 2014-12-07 14:30 |
add_months(date/datetime, integer)返回date/datetime类型
为date或datetime的数据类型以月为单位增加。
示例
select dcol, add_months(dcol, 1)
as add_one_month from date_tab;
dcol add_one_month
02/28/2015 03/28/2015
02/29/2016 03/29/2016
01/29/2015 02/28/2015
03/31/2015 04/30/2015
last_day(date/datetime) 返回date/datetime
返回当月的最后一天相的应值。
select today as today, last_day(today) as last,
last_day(today) - today as days_left from systables where tabid = 1;
today last days_left
03/12/2015 03/31/2015 19
next_day(date/datetime, char(3)) 返回date/datetime
返回从参数1开始,参数2指定的星期x,date/datetime类型。
示例
select ship_date, next_day(ship_date, 'SAT') as next_saturday,
next_day(ship_date, 'SAT') - ship_date as num_days from orders;
ship_date next_saturday num_days
06/01/2014 06/03/2014 2
02/12/2015 02/17/2015 5
months_between(date/datetime, date/datetime) 返回两个日期间的月数。
示例
select col_datetime, col_date, months_between(col_datetime, col_date) as months_between from mytab2;
col_datetime 2015-12-13 08:40:30.00000
col_date 11/13/2014
months_between 13.0000000000000
SYSDATE
GBase 8s支持SYSDATE来返回一个系统当前时间,默认格式为YEAR TO FRACTION(5),另一个时间常用关键字CURRENT的默认格式为YEAR TO FRACTION(3),SYSDATE可以看做是CURRENT的一个同义词。
TO_DATE()
标识 | 含义 |
-/,.;:”text” | 标点符号和引号文本会复制到输出结果中。 |
AD or A.D. | 公元 |
AM or A.M. | 上午 |
BC or B.C. | 公元前 |
CC or SCC | 世纪,S用 “-“表示公元前 |
D | 一周的第几天 (1 -7). |
DAY | 9位长度的英文星期表示,空缺用空格填充。 |
DD | 一月中的第几天 (1 -31). |
DDD | 一年中的第几天 (1 -366). |
DY | 星期的缩写. |
IW | ISO 一年中的第几周(1-53) |
IYY or IY or I | ISO年的最后的三、二、一位 |
IYYY | ISO 标准显示的4位年. |
HH or HH12 | 12格式的小时 (1 -12). |
HH24 | 24格式的小时 (0-23). |
J | 从公元前4712一月一日开始的天数。 |
MI | 分钟 (0-59). |
MM | 两位阿拉伯数字显示的月份(01 -12; JAN = 01) |
MONTH | 月份的英文全称,9位字符,使用空格填充空缺 |
MON | 月份的英文简写 |
RM | 落马数字显示的月份 (I-XII; JAN = I). |
Q | 一年中的第几个季度(1, 2, 3, 4; 一至三月 = 1) |
RR | 年号的后两位 |
WW | 一年中的第几周(1-53) |
W | 一个月中的第几周 (1 -5) |
PM or P.M. | 下午 |
SS | 秒 (0-59). |
SSSSS | 当天经过的秒 (0-86399). |
Y/YYY | 使用/分隔的年 |
YEAR or SYEAR | 拼写出的年,S用 “-“表示公元前 |
YYYY or SYYYY | 4为年,S用 “-“表示公元前 |
YYY or YY or Y | 年的最后的三、二、一位 |
3)位操作和特殊函数的迁移
GBase 8s支持的位操作类函数比DB2更为丰富。同时,DBINFO函数在GBase 8s中用于返回数据库相关信息,其使用方式需根据GBase 8s的特点进行适配。
GBase 8s支持以下二进制函数
bitand(arg1, arg2)
bitor(arg1, arg2)
bitxor(arg1, arg2)
bitnot(arg1)
bitandnot(arg1, arg2)
以上函数中DB2仅支持bitand。
arg1, arg2 可以使任意的数字类型值,使用时会被转化成64位整形值。
小数数值在转换时会被自动截断。
bitnot的参数最大值为9,223,372,036,854,775,806。
特殊函数 DBINFO()
DBINFO实际上是一组函数,返回不同类型的数据库的相关信息。在参数位置指定一个特定的选项,就可以调用相应的函数功能。可以在SQL语句和UDR中使用DBINFO选项。
参数 | 返回值说明 |
('dbhostname') | 应用程序连接的数据库服务器的主机名 |
('dbname') | 应用程序连接的数据库名称 |
('dbspace' tblspace_num) | tblspace number 对应的 dbspace 名 |
('get_tz') | 时区 |
('serial8') | 插入表中的最后一个SERIAL8值 |
('bigserial') | 插入表中的最后一个BIGSERIAL值 |
('sessionid') | 当前会话的会话号 |
('cdrsession') | 线程是否执行了企业级复制(ER)操作 |
('sqlca.sqlerrd1') | 插入表中的最后一个SERIAL值 |
('sqlca.sqlerrd2') | 已经被SELECT, INSERT, DELETE, UPDATE, EXECUTE PROCEDURE, 和 EXECUTE FUNCTION 语句计算过的行数 |
('utc_current') | SQL执行时刻的UTC时间值(从1970-01-01 00:00:00+00:00计算的整数秒) |
('utc_to_datetime', table.column) | 将指定字段存放的整数值当做UTC时间值转换成DATETIM值 |
('utc_to_datetime', utc_value) | 将UTC时间值转换成DATETIM值 |
('version', 'parameter') | 应用程序所连接的数据库服务器类型和它的版本号 |
GBase 8s支持的函数列表如下:
ABS | DECRYPT_CHAR | NVL2 |
ACOS | ENCRYPT_AES | OCTET_LENGTH |
ACOSH | ENCRYPT_TDES | POW |
ADD_MONTHS | EXP | QUARTER |
ASCII | EXTEND | RANGE |
ASIN | FLOOR | REPLACE |
ASINH | FORMAT_UNITS | ROOT |
ATAN | GETHINT | ROUND |
ATAN2 | HEX | RPAD |
ATANH | INITCAP | RTRIM |
AVG | LAST_DAY | SIN |
BITAND | LENGTH | SQLCODE(SPL) |
BITANDNOT | LOCOPY | SQRT |
BITNOT | LOG10 | STDEV |
BITOR | LOGN | SUM |
BITXOR | LOTOFILE | TAN |
CARDINALITY | LOWER | TANH |
CEIL | LPAD | TO_CHAR |
CHAR_LENGTH | LTRIM | TO_DATE |
CHR | MAX | TO_NUMBER |
CONCAT | MDY | TRIM |
COS | MIN | TRUNC |
COUNT | MOD | UPPER |
DATE | MONTH | VARIANCE |
DAY | NEXT_DAY | WEEKDAY |
DBINFO | NULLIF | YEAR |
DECODE | NVL |
4、开发环境的配置与优化
1)语言环境的设置
GBase 8s可以支持许多语言、文化和代码集。所有特定于文化的信息汇集于单个环境中,称为 Global Language Support(GLS)语言环境。除了 ASCII 美国英语之外,GLS 允许您在其他语言环境中工作并在 SQL 数据和标识中使用非 ASCII 字符。可以使用 GLS 功能来与特定语言环境定制保持一致。语言环境文件包括特定于文化的信息,如货币和日期格式以及整理顺序。
GBase 8s通过 DB_LOCALE 和 CLIENT_LOCALE 来设置数据库的语言本地化支持设置。正确设置GLS语言环境相关变量(DB_LOCALE, CLIENT_LOCALE),保证GBase 8s数据库服务器、客户端能正确的支持中文字符和支持使用中文的对象名。DB_LOCALE 和 CLIENT_LOCALE 的值由四部分组成(第 4 部分为可选),字符集不区分大小写:
1 | 2 | 3 | 4 |
< 语言 >_ < 国家和地区 > . < 字符集名 / 字符集编码 > [@modifier] |
举例说明 :
CLIENT_LOCALE=en_us.8859-1
CLIENT_LOCALE=en_us.819
# 以上两个为同一字符集:819 为 8859-1 的编码
DB_LOCALE=zh_cn.gb
数据库服务端
在创建数据库时(为了统一系统数据库与应用数据库的字符集,在创建数据库实例时),请按如下步骤设置数据库的DB_LOCALE值。
1.设置环境变量DB_LOCALE
set DB_LOCALE=zh_cn.gb
2.创建数据库create database dbname
3.验证当前数据库字符集
SELECT dbs_collate FROM sysmaster:sysdbslocale
WHERE dbs_dbsname = ‘database_name’
客户端
4.当我们使用ODBC/JDBC连接数据库时,我们需要在连接信息中正确设置语言环境变量:
DB_LOCALE和CLIENT_LOCALE。
5.设置语言环境变量
DB_LOCALE=zh_cn.gb
CLIENT_LOCALE=zh_cn.gb
特别注意,在创建数据库前请设置好环境变量DB_LOCALE为规划的字符集,因为数据库一旦创建就不能修改其字符集,除非重新创建。
在默认情况下GBase 8s将使用en_us.8859-1字符集。
支持的中文字符集有
字符集名称 |
utf8 |
gb |
gb18030-2000 |
big5(ILS) |
Shift-Big-5(ILS) |
ccdc(ILS) |
2)JDBC的配置
- 安装配置 JDBC
JDBC Driver 安装软件集成在CSDK软件安装包中,也可以下载单独的JDBC安装包。安装完 JDBC Driver 后,需要将文件 ifxjdbc.jar 添加到环境变量 CLASSPATH 中。
- 设置JDBC Driver 环境变量
CLASSPATH=${CLASSPATH}:${GBASEDBTDIR}/jdbc/lib/ifxjdbc.jar
export CLASSPATH
- 设置JDBC连接字符串
在Java程序中使用JDBC连接数据库,首先应该加载使用的 JDBC 类,JDBC Driver的类名为com.gbasedbt.jdbc.IfxDriver。
建立Java程序与GBase 8s数据库的连接需要使用 DriverManager.getConnection() 方法,该方法中的URL参数为一个数据库的连接字符串,指定数据库的连接信息。使用不同的 JDBC 所需的 URL 参数也不相同。
使用JDBC Driver 连接数据库,连接字符串的格式如下:
jdbc:gbasedbt-sqli://[{ip-address|host-name}:{port-number|service-name}][/dbname]: GBASEDBTSERVER=servername[{;user=user;password=password] |CSM=(SSO=database_server@realm,ENC=true)} [;name=value[;name=value]...]
其中,“jdbc:gbasedbt-sqli”指定使用的JDBC为JDBC Driver;
“{ip-address|host-name}”为数据库服务器的IP地址主机名;
“{port-number|service-name}”为数据库服务器监听客户端连接的端口号或服务名;
“dbname”为数据库名;
“servername”为数据库实例名。
URL示例:
jdbc:gbasedbt-sqli://10.13.147.9:9088/sysmaster:GBASEDBTSERVER=demoserver
jdbc:gbasedbt-sqli://9.125.66.130:6346/db18030:GBASEDBTSERVER=instance_name; NEWCODESET=gb18030,gb18030-2000,5488;DB_LOCALE=zh_cn.gb18030-2000;CLIENT_LOCALE=zh_cn.gb18030-2000;
- 环境变量
GBase 8s常用环境变量:
参数名 | 说明 |
GBASEDBTDIR | 数据库安装路径 |
GBASEDBTSERVER | 实例名 |
ONCONFIG | 配置文件名称 |
DB_LOCALE | 数据库字符集 |
CLIENT_LOCALE | 客户端字符集 |
PATH | 路径(必须包含$GBASEDBTDIR/bin) |
数据库应用的迁移不仅仅是技术的转移,更是企业适应新技术、优化业务流程、提升服务质量的契机。DB2至南大通用GBase 8s的迁移过程中,每一个细节都可能影响到最终的应用性能和用户体验。
随着技术的不断演进,数据库应用迁移将成为企业技术升级的常态。我们期待,通过本系列文章的分享,能够帮助更多的企业在迁移的征途上,规避风险,把握机遇,实现技术与业务的双重飞跃。