我这里有一张表的列类型是bytea型,也就是文件的二进制数据,它属于大对象(Large Objects)。
(什么是大对象) 把二进制数据插入表中需要以下几个步骤。
postgreSQL官方文档中,存储二进制是用Java的PreparedStatement#setBinaryStream方法。
File file = new File("myimage.gif"); FileInputStream fis = new FileInputStream(file); PreparedStatement ps = conn.prepareStatement("INSERT INTO images VALUES (?, ?)"); ps.setString(1, file.getName()); ps.setBinaryStream(2, fis, file.length()); ps.executeUpdate(); ps.close(); fis.close(); 复制代码
读取二进制则用ResultSet.getBytes()
PreparedStatement ps = con.prepareStatement("SELECT img FROM images WHERE imgname = ?"); ps.setString(1, "myimage.gif"); ResultSet rs = ps.executeQuery(); if (rs != null) { while (rs.next()) { byte[] imgBytes = rs.getBytes(1); // 业务 } rs.close(); } ps.close(); 复制代码
那Spring+mybatis+postgreSQL中怎么使用呢。也不复杂。
实体类的编码相当的简单。我们只需要把相关的二进制字段声明为byte数组类型,Mybatis就会自动处理。这是因为在MyBatis 3.4中提供了TypeHandler处理BLOB/CLOB数据。
// 实体类字段 public class Entity { ...... private byte[] phototemplate; ..... } 复制代码
像往常一样我把数据insert到表中时,出现了以下PSQLException。
大对象不能用于自动提交模式(Large Objects may not be used in auto-commit mode) 复制代码
于是改成了手动提交事务,终于成功插入了数据。 有时候我们需要手动提交事务,比如说很大的数据分次提交,避免内存溢出。又或者插入二进数据到表中。
这里的关键是自己把DataSourceTransactionManager注入,并使用它进行事务处理。
import org.springframework.jdbc.datasource.DataSourceTransactionManager; @Service public class IndicationmessagesServiceImpl { @Autowired MyMapper mapper; @Autowired private DataSourceTransactionManager transactionManager; public void insert() throws Exception { // 业务逻辑 // TODO DefaultTransactionDefinition transDefinition = new DefaultTransactionDefinition(); // 开始新事物 transDefinition.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRES_NEW); TransactionStatus transStatus = transactionManager.getTransaction(transDefinition); try { mapper.insert(entity); // 提交事务 transactionManager.commit(transStatus); } catch (Exception e) { // 回滚事务 transactionManager.rollback(transStatus); throw new Exception(e); } } } 复制代码
我这里是读取图片文件的二进制数据,然后赋值给上面的phototemplate字段。
private byte[] readAll(InputStream inputStream) throws IOException { byte[] buffer = new byte[1024]; try (ByteArrayOutputStream bout = new ByteArrayOutputStream();) { int len; while (-1 != (len = inputStream.read(buffer))) { bout.write(buffer, 0, len); } return bout.toByteArray(); } } 复制代码
最后执行上述service的insert方法,插入到数据库。
select phototemplate结果