SQL SERVER 批量备份所有数据库

有时候,我们希望一次性备份指定的几个SQL SERVER数据库文件,以下有个简单的SQL可以实现

可以自己设定Where的条件,批量备份数据库的sql脚本,可以自行设置备份目录,如果目录不存在会自动创建该目录

(如果脚本复制到查询分析器有红线,不用怕,依旧可以执行)

USE [master]
DECLARE @backupfile NVARCHAR(1024)  
DECLARE @backdesc NVARCHAR(1024)  
DECLARE @filename NVARCHAR(1024)  
DECLARE @path NVARCHAR(1024)  
DECLARE @dbname SYSNAME
DECLARE @extension_name NVARCHAR(50)
SET @path = N'D:\DBBackup\';   -- 此处是服务器的备份文件输出路径
SET @extension_name = N'.bak';
IF (OBJECT_ID('tempdb..#Temp') IS NOT NULL)  
  DROP TABLE #Temp  
CREATE TABLE #Temp (id INT IDENTITY,a INT,b INT,c INT)
DECLARE @fpath NVARCHAR(3)
SET @fpath=LEFT(@path,3)
INSERT #Temp EXEC master..xp_fileexist @fpath
INSERT #Temp EXEC master..xp_fileexist @path
--如果指定盘符有误不存在,则返回错误提示:
IF EXISTS(SELECT 1 FROM #Temp WHERE id=1 AND c=0)
BEGIN
    PRINT CHAR(10) + N'输入的盘符不存在,请重新输入!'
	----临时表删除--------
IF (OBJECT_ID('tempdb..#Temp') IS NOT NULL)  
BEGIN  
  DROP TABLE #Temp  
END
RETURN
END
--如果不存在指定的文件夹,则创建:
ELSE IF EXISTS(SELECT 1 FROM #Temp WHERE b=0 AND id=2)
BEGIN
PRINT CHAR(10) + N'正在创建目录'
EXEC sp_configure 'show advanced options',1
reconfigure
EXEC sp_configure 'xp_cmdshell',1
reconfigure
    DECLARE @mddir NVARCHAR(100)
    SET @mddir='md '+@path
    EXEC master..xp_cmdshell @mddir
	PRINT CHAR(10) + N'创建目录完成'
END
----临时表删除--------
IF (OBJECT_ID('tempdb..#Temp') IS NOT NULL)  
BEGIN  
  DROP TABLE #Temp  
END
--备份
PRINT CHAR(10) + N'开始备份所有数据库'
DECLARE tmp_Cur CURSOR  
FOR  
    SELECT  name  
    FROM    sys.databases  
    WHERE ([name] LIKE '%MGMT' )  -- 此处条件可以自定义,
    ORDER BY Name
 
OPEN tmp_Cur
FETCH NEXT FROM tmp_Cur INTO @dbname;  
WHILE @@FETCH_STATUS = 0    
    BEGIN  
        -- 得到完整目标文件,数据库将备份到这个文件中  
        SET @backupfile = @path + @dbname + @extension_name
        --SELECT  @backupfile  
        SET @backdesc =@dbname + N'-完整 数据库 备份'  
 
        -- 开始备份, COMPRESSION 参数表示压缩,可节省磁盘空间
  PRINT CHAR(10) + N'开始备份 '+@dbname
  PRINT CHAR(10)
        BACKUP DATABASE @dbname TO DISK = @backupfile WITH NOFORMAT, NOINIT,  NAME = @backdesc, SKIP, NOREWIND, NOUNLOAD,  STATS = 10, COMPRESSION  
        PRINT CHAR(10) + @dbname + N' 备份完成 '
        FETCH NEXT FROM tmp_Cur INTO @dbname  
    END  
CLOSE tmp_Cur
DEALLOCATE tmp_Cur
PRINT CHAR(10) + N'所有数据库备份完成'

执行完毕后,就可以在服务器的D:\DBBackup路径上找到这些BAK文件

使用 Docker 快速部署 shadowsocks

Step1:拉取 shadowsocks-libev

docker pull appso/shadowsocks-libev

Step2:创建 shadowssocks配置文件

mkdir -p /etc/shadowsocks-libev/
vi /etc/shadowsocks-libev/config.json

将下面的内容修改后,粘贴进去。其中server_port就是可以随便改,比如,我这里是8188。密码修改成自己的

{
  "server": "0.0.0.0",
  "server_port": 8188,
  "password": "密码",
  "timeout": 600,
  "method": "aes-256-gcm",
  "fast_open": false,
  "mode": "tcp_and_udp"
}

Step3:保存退出后,启动Docker容器

docker run -d -p 8188:8188 -p 8188:8188/udp \
       --name ss-libev \
       --restart=always \
       -v /etc/shadowsocks-libev:/etc/shadowsocks-libev \
       appso/shadowsocks-libev

这样服务端就算是配置完成了

接下来,就可以下载对应客户端文件,去各个终端连接服务器的8188端口进行使用了

Windows客户端:点击下载

MAC客户端:点击下载

Android客户端:点击下载

Docker部署.Net Core 3.1程序(超详细)

首先,我们把编译好的.Net Core 3.1程序上传到宿主机的特地目录,如下图,确保你的程序路径在netcoreapp3.1/publish/文件夹中,以下是以我的程序Web.dll为例

然后,在netcoreapp3.1文件同级,新建Dockerfile文件,并且为了防止DOCK镜像中可能不存在字体,我们在同级别目录放一个字体文件 simsun.ttc

Dockerfile的内容如下,以下我以运行我的Web.dll程序为例子,为了调试方便,看到错误信息,ASPNETCORE_ENVIRONMENT暂时设置为Development,容器内端口设置为80,容器内的工作目录设置为/app

# 使用官方.NET Core运行时镜像作为基础镜像
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
 
# 设置工作目录
WORKDIR /app
 
# 复制项目发布文件到容器中的工作目录
COPY ./netcoreapp3.1/publish/ .

COPY simsun.ttc /usr/share/fonts/
 
# 设置环境变量,端口
ENV ASPNETCORE_ENVIRONMENT=Development
ENV ASPNETCORE_URLS=http://+:80
 
# 当容器启动时,运行应用程序
ENTRYPOINT ["dotnet", "Web.dll"]

接下来,在控制台,定位到指定目录,用以下命令生成镜像,然后就会新增一个mathapp的Image镜像

sudo docker build -t mathapp .

此时,我们可以试着用这个镜像部署一个容器mathapp,并且把宿主机的8080端口,映射到容器80

sudo docker run --name mathapp -d -p 8080:80 mathapp

这时,我们就可以在游览器地址栏输入:http://服务器IP:8080 来访问自己的.Net Core程序了

接下来,我们为了后续更新方便,也可以试着在宿主机做个文件映射,首先,把容器内刚刚的/app工作目录的文件,复制到宿主机

sudo docker cp mathapp:/app /home/ec2-user/www

此时,我们看到,宿主机的对应目录中多了一个app文件,里面就是我们容器的工作目录文件

此时,我们可以删除之前创建的测试容器,创建全新容器,然后把这个目录挂载到新容器上

sudo docker stop mathapp
sudo docker rm mathapp
sudo docker run -d -p 8080:80 --name mathapp --restart=always -v /home/ec2-user/www/app:/app mathapp

接下来,后续更新只要更新宿主机中的文件,然后重启对应的docker容器即可

Docker部署wordpress

一、拉取wordpress镜像

docker pull wordpress

二、部署启动Docker容器,把宿主机当前用户的本地路径挂载到容器上,宿主机的端口可以设置成8081,这样,容器内的 WordPress 网站就会使用 /data 目录作为持久存储,你可以将数据保存在该目录下,即使容器被删除或重新创建,数据也不会丢失。请确保在运行此命令之前,已经在主机上创建了目标挂载点。

docker run -it --name mywordpress2 -p 8081:80 -v ~/www/blog:/var/www/html -d wordpress

此时在浏览器访问http://localhost:8081/wp-admin/setup-config.php进行安装。

此时需要配置数据库信息,DOCKER配置MYSQL数据库的方法,参考如下:Centos下的Docker环境RabbitMQ以及SqlServer和MySql搭建

如果您已经在 Docker 容器中分别安装了 WordPress 和 MySQL,并且想要让它们链接起来,可以按照以下步骤进行操作,首先,需要查找正在运行的 MySQL 容器的 IP 地址。可以使用以下命令:

docker inspect 容器id或容器名 | grep IPAddress

此时,会返回DOCKER容器中MYSQL对应的IP地址,回到刚刚的WordPress配置页面将数据库主机填上你获取的数据库ip地址即可

配置完毕后,如果是小内存服务器,可以再在WordPress的根目录的wp-config.php文件上,添加一个内存限制,如下,就是限制到128兆内存

define('WP_MEMORY_LIMIT', '64M');
define('WP_MAX_MEMORY_LIMIT', '128M');

同时,也可以对Docker的容器内存大小进行限制,(例:不能超过148M)

docker update --restart=always --memory="148m" --memory-swap="148m" 容器ID

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