zoukankan      html  css  js  c++  java
  • 记一次H2数据迁移到mysql的过程

    1 思路

    H2数据迁移到mysql,网上查找了一圈,没有现成的工具。
    有几种方法,不过都可能出现各种bug,需要调试:

    1. H2导出为csv文件然后导入mysql.
    2. H2导出为sql文件然后导入mysql的过程
    3. 使用转换工具软件,比如Spectral Core(https://www.fullconvert.com/howto/h2-to-mysql 没试过) ,比如IDEA。
      在使用第二种方法迁移数据成功后,我尝试了idea,我觉得非常好用,只是测试了导出数据到.sql文件,比使用h2内置方法导出的.sql文件人性化多了,稍微修改就能兼容和导入到mysql。当然我也没尝试完整的导出导入,因为已经迁移完成了,没必要了。
      方法:选中要导出的表,右击,选择Dump Data to File(s) -- SQL Inserts,参考如下截图:

    下一次我会使用IDEA来进行不同数据库之间的数据迁移,原因如下:

    1. 兼容10多种数据库。idea不仅可以连接mysql和h2,还能连接oracle等10多种数据库。
    2. 导出的sql文件中的sql语法比较通用,和其他数据库兼容性好。
    3. 一次可以导出一张表、多张表、所有表。
    4. 可以导出为一个文件和可以导出为多个文件,一张表导出成一个文件。
    5. 导出时可以添加建表语句,也可以不加,如果被导入数据的数据库中已存在表结构,则不需要建表语句。

    我选择了第二种方法。这种方法遇到了很多坑,原因有多种,比如h2的导出sql文件完全是为了用于h2的导入,h2和mysql语法不同,需要转换,又比如hibernate执行原生的insert语句有bug。下面慢慢来说。

    注:mysql中创建数据库的语法:create database halo default character set utf8mb4 default collate utf8mb4_unicode_ci;

    2 导出h2数据为.sql文件

    java -cp $H2DRIVERS org.h2.tools.Script -url jdbc:h2:/root/.halo/db/halo -user root -password root -script halo_h2_db_exp_original20200613.sql
    # 或者如下的语法
    java -cp ./h2-1.4.200.jar org.h2.tools.Script -url jdbc:h2:/root/.halo/db/halo -user root -password root -script halo_h2_db_exp_original20200613.sql
    
    # 本地url的格式:jdbc:h2:/root/.halo/db/halo
    # 远程url的格式:jdbc:h2:tcp://192.168.6.16:8082/root/.halo/db/halo
    
    1. 坑1:STRINGDECODE
      导出sql文件中,所有的中文都是u0011这种unicode字符,h2打算在导入数据时,使用内置函数STRINGDECODE解码,比如:
      INSERT INTO SYSTEM_LOB_STREAM VALUES(278, 0, STRINGDECODE('<h1 id="\u0011\u2390\u0013aaabbbccc">****</h1>')
      解决方法:写java程序将unicode字符全部转换成中文。然后用正则表达式将STRINGDECODE全部去掉。

    IDEA中的操作:
    STRINGDECODE('(.*?)'), NULL); 替换为 '$1', NULL);
    GEDIT和notepadqq中的操作:
    STRINGDECODE('(.*?)'), 替换为 '1',

    1. 坑2:建表的sql语法不同。
      解决方法:
      (1)在建表语句最后添加默认字符集和默认校验方式:ENGINE=InnoDB AUTO_INCREMENT=40 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC
      另外,AUTO_INCREMENT=40,设置自增长到哪个数字了。这个数字还要到sql文件的序列中去找:
    -- CREATE SEQUENCE `halo`."SYSTEM_SEQUENCE_07030136_5506_425A_9226_CC6A332680DA" START WITH 39 BELONGS_TO_TABLE;
    -- CREATE SEQUENCE `halo`."SYSTEM_SEQUENCE_85A72195_448B_47C7_91E3_8EDCBF47C0B5" START WITH 38 BELONGS_TO_TABLE;
    -- CREATE SEQUENCE `halo`."SYSTEM_SEQUENCE_28935B3E_1674_4941_9D8B_E107ADBFE655" START WITH 2 BELONGS_TO_TABLE; 
    -- CREATE SEQUENCE `halo`."SYSTEM_SEQUENCE_8A63B720_7E60_4B97_B457_77B9D788B782" START WITH 100 BELONGS_TO_TABLE;  
    -- CREATE SEQUENCE `halo`."SYSTEM_SEQUENCE_BA607316_C0CA_4AC9_93B7_4EDD398DCE5E" START WITH 242 BELONGS_TO_TABLE;
    -- CREATE SEQUENCE `halo`."SYSTEM_SEQUENCE_C77F783A_7DED_4E69_9C04_901BA9342C28" START WITH 9 BELONGS_TO_TABLE; 
    -- CREATE SEQUENCE `halo`."SYSTEM_SEQUENCE_69675EBF_E100_4418_A967_F88A376A4AEF" START WITH 5775 BELONGS_TO_TABLE;           
    -- CREATE SEQUENCE `halo`."SYSTEM_SEQUENCE_95A9EFBB_A2DE_4C87_8D19_A805E62C0173" START WITH 1 BELONGS_TO_TABLE; 
    -- CREATE SEQUENCE `halo`."SYSTEM_SEQUENCE_7137CFFF_AD51_432D_AD29_C22596D7D471" START WITH 73 BELONGS_TO_TABLE;
    -- CREATE SEQUENCE `halo`."SYSTEM_SEQUENCE_56A6F5AE_2FC4_437F_A7BD_3B12F355782E" START WITH 20 BELONGS_TO_TABLE;
    -- CREATE SEQUENCE `halo`."SYSTEM_SEQUENCE_3FA77B52_1B71_4B7C_B75F_7CD707111A1C" START WITH 73 BELONGS_TO_TABLE;
    -- CREATE SEQUENCE `halo`."SYSTEM_SEQUENCE_5749AACE_18C3_42AE_A57F_F776A4CEB70B" START WITH 35 BELONGS_TO_TABLE;
    -- CREATE SEQUENCE `halo`."SYSTEM_SEQUENCE_7C9D7387_4BD6_4031_ACB0_EBF15B600A93" START WITH 6666 BELONGS_TO_TABLE;          
    -- CREATE SEQUENCE `halo`."SYSTEM_SEQUENCE_7437AF47_F79E_47AE_B97A_73C915A54E73" START WITH 1155 BELONGS_TO_TABLE;           
    -- CREATE SEQUENCE `halo`."SYSTEM_SEQUENCE_558AED66_5DC3_46BF_8E83_C8FF7AF1F02F" START WITH 1257 BELONGS_TO_TABLE;          
    -- CREATE SEQUENCE `halo`."SYSTEM_SEQUENCE_42A96F72_A81E_4741_AF00_3EA740EB24E7" START WITH 39 BELONGS_TO_TABLE;
    

    (2)修改建表语句中的字段类型为mysql语法的。
    (3)每张表都有一个主键字段ID,原来是设置自增长的,使用序列来实现,mysql中没有序列,但是也可设置自增长,所以这么修改:ID INT NOT NULL PRIMARY KEY AUTO_INCREMENT
    (4)H2的字段是用双引号"包裹起来的,而mysql是用飘号`,需要用正则来替换。

    eg.   `$1` VARCHAR(200) NOT NULL,
    	"([A-Z0-9]+_?[A-Z0-9]*?)" VARCHAR(  替换为   `1` VARCHAR( 或者  `$1` VARCHAR(,notpad++使用 1,idea使用  $1 
    	"([A-Z0-9]+_?[A-Z0-9]*?)" BIGINT(  替换为    `$1` BIGINT(
    	"([A-Z0-9]+_?[A-Z0-9]*?)" TINYINT(  替换为   `$1` TINYINT(
    
    1. java代码报错:Caused by: org.hibernate.QueryException: Space is not allowed after parameter prefix ':'
      原因:参数前缀:(即引用占位符)的前后都不允许有空格。(其实不是这个原因)
      举例如下:
    # error
    ...AND apply.startTime >=: startTime1 AND apply.endTime <=: endTime1   
    # correct
    ...AND apply.startTime >=:startTime1 AND apply.endTime <=:endTime1   
    

    解决方法:拼接时给concat参数加上英文单引号。

    1. java代码报错:java.lang.IllegalArgumentException: Illegal group reference
      String test = "abc";
      test = test.replaceAll("abc", "1111111111$$");
      //以上语句会报异常java.lang.IllegalArgumentException: Illegal group reference,解决方法为改写以下形式:
      test = test.replaceAll("abc", java.util.regex.Matcher.quoteReplacement("dXNlcjM1NDk2NQ$$"));

    2. java代码报错:data too long for column FORMAT_CONTENT``
      解决方法:将FORMAT_CONTENT字段类型由text(最长4K)改为mediumtext(最长16M)

    3. java代码报错:java.lang.IllegalArgumentException: org.hibernate.QueryException: Unmatched braces(大括号) for alias path
      原因:我使用的原生sql语句,拼接后直接执行。此时,因为insert语句中有{括号所以会报错,解决方案就是去掉{或者加上},使{}不出现或成对出现。
      总之,当保存的字段内容有其他特殊符号,或者比较复杂的内容时,容易出现该错误,容易使程序解析不了SQL语句。其实也就是因为insert into语句完全是用手动拼字符串而成的SQL语句。
      解决方法:

      1. 所有{后添加}
        eg. id=549的posts记录是这么处理的。
      2. 改为字段内容提取出来成为参数,使用query.setParameter(1,strParam)来设置参数。这样也是防止了SQL注入。
    4. java代码报错:IllegalArgumentException: Could not locate ordinal(顺序的) parameter [1], expecting one of []
      原因:list中没有值可以被调用。这个不讲了,很简单。

    全是坑,不用hibernate了;最终使用了java原生的jdbc方法来执行insert语句,非常香!(原来使用query = em.createNativeQuery(sql)生成Query对象,再执行query.executeUpdate())

    3 小结

    1. 下次使用IDEA来迁移试试。
    2. 迁移之前,保存草稿时,halo系统经常报错“网络异常”,迁移之后,现在不报错了。
  • 相关阅读:
    wpf Behavior
    wpf Trigger
    语法糖
    Lambda 表达式
    wpf 3D动画
    IEnumerable接口学习
    Delegates, Events, and Anonymous Methods 委托、事件与匿名方法
    wpf 平滑效果随记
    软件工程第一篇博客
    记考研高数第一课
  • 原文地址:https://www.cnblogs.com/mediocreWorld/p/15188931.html
Copyright © 2011-2022 走看看