Go中的单元测试和基准测试

TDD

Test-Driven Development: 测试驱动开发,是敏捷开发中的一项核心实践和技术,也是一种设计方法论。TDD的原理是在开发功能代码之前,先编写单元测试用例代码,测试代码确定需要编写什么产品代码。

APP接入收发红包功能

APP 如何接入收发红包功能

使用支付宝的现金红包方案

现金红包简介

现金红包- 开发入门

现金红包是基于支付宝的支付能力推出的一款针对收发红包场景的产品,现金红包根据业务场景的不同分为 B2C 红包和 C2C 红包。通过该能力可以发送现金红包,用户领取之后现金红包可以进入到其支付宝余额中,用于消费,转账和提现。

阿里云MySQL分析实例

MySQL分析实例是 AnaylticDB MySQL (简称ADB)的一种标准适用场景,它可实现对MySQL的分析加速。针对RDS MySQL用户的复杂分析查询卡顿或者响应慢的问题,MySQL分析实例给出了完美的解决方案。只需创建一个MySQL分析实例,即可在新实例上实现复杂查询语句的分析加速。一般适用于慢查询RT>=10s、SQL语句复杂(例如join、like、group by、order by、count、distinct)的场景,尤其是大数据量下的复杂查询,性能提升十倍,甚至百倍。

php和go对比

php 优缺点

优点

  • php 支持泛型
  • php 支持 in_array
  • php 同个函数的数组返回值,key可以随意变化

缺点,可维护性差

  • 数据类型没有强制要求提前声明,同个变量可以支持多种数据类型的值
  • 关联数组字段没有声明,不清楚该关联数组有哪些字段
  • 服务器部署 php 项目代码占用的资源更多

go 优缺点

优点

Go 常用案例

golang中判断两个slice是否相等

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package main

import (
    "bytes"
    "fmt"
)

func main() {
    a := []byte{0, 1, 3, 2}
    b := []byte{0, 1, 3, 2}
    c := []byte{1, 1, 3, 2}

    fmt.Println(bytes.Equal(a, b))
    fmt.Println(bytes.Equal(a, c))
}

计算中文长度

1
2
3
title := "中国人a"
fmt.Println(len([]rune(title))) // 第一种方案:输出 4
fmt.Println(utf8.RuneCountInString(title)) // 第二种方案:输出 4

数据库初始化

什么是 DSN 信息?

位运算使用技巧

位运算概览

符号 描述 运算规则
& 两个位都为1时,结果才为1 【选中A标签和B标签的用户bitmap=选中A标签的用户bitmap & 选中标签的用户bitmap】
| 两个位都为0时,结果才为0 【选中A或B标签的用户bitmap=选中A标签的用户bitmap
^ 异或 两个位相同为0,相异为1【可用于取非数据,如不包含某个标签的用户bitmap=全量用户bitmap ^ 包含某个标签的用户bitmap】
~ 取反 0变1,1变0
« 左移(每左移 1 位就乘以 2) 各二进位全部左移若干位,高位丢弃,低位补0 【2的10次方=1024】
» 右移(每右移 1 位就除以 2) 各二进位全部右移若干位,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移)

优点

Go Micro

micro 常用的几个命令

  • micro server //启动服务端
  • micro login //登录服务 user: admin pass: micro
  • micro new XXX //新建服务
  • micro services //服务列表
  • micro run XXX //挂载服务
  • micro status //查看服务状态
  • micro logs XXX //查看XXX服务日志
  • micro service XXX //XXX服务详情
  • micro XXX –参数=值 //调用XXX服务返回结果

学习链接

Micro 框架

无限极分类树

分类树

一般的分类树状结构有两种方式:

  • 一种是adjacency list,也就是是id,parent_id这种形式。
  • 另一种是nested set,即左右值的形式。

左右值形式查询起来比较高效,无需递归等,推荐使用,但是没有pid形式简单直观。

Go的一些坑

代码格式化

golang 自带的 go fmt 默认是是 tab 缩进, 而 goland IDE 的格式化默认是空格缩进【快捷键:option+command+L】

json的坑

[]uint8 转 json 后,得不到想要的结果

  • 期待结果:[1, 2, 3]
  • 输出结果:“AQID”
1
2
3
4
5
func main() {
   arr := []uint8{1, 2, 3}
   b, _ := json.Marshal(arr)
   fmt.Println(string(b))
}

slice/map/channel本身就是引用类型

slice

多系统对接-签名校验案例(PHP)

config/Sign.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<?php

// 第三方平台调用『当前系统』接口的签名密钥
return [
    // 签名生命周期设置,单位秒
    'sign_ttl' => env('SIGN_TTL', 600),

    // 签名类型
    'sign_type_xxx' => 'xxx', //  xxx系统
    'sign_type_test' => 'test', //  test系统

    // 密钥
    'sign_type_secret' => [
        'xxx' => env('SIGN_SECRET_XXX', 'test_123456'),
        'test' => env('SIGN_SECRET_TEST', 'test_123456'),
    ],
];

app/Services/AuthSign.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?php

namespace App\Services;

// 第三方平台请求的签名校验
class AuthSign
{
    /**
     * 签名校验
     * @param string $signType 签名类型,对接哪个第三方系统的标识
     * @param string $sign 签名
     * @param int $requestTime 请求时间戳
     * @return array
     */
    public static function checkSign(string $signType, string $sign, int $requestTime): array
    {
        // 签名类型:新增对外接口签名类型时,需要去配置新的签名类型和密钥
        $signSecret = config('sign.sign_type_secret')[$signType] ?? '';

        if ($signSecret == '') {
            return ['result' => false, 'msg' => '该签名类型还没配置'];
        }

        if ($sign != md5("{$requestTime}-{$signType}-{$signSecret}")) {
            return ['result' => false, 'msg' => '签名有误'];
        }

        $currentTime = time();
        if ($currentTime < $requestTime || ($currentTime-$requestTime) > config('sign.sign_ttl')) {
            return ['result' => false, 'msg' => '签名已过期'];
        }

        return ['result' => true, 'msg' => '签名校验成功'];
    }

    /**
     * 生成签名
     * @param string $signType 签名类型,对接哪个第三方系统的标识
     * @return array
     */
    public static function getSign(string $signType): array
    {
        $signSecret = config('sign.sign_type_secret')[$signType] ?? '';
        if ($signSecret == '') {
            return ['result' => false, 'msg' => '该签名类型还没配置'];
        }
        $requestTime = time();
        return ['result' => true, 'time' => $requestTime, 'sign' => md5("{$requestTime}-{$signType}-{$signSecret}")];
    }
}

app/Http/Middleware/AuthSignTest.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php

namespace App\Http\Middleware;

use App\Facades\Response;
use Symfony\Component\HttpFoundation\Response as FoundationResponse;
use Closure;

// 『test系统』请求『当前系统』接口的签名校验
class AuthSignTest
{
    public function handle($request, Closure $next)
    {
        $sign = $request->header('sign') ?: '';
        $time = $request->header('time') ? : '';

        if (empty($sign) || empty($time)) {
            return Response::fail('传参有误', [], FoundationResponse::HTTP_UNAUTHORIZED);
        }

        $signData = \App\Services\AuthSign::checkSign(config('sign.sign_type_test'), $sign, (int)$time);
        if (!$signData['result']) {
            return Response::fail("sign校验失败:{$signData['msg']}", [], FoundationResponse::HTTP_UNAUTHORIZED);
        }

        return $next($request);
    }
}

app/Http/Kernel.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
    // 注册中间件
    protected $routeMiddleware = [
        'auth.test' => \App\Http\Middleware\AuthSignTest::class,
    ];
}

routes/api_sign.php

1
2
3
4
5
6
<?php

// 路由使用签名做校验
Route::group(['prefix' => 'mini', 'middleware' => ['auth.test', 'request.log'], 'namespace' => 'test'], function () {
    Route::put('xxx', 'SignController@setXXX');
});