月度归档:2014年09月

CI连接Oracle 11G数据库

CI连接Oracle 11G数据库

CI框架算是个人最喜欢的PHP框架之一,易用性上没的说,还有完备的中文文档,不过大多数时候是搭配MySQL一起使用。

不过最近接触的一个项目使用的是Oracle 11G数据库,开发前给大家搭环境的时候发现连接有一些问题,主要来说是安装配置上的一些问题。

环境

  • CodeIgniter 2.2.0
  • Oracle 11G R2
  • CentOS 6.4
  • PHP 5.2

扩展安装

首先CI本身是能支持Oracle数据库的,在DB Driver的代码中可以明确地看到,下面需要的就是安装oci8扩展了。

oci8扩展在安装上和其他的PHP扩展没有太多的区别,稍微有点区别的是需要下载安装一个Instant Client,Windows下的下载安装倒也还算顺利,然后Linux下的下载真是让人哭笑不得了,因为页面上的js错误,点击我同意按钮之后是不会出现熟悉的下载功能的,即各个链接仍然连接到本页,不过没有关系,看了下页面源码,还是找出了rpm包的实际下载链接(当然这个也是要注册Oracle的账户才能下载的)。

http://download.oracle.com/otn/linux/instantclient/112010/oracle-instantclient11.2-basic-11.2.0.1.0-1.x86_64.rpm

同时还需要安装devel包否则在编译扩展时会出现找不到头文件的情况。

http://download.oracle.com/otn/linux/instantclient/112010/oracle-instantclient11.2-devel-11.2.0.1.0-1.x86_64.rpm

之后就是常规的phpize && configure && make && make install了。

多说一句,如果通过rpm包安装了sqlplus之后不能使用,出现诸如:

sqlplus64: error while loading shared libraries: libsqlplus.so: cannot open shared object file: No such file or directory

的问题时,可以考虑通过:

export LD_LIBRARY_PATH=/usr/lib/oracle/11.2/client64/lib:$LD_LIBRARY_PATH

的方式来解决。

CI配置

下面来看在autoload配置文件中已经配置了autoload database配置的情况下CI的配置。

网上对于CI的配置主要区别在hostname这一个项目,有写成tnsnames.ora样式的,这个自己没实验成功,最后读了一下CI连接部分的代码,确定了连接中hostname配置应该是:

//数据库IP:数据库端口/数据库名称

最终连接成功的配置如下:

$db['default']['hostname'] = "//192.168.1.200:1521/db200";
$db['default']['username'] = 'learn';
$db['default']['password'] = '123456';
$db['default']['database'] = '';
$db['default']['dbdriver'] = 'oci8';

db200是dbca安装数据库时指定的名称。

环境搭好之后开发自然是要开始了。

以上。

又写了一个Hello world

又写了一个Hello world

近期有两天没有需求的日子,下周leader说让我去和前端学习一下,不过要先写个通关作业简单了解一下js。于是花两天时间又写了个Hello world。

简单记录一下,代码包含大量的调试语句,暂时不贴代码,后期还得试着填坑,写出一个完善的hello world。

要求

这个通关作业要求主要有下面一些东西:

  • 用Node.js自己实现一个简单的Http服务,实现BigPipe输出页面
  • 通过$Import加载js依赖模块
  • 通过register方式注册js模块
  • 实现自定义事件的支持,以及广播与事件代理

时间所限,自己只在chrome上完成了测试。

实现

整体设计

虽然是个Hello world,但是还是简单的思考了一下结构,大致的流程如下图:

流程图

Http服务

Node.js的Http模块的使用例子几乎是学习Node.js各类教程的标配了(比如七天学会Node.js……),实现的过程中基本上也是沿用了基本的写法。

其实感觉直接使用Express完成。

加载依赖模块

js代码如果能够把每一个部分代码拆分出来单独开发,只加载所需模块,那么对于开发维护,以及网络开销以及用户的体验上个人觉得都是有很大的帮助。自己理解是这一方式可以在浏览器端完成(比如requirejs最近同学推荐的seajs),也可以在服务器端通过主动的合并成单一文件返回给用户。

作业里面的方式是通过在服务器端合并的方式进行的。

由于对Node.js的异步编程思想并没有完全掌握,原先希望的通过异步的加载依赖文件的方式实现了一个下午也没有实现,眼看deadline就要到了,只能换成递归的方式进行处理,依赖文件首先读取并输出。

中间使用了UglifyJS2先对代码进行压缩操作,减小返回数据的大小,顺路去掉注释,简化匹配$Import语句使用的正则表达式。

在所有依赖完成读取之后,添加业务逻辑代码。

BigPipe

BigPipe工作中经常接触,这里的实现并没有特别之处,仍然是首先输出骨架,之后输出各个Pagelet。

具体来说这里使用了Node.js提供的信号功能,骨架输出完成之后会发出骨架已输出(设为skeleton_ready),同时计数器设定为Pagelet的数目。之后监听这一信号的各个Pagelet开始执行计算,完成之后直接输出用于渲染的<script>标签。骨架部分同时会监听Pagelet输出完成信号(设为pl_ready),之后计数器-1,当计数器为0时输出封闭标签</body></html>

Node.js通过repsonse对象的write方法返回值就能确定缓冲区是否已经刷新(参见文档),类似的,通过PHP实现的话还需要手动的进行ob_flush && flush。

从页面代码上看,大致是这样的一个效果:

代码效果

register

这里方法名任意,register的意义在于将当前的Pagelet(以下简称pl)的业务代码加入到当前运行环境中,register作为一个方法,第一参数为模块名称,也就是代码的路径,第二参数即为对应的回调方法。

register方法根据参数1,将回调方法绑定到指定的节点上,例如当前js对象的名称为Xe,pl的名称为pl.index.top,回调方法为func1(){...},那么在register操作完成之后就可以通过Xe.pl.index.top()调用func1(){...}

所有的依赖模块都通过这一方式进行组织。

自定义事件

对于自定义事件,目前了解到的应用场景,主要是单个pl中的模块之间的通信,实现上简单的通过保存自定义事件以及对应的回调方法的对应关系,通过对象的call方法调用自定义事件对应的回调方法。

为了能让回调能够异步的执行,还需要使用setTimeout方法。

广播

广播用于pl之间的通信,实现方式与自定义事件类似,但是不同点在于,广播中是通过频道对象调用回调方法,在每个频道中维护广播事件与回调之间的关系。

同理,也需要结合使用setTimeout方法。

使用上,每个模块都需要import这一个频道,同时向这个频道订阅指定的事件,绑定对应的回调方法。

事件代理

目前事件代理做法是将事件绑定到pl的顶部节点中,同时阻止事件进一步冒泡,由pl的顶级节点处理。

每个事件代理上都有一个对象维护回调方法与节点的对应关系。自己的实现中所有的节点绑定方法都会绑定一个共有的事件处理方法,在这一个方法中获取节点类型以及事件信息,之后调用具体的事件处理回调方法。

Todo

  • js依赖文件的异步加载

其他

有关静态服务器的实现,读了@朴灵大神文章《Node.js静态文件服务器实战》感觉有些启发。