本文目录
一、PDO操作事务
事务:是一个整体,要么一起执行,要么一起回滚
事务的特性:原子性、一致性、隔离性、永久性
需要将多个SQL语句作为一个整体执行,就需要使用到事务
语法:
start transaction 或 begin 开启事务
commit 提交事务
rollback 回滚事务
例:
创建测试数据:
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语句多次执行的问题,提高了执行效率。
预处理语句:
prepare 预处理名字 form ‘sql语句’
执行预处理
execute 预处理名字 [using 变量]
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异常模式
PDO::ERRMODE_EXCEPTION 抛出异常
PDO::ERRMODE_SILENT 中断
PDO::ERRMODE_WARNING 警告
四、单例模式封装MyPDO类
4.1 步骤
1、单例模式
2、初始化参数
3、连接数据库
4、执行增删改
5、执行查询
a、返回二维数组
b、返回一维数组
c、返回一行一列
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、执行查询
a、返回二维数组
b、返回一维数组
c、返回一行一列
例:
<?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);
效果:
在学习的php的路上,如果你觉得本文对你有所帮助的话,那就请关注点赞评论三连吧,谢谢,你的肯定是我写博的另一个支持。