第一次使用linux并编写了一个dump mysql的程序,记录下简单的步骤

机器安装linux redhat5.0 64位。客户管理员给了我账户密码,我用SecureCRT登录。

连接后:

ls  列表文件,当然支持通配符

cd path 进入某个目录   *SecureCRT中可以像window一样复制路径,比较方便。

cd .. 返回上层

cd ~ 切换到用户目录

cd / 切换到根目录

rm -f aaa.zip  删除文件

rm -rf aaa 删除目录 r应该是循环的意思

reboot 重启

date -s 12/31/2015 修改日期

zip -r abc.zip abc 压缩

unzip abc.zip 解压缩

rz    SecureCRT从本地传文件上去。一般用zip就行。注意看是否100%,0 error。遇到已经存在的文件要先rm掉才能上传。

sz aa.zip  从linux往本地下载一个文件。下载的位置在win7的“下载”文件夹。

linux可执行文件可以无后缀,或者 .o,  执行时就算在当前目录也要输入 ./abc  才能执行

如果提示Permission denied,则执行chmod 777 abc 修改权限即可


安装mysql可以直接下载rpm安装包

MySQL-server-community-5.0.96-1.rhel5.x86_64.rpm

MySQL-client-community-5.0.96-1.rhel5.x86_64.rpm

安装rpm包: rpm -ivh abc.rpm

注意:可能为了商业开发的稳定性,并未使用更高版本


为了开发必须有lib库,这个安装client是没有的。我采用下载源码来安装

下载mysql5.0.96的源码:mysql-5.0.96.tar.gz,解压缩到某个path,然后su切换到root账号,cd path
  然后执行:
  ./configure --prefix=/usr/local/mysql/ --without-server --with-named-curses-libs=/usr/lib/libncursesw.so.5
  注意看到:Thank you for choosing MySQL! 的提示才算成功否则百度错误提示解决

  执行:make
  执行:make install
  安装后可以拷贝一份mysql的HEADER头文件和lib库文件,到其他电脑上也方便


为了测试目的安装的mysql没有自动启动,执行: mysqld --user=root 启动它

mysql进入命令行。

use database 切换数据库

show tables; 看表名

exit 退出命令行


编写c程序用vim工具

vim abc.c

进去默认是只读的,按i 进入编辑状态,需要保存时,按esc,进入命令模式按 :wq 保存退出  :w只保存不退出


程序编写好后,我将其单独放入一个文件夹内,并把mysql的头文件和mysql的库文件放入HEADER和LIB文件夹,建立sh文件便于快速编译和运行

compile.sh  //编译时用

#!/bin/sh
rm -f abc
cc -o abc abc.c -L ./LIB -lmysqlclient

说明: 第一行删除可执行文件,第二行编译并用-L参数指定库路径。为了简单我已经把源码编译得到的mysq库放入了单独的文件夹,便于带到其他地方。

run.sh //运行时用

#!/bin/sh
export LD_LIBRARY_PATH=./LIB:$LD_LIBRARY_PATH
cd usr/abc
find ./LOG -size +50M -exec rm {} \;
./abc | tee -a ./LOG/2.log

说明:第一行 指定lib,第二行切换到当前目录,这样定时任务时,不会说相对路径找不到,第三行删除日志,当体积大于50M时,第四行执行并输出过程为日志文件


如果用虚拟机安装的linux是启动到桌面的,则打开网络可以看到主机,输入管理员账户密码,就能打开磁盘分区拷贝文件。

默认是非root登录的,比如chen,只需要打开终端,输入: su 提示输入密码,就能切换到root,其他操作同上述。


最后说一下程序的目标:dump mysql的表同步到镜像的数据库中去。

查询目标mysql上的information_schema中的tables表,得到某个表最后的同步时间,如果早于今天凌晨或者不存在这个表则调用命令行mysqldump导出。最后用mysql命令连接远程的目标主机执行导入。之前其他人开发的拷贝程序不是闭环控制,在网络闪断的情况下几乎天天失败,拷贝和导入脱节,两部分都未对最终结果负责。


为何要使用c来做这个简单程序是因为客户不需要这个机器安装更多的东西,比如php。用c编写比较简单一点。不会额外增加什么。

当然作为初识linux和c在linux,以及调用mysql编程,作为一个机会练习吧。


具体源码

/* auth : chen
   dt: 2015-06-20
   func: 实现从v3000拷贝表格及其数据到缓冲服务器
*/


#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#include </usr/include/sys/stat.h>
#include <./HEADER/mysql.h>

//延迟时间,这样定时任务可以设置到统一的时间,但是拷贝过程会分布到0-30分钟之间。
//为了计算式中不被零除,默认1.
#define DELAY_MINUTE 1

//文件最小体积
#define MIN_FILESIZE 595


struct _strc_tbllist{
 int type;   //1.固定表 2.月表 3.日表  11:固定表e_customer如果不存在头天晚上9点之后的表,则更新
       //22.月表,但是每天要更新
 char tblnamePre[80];
 char tblnameNew[80];   
};


int printtime(){
  time_t now; //实例化time_t结构
  struct tm *timenow; //实例化tm结构指针
  time(&now);
  //time函数读取现在的时间(国际标准时间非北京时间),然后传值给now
  timenow = localtime(&now);
  //localtime函数把从time取得的时间now换算成你电脑中的时间(就是你设置的地区)
  printf("%04d-%02d-%02d %02d:%02d:%02d\n",1900+timenow->tm_year,timenow->tm_mon+1,timenow->tm_mday,
                    timenow->tm_hour,timenow->tm_min,timenow->tm_sec);
}

int gettime_yyyymm(char* dt,int AddDay){
  time_t now; //实例化time_t结构
  struct tm *timenow; //实例化tm结构指针
  time(&now);
 
  now += (86400*AddDay);
 
  //time函数读取现在的时间(国际标准时间非北京时间),然后传值给now
  timenow = localtime(&now); 
 
  sprintf(dt,"%04d%02d",1900+timenow->tm_year,timenow->tm_mon+1);
}

int gettime_yyyymmdd(char* dt,int AddDay){
  time_t now; //实例化time_t结构
  struct tm *timenow; //实例化tm结构指针
  time(&now);
  now += (86400*AddDay);
 
  //time函数读取现在的时间(国际标准时间非北京时间),然后传值给now
  timenow = localtime(&now);
 
  sprintf(dt,"%04d%02d%02d",1900+timenow->tm_year,timenow->tm_mon+1,timenow->tm_mday);
}

int gettime_yyyy_mm_dd(char* dt,int AddDay){
  time_t now; //实例化time_t结构
  struct tm *timenow; //实例化tm结构指针
  time(&now);
  now += (86400*AddDay);
 
  //time函数读取现在的时间(国际标准时间非北京时间),然后传值给now
  timenow = localtime(&now);
 
  sprintf(dt,"%04d-%02d-%02d",1900+timenow->tm_year,timenow->tm_mon+1,timenow->tm_mday);
}

int gettime_daynumber(){
  time_t now; //实例化time_t结构
  struct tm *timenow; //实例化tm结构指针
  time(&now);
  //time函数读取现在的时间(国际标准时间非北京时间),然后传值给now
  timenow = localtime(&now);
 
  return timenow->tm_mday;
}

int ReadConfig(char* CfgFile,char* PlatFormID,char* IP,char* Port,char* User,char* Pwd){
 //conf中的配置信息
  FILE *fp;
  char StrLine[1024];
 
  if((fp = fopen(CfgFile,"r"))== NULL) //判断文件是否存在及可读
  {
  printf("fopen [config file] error\n");
  return -1;
  }
  //read it
  int r = 0;
  while (!feof(fp))
 {
  r ++;
  //特别注意fgets包含了末尾的回车符\n,之前涉及到登录时一直存在问题。注意!!!
  fgets(StrLine,1024,fp);  //读取一行
  StrLine[strlen(StrLine) -1] = '\0';  //抹掉回车符号
  switch(r){
   case 12: //platform
    strcpy(PlatFormID,StrLine);
    printf("PlatFormID: %s\n", PlatFormID); //输出
    break;
   case 14: //ip
    strcpy(IP,StrLine);
    printf("IP: %s\n",IP); //输出
    break;
   case 16: //port
    strcpy(Port,StrLine);
    printf("Port: %s\n",Port); //输出
    break;
   case 18: //User
    strcpy(User,StrLine);
    printf("User: %s\n", User); //输出
    break;
   case 20:
    strcpy(Pwd,StrLine);
    printf("Pwd: %s\n", Pwd); //输出
    break;
  }  
 }
 fclose(fp);
 return 1;
}


int ReadTableList(char* TableListFile,struct _strc_tbllist _tablelist[100]){
 //conf中的配置信息
  FILE *fp;
  char StrLine[1024];
 
  if((fp = fopen(TableListFile,"r"))== NULL) //判断文件是否存在及可读
  {
  printf("fopen [config file] error");
  return -1;
  }
  //read it
  int r = -1;
  int s;
  char tbltype[6];
  while (!feof(fp))
 {  
  //特别注意fgets包含了末尾的回车符\n,之前涉及到登录时一直存在问题。注意!!!
  fgets(StrLine,1024,fp);  //读取一行
  StrLine[strlen(StrLine) -1] = '\0';  //抹掉回车符号

  if(r > -1){
   //找到开始{}一对括号作为开始和结束
   if(strcmp(StrLine,"}")==0){
    break; 
   }
   //输出
   printf("Table List: %s\n",StrLine);    
   for(s = 0;s < strlen(StrLine);s++){
    if(StrLine[s] == ','){
     memset(tbltype,0,6);
     memcpy(tbltype,StrLine,s);
     
     //赋值
     _tablelist[r].type = atoi(tbltype);
     strcpy(_tablelist[r].tblnamePre,&StrLine[s+1]);
     break;
    }
   }
   r ++; 
  }else{
   //找到开始{}一对括号作为开始和结束
   if(strcmp(StrLine,"{")==0){
    r = 0;  //第一个
    continue; 
   }
  }   
 }
 fclose(fp);
 
 printf("Table Qty: %d\n\n",r);
 return r;
}


unsigned long get_filesize(const char *path){ 
 unsigned long filesize = -1;     
 struct stat statbuff; 
 if(stat(path, &statbuff) < 0){ 
  return filesize; 
 }else{ 
  filesize = statbuff.st_size; 
 } 
  return filesize; 


int main(int argc,char** argv){
 printf("\n\n\n-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n");
  printtime();
  printf("系统拷贝数据开始...\nbegin export and import...\n\n");
 
  //延迟执行,这样每个服务器可以分布开
  srand((unsigned) time(NULL)); //用时间做种,每次产生随机数不一样
  int delay_second = 0;
  if(DELAY_MINUTE <= 1){
   //not delay 
  }else{
   delay_second = 60*(rand()% DELAY_MINUTE + 1);
   printf("将各台服务器执行时间分布错开: 延迟触发 %d 秒++++++++++++++++\n",delay_second);
   sleep(delay_second);
  }
 
  //因为这个程序会从凌晨1点执行到早晨7点
  //7:30分执行更新动作
  //所以首先按table create time来判断某个表是否成功创建,如未创建,加入到mysqldump的列表中去
 
  int TBL_QTY;
  struct _strc_tbllist tablelist[100];
 
  #define TBL_LISTS "./tables.tbl"
  TBL_QTY = ReadTableList(TBL_LISTS,tablelist);    

  //读取配置文件信息
  #define CONFIG_FILE "./host.cfg"
  char PlatFormID[127],IP[127],User[127],Pwd[127];
  char Port[16];
  char DB_SCHEMA[64] = "information_schema";
  char DB_PLATFORM[64] = "v_";
 
  if(ReadConfig(CONFIG_FILE,PlatFormID,IP,Port,User,Pwd)<0){
   return -1;
  }                 
 
  //mysql init 
  MYSQL my_conn_schema; 
 MYSQL_RES *result; 
 int res;  
 mysql_init(&my_conn_schema);

 //连接到information_schema数据库
 if(!mysql_real_connect(&my_conn_schema,IP,User,Pwd,DB_SCHEMA,60000,NULL,0)){   
  printf(">>>>>>>>connect [information_schema db] 失败!\n原因: %s\n",mysql_error(&my_conn_schema));
  return -1;
 }
 
 //正常的提示
 printf("connect [information_schema db] 成功++++++++++++++++++++++++++++++++++++++++++++++++\n\n\n");
  
 //排查fixed表
 char SQL[2048];
 char MyDump[1024],MyImport[1024];
 char ChangeDB[60];
 char SourcePath[60] = "./SQL_EXPORT/";
 char yyyymm[7],yyyymmdd[9],yyyy_mm_dd[11];
 int daysnumber; 
 char dt_tmp[10];
 //db name
 strcat(DB_PLATFORM,PlatFormID);
 
 //daysnumber
 daysnumber = gettime_daynumber();
  
 int beginday,endday;        //当天需要检查多个表时使用。避免某天不成功第二天可以补救
 int t;
 int d;
 for(t = 0;t < TBL_QTY;t++){
  //区分某天拷贝哪些表  
  switch(tablelist[t].type){
   case 1:
    beginday = -1;  //只用执行一次内循环
    endday = 0;
    break;
   case 11:
    beginday = -1;  //只用执行一次内循环
    endday = 0;
    break;
   case 2:          //1-4号检查,并且只检查上个月的表
    //原则上,如果不是1号就不执行拷贝,实际条件下可能1号出问题,则1-4天都检查一遍
    if(daysnumber >= 4){
     printf("此表只在1-4号检查执行,跳过++++++++++++++++\n\n");
     continue;
    }
    beginday = (-1)*daysnumber;
    endday = (-1)*daysnumber +1;  //通过上限控制只执行一次
    break;
   case 22:
    //5-31号只判断上月的
    if(daysnumber > 4){
     beginday = -1;
     endday = 0; 
    }
    //1-4号既要判断上月的,又要判断本月的
    if(daysnumber <= 4){
     beginday = (-1)*daysnumber;  //上个月的
     endday = 0;   //昨天的
    }
    break;
   case 3:
    beginday = -36;    //检查31天内的未成功拷贝的表,这个表按名称即可判断不需要判断导入时间
    endday = 0;
    break;
   case 33:
    beginday = -36;    //检查31天内的未成功拷贝的表,这个表按名称即可判断不需要判断导入时间
    endday = 0;
    break;   
  }
  
  for(d =beginday;d<endday;d++){   
   //不同类型的表需要动态添加后缀,比如20150601
   strcpy(tablelist[t].tblnameNew,tablelist[t].tblnamePre); 
   
   switch(tablelist[t].type){
    case 1:
     //do nothing 
     break;
    case 11:
     //do nothing 
     break;
    case 2:
     //增加月份后缀
     gettime_yyyymm(yyyymm,d);
     strcat(tablelist[t].tblnameNew,yyyymm);
     break;
    case 22:
     //1-4号既要判断上月的,又要判断本月的
     if(daysnumber <= 4){
      //上个月执行完就执行昨天的,中间几天不用判断,因为是月表
      if(d > beginday){
       d = endday -1;
      }
     }
    
     //增加月份后缀
     gettime_yyyymm(yyyymm,d);
     strcat(tablelist[t].tblnameNew,yyyymm);
     break;
    case 3:
     gettime_yyyymmdd(yyyymmdd,d);
     strcat(tablelist[t].tblnameNew,yyyymmdd);
     break;
    case 33:
     gettime_yyyymmdd(yyyymmdd,d);
     strcat(tablelist[t].tblnameNew,yyyymmdd);
     break;    
   }
   
   //SELECT create_time
   //FROM TABLES
   //WHERE TABLE_SCHEMA = 'v_9999' AND
   //table_name = 'e_customer'
   strcpy(SQL,"SELECT create_time\n"
         "FROM TABLES\n"
         "WHERE TABLE_SCHEMA = \'vos_");
   strcat(SQL,PlatFormID);
   strcat(SQL,"\' AND\n");
   strcat(SQL,"table_name = \'");
   strcat(SQL,tablelist[t].tblnameNew);  
   strcat(SQL,"' AND\n");
   
   //不同类型的表需要动态添加后缀,比如20150601
   switch(tablelist[t].type){
    case 1:
     strcat(SQL,"create_time > CURRENT_DATE()");
     break;
    case 2:
     strcat(SQL,"1 = 1");  //日表只需要判断是否存在,不需要判断日期
     break;
    case 3:
     strcat(SQL,"1 = 1");  //日表只需要判断是否存在,不需要判断日期
     break;
    case 33:
     strcat(SQL,"1 = 1");  //日表只需要判断是否存在,不需要判断日期
     break;   
    case 11:
     strcat(SQL,"create_time > \'");
     gettime_yyyy_mm_dd(yyyy_mm_dd, -1);
     strcat(SQL,yyyy_mm_dd);
     strcat(SQL," 21:00:00.001\'");
     break;
    case 22:
     strcat(SQL,"create_time > date_add(CURRENT_DATE(),interval ");
     memset(dt_tmp,0,sizeof(dt_tmp));
     sprintf(dt_tmp,"%d",d +1);
     strcat(SQL,dt_tmp);
     strcat(SQL," day)");
     break;        
   } 
   
   printf("执行SQL:-----------------------[表 %d: %s]---[第 %d 天]-----------------------\n",
        t,tablelist[t].tblnameNew,d);  
   printf(tablelist[t].tblnamePre);
   printf("\n"); 
   
   printf(SQL);
   printf("\n\n");
   
   res=mysql_query(&my_conn_schema,SQL);//查询 
   if(res != 0){
    printf(">>>>>>>>res=mysql_query(&my_conn_schema,SQL<判断表是否存在>) 时失败: res = %d\n",res);
    return -1;
   }
   
   result=mysql_store_result(&my_conn_schema);//保存查询到的数据到result 
   if((unsigned long)mysql_num_rows(result)>0){ 
    printf("已经同步了这个表 [跳过]++++++++++++++++\n\n");
    continue;
   }
  
    //需要导出的
   printf("尚未同步这个表,加入到mysqldump列表中去++++++++++++++++\n");
   
   //导出文件名
   char ExportFile[255];
   strcpy(ExportFile,SourcePath);
   strcat(ExportFile,tablelist[t].tblnamePre);
   strcat(ExportFile,".sql");
   
   //注意本地mysql没有密码,所以mysqldump不需要加什么密码等参数
   strcpy(MyDump,"mysqldump v9999 ");
   strcat(MyDump,tablelist[t].tblnameNew);
   strcat(MyDump," --skip-comments");
   
   
   strcat(MyDump,">");
   strcat(MyDump,ExportFile);
   
   //执行
   printf("执行导出命令: %s\n",MyDump);
   //删除文件先
   remove(ExportFile);
   system(MyDump);
   
   //如果命令行有错误,仍然生成空文件,所以判断文件是否写成功  
   if(get_filesize(ExportFile)<= MIN_FILESIZE){
    printf("导出出现异常,跳过该表的导入++++++++++++++++\n\n");
    continue;
   }  
   
   //连接到平台数据库,导入
   //格式: mysql -u root -p123456 test <d:\a.sql
   strcpy(MyImport,"mysql -h");
   strcat(MyImport,IP);
   strcat(MyImport," -P");
   strcat(MyImport,Port);
   strcat(MyImport," -u");
   strcat(MyImport,User);
   strcat(MyImport," -p");
   strcat(MyImport,Pwd);
   strcat(MyImport," ");
   strcat(MyImport,DB_PLATFORM);
   strcat(MyImport," < ");
   strcat(MyImport,ExportFile);
   
   printf(MyImport);
   printf("\n");
   
   //执行
   system(MyImport);
   printf("\n");
  } //for d
 }//for t
 
 mysql_free_result(result);//释放结果资源 
 mysql_close(&my_conn_schema);//断开连接

 //结束提示
 printf("已经结束全部的处理过程++++++++++++++++++++++++++++++++\n\n\n");
 
  //main结束
  exit(0);
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值