<?php
	/**
	
	PDO针对不同到的数据库服务器使用特定的驱动程序访问,
	即对外接口相同,内部驱动不同。
	
	在windows下安装PDO:
	使用哪种数据库只要在\php5\ext目录下放入扩展文件和对
	应驱动程序文件,然后在php.ini文件中开启对相应的扩展
	与驱动的支持即可。以下是针对mysql数据库的安装步骤。
		1.安装扩展文件:\php5\ext\php_pdo.dll,安装此扩展
	可使用PDO Function函数库。
		2.安装PDO mySql的驱动:\php5\ext\php_pdo_mysql.dll
		3.在php.ini文件的680行附近指定扩展文件与驱动文件。
		4.重新启动服务器。

	PDO中包含三个预定义的类:
		PDO:和数据库连接有关(连接,执行sql语句)
		PDOStatement:PDO预处理类(准备语句,处理结果集)
		PDOException:异常类
		很多常量
		
	*/
//=============================================================
//------------PDO类方法:(数据库连接,执行语句)----------------

	PDO				//创建PDO对象
	beginTransaction()*//开始事务 
	commit()*		//提交事务 
	rollBack()*		//回滚一个事务 
	errorCode()*	//从数据库返回一个错误代号,如果有的话 
	errorInfo()*		//从数据库返回一个含有错误信息的数组,如果有的话 
	exec()*			//执行一条SQL语句并返回影响的行数 
	query()*		//执行一条SQL语句并返回一个结果集 
	prepare()*		//为执行准备一条SQL语句 
	lastInsertId()*	//返回最新插入到数据库的行(的ID) 
	quote()			//返回添加了引号的字符串,以使其可用于SQL语句中 
	
	getAttribute()*		//取得数据库连接属性 
						//设置属性
	setAttribute()*		//传两个参数,第一个为PDO对象特定的属性名,第二个参数是这个属性名的值
	
						PDO::ATTR_AUTOCOMMIT 	//是否自动提交 true为开启
						PDO::ATTR_CASE			//强制大小写转换
						PDO::ATTR_CLIENT_VERSION //获得客户端版本
						PDO::ATTR_CONNECTION_STATUS	//数据库连接状态信息
						PDO::ATTR_DRIVER_NAME			//获取驱动名
						PDO::ATTR_ERRMODE 		//设置错误模式
						PDO::ATTR_ORACLE_NULLS 	//空字符串转换为Sql的空
						PDO::ATTR_PERSISTENT	 	//设置持久连接
						PDO::ATTR_PREFETCH 		//提前获取数据的大小
						PDO::ATTR_SERVER_INFO	//获取服务器信息
						PDO::ATTR_SERVER_VERSION //获取服务器版本
						PDO::ATTR_TIMEOUT		//设置超时之前等待的秒数
//=============================================================
//-----------------------连接数据库---------------------------
	/*PDO连接数据库的方式与普通连接数据库的扩展有所不同。
	首先要创建PDO对象:
	$PDO = new PDO($dsn(数据源),"root","320723");
	dsn:(data source name)数据源。
	数据源:连接哪种数据库的驱动,即主机位置,库名。
	连接不同数据库使用不同的驱动,查看手册中的PDO Drivers
	
	连接mysql的数据源格式:
	$dsn = mysql:host=localhost;dbname=film;port=3306;
		mysql:mysql的驱动
		host = 主机
		dbname = 库名
		port = 端口

	可将dsn放入文件:如在hello.txt文件中写入mysql:host=localh
	ost;dbname=film;port=3306;在参数中:new PDO("uri:filename"
	,"","");也可将文件放入远程。
	也可以将dsn放入配置文件:在配置文件中加入子区域[PDO],然
	后在子区域下加入pod.dsn.mysqlpdo = mysql:localhost;dbname=
	film;port=3306;,在参数中的写法是new PDO("mysqlpdo","","");
	其中mysqlpdo为自定义名。
	*/
	//---------------------------------------------------------*
	//----------------------常用连接方法----------------------
	try{
		$arr = array(PDO::ATTR_PERSISTENT=>true);
		$dsn = "mysql:host=localhost;dbname=film;port=3306";
		$pdo=new PDO($dsn,"root","320723",$arr);
		//设置错误模式,在sql语句执行错误时可抛出异常
		$pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
	}catch(PDOException $e){
		echo $e->getMessage();
		exit;
	}
	
	try{
		$dsn = "mysql:host=localhost;dbname=lamp85";
		//array('3'=>'1')错误设置,1为警告级别
		$pdo = new PDO($dsn,'root','',array('3'=>'1'));
	}catch(PDOException $e){
		echo $e->getMessage();
	}
	//---------------------------------------------------------
	//--------------------设置连接数据库属性------------------
	
	/*在new PDO("","","","array())第四个参数中的数组是对PDO底
	层驱动的一些设置。调优的参数和设置属性的参数相似*/
	$arr = array(PDO::ATTR_AUTOCOMMIT=>0,PDO::ATTR_PERSISTENT=>true);
		PDO::ATTR_AUTOCOMMIT=>0	//关闭自动提交
		PDO::ATTR_PERSISTENT=>true	//建立持久连接
	
	/*若在连接数据库时没有设置属性,连接之后也可通过setAttr
	ibute()来设置属性*/
	$pdo->setAttribute(PDO::ATTR_AUTOCOMMIT,1);
	$pdo->setAttribute(3,1);
	
	PDO::ATTR_ERRMODE;		//3
	PDO::ERRMODE_SILENT;		//0
	PDO::ERRMODE_WARNING;	//1
	PDO::ERRMODE_EXCEPTION;	//2
//========================错误处理=============================
//--------------------------------------------------------------
	/*
	在PDO中错误模式有三种,1.默认模式:ERRMODE_SILENT,2.警
	告模式:ERRMODE_WARNING,3.异常模式 ERRMODE_EXCEPTION。
	一般在执行PDO语句时,默认不提示错误信息,即为模式一,可
	以用errorCode()与errorInfo()两个方法获取错误代码与错误信
	息。通过setAttribute(,)可设置错误模式,第一个参数为PDO::
	ATTR_ERRMODE即错误模式,第二个参数为要设置的三种错误模式
	之一,也可以用0、1、2对应代替三种模式。在三种模式中,常
	用的是第三种错误模式,即异常模式;在使用异常模式时将代
	码写在try catch中出现错误可调用PDO中的getMessage()方法来
	抛出异常。*/
	//----------------------------------------------------------
	//------------错误模式1:默认模式ERRMODE_SILENT-------------
	//模式一情况下try catch 抛不出异常,不建议使用
	$row=$pdo->exec($sql);
	if(!$row){
			echo $pdo->errorCode();//错误代码
			print_r($pdo->errorInfo());//错误信息
	}else{
		echo "执行成功";
	}
	//---------------------------------------------------------
	//------------错误模式2:警告模式 ERRMODE_WARNING----------
	/*模式二情况下try catch 抛不出异常,在模式二中errorCode
	errorInfo方法同样可以使用*/
	$pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_WARNING);
	//---------------------------------------------------------
	//---------错误模式3:异常模式 ERRMODE_EXCEPTION-----------*

	/*使用ERRMODE_EXCEPTION错误模式时,将PDO代码写在try catch
	中,在出现错误时调用PDO中的getMessage()方法可以抛出异常*/
	
	$pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
	try{
		$pdo->exec($sql);
	}catch(PDOException $e){
		$e->getMessage();
	}
//==============================================================
//---------------------执行Sql语句(不推荐)---------------------
	/*执行SQL语句exec() query() prepare()
		query()		执行有结果集的语句(select)
		exec()		执行有影响行数的语句(update,delete,insert)
	*/
	//----------------------------------------------------------
	//-------------------------exec-----------------------------
	try{
		$sql = "insert into film() values()";
		$pdo->exec($sql);
		echo "last ID: ".$pdo->lastInsertId();//获取最后插入的id
	}catch(PDOException $e){
		echo $e->getMessage();
	}
	//----------------------------------------------------------
	//--------------------------query---------------------------
	try{
		$stmt=$pdo->query("select * from film");
		foreach($stmt as $row){
			print_r($row);
			echo "<br>";
		}
	}catch(PDOException $e){
		echo $e->getMessage();
	}
//=============================================================
//-----------------PDOStatement预处理类方法-------------------
	bindColumn				//绑定一个PHP变量到结果集中的输出列 
	bindParam*				//绑定一个PHP变量到一个预处理语句中的参数 
	bindValue				//绑定一个值到与处理语句中的参数 
	closeCursor				//关闭游标,使语句可以再次执行 
	errorCode*				//返回一个错误代号
	errorInfo*				//返回一个包含错误信息的数组

	getAttribute				//返回一个 PDOStatement 属性 
	setAttribute				//设置一个PDOStatement属性 
	getColumnMeta			//返回结果集中某一列的结构(metadata?)
	nextRowset				//返回下一结果集 
	setFetchMode			//为 PDOStatement 设定获取数据的方式 
	//结果集中使用的方法
	execute					//执行一条预处理语句 
	fetch					//从结果集中取出一行 
	fetchAll					//从结构集中取出一个包含了所有行的数组 
	fetchColumn				//返回结果集中某一列中的数据
	rowCount				//返回SQL语句执行后影响的行数,select,update,delete
	columnCount				//返回结果集中的列的数量
//==================使用预处理方法执行语句====================
//--------------------------------------------------------------
	/*
	使用预处理的优点在于,它将要执行的语句集中一起执行,提
	高效率。使用prepare()方法预处理语句,返回预处理对象。
	
	预处理方法执行语句流程:
		方式一:
			1.prepare()		准备语句并返回对象
			2.bindparam()	绑定参数并给参数赋值
			3.execute()		执行语句
		方式二:
			1.prepare()			准备语句并返回对象
			2.execute(array())	绑定数组参数并执行语句
	*/
	//----------------------------------------------------------
	//---------------------1.名字参数方式----------------------
	//准备一条语句
	$stmt=$pdo->prepare("insert into film(title,content)values(:title,:content)");
	//绑定参数
	$stmt->bindparam(":title",$title,PDO::PARAM_STR);//第三个参数是数据类型,可不填
	$stmt->bindparam(":content",$content);
	//给变量赋值
	$title="title";
	$content="content";
	//执行语句
	if($stmt->execute()){
		echo "执行成功";
		echo "lsat Id: ".$pdo->lastInsertId();//获取最后的id
	}else{
		echo "执行失败";
	}
	//---------------------------------------------------------
	//---------------------2.?参数方式------------------------
	//准备一条语句
	$stmt=$pdo->prepare("insert into film(title,content)values( ?,?)");
	//绑定参数
	$stmt->bindparam(2,$content);
	$stmt->bindparam(1,$title);
	//给变量赋值
	$title="title";
	$content="content";
	//执行语句
	if($stmt->execute()){
		echo "执行成功";
		echo "lsat Id: ".$pdo->lastInsertId();//获取最后的id
	}else{
		echo "执行失败";
	}
//======================绑定并执行的方法=======================
//------------------------1.名字参数方法-----------------------
	//准备一条语句
	$stmt=$pdo->prepare("update film set title=:title,content=:content where id=:id" );
	//用数组的方法绑定传值并执行
	$stmt->execute(array("title"=>"title","content"=>"content","id"=>306));
	$stmt->execute(array("title"=>"title2","content"=>"content","id"=>305));
	//----------------------------------------------------------*
	//--------------------------2.?参数方法---------------------
	$stmt=$pdo->prepare("update film set title=?,content=? where id=?" );
	//用数组的方法绑定传值并执行
	$stmt->execute(array("title","content",306));
	$stmt->execute(array("title2","content",305));
//=======================查询数据方法==========================
//-----------------------fetch逐条获取-------------------------*
	//准备一条语句
	$stmt=$pdo->prepare("select id,title,addtime from film where id>:id");
	//绑定并执行一条语句,此步没有就不写
	$stmt->execute(array(":id"=>300));

	/*fetch()方法默认返回关联数组和索引数组,括号中的参数
	定义了返回形式,参数有:PDO::FETCH_NUM以索引形式返回,
	PDO::FETCH_ASSOC以关联形式返回,也可以通过setFetchMode
	()来设置获取模式,参数同上,只需设置一次即可。每执行
	一次fetch获取一条结果集*/
	$row=$stmt->fetch(PDO::FETCH_ASSOC);
	print_r($row);
	
	//或者使用循环方式来获取结果集
	while($row=$stmt->fetch()){
		print_r($row);
	}
	//---------------------------------------------------------
	//------------------fetchAll一次获取全部结果集------------
	//设置获取模式
	$stmt->setFetchMode(PDO::FETCH_ASSOC);
	//以二维数组的方式获取全部数据
	$data=$stmt->fetchAll();
	print_r($data);
	//---------------------------------------------------------*
	//-----------------绑定列方式获取结果集bindColumn---------
	$stmt=$pdo->prepare("select id,title,addtime from film where id>:id");
	//执行语句execute放在绑定前或后都可以
	$stmt->execute(array(":id"=>300));
	//将列名与值绑定 效果同 list()=array()
	$stmt->bindColumn("id",$id);
	$stmt->bindColumn("title",$title);
	$stmt->bindColumn("addtime",$addtime);
	//每循环一次就将对应的值赋给对应的变量,此方法只有fetch可以使用
	while($stmt->fetch()){
		echo "----$id----$title----$addtime----<br>";
	}
	//---------------------------------------------------------
	//---------------获取某一列中的值fetchColumn--------------
	$stmt=$pdo->prepare("select id,title,addtime from film where id>:id");
	$stmt->execute(array(":id"=>300));
	/*获取某一列,括号中的参数为某一列 0表示查询中的第一列 
	即id列,每次获取一个*/
	while($col=$stmt->fetchColumn(0)){
		echo $col ."<br>";
	}
	//---------------------------------------------------------
	//---------------获取记录的总行数与总列数----------------
	$stmt=$pdo->prepare("select id,title,addtime from film where id>:id");
	$stmt->execute(array(":id"=>300));
	//输出总行数
	echo $stmt->rowCount()."<br>";
	//输出总列数
	echo $stmt->columnCount() ."<br>";
	//----------------------------------------------------------
	//------------用getColumnMeta获取表信息中的列名-----------
	$stmt=$pdo->prepare("select id,title,addtime from film where id>:id");
	$stmt->execute(array(":id"=>300));
	//次循环控制列数
	for($i=0;$i<$stmt->columnCount();$i++){
		//取得列信息中的列名
		$field=$stmt->getColumnMeta($i);
		echo $field["name"]."-----";
	}
//====================PDO中的事务处理==========================
//--------------------------------------------------------------
	//事物处理简单示例
	$pdo->beginTransaction();
	
	$num = 2000;
	$sql = "update user set money=money-{$num} where id=2";
	$rows = $pdo->exec($sql);
	
	$sql = "update user set money=money+{$num} where id=1";
	$rows += $pdo->exec($sql);
	
	if($row == 2){
		$pdo->commit();
	}else{
		$pdo->rollBack();
	}
//--------------------------------------------------------------
//--------------------------------------------------------------

	/*事物处理用于转账等问题的处理,必须是InnoDB表类型,type
	=InnoDB 必须设置主键primary key */
	
	$pdo->beginTransaction()	//开始事务
	$pdo->commit()			//方法标明回滚结束点
	$pdo->rollBack()			//执行回滚
	//预处理实例
	try {
		$dbh = new PDO("mysql:host=localhost;dbname=test", "root","");
		$dbh->query('set names utf8;');
		$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
		//或在此关闭自动提交
		$dbh->setAttribute(PDO::ATTR_AUTOCOMMIT,false);
		//开始事务
		$dbh->beginTransaction();
		$dbh->exec("INSERT INTO 'test'.'table' ('name' ,'age')VALUES ('mick', 22);");
		$dbh->exec("INSERT INTO 'test'.'table' ('name' ,'age')VALUES ('lily', 29);");
		$dbh->exec("INSERT INTO 'test'.'table' ('name' ,'age')VALUES ('susan', 21);");
		$dbh->commit();
		//开启自动提交
		$dbh->setAttribute(PDO::ATTR_AUTOCOMMIT,true);
	} catch (PDOException $e) {
		$dbh->rollBack();		//回滚
		echo "Failed:" . $e->getMessage();
	}
//=============================================================
//-----------------PDOException异常类--------------------------
	class PDOException extends Exception{
		// 对应 PDO::errorInfo()
		// 或 PDOStatement::errorInfo()
		public $errorInfo = null;
		// 文本化的错误信息
		// 使用Exception::getMessage() 获取它
		protected $message;
		// SQLSTATE 错误代号
		// 使用Exception::getCode() 获取它
		protected $code;
	}
//=============================================================
//--------------------PDO驱动对应的数据库---------------------
	/*
	PDO_DBLIB			FreeTDS / Microsoft SQL Server / Sybase 
	PDO_FIREBIRD		Firebird/Interbase 6 
	PDO_MYSQL			MySQL 3.x/4.x 
	PDO_OCI				Oracle Call Interface 
	PDO_ODBC			ODBC v3 (IBM DB2, unixODBC and win32 ODBC) 
	PDO_PGSQL			PostgreSQL 
	PDO_SQLITE			SQLite 3 and SQLite 2 */
//=============================================================
//-------------------------------------------------------------
	PDO::ATTR_AUTOCOMMIT
	/*在设置成true的时候,PDO会自动尝试停止接受委托,开
	始执行*/
	PDO::ATTR_PREFETCH
	/*设置应用程序提前获取的数据大小,并非所有的数据库
	哦度支持*/
	PDO::ATTR_TIMEOUT
	/*设置连接数据库超时的值*/
	PDO::ATTR_ERRMODE
	/*设置Error处理的模式*/
	PDO::ATTR_SERVER_VERSION
	/*只读属性,表示PDO连接的服务器端数据库版本*/
	PDO::ATTR_CLIENT_VERSION
	/*只读属性,表示PDO连接的客户端PDO驱动版本*/
	PDO::ATTR_SERVER_INFO
	/*只读属性,表示PDO连接的服务器的meta信息*/
	PDO::ATTR_CONNECTION_STATUS
	PDO::ATTR_CASE
	/*通过PDO::CASE_*中的内容对列的形式进行操作*/
	PDO::ATTR_CURSOR_NAME
	/*获取或者设定指针的名称*/
	PDO::ATTR_CURSOR
	/*设置指针的类型,PDO现在支持PDO::CURSOR_FWDONLY和
	PDO::CURSOR_FWDONLY*/
	PDO::ATTR_DRIVER_NAME
	/*返回使用的PDO驱动的名称*/
	PDO::ATTR_ORACLE_NULLS
	/*将返回的空字符串转换为SQL的NULL
	PDO::ATTR_PERSISTENT
	/*获取一个存在的连接*/
	PDO::ATTR_STATEMENT_CLASS
	PDO::ATTR_FETCH_CATALOG_NAMES
	/*在返回的结果集中,使用自定义目录名称来代替字段名。*/
	PDO::ATTR_FETCH_TABLE_NAMES
	/*在返回的结果集中,使用自定义表格名称来代替字段名。*/
	PDO::ATTR_STRINGIFY_FETCHES
	PDO::ATTR_MAX_COLUMN_LEN
	PDO::ATTR_DEFAULT_FETCH_MODE
	/*Available since PHP 5.2.0*/
	PDO::ATTR_EMULATE_PREPARES
	/*Available since PHP 5.1.3.*/

	//数据类型
	PDO::PARAM_BOOL
	//表示一个布尔类型
	PDO::PARAM_NULL
	//表示一个SQL中的NULL类型
	PDO::PARAM_INT
	//表示一个SQL中的INTEGER类型
	PDO::PARAM_STR
	//表示一个SQL中的SQL CHAR,VARCHAR类型
	PDO::PARAM_LOB
	/*表示一个SQL中的large object类型*/
	PDO::PARAM_STMT
	//表示一个SQL中的recordset类型,还没有被支持
	PDO::PARAM_INPUT_OUTPUT
	/*Specifies that the parameter is an INOUT parameter
	 for a stored procedure.You must bitwise-OR this 
	 value with an explicit PDO::PARAM_*data type.*/
	PDO::PARAM_EVT_ALLOC
	//Allocation event
	PDO::PARAM_EVT_FREE
	//Deallocation event
	PDO::PARAM_EVT_EXEC_PRE
	//Event triggered prior to execution of a prepared statement.
	PDO::PARAM_EVT_EXEC_POST
	//Event triggered subsequent to execution of a prepared statement.
	PDO::PARAM_EVT_FETCH_PRE
	//Event triggered prior to fetching a result from a resultset.
	PDO::PARAM_EVT_FETCH_POST
	//Event triggered subsequent to fetching a result from a resultset.
	PDO::PARAM_EVT_NORMALIZE
	/*Event triggered during bound parameter 
	registration allowing the driver to normalize 
	the parameter name*/

	//调优的参数和设置属性的参数相似
	PDO::FETCH_LAZY
	//将每一行结果作为一个对象返回
	PDO::FETCH_ASSOC
	//仅仅返回以键值作为下标的查询的结果集,名称相同的数据只返回一个
	PDO::FETCH_NAMED
	//仅仅返回以键值作为下标的查询的结果集,名称相同的数据以数组形式返回
	PDO::FETCH_NUM
	//仅仅返回以数字作为下标的查询的结果集
	PDO::FETCH_BOTH
	//同时返回以键值和数字作为下标的查询的结果集
	PDO::FETCH_OBJ
	//以对象的形式返回结果集
	PDO::FETCH_BOUND
	/*将PDOStatement::bindParam()和PDOStatement::
	bindColumn()所绑定的值作为变量名赋值后返回*/
	PDO::FETCH_COLUMN
	//表示仅仅返回结果集中的某一列
	PDO::FETCH_CLASS
	//表示以类的形式返回结果集
	PDO::FETCH_INTO
	//表示将数据合并入一个存在的类中进行返回
	PDO::FETCH_FUNC
	PDO::FETCH_GROUP
	PDO::FETCH_UNIQUE
	PDO::FETCH_KEY_PAIR
	//以首个键值下表,后面数字下表的形式返回结果集
	PDO::FETCH_CLASSTYPE
	PDO::FETCH_SERIALIZE
	//表示将数据合并入一个存在的类中并序列化返回
	PDO::FETCH_PROPS_LATE
	//Available since PHP 5.2.0
	PDO::FETCH_ORI_NEXT
	//获取结果集中的下一行数据,仅在有指针功能时有效
	PDO::FETCH_ORI_PRIOR
	//获取结果集中的上一行数据,仅在有指针功能时有效
	PDO::FETCH_ORI_FIRST
	//获取结果集中的第一行数据,仅在有指针功能时有效
	PDO::FETCH_ORI_LAST
	//获取结果集中的最后一行数据,仅在有指针功能时有效
	PDO::FETCH_ORI_ABS
	//获取结果集中的某一行数据,仅在有指针功能时有效
	PDO::FETCH_ORI_REL
	//获取结果集中当前行后某行的数据,仅在有指针功能时有效



	PDO::ERRMODE_SILENT
	//发生错误时不汇报任何的错误信息,是默认值
	PDO::ERRMODE_WARNING
	//发生错误时发出一条php的E_WARNING的信息
	PDO::ERRMODE_EXCEPTION
	//发生错误时抛出一个PDOException
	PDO::ERR_NONE (string)
	//设定没有错误时候的错误信息

	PDO::CASE_NATURAL
	//回复列的默认显示格式
	PDO::CASE_LOWER
	//强制列的名字小写
	PDO::CASE_UPPER
	//强制列的名字大写

	PDO::NULL_NATURAL
	PDO::NULL_EMPTY_STRING
	PDO::NULL_TO_STRING

	PDO::CURSOR_FWDONLY
	//建立一个只能向后的指针操作对象
	PDO::CURSOR_SCROLL
	//建立一个指针操作对象,传递PDO::FETCH_ORI_*中的内容来控制结果集
//=============================================================
//-------------------------------------------------------------