Docker环境部署Nginx

1、运行容器

docker run --name nginx -d nginx

2、在宿主机的当前用户文件夹下创建nginx的目录结构

mkdir -p ~/nginx/{html,logs,conf,conf.d,cert}

3、把容器中的Nginx目录拷贝到宿主机的当前用户文件夹下

docker cp nginx:/etc/nginx/conf.d/default.conf ~/nginx/conf.d/default.conf
docker cp nginx:/etc/nginx/nginx.conf ~/nginx/conf/nginx.conf
docker cp nginx:/usr/share/nginx/html ~/nginx/html

4、此时,宿主机中有了nginx容器的配置,可以停止容器,并删除

docker stop nginx
docker rm nginx

5、现在,我们可以重新创建一个新的nginx容器,并且把宿主机刚刚复制出的文件挂载到容器上

docker run --name=nginx \
           -p 80:80 \
           -p 443:443 \
           -v ~/nginx/conf.d:/etc/nginx/conf.d \
           -v ~/nginx/conf/nginx.conf:/etc/nginx/nginx.conf \
           -v ~/nginx/html:/usr/share/nginx/html \
           -v ~/nginx/logs:/var/log/nginx \
           -v ~/nginx/cert:/etc/nginx/cert \
           --privileged=true \
           --restart=always \
           -d \
           nginx

6、平滑重启Nginx

docker exec nginx nginx -s reload

以下为Nginx的一个简单反向代理配置

server {
    listen 80;
    server_name www.域名A.com bbs.域名B.com;
    access_log  /var/log/nginx/www.域名A.com.access.log;
    error_log /var/log/nginx/www.域名A.com.error.log;
    location / {
        proxy_pass http://IP地址:端口;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

分享一个自己写的人教版口算生成器

因为孩子上小学的关系,每日需要练习口算,所以,特地开发了这个和人教版同步的口算生成器,上传到GitHub,有需要的可以在此生成口算:http://math.tzqutao.top/

# 此程序为人教版数学教材配套,按照课文大纲设计口算题,目前囊括以下内容,后续会继续更新

以下是GitHub的开源地址 https://github.com/taizhouqutao/math

包括如下内容

# 一年级(下)

2.1 二十以内的进位加法

2.2 二十以内的退位减法

5.1 认识人民币

6.1 100以内的加法和减法(一)整十数加、减整十数

6.2 100以内的加法和减法(一)两位数加一位数、整十数

6.3 100以内的加法和减法(一)两位数减一位数、整十数

# 二年级(上)

2.1 100以内的加法和减法(二)不进位加

2.2 100以内的加法和减法(二)进位加

2.3 100以内的加法和减法(二)不退位减

2.4 100以内的加法和减法(二)退位减

3.1 表内乘法(一)5的乘法口诀

3.2 表内乘法(一)2、3、4的乘法口诀

3.3 表内乘法(一)6的乘法口诀

4.1 表内乘法(二)7的乘法口诀

4.2 表内乘法(二)8的乘法口诀

4.2 表内乘法(二)9的乘法口诀

# 二年级(下)

2.1 表内除法(一)用2~6的乘法口诀求商

4.1 表内除法(二)

5.1 混合运算

6.1 有余数的除法

7.1 万以内数的认识 整百、整千数的加减法

分享一个自己搞的坦克大战的源码吧

核心方法,构造坐标系,把炮弹对应和坦克对象分别放到2和对象数组里,地形对象也放一个对象数组,不同类型地形需要不同的渲染方式,再构造一个计时器对象,用来驱动坦克移动和开火。

以下是预览效果

游玩方法,键盘空格用来开火,键盘光标用来控制方向
以下是游玩的跳转地址 点击跳转坦克大战游玩

GitHub上的地址 https://github.com/taizhouqutao/WindowsGame

MySQL8 新特性和常用查询优化

1:默认数据引擎改变为InnoDB

Mysql8之前的版本,默认引擎为MyISAM(主要的非事务处理存储引擎),从Mysql8开始,数据库默认引擎为InnoDB(支持事务、分布式、事务部分回滚、行级锁、外键)

2:默认字符集改变为utf8mb4

Mysql8之前的版本,默认字符集为lation1,从Mysql8开始,数据库默认编码改为utf8mb4

3:新增设置系统变量参数(Persist),全局变量的持久化,如下:

show [global|session] variables like '%time_zone%'; 
 set [global|session|persist] time_zone='+8:00';  
 flush privileges; # 立即生效

4:自增变量的持久化

 Create table test1(
 id int auto_increment primary key,
 Val int
 );
 Insert into test1(val) values (1);
 Delete from table where id=1;
 -- 重启数据库
 Insert into test1(val) values (1);
 Select * from test1
 -- 发现id变成了2,但如果是MySQL5的版本,则id会是1
 

5:新增窗口函数

窗口函数类似sum(),count()那样的聚合函数,但是它不会将多行合并,而是将结果多行返回,也就是说,窗口函数是不需要Group By的,以下是几个简单的例子

 select *,sum(count) over() as totalcount from Orders;
 
 select *,count/(sum(count) over()) as totalcount from Orders;

6:新增通用表达式

通用表达试简称CTE,CTE是命名的临时结果集,作用范围是当前语句,CTE可以理解成一个可以复用的子查询,CTE可以引用其他CTE,但是子查询不能引用其他子查询 例如我们在8.0之前的sql,只能使用子查询获取类别名称

 Select g.*,(select name from category where id=g.cat_id)  cat_name from goods g;

但是在8.0之后,我们可以用CTE的方式

 With cte as ( select * from category)    
 Select g.*,(select cte.name from cte where cte.id=g.cat_id)  cat_name from goods g;

相比子查询,cte的效率会更高,因为非递归的cte只会查询一次并可以重复使用。
我们也可以使用cte引用其它cte,达到查询目的,查询例子如下

 With cte1 as ( select * from category),
 cte2 as (select g.*,cte1. name  cat_name  from goods g left join cte1 on g.cat_id=cte1.id) 
 select * from cte2

7:通用表达式CET递归神器

递归cte是特殊的cte,必须以WITH RECURSIVE开头,递归子查询包括两部分,SEED查询和RECURSIVE查询,中间由union[all]分隔, SEED查询只会执行1次,以创建初始数据集, RECURSIVE查询会重复执行,直到无法满足语句条件为止。

With RECURSIVE cte as (
 select 1 n     -- SEED查询
 union all 
 Select n+1 n from cte where n<8)  -- RECURSIVE查询
 Select * from cte;

以下是2个常用场景

场景1:递归查询指定节点的所有后代

 set @customer_id=2; -- 当前节点
 WITH RECURSIVE cte AS
 (
 SELECT 
 a.customer_id, a.inviter_id,
 cast(a.inviter_id as char(255)) path
 FROM t_customer_relation a WHERE a.customer_id=@customer_id
 UNION ALL
 SELECT
 k.customer_id,k.inviter_id,
 concat(cte.path,',', k.inviter_id) path
 FROM t_customer_relation k 
 INNER JOIN cte ON cte.customer_id = k.inviter_id
 )
 SELECT cte.customer_id,cte.inviter_id,cte.path  FROM cte 
 -- left join t_customer d  on cte.customer_id=d.id
 

场景2:根据当前节点,查询自己的祖宗

set @customer_id =29 ; -- 当前节点
 WITH RECURSIVE cte AS(
     SELECT
     customer_id, 
     inviter_id, 
     convert(inviter_id , char(255)) path 
     FROM t_customer_relation WHERE customer_id = @customer_id 
     UNION ALL
     SELECT 
     c.customer_id, 
     c.inviter_id, 
     concat(cte.path,',', c.inviter_id) path 
     FROM t_customer_relation c, cte WHERE c.customer_id= cte.inviter_id
 )SELECT * FROM cte;

8:支持json类型

Mysql是关系数据库,我们如果再Mysql8前如果有此类需求,一般用Blob类型存取。但是存在以下 缺点:

1.无法保证json正确性

2.json的二操作加工需要代码处理

3.读取json的某个字段,必须从数据库读出字段所有内容

4.无法在json上的某个字段建索引

现在,可以试试在表里使用json类型字段。如下:

Create table tb(
 jsdata  json
 );
 Insert into table(’{”key”:”123”}’);

值得注意的是,key的长度不能超过2个字节(65535)。Mysql8.0提供了很多操作json的函数,包括条件查询,具体可以参考官方文档说明

9:其他新特性

a:加密函数(md5(str),sha (str),sha2 (str,hash_length))

b:GROUP BY 不再隐式排序

c:DLL的原子化(drop table table1,table2;如果table2不存在,那table1将不会删除)

d:支持降序索引

e:统计直方图

f:支持表空间加密

g:支持不可见索引(相对于enable,哪怕隐藏时依然和正常索引一样实时更新,查询不再走)

h:跳过锁等待,sql如下:

select * from table where id=1 for update nowait; --有锁就报错)
select * from table where id=1 for update skip locked; --有锁就不理)

MySql时间格式函数

以下命令为MySql的常用时间函数,可以在编写服务端时,为时间运算和分组提供便利,具体函数如下

select now() `当前时间`,
 unix_timestamp(now()) `时间戳(秒)`,
 from_unixtime(unix_timestamp(now())) `时间戳->时间`,
 concat(date_format(utc_date(),'%Y-%m-%d'),date_format(utc_time(),' %H:%i:%s')) `格林尼治时间`,
 month(now()) `月份`,
 monthname(now()) `月份`,
 dayname(now()) `星期`,
 dayofweek(now()) `对应一周中的索引(1周日 2周一 …… 7周六)`,
 weekday(now()) `日期对应的周索引(0周一 1周二 …… 6周日)`,
 week('2021-01-02',0) `计算时间是一年中的第几周`,   --  一周的第一天(日) 范围(0~53)  本年度中有一个周日
 week('2021-01-02',2) `计算时间是一年中的第几周`,   --  一周的第一天(日) 范围(1~53)  本年度中有一个周日
 week('2021-01-02',1) `计算时间是一年中的第几周`,   --  一周的第一天(一) 范围(0~53)  本年度中有3天以上
 week('2021-01-02',3) `计算时间是一年中的第几周`,   --  一周的第一天(一) 范围(1~53)  本年度中有3天以上
 week('2021-01-02',4) `计算时间是一年中的第几周`,   --  一周的第一天(日) 范围(0~53)  本年度中有3天以上
 week('2021-01-02',6) `计算时间是一年中的第几周`,   --  一周的第一天(日) 范围(1~53)  本年度中有3天以上
 week('2021-01-02',5) `计算时间是一年中的第几周`,   --  一周的第一天(一) 范围(0~53)  本年度中有一个周一
 week('2021-01-02',7) `计算时间是一年中的第几周`,   --  一周的第一天(一) 范围(1~53)  本年度中有一个周一
 dayofyear(now()) `一年当中的第几天`,
 date_Add(now(),interval 1 day) `新增一天`,
 date_format(now(),'%Y-%m-%d %H:%i:%s') `时间格式化`

创建MYSQL的定时任务

自MySQL5.1.6起,增加了一个非常有特色的功能-事件调度器(Event Scheduler),可以用做定时执行某些特定任务(例如:删除记录、对数据进行汇总、数据备份等等)。更值得一提的是MySQL的事件调度器可以精确到每秒钟执行一个任务,而操作系统的计划任务(如:Linux的cron或Windows下的任务计划)只能精确到每分钟执行一次。对于一些对数据实时性要求比较高的应用(例如:股票、赔率、比分等)就非常适合。

1、在使用这个功能之前必须确保event_scheduler已开启,可执行

 SET GLOBAL event_scheduler = 1;

2、要查看当前是否已开启事件调度器,可执行如下SQL:

 SHOW VARIABLES LIKE 'event_scheduler';

注:以下为其他常用命令

 ALTER EVENT eventName ON COMPLETION PRESERVE DISABLE;  --关闭事件任务
 ALTER EVENT eventName ON COMPLETION PRESERVE ENABLE;   --开启事件任务
 SHOW EVENTS;                                          --查看事件任务

具体创建语法如下

CREATE EVENT [IFNOT EXISTS] event_name
 ONSCHEDULE schedule
 [ONCOMPLETION [NOT] PRESERVE]
 [ENABLE | DISABLE]
 [COMMENT 'comment']
 DO sql_statement;

schedule:
AT TIMESTAMP [+ INTERVAL INTERVAL]
| EVERY INTERVAL [STARTS TIMESTAMP] [ENDS TIMESTAMP]
  
INTERVAL:
quantity {YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE |
WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE |
DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND}

首先来看一个简单的例子来演示每秒插入一条记录到数据表 

CREATE TABLE aaa(timeline TIMESTAMP);
 CREATE EVENT e_test_insert
 ON SCHEDULE EVERY 1 SECOND
 DO INSERT aaa VALUE(CURRENT_TIMESTAMP);

等待3秒之后,再执行查询看看,可以看到aaa表会有3条数据
再来看看修改他的语法

ALTER EVENT event_name
 [ONSCHEDULE schedule]
 [RENAME TOnew_event_name]
 [ON COMPLETION [NOT] PRESERVE]
 [COMMENT 'comment']
 [ENABLE | DISABLE]
 [DO sql_statement]

以下是几个简单例子

ALTER EVENT e_test DISABLE;   -- 临时关闭事件
 ALTER EVENT e_test ENABLE;   -- 开启事件  
 ALTER EVENT e_test ON SCHEDULE EVERY 5 DAY;  -- 将任务改为5天执行一次:

最后是删除事件语法

DROP EVENT [IF EXISTS] event_name

CentOS 开启防火墙及指定端口

查看防火墙状态

firewall-cmd --state

开启防火墙

systemctl start firewalld.service

重启防火墙

systemctl restart firewalld.service

关闭防火墙

systemctl stop firewalld.service

开启指定端口

firewall-cmd --zone=public --add-port=80/tcp --permanent

–zone # 作用域
–add # 添加端口,格式为:端口/通讯协议
–permanent # 永久生效,没有此参数重启后失效

重新加载后生效

firewall-cmd reload

查看已开启端口

firewall-cmd --list-ports

Centos下的Docker环境RabbitMQ以及SqlServer和MySql搭建

以下为快速构建Centos下的生产环境、包括数据库、消息队列

step1:安装Docker

sudo yum install
 #安装所需的软件包
 sudo yum install -y yum-utils device-mapper-persistent-data lvm2
 #添加Docker稳定版本的yum软件源
 sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
 #更新yum软件源缓存,并安装Docker
 sudo yum install
 sudo yum install -y docker-ce
 #确认Docker服务启动正常
 sudo systemctl start docker

step2:拉取RabbitMQ镜像

docker pull rabbitmq:3.8.3-management

step3:启动RabbitMQ

docker run -d --hostname my-rabbit -p 5672:5672 -p 15672:15672  --name some-rabbit rabbitmq:3.8.3-management

启动命令中设置了映射端口,可以直接访问服务器IP的15672端口来查看,用户名和密码默认都是guest,进入页面后会提示修改密码
到此Docker安装rabbitMq已经完成,且已成功启动。

setp4:拉取SQLServer2019镜像

sudo docker pull mcr.microsoft.com/mssql/server:2019-latest

step5:启动SQLServer2019

docker run -e "ACCEPT_EULA=Y" -e "MSSQL_PID=HMWJ3-KY3J2-NMVD7-KG4JR-X2G8G" -e "MSSQL_SA_PASSWORD=Myun@123jx" --name sqlserver -p 1433:1433 -v /var/opt/mssql:/var/opt/mssql  -d mcr.microsoft.com/mssql/server:2019-latest

step6:连接登录SQLServer后,可以选择执行以下SQL打开代理服务

EXEC sp_configure 'show advanced', 1;
 RECONFIGURE;
 EXEC sp_configure 'allow updates', 0;
 RECONFIGURE;
 EXEC sp_configure 'Agent XPs', 1;
 RECONFIGURE;
 GO

step7:拉取MySQL镜像

docker pull mysql:8.0

step8:在本地宿主机上创建MySQL的配置文件my8.cnf

mkdir ~/mysql8
cd ~/mysql8
mkdir log
vim my8.cnf

以下是my8.cnf内容,以低配的1GB服务器为例子,可以用如下的配置

[mysqld]
pid-file        = /var/run/mysqld/mysqld.pid
socket          = /var/run/mysqld/mysqld.sock
datadir         = /var/lib/mysql
secure-file-priv= NULL
innodb_buffer_pool_size = 16M
performance_schema_max_table_instances=400  
table_definition_cache=400  
table_open_cache=256
performance_schema = off
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
 
# Custom config should go here
# !includedir /etc/mysql/conf.d/

step9:此后可以把MySQL容器启动,然后把宿主机的配置映射到容器内,为了防止被攻击,可以选择宿主机的非常用端口4306

docker run -d --restart=always -p 4306:3306 -v ~/mysql8/log:/var/log/mysql -v ~/mysql8/my8.cnf:/etc/my.cnf -e MYSQL_ROOT_PASSWORD=数据库密码 -e MYSQL_GENERAL_LOG=1 mysql:8.0

step10:此后MySQL容器配置完成,我们可以通过宿主机的4306端口,访问到容器内的MySQL,最后,我们可以把Docker服务设置为开机启动

systemctl enable docker.service

此外,以下为容器自动重启以及Docker固化命令

 docker update --restart=always 容器id

CentOS快速搭建.net6运行环境,部署进程守护

Step1:将yum更新为最新,并且添加添加Node.js源

sudo yum -y update
 
 sudo curl -sL https://rpm.nodesource.com/setup_14.x | sudo bash -

Step2:安装Node.js

yum -y install nodejs

Step3:安装PM2进程守护

npm install pm2 -g

Step4:把Microsoft包签名密钥添加到受信任密钥列表

sudo rpm -Uvh https://packages.microsoft.com/config/centos/7/packages-microsoft-prod.rpm

Step5:安装.net6运行时

sudo yum install aspnetcore-runtime-6.0

Step6:安装pm2进程守护,监控server服务,并且固化,设置自动重启

pm2 start "dotnet 程序名.dll --urls=http://*:端口号 --environment Production" --name PM2进程名
 pm2 save                       
 pm2 startup systemd

WordPress建站教程:用Cravatar替换Gravatar头像,给网站加速

wordpress默认的Gravatar头像可能会造成国内的wordpress站点前台与后台极其缓慢,严重影响网站体验。其实这个头像对wordpress企业建站来说基本没什么用,我们可以直接禁用Gravatar头像来达到网站加速效果。

如果你想使用Gravatar头像,但又想让它的速度快一点,那么我们可以使用国内的Cravatar头像来替换,这是国内大神提供的一个 免费解决方案,使用方法如下:

把下面的代码添加到当前wordpress建站主题的function.php文件中,保存即可生效。如果你的网站安装了Code Snippets插件,也可以把代码添加到插件中,效果一样。
以下代码在wordpress4.1版本亲测可用

if ( ! function_exists( 'get_cravatar_url' ) ) {
     /**
      * 替换 Gravatar 头像为 Cravatar 头像
 
      */
     function get_cravatar_url( $url ) {
         $sources = array(
             'www.gravatar.com',
             '0.gravatar.com',
             '1.gravatar.com',
             '2.gravatar.com',
             'secure.gravatar.com',
             'cn.gravatar.com',
             'gravatar.com',
         );
 
         return str_replace( $sources, 'cravatar.cn', $url );
     }
 
     add_filter( 'um_user_avatar_url_filter', 'get_cravatar_url', 1 );
     add_filter( 'bp_gravatar_url', 'get_cravatar_url', 1 );
     add_filter( 'get_avatar_url', 'get_cravatar_url', 1 );
 }
 
 if ( ! function_exists( 'set_defaults_for_cravatar' ) ) {
     /**
      * 替换 WordPress 讨论设置中的默认头像
      */
     function set_defaults_for_cravatar( $avatar_defaults ) {
         $avatar_defaults['gravatar_default'] = 'Cravatar 标志';
 
         return $avatar_defaults;
     }
 
     add_filter( 'avatar_defaults', 'set_defaults_for_cravatar', 1 );
 }
 
 if ( ! function_exists( 'set_user_profile_picture_for_cravatar' ) ) {
     /**
      * 替换个人资料卡中的头像上传地址
      */
     function set_user_profile_picture_for_cravatar() {
         return '您可以在 Cravatar 修改您的资料图片';
     }
 
     add_filter( 'user_profile_picture_description', 'set_user_profile_picture_for_cravatar', 1 );
 }