通过liquibase将PostgreSQL数据库导入到H2数据库

2023-10-27

1.背景
项目中使用的数据库是PostgreSQL,在做测试时,想使用H2代替。
2.问题
2.1 保留字:在PostgreSQL中使用了几个H2的保留字,例如 "end", "offset", "foreign",这些保留字是不能作为表的字段名。
2.2 字段类型:在PostgreSQL中double precision类型需要被替换成H2的float。
3.方法
liquibase提供一个ant任务:generateChangeLog,可以将PostgreSQL数据库中表,约束和数据都导出到一个xml文件中。然后通过liquibase根据导出的xml文件,在H2中生成数据库。
4.结果
生成xml文件,内容是liquibase的ChangeLog。

在使用generateChangeLog时,需要做一些扩展。
1.generateChangeLog任务

<generateChangeLog
outputFile="xxxxx\\structure.xml"
driver="org.postgresql.Driver"
url="jdbc:postgresql://localhost:5432/db"
username="name"
password="pass"
classpathref="classpath"
loglevel="debug"
databaseClass="xxx.ExtendPostgresDatabase"
changeLogFile="xxxx\\structure.ext"
diffTypes="tables, columns, views, indexes, sequences"
/>

outputFile指定生成的文件,包含指定生成文件的liquibase.serializer.core.xml.XMLChangeLogSerializer。
databaseClass指定任务执行时数据库的类型。
changeLogFile指定生成的自定义文件,当changeLogFile指定时outputFile会被忽略。需要注册自定义的liquibase.serializer.ChangeLogSerializer。
diffTypes指定generateChangeLog任务执行时哪些数据库元素被导出。

2.扩展PostgresDatabase类


import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import liquibase.database.core.PostgresDatabase;
import liquibase.database.typeconversion.TypeConverterFactory;
import liquibase.serializer.ChangeLogSerializerFactory;
import liquibase.snapshot.DatabaseSnapshotGeneratorFactory;

public class ExtendPostgresDatabase
extends PostgresDatabase
{

public static final List<String> reservedWords = Arrays.asList( new String[] { "end", "offset", "foreign" } );

public static final List<String> ignoreTables = new ArrayList<String>();

public static final List<String> ignoreIndexes = new ArrayList<String>();

public static final List<String> ignorePrimaryKeys = new ArrayList<String>();

public static final List<String> ignoreForeignKeys = new ArrayList<String>();

public ExtendPostgresDatabase()
{
TypeConverterFactory.getInstance().register( new Postgres2H2TypeConverter() );//注册类型转换器,将Postgres的数据类型转换成H2
ChangeLogSerializerFactory.getInstance().register( new ExtendXMLChangeLogSerializer() );//注册ChangeLog文件生成器
DatabaseSnapshotGeneratorFactory.getInstance().register( new ExtendPostgresDatabaseSnapshotGenerator() );//注册数据库快照
}

@Override
public boolean isReservedWord( String word )
{
boolean reservedWord = super.isReservedWord( word );
if ( reservedWord )
{
return reservedWord;
}

return reservedWords.contains( word.toLowerCase() );
}

}


3.扩展PostgresDatabaseSnapshotGenerator类



import java.util.Set;

import liquibase.database.Database;
import liquibase.database.structure.ForeignKey;
import liquibase.database.structure.Index;
import liquibase.database.structure.PrimaryKey;
import liquibase.database.structure.Table;
import liquibase.diff.DiffStatusListener;
import liquibase.exception.DatabaseException;
import liquibase.snapshot.DatabaseSnapshot;
import liquibase.snapshot.jvm.PostgresDatabaseSnapshotGenerator;

public class ExtendPostgresDatabaseSnapshotGenerator
extends PostgresDatabaseSnapshotGenerator
{

@Override
public DatabaseSnapshot createSnapshot( Database database, String requestedSchema, Set<DiffStatusListener> listeners )
throws DatabaseException
{
DatabaseSnapshot snapshot = super.createSnapshot( database, requestedSchema, listeners );

//过滤掉不希望被导出的数据库元素
for ( String key : ExtendPostgresDatabase.ignoreIndexes )
{
Index index = snapshot.getIndex( key );
snapshot.getIndexes().remove( index );
}
for ( String key : ExtendPostgresDatabase.ignoreTables )
{
Table table = snapshot.getTable( key );
snapshot.getTables().remove( table );
}
for ( String key : ExtendPostgresDatabase.ignorePrimaryKeys )
{
PrimaryKey primaryKey = snapshot.getPrimaryKey( key );
snapshot.getPrimaryKeys().remove( primaryKey );
}
for ( String key : ExtendPostgresDatabase.ignoreForeignKeys )
{
ForeignKey foreignKey = snapshot.getForeignKey( key );
snapshot.getForeignKeys().remove( foreignKey );
}
return snapshot;
}

@Override
public boolean supports( Database database )
{
return database instanceof ExtendPostgresDatabase;
}

@Override
public int getPriority( Database database )
{
return super.getPriority( database ) + 1;
}

}


4.扩展XMLChangeLogSerializer类


import liquibase.change.ColumnConfig;
import liquibase.serializer.core.xml.XMLChangeLogSerializer;

import org.w3c.dom.Element;

public class ExtendXMLChangeLogSerializer
extends XMLChangeLogSerializer
{

@Override
public String[] getValidFileExtensions()
{
return new String[] { "ext" };//配合generateChangeLog任务中指定的changeLogFile的后缀名
}

public Element createNode( ColumnConfig columnConfig )
{
//如果列的名字是保留字,需要加上转义符,否则在导入H2时会失败。
Element createNode = super.createNode( columnConfig );
String tagName = createNode.getTagName();
if ( tagName.equalsIgnoreCase( "column" ) )
{
String name = createNode.getAttribute( "name" );
if(ExtendPostgresDatabase.reservedWords.contains(name.toLowerCase()))
{
createNode.setAttribute( "name", "\"" + name + "\"" );
}
}

return createNode;

}

}


5.扩展H2TypeConverter类


import liquibase.database.Database;
import liquibase.database.structure.Column;
import liquibase.database.typeconversion.core.H2TypeConverter;

public class Postgres2H2TypeConverter
extends H2TypeConverter
{

@Override
public int getPriority()
{
return super.getPriority()+1;
}

@Override
public boolean supports( Database database )
{
return database instanceof ExtendPostgresDatabase;
}

@Override
public String convertToDatabaseTypeString( Column referenceColumn, Database database )
{
//将PostgreSQL的类型转换成H2类型
if ( "LONGVARCHAR".equals( referenceColumn.getTypeName().toUpperCase() ) )
{
return "LONGVARCHAR";
}

if ( "FLOAT4".equals( referenceColumn.getTypeName().toUpperCase() ) )
{
return "FLOAT";
}

return super.convertToDatabaseTypeString( referenceColumn, database );
}

}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通过liquibase将PostgreSQL数据库导入到H2数据库 的相关文章

  • 优化 LATERAL join 中的慢速聚合

    在我的 PostgreSQL 9 6 2 数据库中 我有一个查询 该查询根据一些股票数据构建计算字段表 它为表中的每一行计算 1 到 10 年的移动平均窗口 并将其用于周期性调整 具体来说 CAPE CAPB CAPC CAPS 和 CAP
  • 使用转义换行符和回车符取消转义字符串

    我正在尝试编写一个 PLPGSQL 函数来混淆 审查 编辑文本 Obfuscate a body of text by replacing lowercase letters and numbers with symbols CREATE
  • Postgres < 9.0 的 DO 块相当于什么

    Postgres 8 4 8 相当于什么 DO BEGIN IF NOT EXISTS THEN EXECUTE END IF END create function f returns void as BEGIN IF NOT EXIST
  • PostgreSQL - 根据另一个单元格值设置默认单元格值

    如果我有一个专栏说column a任何给定值 我想要另一列column b有一个default value根据 的值column a 换句话说 if column a peter then column b default value do
  • 如何在 PostgreSQL 中使用条件和子查询创建唯一索引?

    我使用 PGSQL 并尝试添加下面的索引 CREATE UNIQUE INDEX fk client ON user client fk client WHERE fk client NOT IN SELECT fk client FROM
  • 最近邻居的 Postgis SQL

    我正在尝试计算最近的邻居 为此 我需要传递一个参数来限制与邻居的最大距离 例如 半径1000米内最近的邻居是哪些 我做了以下事情 我用数据创建了表 id name latitude longitude 之后 我执行了以下查询 SELECT
  • Django 中从 sqlite 迁移到 postgresql

    我想迁移自sqlite to PostgreSQL db 我安装了 postgresql 并在其 shell 上创建数据库 然后配置我的 django 设置如下 default ENGINE django db backends postg
  • Npgsql 参数化查询输出与 PostGIS 不兼容

    我在 Npgsql 命令中有这个参数化查询 UPDATE raw geocoding SET the geom ST Transform ST GeomFromText POINT longitude latitude 4326 3081
  • 从 Django 调用 Postgres SQL 存储过程

    我正在开发一个带有 Postgresql 数据库的 Django 项目 我编写了一个可以在 Postgres 上完美运行的存储过程 现在我想从 Django 1 5 调用该存储过程 我已经编写了代码 但它提示错误 CREATE FUNCTI
  • 标量子查询包含多行

    我正在使用 H2 数据库并想要移动一些数据 为此 我创建了以下查询 UPDATE CUSTOMER SET EMAIL SELECT service EMAIL FROM CUSTOMER SERVICE AS service INNER
  • 在 Postgres 中存储加密数据 [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我需要在 Postgres 中以加密形式存储某些数据 显然 我需要对其进行加密 存储 并且能够读取和解密 做这个的最好方式是什么 The bes
  • postgresql 不同的不工作

    我使用以下代码从数据库获取值 但是当我编写这段代码时 测试看看问题出在哪里 我注意到查询没有从数据库中获取不同的值 这是查询 select distinct ca id as id acc name as accName pIsu name
  • 唯一索引或主键违规:“PRIMARY KEY ON PUBLIC.xxx”; SQL语句

    每当我的应用程序启动时 我都会收到以下错误消息 Caused by org h2 jdbc JdbcSQLException Unique index or primary key violation PRIMARY KEY ON PUBL
  • PLpgSQL 函数不返回匹配的标题

    当给定文本时 我试图返回电影名称以及演员和工作人员的数量 当我输入字符串并使用 ilike 时 我的查询返回不匹配的标题 我之前创建了一个视图 其中包含要在函数中输入的电影标题和工作人员数量 我的代码是 create or replace
  • pg_restore错误:角色XXX不存在

    尝试将数据库从一个系统复制到另一个系统 涉及的版本是9 5 0 源 和9 5 2 目标 源数据库名称是foodb与主人pgdba并且目标数据库名称将被命名foodb dev与主人pgdev 所有命令都在将托管副本的目标系统上运行 The p
  • JPA 支持查询 Postgres JSON 字段

    JPA 是否已经支持处理 JSON 字段的查询 如下所示 select from person where info gt gt age numeric 40 select from person where info gt gt firs
  • 在 plpgsql 函数中使用 quote_ident()

    我是创建 plpgsql 函数的新手 我需要一些有关在函数内部执行的动态命令上使用 quote ident 甚至 quote literal 的说明 希望有人能给我一个关于它们如何在函数内部工作的具体解释 TIA 这是一个例子 EXECUT
  • Rails 的多个数据库不适用于远程数据库

    我有一个远程只读 postgres 数据库 它是通过 docker 实例维护的卡尔达诺数据库同步 https github com input output hk cardano db sync 我设法将开发数据库连接到它 它工作正常 但由
  • “WHERE”处或附近的语法错误

    创建 postgres 函数时会导致错误 如下所示 错误 WHERE 处或附近的语法错误 第 19 行 其中 s shift id shiftid 错误 错误 WHERE 处或附近的语法错误 SQL状态 42601 人物 108 请帮忙 C
  • postgresql 选择不同的最新记录

    我有一个像这样的表 id fkey srno remark date 1 A001 1 2 A001 2 3 A002 1 4 A003 1 5 A002 2 我想要基于 max srno 的不同最新记录 例如 2 A001 2 4 A00

随机推荐

  • Mysql 乱码问题--如何查看和修改Mysql 的字符集

    MySQL会出现中文乱码的原因不外乎下列几点 1 server本身设定问题 例如还停留在latin1 2 table的语系设定问题 包含character与collation 3 客户端程式 例如php 的连线语系设定问题 强烈建议使用ut
  • Linux下安装openldap

    Linux下安装openldap 1 安装Berkeley DB 4 7 25 伯克利大学嵌入式数据库方案 openldap用它作为存储方案 root instance 0pk09gjj ldap wget http download or
  • DAC芯片CBM128S085

    一 硬件介绍 1 1 芯片内部框架图 1 2 CBM12S085引脚定义 引脚介绍 DAC SYNC 电平触发控制输入 低电平有效 SCLK 时钟输入 DAC DIN 串行数据输入 VOUTA H则是对应的8个电压模拟输出通道 二 软件实现
  • 找出数组中每个数的右边第一个比它大的数

    vector
  • 人工智能 猴子摘香蕉问题

    1 定义描述环境状态的谓词 AT x w x在w处 个体域 x monkey w a b c box HOLD x t x手中拿着t 个体域 t box banana EMPTY x x手中是空的 ON t y t在y处 个体域 y b c
  • 三角形

    1 2 3 4 5 6
  • function 与 => 的区别

    function 与 的区别主要是他们的作用域的不同 在JS中 箭头函数并不是简单的function 匿名函数的简写语法糖 实际上 箭头函数和匿名函数有个明显的区别 gt 箭头函数内部的this是词法作用域 在编写函数时就已经确定了 fun
  • CentOS8.4安装Redis6.2.6

    一 下载 官网 Redis 我们下载 Stable 稳定版 cd mydata wget https download redis io releases redis 6 2 6 tar gz 二 安装redis6 2 6 1 安装到 us
  • python编一函数s(x) 求级数和_Python 编程基础之高阶函数篇(一)

    高阶函数 能接受函数作为参数的函数 如 f abs def add x y f return f x f y 如果我们用 add 5 9 f 来调用该高阶函数 则返回结果为 14 abs是Python提供的求绝对值的函数 Python中的m
  • Django实现音乐网站 ⒅

    使用Python Django框架做一个音乐网站 本篇主要为歌单列表 歌单详情及推荐页 歌单内容改动 目录 歌单列表 设置路由 视图处理 模板渲染 歌单 单曲列表 设置路由 视图处理 模板渲染 推荐页 歌单列表 模板渲染修改 总结 歌单列表
  • C语言字节数

    bool 1字节 char 1字节 short 2字节 string 4字节 int 4字节 指针4字节 float 4字节 double 8字节 long 4或8字节 long long 8字节 long double 12字节 空类1字
  • ArcFace loss与其他改进loss对比

    ArcFace loss与其他改进loss对比 sphereFace A softmax cos ma 角度距离 cosFace AM softmax cosa m 余弦距离 ArcFace Arc softmax cos a m 角度距离
  • ICCV, ECCV, CVPR,IEEE的关系

    计算机视觉领域世界三大顶级会议分别为CVPR ICCV和ECCV CVPR CVPR 英文全称IEEE Conference on Computer Vision and Pattern Recognition 中文全称是国际计算机视觉与模
  • FeignClient中name和url属性的作用

    定义 feign是声明式的web service客户端 它让微服务之间的调用变得更简单了 类似controller调用service Spring Cloud集成了Ribbon和Eureka 可在使用Feign时提供负载均衡的http客户端
  • node-ffi ffi.Library往电脑窗口的任意光标处输入内容(user32.dll)window电脑

    node ffi ffi Library往电脑窗口的任意光标处输入内容 user32 dll window电脑 类似键盘输入法的效果 前提 遇到问题 解决问题了 补充安装库遇到的问题 类似键盘输入法的效果 我node项目和electron项
  • 语义分割评价指标mIOU的计算

    语义分割评价指标mIOU的计算 注意事项 这是针对重构了的语义分割网络 而不是之前的那个 所以不要询问原来的网络计算miou要怎么做 因为整个文件构架差距过大 建议使用新构架 学习前言 算一下语义分割的miou 做好生态链 什么是mIOU
  • 北大青鸟汉字注释机内码_北大青鸟消防主机如何编写汉字注释?

    北大青鸟消防主机汉字注释有两种 一种是利用编程调试软件进行编写文字注释 另一种是直接在消防主机上对照汉字机内码 进入系统进行编辑 下面小编跟大家介绍的是使用编程调试软件进行文字注释的方法 1 序号 项 序号 项自动生成 不需用户自己填写 2
  • 【SSO单点登录】JWT续签问题 && OAuth2.0 中的refreshToken刷新机制

    本篇速览 JWT续签问题 快过期时返回新的token refreshToken 如何判断refreshToken的有效性 扩展 OAuth2 0 中的refreshToken刷新机制 其他需要刷新token的情况 用户修改了角色权限 删除了
  • SQL优化之 not in

    not in select from dic region old a where a region code not in select b region code from dic region b PL SQL 执行 选择17 行 耗
  • 通过liquibase将PostgreSQL数据库导入到H2数据库

    1 背景 项目中使用的数据库是PostgreSQL 在做测试时 想使用H2代替 2 问题 2 1 保留字 在PostgreSQL中使用了几个H2的保留字 例如 end offset foreign 这些保留字是不能作为表的字段名 2 2 字