解决 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 相关版本插入异常问题:

QQ Photo20140318091839

 

转发请注明出处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