高效导入sql语句工具

一,背景

因为最近项目需要迁移数据库,于是我问了一下后台开发导入数据要多久?结果他说要一个小时,我觉得时间太长了,于是我搜索了一下有关快速插入sql的知识,从而用Node js 写这个小工具,方便快速导入sql。

二,原理

因为我们导出Sql数据是一行一条插入语句,执行sql时候按照每行执行一次,这样子导致写入特别多,大量消耗在网络传输中,于是我们只要把多行插入语句整合一条语句,但这里要知道mysql的一条sql最大长度是1M,所以我合并成一条时候需要注意长度,我用Node js写的工具已经处理这个问题。

三,代码

/**
 * 一个sql多张表处理,针对整体处理
 */
 const fs = require('fs')
 var sql_path = 'd:/t3.sql'
 var sava_sql_path = 'd:/batch.sql'
 const max_sql_len = 1024*1000   //mysql单个最大包1m,怕其他字节占用,我就用1000 比 1024小一些
 var global_sort_table_name = []        //全局表名,用来按照顺序插入
 
 //读取mysql文件
 function read_mysql_file(path){
     let data = fs.readFileSync(path)
     if(data.length > 0){
         data = data.toString()
     }
     return data
 }
 
 //基本解析
 //返回对应的数据
 /**
  * 
  * @param {string} data 
  * @returns 
  */
 function parse(data){
     let line_insert_key = 'INSERT INTO'
     let arrya = data.split('\n')
     let new_inert_sql = []
     var m = new Map();
     arrya.forEach(element => {
         if(element.indexOf(line_insert_key) != -1){
             let real_data = get_insert_sql_value(element)
             if(real_data){
                 if(m.has(real_data.table_name)){
                    let array = m.get(real_data.table_name)
                    array.push(real_data.data)
                 }else{
                    let  array = []
                    array.push(real_data.data)
                    global_sort_table_name.push(real_data.table_name)
                    m.set(real_data.table_name, array)
                 }
             }
         }
     });

     return m
 }
 
 /**
  * 获取插入的sql的语句
  * @param {String} inert_sql 
  */
 function get_insert_sql_value(insert_sql){
     let begin_key = 'VALUES ('
     let end_key = ');'
     let start_pos = insert_sql.indexOf(begin_key)
     let end_pos = insert_sql.indexOf(end_key)

     if(start_pos > 0 && end_pos > start_pos){
         start_pos = start_pos+begin_key.length
         let len = end_pos - start_pos
         
         let insert_right_value = insert_sql.substr(start_pos, len)
         let insert_left_value = insert_sql.substr(0, start_pos - 1)
         let table_name = get_insert_table_name(insert_left_value)

         return {
             table_name: table_name,
             data: insert_right_value
         }
     }
     return null
 }

 //获取插入的表
 function get_insert_table_name(insert_left_value){
    let begin_key = 'INSERT INTO `'
    let end_key = '` VALUES'

    if(insert_left_value && insert_left_value.indexOf('INSERT INTO') >= 0){
        let start_pos = insert_left_value.indexOf(begin_key)
        let end_pos = insert_left_value.indexOf(end_key)
        if(start_pos >= 0 && end_pos > start_pos){
            start_pos = start_pos + begin_key.length
            let len = end_pos - start_pos
            let table_name = insert_left_value.substr(start_pos, len)
            return table_name
        }
    }
    return ""
 }
 
 //创建新的插入数组
 /**
  * 
  * @param {Map} data 
  * @returns 
  */
 function create_new_insert_array(data){
    var data_array
     const template = "INSERT INTO `[表名]` VALUES"
     let current_insert_sql = []
     var new_insert_sql = template
 
     for(let ele of global_sort_table_name){
        data_array = data.get(ele)
        new_insert_sql = template
        let insert_comment = '-- ----------------------------\n'
        insert_comment += '-- ' + 'Records of ' + ele + '\n'
        insert_comment += '-- ----------------------------\n'
        new_insert_sql = insert_comment + new_insert_sql
        new_insert_sql = new_insert_sql.replace('[表名]',ele)
        

        for(let index = 0; index < data_array.length; index++){
            new_insert_sql += '(' + data_array[index]
            new_insert_sql += ')'
            if(new_insert_sql.length + 500 >= max_sql_len || (index+1 == data_array.length)){
                new_insert_sql+= ";"
                current_insert_sql.push(new_insert_sql)
                new_insert_sql = template
                new_insert_sql = new_insert_sql.replace('[表名]',ele)
            }else{
                new_insert_sql += ','
            }
        }
     }
 
     return current_insert_sql
 }
 
 /**
  * 解析完成sql对象
  * 新的文件路径
  * @param {*} sql_object 
  * @param {*} new_file_path 
  */
 function create(data_array, new_file_path){
     let new_data_string = ""
     data_array.forEach(element=>{
         new_data_string += element
         new_data_string += '\n'
     })
     fs.writeFileSync(new_file_path,new_data_string)
 }
 
 function init(){
     console.log("请设置自己原始sql路径和生成sql路径")
     let data = read_mysql_file(sql_path)
     let r = parse(data)
     let data_array = create_new_insert_array(r)
     create(data_array, sava_sql_path)
     console.log('生成' + sava_sql_path + ' 成功')
 }
 
 init()
 

四,使用

你使用需要修改sql_path改成你自己路径

node xxx.js 即可,成功输出文档到sava_sql_path路径

校验数据不否正确,可以对比2份数据库的sql数据即可

java后端部署不同系统后出现乱码

一,背景

项目从windows部署到centos,在客户端获取数据出现中文乱码,自己百度半天,各种编码设置也没有解决问题。

二,排查

根据上下文推测,应该跟系统的编码有问题,因为windows 默认编码gdk,然后centos默认编码是utf-8。所以猜测代码里面涉及系统默认编码问题,于是猜测 String getbytes(),如果改成getbytes(“utf-8”)就没有乱码了。

三,总结

乱码问题,基本都是服务器和客户端编码对不上导致的问题

electron 安全问题思考

背景

新手使用electron 会遇遇到自己的html页面加载的Js无法使用node js功能,Preload加载干什么,上下文隔离的问题,这个对于我使用electron确实造成困扰。

关键词

  • nodeIntegration
  • preload
  • contextIsolation

详解

nodeIntegration

控制渲染进程加载页面是否能够调用node js功能,高版本默认关闭,意思就是加载的html是无法使用node js代码,如果你想用就必须设置 nodeIntegration 为 true。

preload

可以设置加载js,这个页面没有加载前就可以被调用,感觉可以用拦截器来用,具备nodejs 能力,不管nodeIntegration是否打开

contextIsolation

上下文隔离,具体是值proload 加载JS与加载普通的浏览器的dom的隔离,如果不隔离,普通页面和Preload js共享 window对象,你可以在preload js 设置 window.test = 1 ,那么普通页面页可以访问这个。在electron 12后就默认隔离上下文

为什么要这么多限制,对我们新手太不友好了?

如果你只是加载本地文件,那么全部打开都没有关系,防止你加载第三方页面导致安全问题,比喻你electron加载一个https://www.xxx.com 结果这个页面加一段electron 检测代码,然后执行恶意代码,由于你开启了nodeIntegration ,那么代码就可以跑起来。这么多限制防你引用第三方的页面,而不是开发者。但对于新手来说,可能就会带来一点门槛。

总结

按照官方的意思:preload + nodeIntegration【关闭】 + contextIsolation【开启】+普通页面开发,这样子比较安全。我感觉这样子开发有另外的好处,前端页面通用,跟node 弱关系,前端没有node js,通过proload导出函数或者对象即可。

electron 打包后路径使用问题

背景

今天自己给快速打开增加自动启动,但发现开机启动后 无法正常运行。

排查

通过开发者模式发现路径到C盘系统的目录,我原来用的process.cwd(),返回进程的当前工作目录。后面我换成process.execPath 然后通过path 模块获取文件夹路径,这样子获取一定是安装目录执行的exe。同时不要__dirname 这个代表源码目录,因为打包了,所以目录对不上。

function getexecDir(){
    var p = process.execPath;
    return path.dirname(p)
}

PC微信多开最新代码【兼容性非常高】

背景

这个之前上传过,但后来发现有bug,导致可能出现不能多开,后面自己修复同时借鉴微软的handle工具【逆向分析】,win8以后【包含win8】,采用新的API,可以减少内存分配,防止内存不够用,导致内部能多开的情况【出现概率还是非常低的】。

原理

这个之前写过,由于自己博客的数据库,被自己不小心删除,导致文章消失了,通过系统API 【微软没有暴露出来】,遍历所有句柄就可以拿到对应的句柄,然后复制句柄,调用关闭即可。【window 核心编程有讲复制API的知识】

代码:

https://github.com/xvsdf100/PCWeChatMore

下载:

链接:https://pan.baidu.com/s/1RIMHNDf_RTZPuDm5GyPTHw
提取码:1234
复制这段内容后打开百度网盘手机App,操作更方便哦–来自百度网盘超级会员V5的分享

补充

理论可以无限多开【只要电脑内存足够高】,但不建议太多,可能触发微信检测机制,如果你自己微信权重低,可能判定恶意使用。

快速打开url小工具

一,背景

这个很久之前就想开发的小工具,自己陆陆续续开发一段时间,方便快速打开自己常打开的url.为了练手前端,开始用纯原始的js 开发界面,你会在设置界面发现一个丑陋的菜单,这个就是原生js代码弄的,没有用到前端ui控件,后面接触jquery,amazeui,于是导入进来,现在算是前端基本可以快速开发了。话说对于习惯wpf 和 windows 界面开发,用html开发界面确实不太习惯,

说明

软件快速通过关键词或者关键词的缩写打开对应的网址,因为自己常常会开一些web,进行访问。 这个软件有点借鉴utools,这个工具可以对接任何web网页,后续会加入js注入。当前版本只是简单实现web访问快速访问。

本软件只是练手electron 技术而已,后续慢慢补充各种插件和web,实现自己软件自给自足。提高自己快速编码能力和产品的驾驭能力。

使用

  1. 默认快捷键[ctrl+alt+k],自己可以设置界面进行修改
使用
  1. 添加功能
添加
  1. 输入关键词
使用
  1. 回车打开
效果

下载

百度网盘

链接:https://pan.baidu.com/s/1MGlLI4kBGZk1vCG4yJYAnA
提取码:60hu
复制这段内容后打开百度网盘手机App,操作更方便哦–来自百度网盘超级会员V5的分享

juery plugin datetimepicker ie8 兼容处理

一,背景

自己找了一个datetimepicker, 算是比较流行,但自己测试在IE8没法赋值。他的官网是https://xdsoft.net/jqplugins/datetimepicker/

二,排查

我从源代码入手,在不同的事件加入日志,最终找到IE8出现代码的地方。

在2573 地方 这里我改成blur,源码对应的blur.xdsoft,第一次看这种写法,自己才最近开始写前端代码,对jquery不是很属性。ie8 选择事件或者点击其他的就会触发blur事件,IE8以上就不会,于是我直接写屏蔽代码。

三,解决方案

            $('#test').on('blur', function(e){
                console.log("test blur")
                e.stopImmediatePropagation()
            })

四,其他

  • 事件选择器也可以用国人开源 http://www.jemui.com/uidoc/jedate.html
  • 引入js要引入build full 的js,不带full没有事件格式对象,估计作者是方便支持第三方格式支持