神通数据库 JDBC DRIVER中的STREAM

JDBC标准中提供了三种流BinaryStream、AsciiStream和CharacterStream。另外也提供了UnicodeStream。但是标准中申明UnicodeStream已经废弃不用了。在本节中我们将只讨论BinaryStream、AsciiStream和CharacterStream。

AsciiStream和CharacterStream是对应于CHAR、VARCHAR和TEXT类型。当使用AsciiStream读取字符时,会将字符当作Ascii字符读取出来,当使用CharacterStream读取字符时,会将字符当作Unicode-16读取出来。

BinaryStream对应于BINARY和VARBINARY类型。

在ResultSet对象中提供了getAsciiStream()、getCharacterStream()和getBinaryStream()方法,通过这些方法应用程序就可以不一次将数据全部取出来。在ResultSet中,相对于getAsciiStream()和getCharacterStream()对应的方法是getString();与getBinaryStram()相对应的方法是getBytes()。下面就举一个例子,说明两者读取的区别。

在示例中,第一个示例我们先用getBytes()方法从ResultSet对象中将数据取出来, 然后将取出来的数据写到文件中去;第二个示例调用getBinaryStream()方法从ResultSet对象 中取出数据来,然后将取出来的数据同样写到文件中去。这里假设后台数据库已经有表GIFTABLE, 且它的两个字段分别为NAME,它的数据类型为VARCHAR,GIFPICTURE,它的数据类型为VARBINARY。

package com.sun.cts.tests.jdbc.help_doc.ru_men;

import static org.junit.Assert.fail;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

import org.junit.Test;

public class StreamTEST {

	private Connection con;
	private Statement stmt;
	public String DBUSER = "";
	public String DBPASSWD = "";
	public String DBURL = "";
	public String DBDRIVER = "";

	public void init() {
		Properties prop = new Properties();
		try {

			FileInputStream in = new FileInputStream(
					"." + File.separator + "testFile" + File.separator + "cts_env.properties");
			prop.load(in);
			in.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		//从配置文件读取
		// DBUSER = "sysdba";
		DBUSER = prop.getProperty("DBUSER");
		// DBPASSWD = "szoscar55";
		DBPASSWD = prop.getProperty("DBPASSWD");
		// DBURL = "jdbc:oscar://localhost:2003/osrdb";
		DBURL = prop.getProperty("DBURL");
		// DBDRIVER = "com.oscar.Driver";
		DBDRIVER = prop.getProperty("DBDRIVER");
		try {
			Class.forName(DBDRIVER);
			con = DriverManager.getConnection(DBURL, DBUSER, DBPASSWD);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	private void creTable() {
		try {
			stmt = con.createStatement();
			// 创建表
			String sql = "CREATE TABLE GIFTABLE" + "(name varchar(10) not NULL,GIFPICTURE VARBINARY(255))";
			stmt.executeUpdate(sql);
			// 插入数据
			byte[] byBuffer = new byte[200];
			String strInput = "abcdefg";
			byBuffer = strInput.getBytes();
			PreparedStatement pst = con.prepareStatement("INSERT INTO GIFTABLE VALUES(?,?)");
			pst.setString(1, "gif1");
			pst.setBytes(2, byBuffer);
			pst.execute();
			pst.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	private void delTable() {
		try {
			// 删除表
			String sql = "DROP TABLE GIFTABLE";
			stmt.executeUpdate(sql);
			stmt.close();
			con.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}

	}

	private void execute1() {
		try {
			// 获取数据
			String sql = "SELECT GIFPICTURE FROM GIFTABLE WHERE NAME='gif1'";
			ResultSet rs = stmt.executeQuery(sql);
			if (rs.next()) {
				FileOutputStream fos = null;
				byte[] bytes = rs.getBytes(1);
				try {
					fos = new FileOutputStream("test/bin.txt");
					fos.write(bytes);
				} catch (Exception e) {
					String err = e.toString();
					System.out.println(err);
				} finally {
					if (fos != null) {
						try {
							fos.close();
						} catch (IOException ie) {
							System.out.println(ie);
						}
					}
				}
			}
			rs.close();
		} catch (SQLException e1) {
			fail(e1.getMessage());
		}
	}

	private void execute2() {
		ResultSet rs;
		try {
			rs = stmt.executeQuery("SELECT GIFPICTURE FROM GIFTABLE WHERE NAME='gif1'");
			if (rs.next()) {
				FileOutputStream fos = null;
				byte[] bytes = new byte[1024];
				InputStream is = rs.getAsciiStream(1);
				try {
					fos = new FileOutputStream("test/cin.txt");
					int len = 0;
					while ((len = is.read(bytes)) > 0){
						fos.write(bytes, 0, len);
					}
				} catch (Exception e) {
					fail(e.getMessage());
					String err = e.toString();
					System.out.println(err);
				} finally {
					if (fos != null) {
						try {
							fos.close();
						} catch (IOException ie) {
							System.out.println(ie);
						}
					}
					try {
						is.close();
					} catch (IOException ie) {
						System.out.println(ie);
					}
				}
			}
			rs.close();
		} catch (SQLException e1) {
			fail(e1.getMessage());
		}

	}

	@Test
	public void execute() {
		init();
		creTable();
		execute1();
		execute2();
		delTable();
	}

	public static void main(String[] args) throws SQLException {
		new StreamTEST().execute();
	}
}

由execute1()和execute2()可以看出,execute1()中直接将数据全部取出来然后写到文件中去;而execute2()中则是开了一个缓冲区,每次读取的数据不超过缓冲区的大小,然后将读取的数据写到文件中去。这里缓冲区的大小完全由应用程序来指定,这样极大地增强了应用程序的灵活性。别忘了,在使用完流后,请将流关闭。只需简单的调用close()方法就行了。对于AsciiStream和CharacterStream同BinaryStream一样,不在这里一一列举。

讨论到流,必须要讨论另外一种特殊的可以操纵更大数据量的类型BLOB和CLOB。这两种数据类型在前面的数据类型映射中,我们可以发现它们分别对应于JAVA语言中的java.sql.Blob和java.sql.Clob。这两种数据类型,可以存放更大的数据量,理论上是没有限制的,但实际应用中却由应用程序的运行环境所决定,比如内存、硬盘等。对于这两种数据类型,JDBC提供了标准的Blob和Clob接口。Blob是用来处理二进制流,而Clob是用来处理字符流。关于这两种接口更详细的描述,我们将在大对象这一章中给出。总之,使用流可以极大地增加程序的灵活性,使程序在某些情况下更加健壮。