Mark

dbeaver手动导入驱动

December 7, 2023
DB
Mark

因为直接下载dbeaver的时候,是没有带上驱动文件的,所以需要在使用时下载。

但是,如果刚好安装的环境是无法通网的,那么就需要手动传入驱动并安装。

做法如下:

  1. 现在本地有网环境下载驱动文件

dbeaver下载mysql的驱动,会存放在目录:C:\Users\{用户名}\AppData\Roaming\DBeaverData\drivers\maven\maven-central\mysql.

NOTE: 注意替换{用户名}为你本机实际名称。

  1. 把下好的文件传入到无网机器上,同样放到以上目录。

  2. 打开dbeaver数据库->驱动管理器,添加驱动

选中MySQL,然后点击编辑;在弹出框里切到,将已有内容全部删掉,再点击添加文件夹,然后选择上面驱动存放的目录,即可确定保存。

如此,即可手动导入驱动文件。

Mysql 8.0.33在使用窗口函数的同时不能用count(distinct *)

October 18, 2023
Mysql 8
Mark

Mysql 8.0.33在使用窗口函数的同时不能用count(distinct *)

比如,我想在窗口函数里使用字段apply_unit_id分组,然后求project_id列不重复值的数量:

select distinct apply_unit_id, count(distinct project_id) over (partition by apply_unit_id)
from weia join weiag on weiag.apply_id = weia.id 
;

此时报错:SQL 错误 [1235] [42000]: This version of MySQL doesn't yet support '<window function>(DISTINCT ..)'

怎么办呢? #

使用 dense_rank()间接计算:

select distinct apply_unit_id, dense_rank() over (partition by apply_unit_id order by project_id) 
+ dense_rank() over (partition by apply_unit_id order by project_id desc) 
- 1
from weia join weiag on weiag.apply_id = weia.id 
;

dense_rank() #

Returns the rank of the current row within its partition, without gaps.

– 返回当前行在其分区内的排名,没有间隙。

...

Wezterm极简配置文件

October 17, 2023
Rust, Wezterm
Mark

Wezterm极简配置文件

-- Pull in the wezterm API
local wezterm = require 'wezterm'

-- This table will hold the configuration.
local config = {}

-- In newer versions of wezterm, use the config_builder which will
-- help provide clearer error messages
if wezterm.config_builder then
  config = wezterm.config_builder()
end

-- This is where you actually apply your config choices

-- For example, changing the color scheme:
config.color_scheme = 'AdventureTime'
-- config.color_scheme = 'Batman'

config.enable_tab_bar = true
config.hide_tab_bar_if_only_one_tab = false
config.show_tab_index_in_tab_bar = false
config.tab_bar_at_bottom = true
config.tab_max_width = 25

-- Font
-- config.font = wezterm.font_with_fallback { 'JetBrains Mono' }
config.font_size = 14
config.freetype_load_target = "Light" -- Possible alternatives are `HorizontalLcd`, `Light`, `Mono`, `Normal`, `VerticalLcd`.

config.mouse_bindings = {  -- Paste on right-click
    {
        event = {
            Down = {
                streak = 1,
                button = 'Right'
            }
        },
        mods = 'NONE',
        action = wezterm.action {
            PasteFrom = 'Clipboard'
        }
    }, -- Change the default click behavior so that it only selects
    {
        event = {
            Up = {
                streak = 1,
                button = 'Left'
             }
         },
        mods = 'NONE',
        action = wezterm.action {
            CompleteSelection = 'PrimarySelection'
         }
    }, -- CTRL-Click open hyperlinks
    {
        event = {
            Up = {
                streak = 1,
                button = 'Left'
             }
         },
        mods = 'CTRL',
        action = 'OpenLinkAtMouseCursor'
    }
}

config.keys = {
    -- 使用 Ctrl+n 来新建标签页,而不是 Ctrl+Shift+T
    { key = "n",          mods = "ALT", action = wezterm.action { SpawnTab = "DefaultDomain" } },
    -- 使用 Alt+左右箭头来切换标签页
    { key = "LeftArrow",  mods = "ALT", action = wezterm.action { ActivateTabRelative = -1 } },
    { key = "RightArrow", mods = "ALT", action = wezterm.action { ActivateTabRelative = 1 } },
}

-- 定义 Alt+数字 切换到对应标签页的快捷键
for i = 1, 9 do
    table.insert(config.keys, {
        key = tostring(i),
        mods = 'ALT',
        action = wezterm.action.ActivateTab(i - 1),
    })
end

-- and finally, return the configuration to wezterm
return config

雪花id的时钟回退问题

September 27, 2023
Snowflake, Time
Mark

雪花id由64位二进制组成,转成字符串则长为19. 它依赖于系统时钟,如果出现时钟回退,会导致已经在用的id再次被生成。

怎么办呢?

  1. 记录上次生成时间,在本次生成时比较时间,如果当前时间比上次生成时间要小,则认为时钟回拨,直接报错。也可以一直重试,直到当前时间不小于上次生成时间。

  2. 采用历史时间则天然的不存在时间回拨问题。但是在超高并发情况下,历史的时间很快用完,时间一直保持在最新时间的话,这个时候还是会出现时间回拨。

  3. Go1.9开始,使用单调时钟: time.Now(), time.Since(), time.Until().

// # Monotonic Clocks

//

// Operating systems provide both a “wall clock,” which is subject to

// changes for clock synchronization, and a “monotonic clock,” which is

// not. The general rule is that the wall clock is for telling time and

// the monotonic clock is for measuring time. Rather than split the API,

// in this package the Time returned by time.Now contains both a wall

...

Vscode go cannot find GOROOT directory

September 13, 2023
Go, Vscode
Mark

今天发现在windows上的vscode一直提示找不到go:go: cannot find GOROOT directory: c:\msys64\mingw64\lib\go

强制设置了go.goroot也不行,直到查看了GOENV文件(C:\Users\xxx\AppData\Roaming\go\env)之后,才发现里面有一行:GOROOT=c:\msys64\mingw64\lib\go,可能是当时在msys2安装go的时候加上的。

去掉它就恢复正常了。

$ go env
set GOENV=C:\Users\xxx\AppData\Roaming\go\env
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOMODCACHE=C:\Users\xxx\go\pkg\mod
set GOOS=windows
set GOPATH=C:\Users\xxx\go
set GOPRIVATE=
set GOPROXY=https://goproxy.cn,https://goproxy.io,direct
set GOROOT=C:\Program Files\Go

应该是这样的,如果用go env -w 来设置goroot,那么这个值就会保存到GOENV对应的文件里,如果是$env:GOROOT=xxx的方式来设置则不会修改GOENV文件里的内容。这时候,如果vscode是优先从GOENV文件来获取GOROOT的话,就可能会导致与实际的GOROOT不一致。

所以,如果再遇到以上错误,除了echo $env:GOROOT 看一下环境变量值之外,也要看一下GOENV文件。

不同系统之间通过网络对接

September 13, 2023
Go, Vscode
Mark

不同系统之间通过网络对接

数据库事件 #

  1. 可以用个事件表来做,在事务执行过程中添加事件(确保事务完成时事件也存在)。

  2. 在事务提交之后,先尝试做一次事件,如果成功了就把事件状态置为成功;如果失败了也没关系,另外开定时器来扫表进行重试执行。 – 此时不影响正常业务执行

  3. 在事件处理事务里的网络请求里加入超时控制,确保事件不会执行太久,导致接口过慢。

  4. 网络请求支持幂等,防止事件处理事务请求成功了,但是事务挂了导致状态未变更,这种情况下会重复请求多次。

skip locked实现 #

-- 条件字段必须有索引(status, [name, status]),排序字段必须是主键(id),此时刚好是所要锁定的行

start transaction;
-- select * from w_event we where status in (1) order by create_time asc limit 1 for update skip locked; -- 引入create_time作为排序字段时,会将符合条件的行都锁住,`limit 1`不起作用
select * from w_event we where status in (1) order by id asc limit 1 for update skip locked; -- 使用主键字段作排序时,`limit 1`则起作用
select * from w_event we where name = '测试' and status in (1) order by id asc limit 1 for update skip locked; -- 如果有多个字段作为条件,需要建立组合索引
SELECT object_name, index_name, lock_type, lock_mode, lock_data FROM performance_schema.data_locks; -- 查看上锁情况
select * from w_event we where status in (2) order by id asc limit 1 for update skip locked;
select * from w_event we where status in (3) order by id asc limit 1 for update skip locked;
commit;

可打开两个线程来验证上述事务执行,可以看到,当满足条件的记录有两条或以上时,当事务1查到记录1后,事务1未提交时,事务2不会拿到记录1,而是会拿到记录2. 也就实现了有锁则获取下一批数据的效果。

...

Go Empty Struct

September 1, 2023
Go
Mark

package main

import (
	"fmt"
	"unsafe"
)

func main() {
	type A struct{}
	type B struct{}
    // 结构体里的字段都是`Empty Struct`时,占用空间为0
	type S struct {
		A A
		B B
	}
	var s S
	fmt.Println(unsafe.Sizeof(s)) // prints 0
    // 如果是指针,占用空间为8
	fmt.Println(unsafe.Sizeof(&s)) // prints 8

	var x [1000000000]struct{}
    // 可以同时存储A和B类型元素
	x[0] = A{}
	x[1] = B{}
	fmt.Println(unsafe.Sizeof(x)) // prints 0
    // 地址一样
	fmt.Printf("%p, %p", &x[0], &x[1]) // 0x54e3a0, 0x54e3a0
}

See also