首页
复制
搜索
前进
后退
重载网页
和我当邻居
给我留言吧
首页
统计
关于
WOW怀旧
友链
更多
留言
壁纸
直播
Search
1
关于《杀死那个石家庄人》背后的故事
3,798 阅读
2
沈阳故宫之旅
609 阅读
3
摄影记录|鸿恩寺
562 阅读
4
赤壁赋| 知不可乎骤得,托遗响于悲风
423 阅读
5
Laravel-admin 删除行|删除回调
366 阅读
编程技术
GoLang
Vue
PHP
Linux
Redis
网络安全
生活杂记
登录
Search
标签搜索
PHP
随笔
Mysql
Laravel-Admin
Laravel
摄影
设计模式
Ab
Linux
Javascript
MAC
支付
CentOs
sh
嘉陵江
南滨路
蓝易云
redis
万能青年
累计撰写
60
篇文章
累计收到
144
条评论
首页
栏目
编程技术
GoLang
Vue
PHP
Linux
Redis
网络安全
生活杂记
页面
统计
关于
WOW怀旧
友链
留言
壁纸
直播
搜索到
41
篇与
的结果
2021-11-13
EasyWechat 微信小程序接入微信支付|笔记
环境要求{callout color="#f0ad4e"} PHP >= 7.4 PHP cURL 扩展 PHP OpenSSL 扩展 PHP SimpleXML 扩展 PHP fileinfo 拓展{/callout}安装$ composer require overtrue/wechat:~5.0 -vvv使用use EasyWeChat\Factory; // ------------------------ $config = [ // 必要配置 'app_id' => 'xxxx', //小程序ID 'mch_id' => 'your-mch-id', //商家ID 'key' => 'key-for-signature', // API 密钥 // 如需使用敏感接口(如退款、发送红包等)需要配置 API 证书路径(登录商户平台下载 API 证书) 'cert_path' => 'path/to/your/cert.pem', // XXX: 绝对路径!!!! 'key_path' => 'path/to/your/key', // XXX: 绝对路径!!!! 'notify_url' => '默认的订单回调地址', // 你也可以在下单时单独设置来想覆盖它 ]; // ------------------------ $app = Factory::payment($config); $res = $app->order->unify([ 'body' => $desc, //商品简介 'out_trade_no' => $order_code, //订单号 'total_fee' => floatval($info->pay_fee * 100), //价格 单位为分 'spbill_create_ip' => $_SERVER['REMOTE_ADDR'], // 可选,如不传该参数,SDK 将会自动获取相应 IP 地址 'notify_url' => $wx_config['notify_url'], // 支付结果通知网址,如果不设置则会使用配置里的默认地址 'trade_type' => 'JSAPI', // 请对应换成你的支付方式对应的值类型 'openid' => $user_info->openid, //用户的openid ]); // ------------------------ if ($res['return_code'] == 'FAIL') return $this->error_back(-1, '预支付请求失败' . $res['return_msg'], []); // ------------------------ $pay_time = time(); $appId = $res['appid']; $nonceStr = $res['nonce_str']; $prepay_id = $res['prepay_id']; $timeStamp = $pay_time; $key = $wx_config['md5_key']; // ------------------------ $paySign = md5("appId=$appId&nonceStr=$nonceStr&package=prepay_id=$prepay_id&signType=MD5&timeStamp=$timeStamp&key=$key"); // 这个地方就是我所说的二次签名! // ------------------------ // 返回给小程序 $re = []; $re['nonceStr'] = $nonceStr; $re['timeStamp'] = strval($timeStamp); // 小程序支付的timeStamp参数,必须使用这个 timeStamp,因为已经计算到了paySign中 $re['package'] = "prepay_id=" . $prepay_id; $re['paySign'] = $paySign; $re['signType'] = 'MD5'; // ------------------------ //自己的操作逻辑部分--- 然后返回给前端 // ------------------------ return $this->success_back(200, 'success', $re); 回调 /** * * 支付回调地址 */ public function NotifyPayApi(Request $request) { $wx_config = config("app.wx_pay"); $config = [ // 必要配置 'app_id' => $wx_config['app_id'], 'mch_id' => $wx_config['mch_id'], 'key' => $wx_config['md5_key'], // API 密钥 // 如需使用敏感接口(如退款、发送红包等)需要配置 API 证书路径(登录商户平台下载 API 证书) 'cert_path' => '', // XXX: 绝对路径!!!! 'key_path' => '', // XXX: 绝对路径!!!! 'notify_url' => $wx_config['notify_url'], // 你也可以在下单时单独设置来想覆盖它 ]; $app = Factory::payment($config); $response = $app->handlePaidNotify(function ($message, $fail) { if ($message['result_code'] == 'SUCCESS' && $message['return_code'] == 'SUCCESS') { $order_sn = $message['out_trade_no']; // 订单单号 $openid = $message['openid']; // 付款人openID $total_fee = ($message['total_fee']) / 100; // 付款金额 $transaction_id = $message['transaction_id']; // 微信支付流水号 $order_info = $this->FindOrderByOrderCode($order_sn); if (empty($order_info)) return false; // 更新订单 try { DB::beginTransaction(); //数据库逻辑 //插入流水 DB::commit(); return true; } catch (\Exception $e) { Db::rollBack(); return false; } } else { return false; } }); return $response; }就这么简单踩坑的地方就是拿到了 prepay_id 之后居然还要二次签名最后附上EasyWechat的官方地址 https://www.easywechat.com/5.x/payment/
2021年11月13日
361 阅读
0 评论
0 点赞
2021-09-05
笔记 | 深入浅出索引(下)
覆盖索引【举栗】mysql> create table T ( ID int primary key, k int NOT NULL DEFAULT 0, s varchar(16) NOT NULL DEFAULT '', index k(k)) engine=InnoDB;insert into T values(100,1, 'aa'),(200,2,'bb'),(300,3,'cc'),(500,5,'ee'),(600,6,'ff'),(700,7,'gg');执行 select * from T where k between 3 and 5在 k 索引树上找到 k=3 的记录,取得 ID = 300;再到 ID 索引树查到 ID=300 对应的 R3;在 k 索引树取下一个值 k=5,取得 ID=500;再回到 ID 索引树查到 ID=500 对应的 R4;在 k 索引树取下一个值 k=6,不满足条件,循环结束。在这个过程中,回到主键索引树搜索的过程,我们称为回表。执行 select ID from T where k between 3 and 5这时只需要查 ID 的值,而 ID 的值已经在 k 索引树上了,因此可以直接提供查询结果,不需要回表。也就是说,在这个查询里面,索引 k 已经“覆盖了”我们的查询需求,我们称为覆盖索引二级索引查询结果仅仅是主键 此时不需要回表查主键索引 称为覆盖索引由于覆盖索引可以减少树的搜索次数,显著提升查询性能,所以使用覆盖索引是一个常用的性能优化手段。最左前缀原则(name,age)索引示意图索引项是按照索引定义里面出现的字段顺序排序的联合索引(A, B)意味着不需要建立A的索引了,因为这个联合索引意味着建立了(A,B)和(A)这两种索引如果单使用age作为条件,索引是不会生效的,除非单独建立一个age索引,因为它遵循最左原则索引下推mysql> select * from tuser where name like '张%' and age=10 and ismale=1;MySQL 5.6 引入的索引下推优化(index condition pushdown), 可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。无索引下推执行流程索引下推执行流程
2021年09月05日
103 阅读
0 评论
0 点赞
2021-09-05
笔记 | 一条SQL更新语句是如何执行的?
重要的日志模块:redo log(重做日志)WAL(Write-Ahead Logging) 技术: 先写日志,再写磁盘当有一条记录需要更新的时候,InnoDB 引擎就会先把记录写到 redo log里面,并更新内存,这个时候更新就算完成了。同时,InnoDB 引擎会在适当的时候,将这个操作记录更新到磁盘里面redo log 是循环写的,空间固定会用完;binlog 是可以追加写入的。“追加写”是指 binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。write pos: 当前记录的位置,一边写一边后移,写到第 3 号文件末尾后就回到 0 号文件开头checkpoint:是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件。write pos 和 checkpoint 之间:是“粉板”上还空着的部分,可以用来记录新的操作write pos 追上 checkpoint:表示“粉板”满了,这时候不能再执行新的更新,得停下来先擦掉一些记录,把 checkpoint 推进一下【crash-safe】redo log 是 InnoDB引擎所特有的,所以我们如果再使用InnoDB引擎创建表时,如果数据库发生异常重启,之前提交的记录都不会丢失。 InnoDB正因为有了 redo log(重做日志),才有了 crash-safe 的能力(即使mysql服务宕机,也不会丢失数据的能力)。redo log 是 InnoDB 引擎特有的日志重要的日志模块:binlog(归档日志)【更新流程】mysql> update T set c=c+1 where ID=2;执行器先找引擎取 ID=2 这一行。ID 是主键,引擎直接用树搜索找到这一行。如果 ID=2 这一行所在的数据页本来就在内存中,就直接返回给执行器;否则,需要先从磁盘读入内存,然后再返回。执行器拿到引擎给的行数据,把这个值加上 1,比如原来是 N,现在就是 N+1,得到新的一行数据,再调用引擎接口写入这行新数据。引擎将这行新数据更新到内存中,同时将这个更新操作记录到 redo log 里面,此时 redo log 处于 prepare 状态。然后告知执行器执行完成了,随时可以提交事务。执行器生成这个操作的 binlog,并把 binlog 写入磁盘。执行器调用引擎的提交事务接口,引擎把刚刚写入的 redo log 改成提交(commit)状态,更新完成。redo log 用于保证 crash-safe 能力。innodb_flush_log_at_trx_commit 这个参数设置成 1 的时候,表示每次事务的 redo log 都直接持久化到磁盘bingo是server层特有的日志Binlog有两种模式,statement 格式的话是记sql语句, row格式会记录行的内容,记两条,更新前和更新后都有。redolog和binlog的区别redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 层实现的,所有引擎都可以使用。redo log 是物理日志,记录的是“在某个数据页上做了什么修改”;binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如“给 ID=2 这一行的 c 字段加 1 ”。redo log 是循环写的,空间固定会用完;binlog 是可以追加写入的。“追加写”是指 binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。【例子】一个完整的交易过程:账本记上 卖一瓶可乐(redo log为 prepare状态),然后收钱放入钱箱(bin log记录)然后回过头在账本上打个勾(redo log置为commit)表示一笔交易结束。如果收钱时交易被打断,回过头来整理此次交易,发现只有记账没有收钱,则交易失败,删掉账本上的记录(回滚);如果收了钱后被终止,然后回过头发现账本有记录(prepare)而且钱箱有本次收入(bin log),则继续完善账本(commit),本次交易有效。
2021年09月05日
113 阅读
0 评论
0 点赞
2021-09-05
笔记 | 事务隔离:为什么你改了我还看不见?
【事务】事务支持是在引擎层实现的,不是所有的引擎都支持事务,只有InnoDB支持事务特性:原子性、一致性、隔离性、持久性Atomicity(原子性):一个事务(transaction)中的所有操作,或者全部完成,或者全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。即,事务不可分割、不可约简。 Consistency(一致性):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设约束、触发器、级联回滚等。 Isolation(隔离性):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括未提交读(Read uncommitted)、提交读(read committed)、可重复读(repeatable read)和串行化(Serializable)。 Durability(持久性):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。SQL 标准的事务隔离级别包括:读未提交(read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(serializable )读未提交:一个事务还没提交时,它做的变更就能被别的事务看到读提交: 一个事务提交之后,它做的变更才会被其他事务看到可重复读:一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的串行化:顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行【举个栗子】mysql> create table T(c int) engine=InnoDB;insert into T(c) values(1);若隔离级别是“读未提交”, 则 V1 的值就是 2。这时候事务 B 虽然还没有提交,但是结果已经被 A 看到了。因此,V2、V3 也都是 2。若隔离级别是“读提交”,则 V1 是 1,V2 的值是 2。事务 B 的更新在提交后才能被 A 看到。所以, V3 的值也是 2。若隔离级别是“可重复读”,则 V1、V2 是 1,V3 是 2。之所以 V2 还是 1,遵循的就是这个要求:事务在执行期间看到的数据前后必须是一致的。若隔离级别是“串行化”,则在事务 B 执行“将 1 改成 2”的时候,会被锁住。直到事务 A 提交后,事务 B 才可以继续执行。所以从 A 的角度看, V1、V2 值是 1,V3 的值是 2。Oracle 数据库的默认隔离级别其实就是“读提交”MySQL默认的隔离级别是可重复读(Repeatable Read)因此对于一些从 Oracle 迁移到 MySQL 的应用,为保证数据库隔离级别的一致,你一定要记得将 MySQL 的隔离级别设置为“读提交”。配置的方式是,将启动参数 transaction-isolation 的值设置成 READ-COMMITTED。事务隔离的实现在 MySQL 中,实际上每条记录在更新的时候都会同时记录一条回滚操作。记录上的最新值,通过回滚操作,都可以得到前一个状态的值。假设一个值从 1 被按顺序改成了 2、3、4,在回滚日志里面就会有类似下面的记录长事务长事务意味着系统里面会存在很老的事务视图。由于这些事务随时可能访问数据库里面的任何数据,所以这个事务提交之前,数据库里面它可能用到的回滚记录都必须保留,这就会导致大量占用存储空间。set autocommit=0,这个命令会将这个线程的自动提交关掉。意味着如果你只执行一个 select 语句,这个事务就启动了,而且并不会自动提交。set autocommit=1;表示MySQL自动开启和提交事务。 比如执行一个update语句,语句只完成后就自动提交了。不需要显示的使用begin、commit来开启和提交事务。 所以,当我们需要对某些操作使用事务的时候,手动的用begin、commit来开启和提交事务。【查找长事务】可以在 information_schema 库的 innodb_trx 这个表中查询长事务,比如下面这个语句,用于查找持续时间超过 60s 的事务。select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60【避免长事务】监控 information_schema.Innodb_trx 表,设置长事务阈值,超过就报警 / 或者 kill;如果使用的是 MySQL 5.6 或者更新版本,把 innodb_undo_tablespaces 设置成 2(或更大的值)。如果真的出现大事务导致回滚段过大,这样设置后清理起来更方便。确认是否使用了 set autocommit=0 如果是0把它改成 1确认是否有不必要的只读事务。通过 SET MAX_EXECUTION_TIME 命令,来控制每个语句执行的最长时间,避免单个语句意外执行太长时间。
2021年09月05日
124 阅读
0 评论
0 点赞
2021-09-05
笔记 | 深入浅出索引(上)
索引索引的概念:索引的出现其实就是为了提高数据查询的效率,就像书的目录一样。在 MySQL 中,索引是在存储引擎层实现的,索引的常见模型哈希表有序数组搜索树哈希表哈希表是一种以键 - 值(key-value)存储数据的结构,把值放在数组里,用一个哈希函数把 key 换算成一个确定的位置,然后把 value 放在数组的这个位置。不可避免地,多个 key 值经过哈希函数的换算,会出现同一个值的情况。处理这种情况的一种方法是,拉出一个链表。由于哈希表的索引不是递增的,所以新增的时候会很快,但是因为不是有序的,所以哈希索引做区间查询的速度是很慢的。哈希表这种结构适用于只有等值查询的场景,比如 Memcached 及其他一些 NoSQL 引擎。有序数组有序数组索引只适用于静态存储引擎,因为你往中间插入一个记录就必须得挪动后面所有的记录,成本太高时间复杂度是:O(log(N))二叉树特点:节点左子树所有结点的值小于父节点的值,右子树所有结点的值大于父节点的值。查询时间复杂度O(log(N)),更新时间复杂度O(log(N))但是实际上大多数的数据库存储却并不使用二叉树。其原因是,索引不止存在内存中,还要写到磁盘上举栗:你可以想象一下一棵 100 万节点的平衡二叉树,树高 20。一次查询可能需要访问 20 个数据块。在机械硬盘时代,从磁盘随机读一个数据块需要 10 ms 左右的寻址时间。也就是说,对于一个 100 万行的表,如果使用二叉树来存储,单独访问一个行可能需要 20 个 10 ms 的时间nnoDB 的索引模型在 InnoDB 中,表都是根据主键顺序以索引的形式存放的,这种存储方式的表称为索引组织表。InnoDB 使用了 B+ 树索引模型,所以数据都是存储在 B+ 树中的。每一个索引在 InnoDB 里面对应一棵 B+ 树。【主键索引】主键索引的叶子节点存的是整行数据。在 InnoDB 里,主键索引也被称为聚簇索引(clustered index)【非主键索引】非主键索引的叶子节点内容是主键的值。在 InnoDB 里,非主键索引也被称为二级索引(secondary index)。主键长度越小,普通索引的叶子节点就越小,普通索引占用的空间也就越小。【两者的区别】举个栗子:如果语句是 select * from T where ID=500,即主键查询方式,则只需要搜索 ID 这棵 B+ 树;如果语句是 select * from T where k=5,即普通索引查询方式,则需要先搜索 k 索引树,得到 ID 的值为 500,再到 ID 索引树搜索一次。这个过程称为回表。基于非主键索引的查询需要多扫描一棵索引树B+ 树能够很好地配合磁盘的读写特性,减少单次查询的磁盘访问次数。
2021年09月05日
167 阅读
0 评论
0 点赞
1
...
7
8
9