SpringMVC postgreSQL二进制文件存储

1,259 阅读2分钟

引言

我这里有一张表的列类型是bytea型,也就是文件的二进制数据,它属于大对象(Large Objects)。
(什么是大对象) 把二进制数据插入表中需要以下几个步骤。

0. 没有使用Spring以及Mybatis时,处理PostgreSQL二进制数据

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中怎么使用呢。也不复杂。

1. 定义实体类

实体类的编码相当的简单。我们只需要把相关的二进制字段声明为byte数组类型,Mybatis就会自动处理。这是因为在MyBatis 3.4中提供了TypeHandler处理BLOB/CLOB数据。

// 实体类字段
public class Entity {
    ......
    private byte[] phototemplate;
    .....
}

2. 手动提交事务

像往常一样我把数据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);
		}
	}
	

}

3.业务逻辑

我这里是读取图片文件的二进制数据,然后赋值给上面的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结果