分类: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
