寫在前面
寫這片文章是緣於在網上看到幾篇關於在MYSQL寫入圖片遇到亂碼時的問題,剛好最近在寫相關的代碼,就列出幾個解決的方法(雖然現實中是很少直接寫入圖片這種大數據的,但各數據庫廠商在技術上是完全可以實現的.
打開數據庫
String dbType="mysql.";
Properties pros=new Properties();
pros.load(new FileInputStream("src/db.properties"));
Class.forName(pros.getProperty(dbType.concat(DRIVER)));
Connection conn=DriverManager.getConnection(
pros.getProperty(dbType.concat(URL)),pros.getProperty(dbType.concat(USERNAME)),pros.getProperty(dbType.concat(PASSWORD)));
PreparedStatement pstmt=conn.prepareStatement("update dummy set image=? where username=?");
方法一
在原文無出現亂碼情況下,是可以直接將輸入流傳入PreparedStatement.setBlob(index,inputStream)的.
FileInputStream fis=new FileInputStream(file);
pstmt.setBlob(1, fis);
下面開始主題,在出現亂碼情況:
方法二
// method1
//bellow codes are from oracle14.jar
// blob.
// BLOB blob=BLOB.createTemporary(conn, false, BLOB.DURATION_SESSION);
// blob.open(BLOB.MODE_READWRITE);
// method2-with ojdbc6.jar
Blob blob=conn.createBlob();
byte[] temp = new byte[4096];
int length;
OutputStream out = blob.setBinaryStream(1);
// FileCopyUtils.copy(bis, out); the same function as bellow code
while ((length = bis.read(temp)) != -1) {
out.write(temp, 0, length);
}
out.flush();
pstmt.setBlob(1, blob);
方法三
- 插入一個空的blob
Statement st = con.createStatement(); //插入一個空對象empty_blob() st.executeUpdate("insert into dummy(id, username, password,image) values (1, 'other','psw', empty_blob())");
- 鎖定行(for update)
ResultSet rs = st.executeQuery("select image from dummy where id=3 for update");
- 獲取結果集,並利用方法一將inputStream寫入oracle BLOB.getBinaryOutputStream().
- flush並關閉流
- 提交
方法四
for the right syntax to use near 'ºÛ¢çþlô£·ö3ñ³G‹ÿøì´éÂèØn–ÿGA朳P²0`¶á¦�q•n\\]ß½w8zû , .×¹*5r>xm?{¾<œ•' at line 1
方法五
JdbcTemplate template=(JdbcTemplate)ctx.getBean("jdbcTemplate");
final File file=new File("src/other.jpg");
final InputStream bis=new BufferedInputStream(new FileInputStream(file));
try{
final LobHandler lobHandler=(LobHandler)ctx.getBean("oracleLobHandler");
template.execute("update dummy set image=? where username='other'", new AbstractLobCreatingPreparedStatementCallback(lobHandler) {
protected void setValues(PreparedStatement ps, LobCreator lobCreator)
throws SQLException, DataAccessException {
lobCreator.setBlobAsBinaryStream(ps, 1, bis, (int)file.length());//注意這裏是int類型,PreparedStatement提供的是一個long類型
}
});
}catch(Exception e){
e.printStackTrace();
}finally{
bis.close();
}
使用hibernate的例子,clob,
blob
Type mappings for the JDBC classes
java.sql.Clob
and java.sql.Blob
.
These types can be inconvenient for some applications, since the blob or clob object cannot be reused outside of a transaction. Driver support is patchy and inconsistent.
<hibernate-mapping>
<class name="com.yan.entity.Dummy">
<id name="id" />
<property name="username" length="20"></property>
<property name="password" length="20"></property>
<property name="age"></property>
<property name="path" length="80"></property>
<property name="image" type="binary" length="23389042"></property>
</class>
</hibernate-mapping>
注意,在MYSQL不加length屬性時,將默認映射爲tinyblob,如果設定長度,則會自動映射成tinyblob,blob,longblob. Oracle則對於爲raw,以及long raw.
dummy=new Dummy();
dummy.setId(4);
dummy.setUsername("176");
dummy.setPassword("p4");
dummy.setAge(21);
File f=new File("src/176.png");
InputStream is=new FileInputStream(f);
int l=(int)f.length();
byte[] buff=new byte[l];
is.read(buff,0,l);
is.close();
dummy.setImage(buff);
session.saveOrUpdate(dummy);
由於hibernate的binary對應的類型是BinaryType,在實現上是採用PreparedStatement.setBytes(index,buff)方法,所以在MYSQL與ORACLE是通用的.