0%

传统上,第一个程序就是hello world, Qt也不例外。

1
2
3
4
5
6
7
8
9
10
11
#include <QApplication>
#include <QLabel>

int main(int argc, char** argv){
QApplication app(argc, argv);

QLabel lMsg("Hello QT5!");
lMsg.show();

return app.exec();
}

编译

1
2
3
$ qmake -project
$ qmake
$ make

出现错误:

1
hello.cpp:1:24: fatal error: QApplication: No such file or directory

是因为Qt5将大部分桌面部件移到了Qt Widgets模块中,即QApplication已经从原来的QtGui/QApplication移动到QtWidgets/QApplication了。
而qmake默认只连接core和gui下的模块,因此需要修改生成的hello.pro,最后面添加widgets里面的模块:

1
QT += widgets

然后重新qmake和make就可以生成动态连接的目标文件hello,执行

1
$ ./hello

一个最简单的Qt5 GUI程序就出现了。

===
[erq]

之前一直比较抵触Qt,当然就是因为它的授权问题。随着Qt对开源社区越来越友好,授权方式也做了很大的调整,现在授权已不是障碍。
Qt感觉上比GTK/GTK+还是要完善不少,整个的生态也更成熟。
最新版的Qt 5.7全面拥抱C++11标准,对于C++拥趸来讲当然是好事一桩。
虽然linus并不喜欢C++,但不妨碍C++成为一门伟大的语言。
开始学一下Qt,下一步要基于QCAD二次开发一个测绘类应用程序,还有很长的路要走。

下载安装

debian源里的Qt版本略低,从官方下载最新的Qt5.7安装文件qt-opensource-linux-x64-5.7.0.run
添加执行权限,然后将Qt安装到/opt目录

1
2
$ chmod +x qt-opensource-linux-x64-5.7.0.run
# ./qt-opensource-linux-x64-5.7.0.run

如果没有Qt账号,可以提前注册一个,也可以即时注册,安装目录选择/opt/Qt

配置变量

修改bashrc文件,添加:

1
2
3
4
5
6
# qt5.7
export QT_HOME=/opt/Qt/5.7/gcc_64
export PATH=$QT_HOME/bin:$PATH
export CPATH=$QT_HOME/include:$PATH
export LIBRARY_PATH=$QT_HOME/lib:$LIBRARY_PATH
export LD_LIBRARY_PATH=$QT_HOME/lib:$LD_LIBRARY_PATH

然后source以下就可以了

1
$ . .bashrc

===
[erq]

debian安装字体很简单,将字体丢到~/.fonts目录即可,要立即生效可以执行一下fc-cache命令。

服务器安装配置

1
# apt install nfs-kernel-server

编辑/etc/exports文件,添加:

1
/srv/homes 10.100.0.0/24(rw) 192.168.0.0/24(rw)

客户端安装配置

1
# apt install nfs-common

客户端查看服务器资源:

1
2
3
# showmount -e 10.100.0.30
Export list for 10.100.0.30:
/srv/homes 10.100.0.0/24

如果出现错误提示:

1
rpc mount export: RPC: Authentication error; why = Failed (unspecified error)

可以查看nfs服务器/etc/hosts.allow和/etc/hosts.deny的配置,是否允许客户机访问nfs资源,可以简单粗暴的允许所有主机访问,在/etc/hosts.allow最末尾添加ALL:ALL

客户端挂载服务器共享资源:

1
# mount 10.100.0.30:/srv/homes /mnt/share

自动挂载编辑/etc/fstab:

1
2
# nfs
10.100.0.30:/svr/homes /mnt/share nfs defaults 0 0

===
[erq]

物理备库执行实时日志应用时有如下错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
sql> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE USING CURRENT LOGFILE DISCONNECT FROM SESSION;
ORA-38500: USING CURRENT LOGFILE option not available without stand
```js

是因为没有standby redo log日志组,这次好像是丢失了。
查看日志组:
```js
idle>select member from v$logfile;

MEMBER
----------------------------------------------------------------------------------------------------
E:\\ORACLE\\PRODUCT\\10.2.0\\ORADATA\\ORCL\\REDO03.LOG
E:\\ORACLE\\PRODUCT\\10.2.0\\ORADATA\\ORCL\\REDO02.LOG
E:\\ORACLE\\PRODUCT\\10.2.0\\ORADATA\\ORCL\\REDO01.LOG

只有online redo日志文件,没有standby redo日志文件,因此添加:

1
2
3
4
5
6
7
8
SQL>alter database add standby logfile group 4 ('E:\\ORACLE\\PRODUCT\\10.2.0\\ORADATA\\ORCL\\STDBYREDO01.LOG') size 50M;
Database altered.
SQL>alter database add standby logfile group 5 ('E:\\ORACLE\\PRODUCT\\10.2.0\\ORADATA\\ORCL\\STDBYREDO02.LOG') size 50M;
Database altered.
SQL>alter database add standby logfile group 6 ('E:\\ORACLE\\PRODUCT\\10.2.0\\ORADATA\\ORCL\\STDBYREDO03.LOG') size 50M;
Database altered.
SQL>alter database add standby logfile group 7 ('E:\\ORACLE\\PRODUCT\\10.2.0\\ORADATA\\ORCL\\STDBYREDO04.LOG') size 50M;
Database altered.

重新执行日志实时应用就没问题了。

===
[erq]

sql脚本文件内容如下:

1
2
3
4
5
6
7
set linesize 200 
set term off verify off feedback off pagesize 999
set markup html on entmap ON spool on preformat off
spool result.xls
@query.sql
spool off
exit

entmap是指html实体映射,ent是entity的简写

将输出文件的名称改为.html后缀,即可输出html文档.其实输出的内容是完全一样的,只是文件扩展名不同.

sqlplus set指令详见[1]

References:
[1]SET System Variable Summary

===
[erq]

当脚本遇到错误或被用户终止时,有些清理动作需要执行,这时候可以通过捕捉signal来完成这项工作.

trap格式为:

1
trap commands signals

commands可以是任何内建命令,外部命令或者脚本中的函数等.
signals是要捕捉的信号,可以一次扑捉多个信号,只要提供信号列表即可.

系统支持的信号列表:

1
$ kill -l

trap不只可以捕获各种信号,还可以捕获EXIT和ERR。
trap func EXIT允许在脚本结束时调用注册的函数。由于无论正常退出抑或异常退出,因此是写脚本清理函数绝佳所在。
trap func ERR允许在运行出错时调用注册的函数。不过要记住,程序异常退出时,既会调用EXIT注册的函数,也会调用ERR注册的函数。

如果脚本中设置了:

1
set -e

当脚本中任何命令退出码非0时,立即退出脚本,这时候可以扑捉ERR,并设置处理程序:

1
2
3
4
trap 'err_handler ${LINENO} $?' ERR 
function err_handler() {
# some clean works
}

通过捕捉ERR,可以捕捉到程序非正常退出包括SIGINT(Ctrl+C)

${LINENO}为出错的行号,$?为最后执行命令的退出码

References:
[1]关于Linux Shell的信号trap功能你必须知道的细节
[2]12.2. Traps
[3]编写可靠shell脚本的八个建议

===
[erq]

pg_dump可以转储数据库为一个sql脚本文件或其他归档格式文件,比如pg_restore使用的归档格式。

pg_dump默认输出普通的sql脚本,指定-F –format=format来指定pg_restore支持的格式,比如-Fc或-Ft

pg_dumpall内部使用pg_dump来转储数据库,只输出文本格式的sql脚本文件。

在转储的同时可以进行bzip2压缩,比如:

1
$ pg_dumpall -U user -h localhost -c --if-exists --role=postgres bzip2 > db.sql.bz2

-c选项指定在重建数据库对象之前插入清理语句(drop)。

sql脚本文件只能使用psql来执行,如果使用pg_restore,则会有如下错误提示:

1
pg_restore: \[archiver\] input file appears to be a text format dump. Please use psql

其他格式则需要使用pg_restore来恢复。

恢复pg_dumpall转储的sql脚本时,使用超级用户postgres来恢复:

1
2
3
$ sudo -u postgres psql -f reis_2016_08_07.sql > import.log
psql:reis_2016_08_07.sql:24: ERROR: current user cannot be dropped
psql:reis_2016_08_07.sql:33: ERROR: role "postgres" already exists

有错误提示不能drop掉postgres用户和postgres用户已经存在,在sql脚本中有这样两行:

1
2
DROP ROLE IF EXISTS postgres;
CREATE ROLE postgres;

因为当前用户正是postgres,所以会有这样的错误,忽略掉即可。

References:
[1]Postgresql 转存恢复数据经验

expdp是10g及以后新增的数据导出工具,数据导出速度有了很大的提升。而且expdp比exp有了更细粒度的导出支持,比如可以排除指定的表。

expdp真正的数据导出是在服务器端执行的,因此需要先建立directory数据库对象。

创建directory对象

1
sql> CREATE DIRECTORY dir_expdp as '\\\\192.168.0.82\\exp';

directory对象可以使用网络路径,这样可以从数据库服务器expdp到网络上的远程机器。

查询目录对象:

1
sql> SELECT * FROM dba_directories;

当前并没有alter directory对象的支持,如果修改只能先drop,然后再create。

导出数据

expdp使用schemas来指定需要导出的schema,类似于exp的owner参数,可以理解为用户名,其实二者并不同,只是一般二者同名而已。
directory指定使用哪个目录对象,就是上一步创建的目录对象。
dumpfile指定导出的数据文件
logfile指定导出日志文件
exclude指定需要排除的数据库对象,包括table等很多种对象

比如:

1
2
$ expdp system/passwd@orcl schemas=user1,user2 EXCLUDE=TABLE:"IN('table1','table2')"
directory=dir_expdp dumpfile=${dmp_file} logfile=${explog_file}

expdp优化
expdp的优化主要在于提高并行度,也就是指定parallel参数,一般此参数等于cpu个数,并且要小于dump文件的个数,可以在dumpfile中指定%U让expdp自动按需要按顺序生成dump文件

查看cpu数量:

1
sql> show parameter cpu

列如:

1
2
$ expdp system/passwd@orcl schemas=user1,user2 EXCLUDE=TABLE:"IN('table1','table2')"
directory=dir_expdp dumpfile=db_%U.dmp logfile=explog_file parallel=16

还可以使用filesize来限制每个dump文件的最大尺寸。

impdp导入

1
$ impdp system/passwd@orcl schemas=user1,user2 directory=dir_impdp dumpfile=db_%U.dmp logfile=explog_file parallel=16

impdp导入时也可以使用%U来指定输入的dump文件,也可以使用parallel参数来提速.

如果出现错误:

1
ora-31684 object type user already exists

是因为在导入之前已经创建了user的原因,可以忽略掉此错误,或者impdp添加参数exclude=user

使用参数文件

可以将所有的expdp,impdp参数写入一个参数文件,然后在命令行上引用此文件,比如编辑一个expdp.par参数文件:
expdp.par

1
2
3
4
5
6
7
schemas=user1,user2,user3
exclude=TABLE:"IN('table1','table2','table3','table4','table5')"
directory=dir_expdp
dumpfile=db_%U.dmp
logfile=db.log
parallel=4
version=10.2.0.3.0

然后这样使用参数文件:

1
$ expdp parfile=expdp.par

排除对象

使用exclude参数排除对象,其语法为:

1
EXCLUDE=object_type\[:name_clause\] \[, ...\]

Object_type用于指定要排除的对象类型,name_clause用于指定要排除的具体对象.

1
2
3
4
5
6
7
8
9
EXCLUDE=SCHEMA:"='HR'" #排除名字为HR的schema
EXCLUDE=USER #排除所有创建user的DDL语句
EXCLUDE=USER:"='HR'" #排除创建用户HR的DDL语句
EXCLUDE=VIEW,PACKAGE,FUNCTION #排除视图,包和函数
EXCLUDE=INDEX #排除索引
EXCLUDE=GRANT #排除授权
EXCLUDE=TRIGGER #排除触发器
EXCLUDE=TABLE:"IN ('COUNTRIES', 'REGIONS')" #排除某些表
EXCLUDE=SCHEMA:"LIKE 'SYS%'" #排除以SYS开头的schema

exclude参数可以多次出现,也可以将所有的排除写到一个exclude参数中.

include语法与EXCLUDE相同,但二者不能同时使用.

References:
[1]Data Pump Export
[2]优化IMPDP/EXPDP导入导出速度
[3]expdp impdp 数据库导入导出命令详解
[4]ORA-31684 import error Tips

===
[erq]

debian源里的docker叫docker.io,版本略低。这里从官方源安装docker,官方源里叫docker-engine。

安装docker要求内核必须为3.10以上版本,而且必须为64位架构。

debian版本最小支持到wheezy,但是wheezy必须添加backports源.

docker官方源使用https协议,因此先安装以下包:

1
# apt install apt-transport-https ca-certificates

导入doker公钥:

1
2
$ gpg --keyserver pgp.mit.edu --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
$ gpg --export --armor 58118E89F3A912897C070ADBF76221572C52609D sudo apt-key add -

/etc/apt/sources.list.d/docker.lis文件中添加官方源:

当前的testing stretch:

1
deb https://apt.dockerproject.org/repo debian-stretch main

jessie版本:

1
deb https://apt.dockerproject.org/repo debian-jessie main

安装:

1
2
# apt update
# apt update docker-engine

运行docker daemon:

1
$ sudo service docker start

运行docker hello world:

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
$ sudo docker run hello-world

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
c04b14da8d14: Pull complete
Digest: sha256:0256e8a36e2070f7bf2d0b0763dbabdd67798512411de4cdcf9431a1feb60fd9
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker Hub account:
https://hub.docker.com

For more examples and ideas, visit:
https://docs.docker.com/engine/userguide/

docker安装正常。

docker daemon始终以root用户运行,但通过将用户加入docker组,可以使用户访问docker的客户程序不使用root权限来访问docker服务:

1
2
$ sudo gpasswd -a $USER docker
Adding user xxx to group docker

或者

1
$ sudo usermod -aG docker $USER

如果没有docker用户组,请自行建立。将foo替换成你想要的用户名,然后重新启动docker服务:

1
$ sudo service docker restart

updated(07/07/2019):
官方安装源地址发生变化,最新的安装说明参见[2]

References:
[1]Installation on Debian - Docker
[2]Get Docker CE for Debian