sql和java数据类型映射 1.docx
《sql和java数据类型映射 1.docx》由会员分享,可在线阅读,更多相关《sql和java数据类型映射 1.docx(16页珍藏版)》请在冰豆网上搜索。
sql和java数据类型映射1
Sql和java数据类型映射
概述
由于SQL数据类型和Java数据类型是不同的,因此需要某种机制在使用Java类型的应用程序和使用SQL类型的数据库之间来读写数据。
为此,JDBC提供了getXXX和setXXX方法集、方法registerOutParameter和类Types。
本章汇集了影响各种类和接口的数据类型的有关信息,并列出所有的对应关系表(这些表显示了SQL类型和Java类型之间的映射关系)以便于参考。
8.2将SQL数据类型映射为Java类型
不幸的是,不同数据库产品所支持的SQL类型之间有很大的不同。
即使不同的数据库以相同的语义支持SQL类型,它们也可能用不同的名称。
例如,绝大多数的主流数据库都支持一种表示大型二进制值的SQL类型,但Oracle把这种类型叫做LONGRAW,Sybase把它叫做IMAGE,Informix却把它叫做BYTE,而DB2又把它叫做LONGVARCHARFORBITDATA。
幸运的是,JDBC程序员通常并不需要自己去关心目标数据库所用的实际SQL类型的名称。
大多数时候,JDBC程序员将根据一些现有的数据库表来进行编程。
他们无须关心用于创建这些表的确切SQL类型的名称。
JDBC在java.sql.Types类中定义了一系列的常规SQL类型标识符。
这些类型可用于表示那些最为常用的SQL类型。
在用JDBCAPI编程时,程序员通常可以使用这些JDBC类型来引用一般的SQL类型,而无须关心目标数据库所用的确切SQL类型的名称。
在下一节中将对这些JDBC类型进行仔细说明。
程序员用到SQL类型名称的主要地方是在用SQL的CREATETABLE语句创建新的数据库表时。
这种情况下,程序员必须注意应该使用目标数据库所支持的SQL类型名称。
如果需要知道各种SQL类型在某个特定的数据库中的行为的确切定义,我们建议查阅一下数据库文档。
如果想要编写一种可在各种数据库上创建表的可移植JDBC程序,用户主要有两个选择。
第一个选择是:
限制自己只使用那些被广为接受的SQL类型名称(例如INTEGER、NUMERIC或VARCHAR)。
这些类型有可能能适应所有的数据库。
第二个选择是:
用java.sql.DatabaseMetaData.getTypeInfo方法来找出给定的数据库实际上支持哪些SQL类型,然后选择与给定JDBC类型相匹配的特定于数据库的SQL类型名。
JDBC定义了一个从JDBC数据库类型到Java类型的标准映射。
例如,JDBC的INTEGER类型通常映射为Java的int类型。
这可支持简单的接口,将JDBC值读写为简单的Java类型。
Java类型不必与JDBC类型完全形同;它们只须能够用足够的类型信息来代表JDBC类型,从而能正确地存储和取出参数和从SQL语句恢复结果就可以了。
例如,JavaString对象可能并不能精确地与任何JDBCCHAR类型匹配,但它却可给出足够的类型信息来成功地表示CHAR、VARCHAR或LONGVARCHAR类型。
8.3JDBC类型
本节描述各种JDBC数据类型及其与标准SQL类型和Java类型的关联方式。
8.3.1CHAR、VARCHAR和LONGVARCHAR
JDBC类型CHAR、VARCHAR和LONGVARCHAR密切相关。
CHAR表示固定长度的小字符串,VARCHAR表示长度可变的小字符串,而LONGVARCHAR表示长度可变的大字符串。
与JDBCCHAR对应的是SQLCHAR类型,其定义由SQL-92给出,且所有主要的数据库都支持它。
它接受用于指定字符串最大长度的参数,例如CHAR(12)即定义了一个长度为12个字符的字符串。
所有主要的数据库都支持长度达254个字符的CHAR。
与JDBCVARCHAR对应的是SQLVARCHAR类型,其定义由SQL-92给出,且所有的主要数据库都支持它。
它接受用于指定字符串最大长度的参数,例如VARCHAR(12)即定义了一个最大长度为12个字符的字符串。
所有主要数据库都至少支持长度达254个字符的VARCHAR。
当把字符串的值赋给VARCHAR变量时,数据库就记住该字符串的长度,使用SELECT时,它可以返回准确的原始字符串。
不幸的是,对于JDBCLONGVARCHAR类型,目前并没有一致的SQL映射。
所有主要数据库都支持某种类型的长度可变的大字符串,这种字符串支持高达十亿位字节的数据,但SQL类型名称却变化多样。
Java程序员不必区分CHAR、VARCHAR和LONGVARCHAR这三种类型的JDBC字符串。
它们都可表示为JavaString,并且在不知道所需要的确切数据类型时也可正确读写SQL语句。
CHAR、VARCHAR和LONGVARCHAR可映射为String或char[],但String更适合于一般用法。
同时,String类能使String和char[]之间的转换更为容易:
它有一个用于将String对象转换为char[]的方法,还有一个将char[]转换为String对象的构造函数。
必须提及的一个问题是:
如何处理类型为CHAR(n)的固定长度的SQL字符串。
答案是JDBC驱动程序(或DBMS)将用适当的空格来进行填补。
因此,当从数据库中检索CHAR(n)域时,驱动程序将把它转换为长度为n的JavaString对象,对象末尾可能含有一些填补空格。
反之,当把String对象送到某个CHAR(n)域时,驱动程序和/或数据库将在字符串的末尾填上一些必要的空格,使字符串的长度达到n。
方法ResultSet.getString用于分配和返回新的String对象。
我们建议用它来从CHAR、VARCHAR和LONGVARCHAR域中检索数据。
它适用于检索普通的数据,但如果用JDBC类型LONGVARCHAR来储存多个兆字节的字符串时,用它进行检索将显得十分笨拙。
为此,ResultSet接口中有两个方法可供程序员将LONGVARCHAR值作为Java输入流进行检索,之后可从该流中以任意大小的块来读取数据。
这两个方法是:
getAsciiStream和getUnicodeStream,它们将把储存在LONGVARCHAR列的数据作为Ascii或Unicode字符流来传送。
8.3.2BINARY、VARBINARY和LONGVARBINARY
JDBC类型BINARY、VARBINARY和LONGVARBINARY密切相关。
BINARY表示固定长度的小二进制值,VARBINARY表示长度可变化的小二进制值,而LONGVARBINARY表示长度可变化的大二进制值。
不幸的是,这些不同BINARY类型的使用还未被标准化,因而在各种主要数据库提供的支持有很大的不同。
对应于JDBCBINARY类型的SQLBINARY类型,是一种非标准的SQL扩展,只在某些数据库上才实现。
它接受用于指定二进制字节数的参数。
例如,BINARY(12)即定义了一个长度为12个字节的binary类型。
通常,BINARY值被限定在254个字节以内。
对应于JDBCVARBINARY类型的SQLVARBINARY类型,是一种非标准的SQL扩展,只在某些数据库上才实现。
它接受用于指定二进制字节最大数的参数。
例如,VARBINARY(12)即定义了一个长度最大可为12个字节的二进制类型。
通常,VARBINARY的值被限定在254个字节以内。
当把二进制的值赋给VARBINARY变量时,数据库就记住这个所赋值的长度,调用SELECT时,它返回准确的原始值。
遗憾的是,目前还没有一致的SQL类型名称与JDBCLONGVARBINARY类型相对应。
所有主要数据库都支持某种类型的长度可变的大二进制类型,它可支持高达十亿个字节的数据,但SQL类型名称却变化多样。
在Java中,BINARY、VARBINARY和LONGVARBINARY都可用同一byte数组来表示。
由于可在不知道所需的确切BINARY数据类型的情况下正确地读写SQL语句,因此,Java程序员无需区分它们。
检索BINARY和VARBINARY值时,我们建议使用ResultSet.getBytes。
然而,如果类型为JDBCLONGVARBINARY的某列储存的是几兆字节长度的字节数组,则建议用方法getBinaryStream来检索。
与LONGVARCHAR的情形类似,该方法可以使Java程序员将LONGVARBINARY值作为Java输入流检索,然后可从该流中以更小的块来读取。
8.3.3BIT
JDBC类型BIT代表一个位值,可为0或1。
SQL-92定义了SQLBIT类型。
但与JDBCBIT类型不同,这种SQL-92BIT类型带参数,用于定义固定长度的二进制字符串。
幸运的是,SQL-92也允许用简单的非参数化的BIT类型来代表单个的二进制数字。
这种用法对应于JDBCBIT类型。
不幸的是,SQL-92BIT类型只有在“完全”SQL-92中才要求,且目前只有一部份主流数据库支持它。
因此,可移植的代码也许宁愿用JDBCSMALLINT类型,这种类型已得到广泛支持。
JDBCBIT类型的Java映射的推荐类型是Java布尔型。
8.3.4TINYINT
JDBC类型TINYINT代表一个8位无符号整数,其值在0到255之间。
对应的SQL类型TINYINT目前只有一部份的数据库支持它。
因此,可移植的代码也许宁愿用JDBCSMALLINT类型,这种类型已得到广泛支持。
JDBCTINYINT类型的Java映射的推荐类型是Javabyte或Javashort。
8位的Javabyte类型代表一个有符号的整数,其值在-128到127之间,因此对于大的TINYINT值它并非总合适,而16位的Javashort类型却总能存储所有的TINYINT值。
8.3.5SMALLINT
JDBC类型SMALLINT代表一个16位的有符号整数,其值在-32768和32767之间。
对应的SQL类型SMALLINT,其定义由SQL-92给出,并为所有主流数据库所支持。
SQL-92标准将SMALLINT的精度留给实现去决定。
但事实上,所有的主流数据库都至少支持16位。
JDBCSMALLINT类型的Java映射的推荐类型是Javashort类型。
8.3.6INTEGER
JDBC类型INTEGER代表一个32位的有符号整数,其值在-2147483648和2147483647之间。
对应的SQL类型INTEGER,其定义由SQL-92给出,并为所有主流数据库所广为支持。
SQL-92标准将INTEGER的精度留给实现去决定。
但事实上,所有的主流数据库都至少支持32位。
INTEGER类型Java映射的推荐类型是Javaint类型。
8.3.7BIGINT
JDBC类型BIGINT代表一个64位的有符号整数,其值在-9223372036854775808和9223372036854775807之间。
对应的SQL类型BIGINT是SQL的一个非标准扩展。
事实上,目前还没有任何数据库实现SQLBIGINT类型。
我们建议在可移植的代码中避免使用该类型。
BIGINT类型的Java映射的推荐类型是Javalong类型。
8.3.8REAL
JDBC类型REAL代表一个有7位尾数的“单精度”浮点数。
对应的SQL类型REAL,其定义由SQL-92给出。
虽然未得到普遍支持,但在主流数据库中却已得到广泛支持。
SQL-92标准将REAL的精度留给实现去决定。
但事实上,所有的支持REAL类型的主流数据库都支持至少7位数的尾数精度。
REAL类型的Java映射的推荐类型为Javafloat类型。
8.3.9DOUBLE
JDBC类型DOUBLE代表一个有15位尾数的“双精度”浮点数。
对应的SQL类型是DOUBLEPRECISION,其定义由SQL-92给出,并为主流数据库所广为支持。
SQL-92标准将DOUBLEPRECISION的精度留给实现去决定。
但事实上,所有支持DOUBLEPRECISION类型的主流数据库都支持至少15位数的尾数精度。
DOUBLE类型的Java映射的推荐类型为Javadouble类型。
8.3.10FLOAT
JDBC类型FLOAT基本上与JDBC类型DOUBLE相同。
我们同时提供了FLOAT和DOUBLE,其目的是与以前的API实现一致。
但这却有可能产生误导。
FLOAT代表一个有15位尾数的“双精度”浮点数。
对应的SQL类型FLOAT,其定义由SQL-92给出。
SQL-92标准将FLOAT的精度留给实现去决定。
但事实上,所有支持FLOAT类型的主流数据库都支持至少15位数的尾数精度。
FLOAT类型的Java映射的推荐类型为Javadouble类型。
然而,由于SQLFLOAT和单精度的Javafloat类型间可能产生混淆,因此建议JDBC程序员通常选用JDBCDOUBLE类型而不选用FLOAT。
8.3.11DECIMAL和NUMERIC
JDBC类型DECIMAL和NUMERIC两者非常相似。
它们都表示固定精度的十进制值。
相应的SQL类型DECIMAL和NUMERIC,其定义在SQL-92中给出,并得到广泛支持。
这些SQL类型都带有精度和比例参数。
精度是所支持的十进制数字的总位数,比例是小数点后的数字位数。
比例必须永远小于或等于精度。
例如,值"12.345"有5位精度和3位比例,而值".11"有2位精度和2位比例。
JDBC要求所有DECIMAL和NUMERIC类型都必须支持至少15位的精度和比例。
DECIMAL和NUMERIC之间的唯一区别是SQL-92规范要求NUMERIC类型必须以确切指定的精度来表示,而对DECIMAL类型,它允许实现在创建该类型时所指定的精度以外再添加额外的精度。
因此,创建为类型NUMERIC(12,4)的列将总是用12位数来表示,而创建为类型DECIMAL(12,4)的列则可用更大的位数来表示。
DECIMAL和NUMERIC类型的Java映射的推荐类型是java.math.BigDecimal,该Java类型也用绝对精度来表示定点数。
java.math.BigDecimal类型提供了一些数学操作,可对BigDecimal类型与其它的BigDecimal类型、整数类型和浮点数类型进行加、减、乘、除的运算。
用于检索DECIMAL和NUMERIC值的推荐方法是ResultSet.getBigDecimal。
JDBC还允许将这些SQL类型作为简单的Strings或char数组来访问。
因此,Java程序员可用getString来检索DECIMAL或NUMERIC结果。
然而,这将使常见的用DECIMAL或NUMERIC来表示的货币值变得极为尴尬,因为它意味着应用程序编程人员必须对字符串进行数学运算。
当然,也可将这些SQL类型作为Java数值型类型来检索。
8.3.12DATE、TIME和TIMESTAMP
有三种JDBC类型与时间有关:
JDBCDATE类型表示一个由年、月、日组成的日期。
对应的是SQLDATE类型,其定义由SQL-92给出,但只有一部份主流数据库实现它。
某些数据库提供了另外一些支持类似语义的SQL类型。
JDBCTIME类型表示一个由小时、分钟和秒组成的时间。
对应的是SQLTIME类型,其定义由SQL-92给出,但只有一部份主流数据库实现它。
与DATE一样,某些数据库提供了另外一些支持类似语义的SQL类型。
JDBCTIMESTAMP类型表示DATE加上TIME,外加一个纳秒域。
对应的TIMESTAMP类型,其定义由SQL-92给出,但只有少数几个数据库实现它。
由于标准的Java类java.util.Date并不与这三个JDBC日期—时间类型完全匹配(它含有DATE和TIME的信息但不含纳秒信息),因此JDBC定义了三个java.util.Date的子类与SQL类型对应。
它们是:
java.sql.Date,对应于SQLDATE信息。
java.util.Date基本类中的小时、分钟和秒都设为0。
java.sql.Time,对应于SQLTIME信息。
java.util.Date基本类中的年、月、日域设为1970年1月1日。
这是Java纪元的“零”日期。
java.sql.Timestamp,对应于SQLTIMESTAMP信息。
该类扩展了java.util.Date,添加了纳秒域。
所有这三个与时间有关的JDBC类都是java.util.Date的子类,因此它们可用在任何可以使用java.util.Date的地方。
例如,国际化(internationalization)方法将java.util.Date对象用作变量,因此可将这三个与时间有关的JDBC类中任何一个的实例作为参数传给国际化方法。
JDBCTimestamp对象除了具有其父类的日期和时间成份外,还有一个独立的纳秒组件。
如果将java.sql.Timestamp对象用于需要java.util.Date对象的地方,则纳秒组件将丢失。
但由于是以毫秒的精度来储存java.util.Date对象的,因此将java.sql.Timestamp对象转换为java.util.Date对象时可以保持这样的精度。
这可通过将纳秒组件中的纳秒转换为毫秒(用纳秒数除以1,000,000)并将之添到java.util.Date对象中来实现。
转换中可能丢失高达999,999纳秒,但所产生的java.util.Date对象将可精确到毫秒以内。
下述代码段将java.sql.Timestamp对象转换为精度达到毫秒量级的java.util.Date对象:
Timestampt=newTimestamp(100,0,1,15,45,29,987245732);
java.util.Dated;
d=newjava.util.Date(t.getTime()+(t.getNanos()/1000000));
8.4映射示例
任何情况下,当Java程序要从数据库中检索数据时,必须存在某种形式的映射和数据转换。
大多数时候,JDBC程序员将在知道其目标数据库机制的情况下进行编程。
例如,他们将知道数据库含有哪些表、表中每一列的数据类型。
因此,他们可使用ResultSet、PreparedStatement和CallableStatement接口中那些与类型有关的存取方法。
本节给出三个示例,描述各种情形中所要求的数据映射和转换。
8.4.1简单的SQL语句
在最常见的情形中,用户将执行简单的SQL语句,然后取回含有结果的ResultSet对象。
由数据库返回并存放在ResultSet列的值,其类型为JDBC数据类型。
调用ResultSet.getXXX方法将把该值检索为Java数据类型。
例如,如果某个ResultSet列含有一个JDBCFLOAT值,则方法getDouble将把它检索为Javadouble类型。
8.6.6节所示的表显示了哪些getXXX方法可检索哪些JDBC类型(如果用户不知道某个ResultSet列的类型,可通过调用ResultSet.getMetaData方法来获得有关信息,然后再调用ResultSetMetaData的getColumnType或getColumnTypeName方法)。
以下代码段示范了如何获得结果中各列的类型名称:
Stringquery="select*fromTable1";
ResultSetrs=stmt.executeQuery(query);
ResultSetMetaDatarsmd=rs.getMetaData();
intcolumnCount=rsmd.getColumnCount();
for(inti=1;i<=columnCount;i++){
Strings=rsmd.getColumnTypeName(i);
System.out.println("Column"+i+"istype"+s);
}
8.4.2带IN参数的SQL语句
在另一个可能的情况中,用户将发送带输入参数的SQL语句。
这种情况下,用户通过调用PreparedStatement.setXXX方法为每个输入参数赋值。
例如,PreparedStatement.setLong(1,2345678)将把值2345678作为Java的long类型赋给第一个参数。
为了将2345678到数据库中,驱动程序将把它转换为JDBCBIGINT。
驱动程序将把哪种JDBC类型送到数据库中是由Java类型到JDBC类型的标准映射所决定的,如
8.4.3带OUT参数的SQL语句
还有一个情况是,用户要调用已存储过程,将值赋给其INOUT参数,从结果中检索值,然后从参数中检索值。
这种情形极为少见且相当复杂,但它却不失为映射和数据转换的好范例。
这种情况下,首先要做的是用PreparedStatement.setXXX方法对INOUT参数赋值。
此外,由于这些参数同时也用于输出,因此程序员必须为每个参数注册JDBC类型,该类型是数据库所要返回给该参数的值的JDBC类型。
这可用CallableStateme