PDO事务以及异常处理

一、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的路上,如果你觉得本文对你有所帮助的话,那就请关注点赞评论三连吧,谢谢,你的肯定是我写博的另一个支持。

猜你喜欢

转载自blog.csdn.net/weixin_44103733/article/details/113109358