设为首页 收藏本站
查看: 1102|回复: 0

[经验分享] 通过liquibase将PostgreSQL数据库导入到H2数据库

[复制链接]

尚未签到

发表于 2016-11-21 06:25:42 | 显示全部楼层 |阅读模式
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 );
}
}

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-303063-1-1.html 上篇帖子: 使用Apache的mod_authn_dbd和PostgreSQL实施HTTP Basic登录认证 下篇帖子: PostgreSQL启动过程中的那些事五:初始化世界上现有行政区时区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表