分类:Oracle
解决 yii oracle date 类型 默认值 bug
主要问题出在yii对这种类型的读取和保存都有异常,会丢失时间.
解决方式
一、设置当前会话的日期格式,在beforeSave里调用
alter session set nls_date_format = 'yyyy-mm-dd hh24:mi:ss'
二、ar保存时,使用
if(isset($this->create_time)) $this->create_time=new CDbExpression('create_time');
误区
因为时间格式默认不同于 Y-m-d H:i:s 所以bindValue时,oci当成了字符串。。。哥绕了一圈去修改框架,血的教训啊。。我擦。。。
当格式统一后,bindValue 就保持有效了。可以不使用方式二那种蹩脚的处理方式
修复Yii ar 在win环境下 oci_pconnect 访问慢问题
同样的代码,在linux 环境下的 apache访问速度就正常,一样是链接外部数据库。
在开发环境中win(php5.2)链接测试机linux数据库访问里,速度会慢。还是用oci_pconnect的情况下.
折腾过php的不同版本 5.4 ts nts 这些版本。速度依旧烂。
测试机内部apache访问时,速度不慢。觉得是出在win上。
这块无解。尝试分析各sql访问上的速度问题.
log 补充 trace 打印出sql访问日志,单条进行数据分析
'log' => array ( 'class' => 'CLogRouter', 'routes' => array ( array ( 'class' => 'CFileLogRoute', 'levels' => 'trace, error, warning' ) ) ),
发现ar 在获取结构时,一次要花费约1s左右。
其它访问速度正常。
ar开启缓存。第一次访问时较慢,后续访问均明显变快,和原来mysql环境下差不多。
'db' => array ( 'class'=>'ext.oci8Pdo.OciDbConnection', 'connectionString' => 'oci:dbname=//xxx/xx;charset=UTF8;', // 开启表结构缓存(schema caching)提高性能 'schemaCachingDuration'=>3600, ),
oracle 常用命令收集,持续更新
-----------------------------------------------oracle 修改字段类型 ,有数据情况下修改 -- 插入新的列 注意类型和不要和原来的列冲突 ALTER TABLE tb_test ADD permile_temp NUMBER (5, 2); -- 更新老数据到新的列 UPDATE tb_test SET permile_temp = permile; -- 老列重命名或者删除即可(有数据的情况下可以修改名字) ALTER TABLE DROP COLUMN permile; -- 修改名字成自定的列,完成字段类型修改 ALTER TABLE TEST RENAME COLUMN permile_temp TO permile; -- 没有数据,可能需要进行提交 COMMIT; ----------------------------------------------- --当前的连接数 -- 需要dba权限 SELECT COUNT (*) FROM v$process; -- 查询出锁死的session -- 需要dba权限 SELECT object_name, machine, s. SID, s.serial# FROM v$locked_object l, -- 需要dba权限 dba_objects o,-- 需要dba权限 v$session s -- 普通权限即可查询。不过无法进行相关处理. WHERE l.object_id = o.object_id AND l.session_id = s. SID; -- 关闭锁死的session ( 使用两个参数,上面查询出来的 sid 和 serial ) ALTER SYSTEM KILL SESSION '319,1948'; -- 需要授权
YII mysql 迁移 oracle 小写处理
因为框架内联绝大多数代码是未进行引号包裹的。
oracle 纯sql的情况下,默认当做大写,影响很大。只能统一数据库和字段,表名大写转移。
Ar 兼容小写处理
编写 CActiveRecordO 集成 CActiveRecord
修改以下函数进行小写兼容
$model->field
public function __get($name) { $upname = strtoupper ( $name ); if (isset ( $this->_attributes [$upname] )) { return $this->_attributes [$upname]; } elseif (isset ( $this->getMetaData ()->columns [$upname] )) return null; elseif (isset ( $this->_related [$name] )) return $this->_related [$name]; elseif (isset ( $this->getMetaData ()->relations [$name] )) return $this->getRelated ( $name ); else return parent::__get ( $name ); }
$model->field=val;
public function __set($name, $value) { $upname = strtoupper ( $name ); if (($this->setAttribute ( $name, $value ) === false && $this->setAttribute ( $upname, $value ) === false)) { if (isset ( $this->getMetaData ()->relations [$name] )) $this->_related [$name] = $value; else parent::__set ( $name, $value ); } $name = $upname; }
empty($model->field) //判断
public function __isset($name) { $upname = strtoupper ( $name ); if (isset ( $this->_attributes [$upname] )) return true; elseif (isset ( $this->getMetaData ()->columns [$upname] )) return false; elseif (isset ( $this->_related [$name] )) return true; elseif (isset ( $this->getMetaData ()->relations [$name] )) return $this->getRelated ( $name ) !== null; else return parent::__isset ( $name ); }
默认 getAttributes setAttributes 抱成别的函数进行重写,因为内部调用太多地方,不可直接重写该函数,另外编写函数getAttributesWithO 之类的即可
public function getAttributesWithO($names = true) { $attributes = $this->getAttributes ( $names ); $attributes = array_change_key_case ( $attributes, CASE_LOWER ); return $attributes; } public function setAttributesWithO($attributes = array(), $safeOnly = true, $hasClob = false) { $attributes = array_change_key_case ( $attributes, CASE_UPPER ); if ($hasClob && $this->getMetaData ()->columns && is_array ( $this->getMetaData ()->columns )) { foreach ( $this->getMetaData ()->columns as $key => $column ) { if (stristr ( $column->dbType, "CLOB" ) && empty ( $attributes [$key] )) { $attributes [$key] = ''; } } } $this->setAttributes ( $attributes, $safeOnly ); } public function getClobByKey($key) { if (! empty ( $this->$key ) && is_object ( $this->$key ) && get_class ( $this->$key ) == 'OCI-Lob') { $this->$key = $this->$key->read ( 50000 ); } }
pdo 对clob各种奇葩问题。需要调整pdo为oci8相关处理
http://www.yiiframework.com/extension/oci8pdo/
public function afterFind() { $this->getClobByKey ( 'description' ); return true; }
内部组件需要进行特殊处理。
主要出现在需要调用数据库实现相关功能的组件,如:CDbAuthManager,CDbHttpSession
重写相关即可
主要为大小写冲突问题。
public function hasItemChild($itemName,$childName) { return $this->db->createCommand() ->select('parent') ->from($this->itemChildTable) ->where('parent=:parent AND child=:child', array( ':parent'=>$itemName, ':child'=>$childName)) ->queryScalar() !== false; }
select (‘parent’) 会返回 select “parent” 导致大小写异常,where parent =又是小写处理,纠结吧。。。
所以只能将被小写了的地方进行大写转换处理。
将被大写返回的数组,需要进行小写转换下。
$row=array_change_key_case ( $row, CASE_LOWER );
oci 修复个setFetchModel的小异常问题,兼容有点问题,不过只在权限判断中出现,其它暂时未发现
http://www.php.net/manual/en/pdostatement.setfetchmode.php
public function setFetchMode($mode, $colClassOrObj = null, array $ctorArgs = array()) { // yii 内部调用 // parent::setFetchMode($mode,$colClassOrObj,$ctorArgs); // return true; if ($mode == PDO::FETCH_COLUMN||$mode==PDO::FETCH_ASSOC) { $this->_fetchMode = $mode; return true; } // 52: $this->_statement->setFetchMode(PDO::FETCH_ASSOC); if ($colClassOrObj !== null || ! empty ( $ctorArgs )) { throw new PDOException ( 'Second and third parameters are not implemented for Oci8PDO_Statement::setFetchMode()' ); // see http://www.php.net/manual/en/pdostatement.setfetchmode.php } $this->_fetchMode = $mode; return true; }
php 序列生成工具
<?php /** * * 现在简单实现,可以处理成,根据对应的表,生成对应的序列进行生成,主要同步自增id * */ class OracleTools { /** * 通过序列获取最新的id * 如果制定表,如果表不存在,则创建新表。并以原表的id+1000的数据添加. * 可以单独指定需要序列的表名和id */ public static function getNewId($seqname = "common", $id = "id", $tablename = "", $maxvalue = 0, $startbyzero = false) { $sseqname = $seqname; if (empty ( $tablename )) $tablename = $seqname; $seqname = "O2O_SEQ_{$seqname}"; $exists = sql_fetch ( "SELECT count(1) existsrow FROM all_sequences WHERE sequence_name = '$seqname' AND sequence_owner = '" . Yii::app ()->db->username . "'", 'existsrow' ); if (! $exists) { $lastid = 1; if (! $startbyzero) { $lastid = sql_fetch ( "SELECT {$id} FROM {$tablename} WHERE ROWNUM =1 ORDER BY {$id} DESC ", $id ); $lastid += 1000; } if (! $maxvalue) { $maxvalue = '9999999999999999'; } sql_execute ( "CREATE SEQUENCE {$seqname} start WITH {$lastid} increment BY 1 MAXVALUE {$maxvalue} minvalue 1 cycle" ); } $id = sql_fetch ( "SELECT {$seqname}.nextVal newid FROM dual", 'newid' ); return $id; } public static function dropSeq($seqname = "common") { $seqname = "O2O_SEQ_{$seqname}"; sql_execute ( "DROP SEQUENCE {$seqname} " ); } }
YII MYSQL 转移至 Oracle
1.字段大小写有所不同,特别注意,mysql不区分在小写,oracle区分大小,如果使用小写需要用“”进行引起。如yii ar 自定义t,在相关使用时,需要用“t”进行表示。
$criteria->order .= '"t".ID desc'; $models = AdminLog::model ()->with ( 'admin' )->findAll ( $criteria );
2.逻辑上,分组排序不同于mysql,需要用
$criteria->select = "ICON,ROW_NUMBER () OVER ( PARTITION BY ICON ORDER BY ordernum asc )"; // $criteria->group = "ICON"; $models = Menu::model ()->findAll ( $criteria );
3.主键自增也有所不同,凡原来涉及insert null操作相关地方,需要用OracleTools::getNewId()获取id进行替换,现在使用通用序列,后需特殊字段,需要进行特殊处理
protected function beforeSave() { $this->ID = OracleTools::getNewId (); if ($this->hasEventHandler ( 'onBeforeSave' )) { $event = new CModelEvent ( $this ); $this->onBeforeSave ( $event ); return $event->isValid; } else return true; }
<?php /** * * 现在简单实现,可以处理成,根据对应的表,生成对应的序列进行生成,主要同步自增id * */ class OracleTools { const TABLE_COMMOON = "seq_common"; /** * 通过序列获取最新的id */ public static function getNewId($tablename = "seq_common") { $id = sql_fetch ( "SELECT seq_common.nextVal newid FROM dual", 'newid' ); return $id; } }
mysql 表结构+数据 转 oracle
一、命令操作(没有试过)
参考:
http://stackoverflow.com/questions/8395612/how-to-convert-a-mysql-database-to-an-oracle-database
官方参考:
https://dev.mysql.com/doc/refman/5.1/en/mysqldump.html
二、工具操作(只考虑短期简单的):
参考:
Convert Mysql to Oracle
http://dbmover.com/download/mysqltooracle_cn.zip
需要注意:
1. 特殊类型会导致数据不出来,如(tinyint)
2.主键会丢失,需要重新设置
3. 特别需要留意大小写的问题.oracle 默认是将字段转换为大写。如果有小写的字段,需要用”包起来。mysql默认是大小兼容.
4.特殊字段需要注意 id ,uid 这类会识别有问题。不用“”包括会出问题。
注:导出数据表,用eclipse之类的快速转大写工具,将表结构转成大写(字段,以及相关主键关联:以navicat为例,表结构在各自数前。主键关联在最底部),再回导。
三、相关比对和注意事项(长期处理的,多了解点总是好的。)
http://www.cnblogs.com/yan5lang/archive/2010/03/08/1680649.html
转发请注明出处http://blog.martoo.cn
如有漏缺,请联系我 QQ 243008827
yii 跨mysql & oracle 实现同表数据同步解决方案
只限数据,不涉及其它。
oracle 数据库ar使用
参考:http://blog.martoo.cn/?p=459
oracle 编码注意事项
编码需要在connectionString 后指定 .charset
直接配置charset 无效..
'odb'=>array( 'class'=>'CDbConnection', 'connectionString'=>'oci:dbname=//xxxxxxx/xxx;charset=utf8;', 'username'=>'xxxx', 'password'=>'xxxx', 'charset'=>'utf8', 'tablePrefix'=>'xxx_' ),
需要明白一个点。任何业务流程操作后,最终只在数据这块同步。
所以yii 原ar的修改只需要在save 动作之后,同步数据。
即afterSave 事件处理.
demo:
public function afterSave(){ if($this->hasEventHandler('onAfterSave')) $this->onAfterSave(new CEvent($this)); $omodel= OUser::model()->findByPk($this->getPrimaryKey()); if(!$omodel){ $omodel=new OUser(); }else{ } //因为大小写问题。这里将key $item=array_change_key_case($this->getAttributes(false), CASE_UPPER); 进行该处理 $omodel->setAttributes($this->getAttributes(false),false); $omodel->save(); }
补充yii 相关版本插入异常问题:
转发请注明出处http://blog.martoo.cn
如有漏缺,请联系我 QQ 243008827
Navicat连接Oracle数据库失败,提示“unsupported server charset ZHS16GBK”的解决方法
参考:http://hi.baidu.com/nju520/item/da42f6dfce72e217e1f46f17
补充,需要将新版本目录完全覆盖。只替换相关dll文件还是会有问题。
当前版本为 navicat 11.2
转发请注明出处http://blog.martoo.cn
如有漏缺,请联系我 QQ 243008827