一、PDO操作事务
事务:是一个整体,要么一起执行,要么一起回滚 事务的特性:原子性、一致性、隔离性、永久性 需要将多个SQL语句作为一个整体执行,就需要使用到事务
语法:
例:
创建测试数据:
CREATE TABLE bank (
cardid char(4) PRIMARY KEY COMMENT '卡号',
balance decimal(10,2) not null COMMENT '余额'
)ENGINE=INNODB charset=utf8 COMMENT '银行卡号表'
INSERT INTO bank VALUES ('1001',1000),('1002',1)
效果:
PDO操作事务: 例题:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<?php
if (!empty($_POST)) {
$dsn='mysql:port=3306;host=localhost;dbname=data;charset=utf8';
$pdo=new PDO($dsn, 'root', 'root');
$out=$_POST['card_out']; // 转出卡号
// echo $out;
$in=$_POST['card_in']; // 转进卡号
$money=$_POST['money']; // 金额
$pdo->beginTransaction(); // 开启事务
$flag1=$pdo->exec("update bank set balance=balance-$money where cardid='$out'");
$flag2=$pdo->exec("update bank set balance=balance+$money where cardid='$in'");
$stmt = $pdo->query("select balance from bank where cardid='$out'"); // 查看转出的账号是否大于0
$flag3=$stmt->fetchColumn()>=0?1:0;
if ($flag1 && $flag2 && $flag3) {
$pdo->commit(); // 提交事务
echo '转账成功';
}
else {
$pdo->rollBack(); // 回滚事务
echo '转账失败';
}
}
?>
<form action="" method="post">
转出卡号:<input type="text" name="card_out"> <br>
转入卡号:<input type="text" name="card_in"><br>
金额:<input type="text" name="money">
<input type="submit" value="提交">
</form>
</body>
</html>
效果:
二、PDO操作预处理
复习MySQL中预处理: 预处理好处:编译一次多次执行,用来解决一条SQL语句多次执行的问题,提高了执行效率。
预处理语句:
执行预处理
2.1 PDO中的预处理(位置占位符):
方法一:
<?php
$dsn='mysql:port=3306;host=localhost;dbname=data;charset=utf8';
$pdo=new PDO($dsn, 'root', 'root');
// 创建预处理对象
$stmt=$pdo->prepare('insert into bank values (?,?)'); // ?是占位符
// 执行预处理
$cards=[
['1003',500],
['1004',100]
];
foreach($cards as $card) {
$stmt->bindParam(1, $card[0]); // 占位符的位置从1开始
$stmt->bindParam(2, $card[1]);
$stmt->execute(); // 执行预处理
}
效果:
方法二:
<?php
$dsn='mysql:port=3306;host=localhost;dbname=data;charset=utf8';
$pdo=new PDO($dsn, 'root', 'root');
// 创建预处理对象
$stmt=$pdo->prepare('insert into bank values (?,?)'); // ?是占位符
// 执行预处理
$cards=[
['1005',520],
['1006',1000]
];
foreach($cards as $card) {
$stmt->bindValue(1, $card[0]);
$stmt->bindValue(2, $card[1]);
}
效果:
方法三:
<?php
$dsn='mysql:port=3306;host=localhost;dbname=data;charset=utf8';
$pdo=new PDO($dsn, 'root', 'root');
// 创建预处理对象
$stmt=$pdo->prepare('insert into bank values (?,?)'); // ?是占位符
// 执行预处理
$cards=[
['1007',520],
['1008',1000]
];
foreach($cards as $card) {
$stmt->execute($card); // 如果占位符的顺序和数组的顺序一致,可以直接传递参数
}
效果:
2.2 PDO中的预处理(参数占位符)
例:
<?php
$dsn='mysql:port=3306;host=localhost;dbname=data;charset=utf8';
$pdo=new PDO($dsn, 'root', 'root');
// 创建预处理对象
$stmt=$pdo->prepare('insert into bank values (:p1,:p2)'); // :p1,:p2是参数占位符
// 执行预处理
$cards=[
['p1'=>'1009','p2'=>5200],
['p1'=>'1010','p2'=>10000]
];
foreach($cards as $card) {
/*
// 方法一
$stmt->bindParam(':p1', $card['p1']);
$stmt->bindParam(':p2', $card['p2']);
$stmt->execute();
*/
// 方法二 当数组的下标和参数吗一致的时候就可以直接传递关联数组
$stmt->execute($card);
}
效果:
小结:
1、?是位置占位符
2、参数占位符以冒号开头。
3、$stmt->bindParam()
和$stmt->bindValue()
区别是前者只能是变量后者可以是变量或者是值。
4、预处理的好处:提高执行效率,提高安全性。
三、PDO异常处理
例:
<?php
try {
$dsn='mysql:port=3306;host=localhost;dbname=data;charset=utf8';
$pdo=new PDO($dsn, 'root', 'root');
// 设置PDO错误模式属性,PDO自动抛出异常
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->query('select * from nesswk');
} catch (PDOException $ex) {
echo '错误信息: '.$ex->getMessage(),'<br>';
echo '错误文件: '.$ex->getFile(),'<br>';
echo '错误行号: '.$ex->getLine();
}
效果:
小结: 1、PDOException是PDO的异常类 2、实例化PDO会自动抛出异常 3、其他操作不会抛出异常,需要设置PDO的异常模式 4、PDO异常模式
四、单例模式封装MyPDO类
4.1 步骤
1、单例模式 2、初始化参数 3、连接数据库 4、执行增删改 5、执行查询
4.2 代码实现
1、单例模式 2、初始化参数 3、连接数据库 如下:
<?php
class MyPDO {
private $type; // 数据库类别
private $host; // 主机地址
private $port; // 端口号
private $dbname; // 数据库名
private $charset; // 字符集
private $user; // 用户名
private $pwd; // 密码
private $pdo; // 保存PDO对象
private static $instance;
private function __construct($param) {
$this->initParam($param);
$this->initPDO();
}
private function __clone() {
}
public static function getInstance($param=array()) {
if (!self::$instance instanceof self) {
self::$instance=new self($param);
}
return self::$instance;
}
// 初始化参数
private function initParam($param) {
$this->type=$param['type']??'mysql';
$this->host=$param['host']??'127.0.0.1';
$this->port=$param['port']??'3306';
$this->dbname=$param['dbname']??'data';
$this->charset=$param['charset']??'utf8';
$this->user=$param['user']??'root';
$this->pwd=$param['pwd']??'root';
$this->pdo=$param['pdo']??'pdo';
}
// 初始化PDO
private function initPDO() {
try {
$dsn="{$this->type}:host={$this->host};port={$this->port};dbname={$this->dbname};charset={$this->charset}";
$this->pdo=new PDO($dsn, $this->user, $this->pwd);
} catch (PDOException $ex) {
echo '错误信息: '.$ex->getMessage(),'<br>';
echo '错误编号: '.$ex->getCode(),'<br>';
echo '错误文件: '.$ex->getFile(),'<br>';
echo '错误行号: '.$ex->getLine(),'<br>';
exit;
}
}
}
// 测试
$param=array(
);
$mypdo=MyPDO::getInstance($param);
var_dump($mypdo);
效果:
4、执行增删改 例:
<?php
class MyPDO {
private $type; // 数据库类别
private $host; // 主机地址
private $port; // 端口号
private $dbname; // 数据库名
private $charset; // 字符集
private $user; // 用户名
private $pwd; // 密码
private $pdo; // 保存PDO对象
private static $instance;
private function __construct($param) {
$this->initParam($param);
$this->initPDO();
$this->initException();
}
private function __clone() {
}
// 显示异常
private function showException($ex, $sql='') {
if ($sql!='') {
echo 'SQL语句失败<br>';
echo '错误的SQL语句是:'.$sql,'<br>';
}
echo '错误信息: '.$ex->getMessage(),'<br>';
echo '错误编号: '.$ex->getCode(),'<br>';
echo '错误文件: '.$ex->getFile(),'<br>';
echo '错误行号: '.$ex->getLine(),'<br>';
exit;
}
public static function getInstance($param=array()) {
if (!self::$instance instanceof self) {
self::$instance=new self($param);
}
return self::$instance;
}
// 设置异常模式
private function initException() {
// 设置PDO错误模式属性,PDO自动抛出异常
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
// 初始化参数
private function initParam($param) {
$this->type=$param['type']??'mysql';
$this->host=$param['host']??'127.0.0.1';
$this->port=$param['port']??'3306';
$this->dbname=$param['dbname']??'data';
$this->charset=$param['charset']??'utf8';
$this->user=$param['user']??'root';
$this->pwd=$param['pwd']??'root';
$this->pdo=$param['pdo']??'pdo';
}
// 初始化PDO
private function initPDO() {
try {
$dsn="{$this->type}:host={$this->host};port={$this->port};dbname={$this->dbname};charset={$this->charset}";
$this->pdo=new PDO($dsn, $this->user, $this->pwd);
} catch (PDOException $ex) {
$this->showException($ex);
}
}
// 执行增删改操作
public function exec($sql) {
try {
return $this->pdo->exec($sql);
} catch (PDOException $ex) {
$this->showException($ex, $sql);
}
}
// 获取自动增长的编号
public function lastInsertId() {
return '自动增长的编号是:'.$this->pdo->lastInsertId();
}
}
// 测试
$param=array(
);
$mypdo=MyPDO::getInstance($param);
echo $mypdo->exec('delete from bank where cardid=1010');
if ($mypdo->exec("insert into shows values (null,'b', 'bbb', CURRENT_TIMESTAMP)")) {
echo $mypdo->lastInsertId();
}
效果:
5、执行查询
例:
<?php
class MyPDO {
private $type; // 数据库类别
private $host; // 主机地址
private $port; // 端口号
private $dbname; // 数据库名
private $charset; // 字符集
private $user; // 用户名
private $pwd; // 密码
private $pdo; // 保存PDO对象
private static $instance;
private function __construct($param) {
$this->initParam($param);
$this->initPDO();
$this->initException();
}
private function __clone() {
}
// 显示异常
private function showException($ex, $sql='') {
if ($sql!='') {
echo 'SQL语句失败<br>';
echo '错误的SQL语句是:'.$sql,'<br>';
}
echo '错误信息: '.$ex->getMessage(),'<br>';
echo '错误编号: '.$ex->getCode(),'<br>';
echo '错误文件: '.$ex->getFile(),'<br>';
echo '错误行号: '.$ex->getLine(),'<br>';
exit;
}
public static function getInstance($param=array()) {
if (!self::$instance instanceof self) {
self::$instance=new self($param);
}
return self::$instance;
}
// 设置异常模式
private function initException() {
// 设置PDO错误模式属性,PDO自动抛出异常
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
// 初始化参数
private function initParam($param) {
$this->type=$param['type']??'mysql';
$this->host=$param['host']??'127.0.0.1';
$this->port=$param['port']??'3306';
$this->dbname=$param['dbname']??'data';
$this->charset=$param['charset']??'utf8';
$this->user=$param['user']??'root';
$this->pwd=$param['pwd']??'root';
$this->pdo=$param['pdo']??'pdo';
}
// 初始化PDO
private function initPDO() {
try {
$dsn="{$this->type}:host={$this->host};port={$this->port};dbname={$this->dbname};charset={$this->charset}";
$this->pdo=new PDO($dsn, $this->user, $this->pwd);
} catch (PDOException $ex) {
$this->showException($ex);
}
}
// 执行增删改操作
public function exec($sql) {
try {
return $this->pdo->exec($sql);
} catch (PDOException $ex) {
$this->showException($ex, $sql);
}
}
// 获取自动增长的编号
public function lastInsertId() {
return '自动增长的编号是:'.$this->pdo->lastInsertId();
}
// 判断匹配的类型
private function fetchType($type) {
switch ($type) {
case 'num':
return PDO::FETCH_NUM;
case 'both':
return PDO::FETCH_BOTH;
case 'obj':
return PDO::FETCH_OBJ;
default:
return PDO::FETCH_ASSOC;
}
}
// 获取所有数据,返回二维数组
public function fetchAll($sql,$type='assoc') {
try {
$stmt=$this->pdo->query($sql); // 获取PDOStatement对象
$type=$this->fetchType($type); // 获取匹配方法
return $stmt->fetchAll($type);
} catch (PDOException $ex) {
$this->showException($ex, $sql);
}
}
// 获取一维数组
public function fetchRow($sql, $type='assoc') {
try {
$stmt=$this->pdo->query($sql); // 获取PDOStatement对象
$type=$this->fetchType($type); // 获取匹配方法
return $stmt->fetch($type);
} catch (PDOException $ex) {
$this->showException($ex, $sql);
}
}
// 返回一行一列
public function fetchColumn($sql) {
try {
$stmt=$this->pdo->query($sql);
return $stmt->fetchColumn();
} catch (PDOException $ex) {
$this->showException($ex, $sql);
}
}
}
// 测试
$param=array(
);
$mypdo=MyPDO::getInstance($param);
// echo $mypdo->exec('delete from bank where cardid=1010');
// if ($mypdo->exec("insert into shows values (null,'b', 'bbb', CURRENT_TIMESTAMP)")) {
// echo $mypdo->lastInsertId();
// }
$list=$mypdo->fetchAll('select * from news', 'obj');
echo '<pre>';
var_dump($list);
echo '<br>';
$list=$mypdo->fetchRow('select * from shows where id=1', 'obj');
echo '<pre>';
var_dump($list);
echo '<br>';
$list=$mypdo->fetchColumn('select count(*) from shows', 'obj');
echo '<pre>';
var_dump($list);
效果:
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!