最近需要迁移一个数据库,06年开始用的,oracle 9i,迁移用的是oracle10g的,由于用了10多年了,数据库存在一些表空间文件损坏,数据有一些坏点,导致用一般的 imp 和 exp 方式无法正常迁移。
里面有一个有 blob 字段的表,2w多条记录,但是这个表的内容达到了40g,由于里面的内容存在损坏,无法正常通过dmp 导入导出,甚至plsql特有 的导入导出也不行。
解决方案:
一. 收集老数据库的信息(服务命名,表空间,用户的创建和角色权限)
二. 建立新数据库,用获取的服务命名创建数据库实例,创建符合容量的表空间,通过老数据库的用户sql 来创建用户,确保这些用户的角色和权限正常,并且使用的表空间也正确。
导出每个用户的数据dmp,把带有blob 字段的表排除在外。
处理表数据,还要确认所有的对象有正确导入,如触发器,视图,dblinks和序列等。
五. 通过java 代码迁移带blob 的表
我尝试了不少方式,发现用java 代码来处理的话,其实更灵活和效率更高,效率比dmp 的方式高多了。
用java 代码, 读取blob 的内容简单,getBlob就可以拿到,但是写入blob 字段的话,不能直接插入,并且需要使用io 流才行,直接的update 和setBlob 的方式是不行的。
1. 写入的数据库连接不能用自动事务,因为blob 字段的写入是通过io和更新的方式进行
conn.setAutoCommint(false);
...............写入数据后
conn.commit();
...............关闭连接前
conn.setAutoCommint(true);
...............连接不用了关闭
conn.close();
2. 读取blob 数据,这个不难,简单直接
java.sql.Blob blob_obj = null; //建立一个blob 对象
blob_obj = rs.getBlob(*); //*具体参数看实际情况
3. 写入blob 数据,这个要分多个步骤,不能直接写入
a. 先插入记录到表中,并且blob 要先写入空的内容,用empty_blob() 函数。
如,insert into tableblob values(?,?,empty_blob()), 最好表中有主键。
b. 再通过主键获取blob 字段的对象
java.sql.Blob blob_obj_t = null; //建立一个blob 对象指向要写入的blob 字段
select blob_obj from tableblob where id=? ,通过主键获取blob字段对象
blob_obj_t = rs2.getBlob(1);
c. 使用IO 流写入blob 字段内容
InputStream in = blob_obj.getBinaryStream();
OutputStream out = blob_obj_t.setBinaryStream(1L);
byte[] buffer = new byte[1024];
int length = -1;
while((length = in.read(buffer)) != -1){
out.write(buffer,length);
}
//数据写入完成,关闭IO,这个是必须的
in.close();
out.close();
//提交数据
conn.commit();
d. 注意每个prepareStatement 对象在操作后记得及时关闭,因为每个ps 对象都会使用一个游标,oracle 的游标是有数量限制的,超过数量就会返回异常,ps.close() 可以让游标得到回收,避免这个异常。
4. 检查这些表的触发器,索引主键,授权等是否正确,是否有关联的视图编译异常等。