所有数据库迁移都使用Flyway。现在是迁移时处理二进制数据(图像(的时候了。我使用的是Postgresql和Spring Data JPA。
首先,我使用Postgresql在数据库列photo oid
中得到了这个字段
@Entity
public class Person {
// omitted
@Lob
private byte[] photo;
}
我的迁移脚本看起来像这个
V1__CREATE_DB.sql
V2__INSERT_PERSON.sql
V3__INSERT_PHOTO.java
起初,我没能成功地使用JdbcTemplate
迁移(更新(一个有照片的人。后来我发现,通过这样做,我可以将类型oid
更改为bytea
。
@Lob
@Type(type = "org.hibernate.type.BinaryType")
private byte[] photo;
然后我让迁移代码看起来像这个
public void migrate(Context context) throws IOException {
JdbcTemplate template = ...
List<String> locations = ... // photo physical locations/paths
for(String location: locations) {
InputStream image = ... // from location
Long id = ... // get id from image name
template.update("UPDATE person SET photo = ? where id = " + id,
new Object[] { new SqlLobValue(image.readAllBytes(), new DefaultLobHandler()) },
new int[] { Types.BLOB }
);
}
}
此V3__迁移按预期运行,但
是否有更好的方法来实现此迁移?我是否也应该为
oid
执行此操作?在这种情况下,如何执行?除了明显的存储容量差异外,是否有理由不选择
bytea
而不是oid
?
在几乎打破谷歌之后,我终于找到了一个如何使用JdbcTemplate更新列photo oid
的解决方案。
DefaultLobHandler lobHandler = new DefaultLobHandler();
lobHandler.setWrapAsLob(true);
jdbcTemplate.execute("UPDATE person SET photo = ? where id = ?", new AbstractLobCreatingPreparedStatementCallback(lobHandler) {
protected void setValues(PreparedStatement ps, LobCreator lobCreator) throws SQLException {
lobCreator.setBlobAsBinaryStream(ps, 1, image, image.available());
ps.setLong(2, id);
}
}