谢谢作者的好文章,请参考林信良(良葛格)的专栏
如果要將 將檔案存入資料庫 ,我們在JDBC中可以使用CLOB與BLOB來分別針對文字檔案與二進位檔案進行儲存,Spring中可以透過JdbcTemplate來處理CLOB與BLOB。 舉個例子來說,假設您的MySQL資料庫表格如下:
1 2 3 4 5 CREATE TABLE test ( id INT AUTO_INCREMENT PRIMARY, txt TEXT, image BLOB );
假設我們現在分別讀進一個文字檔案與二進位檔案,並想將之儲存至資料庫中,則我們可以使用JdbcTemplate,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 final File binaryFile = new File("c://workspace//wish.jpg" ); final File txtFile = new File("c://workspace//test.txt" ); final InputStream is = new FileInputStream(binaryFile); final Reader reader = new FileReader(txtFile); JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); final LobHandler lobHandler = new DefaultLobHandler(); jdbcTemplate.execute("INSERT INTO test (txt, image) VALUES(?, ?)" , new AbstractLobCreatingPreparedStatementCallback(lobHandler) { protected void setValues(PreparedStatement pstmt, LobCreator lobCreator) throws SQLException, DataAccessException { lobCreator.setClobAsCharacterStream(pstmt, 1, reader, (int ) txtFile.length()); lobCreator.setBlobAsBinaryStream(pstmt, 2, is, (int ) binaryFile.length()); } } ); reader.close(); is.close();
JdbcTemplate中傳入了AbstractLobCreatingPreparedStatementCallback的實作,並傳入一 個 LobHandler,對於MySQL(MS SQL Server或Oracle 10g),這邊使用DefaultLobHandler即可,對於Oracle 9i特定的LOB處理,我們可以使用OracleLobHandler。
如果要從資料庫中將資料讀取出來,並另存為檔案,我們可以使用以下的程式:
1 2 3 4 5 6 7 8 9 10 11 12 13 final Writer writer = new FileWriter("c://workspace//test_bak.txt" ); final OutputStream os = new FileOutputStream(new File("c://workspace//wish_bak.jpg" )); jdbcTemplate.query("SELECT txt,image FROM test WHERE id = ?" , new Object[] { new Integer(1)} , new AbstractLobStreamingResultSetExtractor() { protected void streamData(ResultSet rs) throws SQLException, IOException, DataAccessException { FileCopyUtils.copy(lobHandler.getClobAsCharacterStream(rs, 1), writer); FileCopyUtils.copy(lobHandler.getBlobAsBinaryStream(rs, 2), os); } } ); writer.close(); os.close();
在使用Spring搭配Hibernate時,可以簡化對Lob型態的處理,只要在SessionFactory建構時指定LobHandler,例如: * beans-config.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN" "http://www.springframework.org/dtd/spring-beans.dtd" > <beans> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" > <property name="driverClassName" > <value>com.mysql.jdbc.Driver</value> </property> <property name="url" > <value>jdbc:mysql: </property> <property name="username" > <value>root</value> </property> <property name="password" > <value>123456</value> </property> </bean> <bean id="lobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler" /> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" destroy-method="close" > <property name="dataSource" > <ref bean="dataSource" /> </property> <property name="lobHandler" > <ref bean="lobHandler" /> </property> <property name="mappingResources" > <list> <value>onlyfun/caterpillar/User.hbm.xml</value> </list> </property> <property name="hibernateProperties" > <props> <prop key="hibernate.dialect" > org.hibernate.dialect.MySQLDialect </prop> </props> </property> </bean> <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate" > <property name="sessionFactory" > <ref bean="sessionFactory" /> </property> </bean> </beans>
在這邊指定LobHandler時,對於MySQL、DB2、MS SQL Server、Oracle 10g,使用DefaultLobHandler即可,而對於Oracle 9i,則可以使用OracleLobHandler。 接下來的操作與一般對HibernateTemplate的操作無異,例如您的資料庫表格為:
1 2 3 4 5 CREATE TABLE user ( id INT auto_increment PRIMARY Key, txt TEXT, image BLOB );
Spring的ClobStringType可以將CLOB映射至String,而BlobByteArrayType可以將BLOB映射至byte[],所以我們可以設計一個User類別如下: * User.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package onlyfun.caterpillar; public class User { private Integer id; private String txt; private byte [] image; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public byte [] getImage() { return image; } public void setImage(byte [] image) { this.image = image; } public String getTxt() { return txt; } public void setTxt(String txt) { this.txt = txt; } }
Use.hbm.xml沒什麼特別的: * User.hbm.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" > <hibernate-mapping> <class name="onlyfun.caterpillar.User" table="user" > <id name="id" column="id" > <generator class="native" /> </id> <property name="txt" column="txt" /> <property name="image" column="image" /> </class> </hibernate-mapping>
以下是個簡單的儲存與讀取Lob的程式片段示範:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 ApplicationContext context = new FileSystemXmlApplicationContext("beans-config.xml" ); InputStream is = new FileInputStream(new File("c://workspace//wish.jpg" )); byte [] b = new byte [is.available()]; is.read(b); is.close(); User user = new User(); user.setTxt("long...long...text" ); user.setImage(b); HibernateTemplate hibernateTemplate = (HibernateTemplate) context.getBean("hibernateTemplate" ); hibernateTemplate.save(user); user = (User) hibernateTemplate.execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException, SQLException { User user = (User) session.load(User.class, new Integer(1)); Hibernate.initialize(user); return user; } } ); System.out.println(user.getTxt()); b = user.getImage(); OutputStream os = new FileOutputStream(new File("c://workspace//wish_bak.jpg" )); os.write(b); os.close();