红联Linux门户
Linux帮助

使用copy函数完成数据库迁移

发布时间:2016-02-23 16:07:49来源:linux网站作者:Jason‘

最近在该一个迁移工具的迁移方式,从ora8迁移到postgresql使用原来的插入迁移速度太慢了,老板说让使用缓存迁移,即使用postgresql的copy函数,因此去pg官网查阅了相关资料,我们需要迁移的数据量大约有3000万条,需要时间在半个小时之内,这个迁移第一步先把相关的表结构迁移过去,然后开始导入数据,下面是我缓存迁移写的一段代码,核心都在里面:


private boolean toPostgresql(int tableIndex) throws SQLException, IOException
{
int success_flag = 0; // 设置成功标志

boolean isHasError = false;

TableConfig tableConfig = (TableConfig) tableConfigList.get(tableIndex);
ITable destTable = tableConfig.getDestTable(); // 可以通过这个获得目的表的表名字
ITable srITable = tableConfig.getDestTable();
// srITable.
String dest_tablename = destTable.getName().toString();
String dest_schema = destTable.getSchemaName();

Statement stmt = null;
ResultSet rs = null;

Setfetchsize s1=new Setfetchsize();
try
{
s1.getxml_setfetchsize();
} catch (ParserConfigurationException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
int stmt_setfetchsize = s1.getSetfetchsize_num();// 设置setfetchsize
// 取值大小
stmt = srcConn.createStatement();
stmt.setFetchSize(stmt_setfetchsize);
rs = getSrcResultSet(tableConfig, stmt);
ResultSetMetaData rsmd = rs.getMetaData();// 为了获得字段用的
// System.out.println("缓存setfetchsize设置为:"+stmt_setfetchsize);
int columnCount = rsmd.getColumnCount(); // 获得字段的个数
StringBuilder sbuild = new StringBuilder();
//System.out.println("stmt_setfetchsize实际取值为:"+stmt.getFetchSize());
/**
* 把结果集的数据拼接成字符串语句,保存到sbulid中 大小受缓存大小影响
*/
KBCopyOutputStream kb_output = new KBCopyOutputStream((BaseConnection) destConn, "COPY " + dest_schema + "." + dest_tablename + "FROM STDIN");

while (rs.next())
{

row_totalnum += 1; // 记录总数据的总行数
for (int i = 1; i <= columnCount; i++)
{
String val = rs.getString(i);
int coltype = rsmd.getColumnType(i);
// 对字符字段的转义字串进行处理,使其转义效果失效
if (coltype == Types.CHAR || coltype == Types.VARCHAR || coltype == Types.NCHAR || coltype == Types.NVARCHAR || coltype == Types.LONGVARCHAR)
{
int valen = val.length();
sbuild.ensureCapacity(valen + 4);
for (int j = 0; j < valen; j++)
{
char ch = val.charAt(j);
switch (ch)
{
case '\t' :
sbuild.append("\\t");
break;
case '\n' :
sbuild.append("\\n");
break;
case '\r' :
sbuild.append("\\r");
break;
case '\\' :
sbuild.append("\\\\");
break;
default :
sbuild.append(ch);
}
}
} else
sbuild.append(val);

if (i < columnCount)
sbuild.append('\t');
}
sbuild.append('\n');

String s = sbuild.toString();
byte[] bytes = s.getBytes("UTF-8");
kb_output.write(bytes);
if (row_totalnum % 10 == 0)
{
successRowNum = 0;
addToSuccessNum(row_totalnum);
}
// System.out.print(s);
sbuild.setLength(0);
}
kb_output.close();
success_flag = 1;
destConn.commit();

if (success_flag == 1)
{
writeFinishResult(srITable.getFullName(), destTable.getFullName(), row_totalnum, row_totalnum, 0);
successRowNum = 0;
addToSuccessNum(row_totalnum);
} else
{
writeFinishResult(srITable.getFullName(), destTable.getFullName(), row_totalnum, 0, row_totalnum);
addToErrorNum(row_totalnum); // copyin执行失败返回错误数
}
writeSteps(" ");
return !isHasError;
}


我们的setfetchsize可以自己设置一下,这个目的是减少来回访问oracle拿取数据的开销,具体用法可以查看相关资料,主要是访问的数据量大的时候用的。上面的代码有个小缺陷,就是我把处理过的数据都放到一个stringbuilder里了,当数据量很大超过内存时候,估计就跑不动了,你可以对stringbuilder里的数据进行大小判断一下,当满足的时候commit一下啊就行,这个数据迁移是在一个事务中进行的,所以最后有个commit提交!


本文永久更新地址:http://www.linuxdiyf.com/linux/18337.html