最近对蓝星际语音平台数据库访问的接口进行了优化和功能升级,使用Koodoo语言来访问数据库更加简单方便了,而且在语音平台核心部分采用了连接池机制,对于大容量应用性能提升十分明显,而且可以不用原来频繁采用的线路间函数调用,可以在物理线路上直接写SQL语句来访问数据库。
那我们就先来谈谈连接池。我们做语音IVR或CTI方面应用,在很多情况下单机的线路数是很多的,蓝星际语音平台的很多电信用户都达到了单机24E1,也就是720线/机,因为Koodoo语言的脚本是部署在每条单独的线路上运行的,如此高的容量,如果每条线路都去连接数据库的话,除了数据库本身有连接数限制以外(很多商品化数据库以连接数作为许可卖钱),大量的连接将造成性能的急剧下降。
为了解决这个问题,市场上的大部分语音平台采用外部数据库网关的方式,流程编写者需要在网关上用C/C++或其他高级语言编写数据库访问的服务,语音平台的流程脚本则通过TCP/IP等方式访问数据库网关,这种方式的弊端很明显,一是需要部署额外的数据库网关,增加管理复杂性,二是存在通讯开销会降低性能,而且因为序言网络通讯,因此对于数据结果集大小有限制。此外也很难进行调试,故障点增加了,一旦出问题往往不知道在哪个环节。
Koodoo语言提供了虚拟线路和线路间通讯的机制,我们可以在虚拟线路上运行编写好的数据库访问服务的脚本,把常见的业务封装成函数,函数内是实际的SQL语句,在物理线路上编写同名的函数,参数顺序也一样,物理线路上的函数会自动调用数据库服务脚本中的同名函数。每个虚拟线路相当于一个连接,可以配置多几条虚拟线路运行相同的数据库服务脚本,我们的系统会自动进行分配,让当前最空闲的虚拟线路去进行处理,这其实就是连接池的概念。因为物理线路和虚拟线路是运行在同一个进程空间内的线程,他们之间通过内存进行消息通讯的,所以性能很好,而且虚拟线路上的脚本和物理线路上的脚本都是用Koodoo 语言来完成,整合起来也还算方便。额外的好处是,线路间函数调用的方式要求把业务分解成一个个的函数,等于强制的模块化,对于业务功能的整理和维护带来了好处。
但是,这种方式还是存在一些不方便之处,比如相同的业务函数要写两遍,要保证相同的函数名字和参数顺序,如果业务发生修改,则同时要修改两个地方,难免挂一漏万,也增加调试的复杂性,也就是不方便重构。此外,在开发平台没办法调试,因为要两个脚本在两条线路上运行,所以往往在开发平台写出来的脚本不能部署到运行平台,还要根据上面的方法进行改写,拆成服务端脚本和调用端脚本。最后,因为封装成函数,如果有多条记录返回,则不太好处理,因为函数只是参数形式返回,如果要在一个结果集里面循环处理,则颇为不便。
从V1.87版本开始,系统内嵌连接池,这种方法可以大大简化数据库的编程。在运行平台配置文件BsTelRun.cfg中增加了一个新的配置项:
DB_MAX_CONN = 5 // 最大数据库连接数,如为0则不受限制
按上面配置后,假设1000条线路上都运行相同的脚本,他们都连接相同的数据库,但根据应用流程在中途执行不同的SQL操作,那么在脚本开始部分,使用DbOpen()进行连接的时候,系统内部会自动维护一个连接池(对于相同连接参数),池里面最多只有 5个连接。
那么在某线路在具体执行SQL语句的时候究竟采用哪个连接呢?系统会从连接池里面找一个空闲的连接执行SQL操作,结果集则返回给调用的线路。如果当前连接池里面的全部连接都在忙,则系统会等候,直到有空闲的连接,或者超时。由此可见,这种方法是很高效的,不需要额外的虚拟线路,而且数据库操作的函数完全做到了兼容。在开发平台写好的脚本,可以直接部署到运行平台。
如果物理线路很多,SQL调用比较繁忙,则可以通过调大配置文件中的DB_MAX_CONN配置项,来达到优化的目的。当然,如果你还是喜欢线路间函数调用的方式,或者原来的代码是线路间函数调用的方式,不想花时间改用新方式,也没有问题,照样可以工作的很好,系统做到了完全兼容。
除了性能提升和编程方式的简化,新版本增加了一个函数,可以将结果集和数组绑定,这是个非常方便的功能:
3.9 执行一个SQL命令并将结果集映射到数组: DbExecMap(iHd, cmd, m, indexType, keyFieldName);
参 数:iHd - 操作句柄,已经打开的数据库连接
cmd - 合法的SQL命令,可以是SQL语句或存储过程调用
m - 数组变量: m[下标1][下标2], 下标1表示行(记录), 下标2表示列(字段)
indexType - 指出下标2的类型, 0-用0开始的连续数字作下标,
1-用字段名作下标, 2-将字段名转换成大写作下标, 3-将字段名转换成小写作下标
keyFieldName - 如果为字符串,则表示键值字段名,如果为""则表示下标1为整型记录号, 从1开始
如果为整型数,表示指出字段编号,为从0开始的顺序号
原来要取结果,必须用下面几个函数配合使用,比较麻烦:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
新版本只要用一个DbExecMap()就轻松搞定了,以数组表示的结果集,显得更加直观,也能够修改结果集的内容(只是改数组的值,不会回写到数据库)。
我还是举例来说明一下吧,“代码不会骗人”:假设数据库里面有一张表tUsers, 里面有这几个字段:Name(姓名),Sex(性别),Note(说明);其中姓名是Key字段,每条记录的 Name都不相同。那么我们可以执行这样的操作:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
那我们就可以这样来直接操作结果集了:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
当然,数组m会占用一定的内存,如果要将m占用的内存释放,可以这样:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
最新版本的Koodoo语言还增加了集合运算,这样可以对异构的数据库结果集进行运算:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
连接池让蓝星际语音平台具有现代应用服务器的性能,结果集绑定到数组则让数据处理更加直观,高效+直观,就是我们所追求的目标。
bluesen 2007.3 于深圳