清单 2. 以外部编码方式存储
String url = "jdbc:db2://localhost:50000/testdb";
Connection con;
PreparedStatement stmt;
ResultSet rs;
try
{
// Load the IBM DB2 Driver for JDBC and SQLJ
Class.forName("com.ibm.db2.jcc.DB2Driver");
// Create the connection using the IBM DB2 Driver for JDBC and SQLJ
con = DriverManager.getConnection (url,
"db2admin","db2admin");
con.setAutoCommit(true);
// Create the Statement
stmt = con.prepareStatement("insert into T1 values(?)");
//insert a xml data, readfile from a.xml with UTF-8 encoding
String xml = readfile("c:/temp/a.xml");
stmt.setString(1, xml);
stmt.executeUpdate();
//insert a xml data, readfile from b.xml with GBK encoding
stmt = con.prepareStatement("insert into T1 values(?)");
xml = readfile("c:/temp/tmp/b.xml");
stmt.setString(1, xml);
stmt.executeUpdate();
// Close the Statement
stmt.close();
con.close();
}
catch (Exception e){
e.printStackTrace();
}
|
在这一段程序中,分别读取 a.xml 和 b.xml ,并且按照正确的编码转换为字符串,然后插入到数据库中。其中,文件 a.xml 是 UTF-8 编码的文件,b.xml 是 GBK 编码的文件。
清单 3. a.xml(UTF-8 编码的文件)
<?xml version="1.0" encoding="UTF-8"?>
<node>
你好
</node>
|
清单 4. b.xml(GBK 编码的文件)
<?xml version="1.0" encoding="GBK"?>
<node>
你好
</node>
|
从代码中可以看出,读取完文件以后,xml 文档(字符串类型)中仍然带有 xml 修饰行,从两个文件中读取到的 XML 文档分别有不同的编码,但是由于使用了方法setString(),这样 DB2 就只会关注程序使用的外部编码,xml 文档中所带有的 encoding 信息被忽略。存储时,将外部编码 UTF-16 转换为 DB2 使用的编码 UTF-8。在 DB2 CLP 中用select * from T1 来查看一下插入的数据,就会发现,插入两条数据是一样的,而且 xml decoration 被去掉了。
以二进制数据类型对 XML 赋值,比如setBytes()。这种情况下,数据库将检查并使用内部编码。用内部编码时,在我们的 readfile 中所做的跟编码相关的工作就交给了 DBMS 去做了。如果在程序中不关心 xml 文档内容,只是简单存储到数据库,那么这种方式应该是被推荐的方式。
清单 5. 以内部编码方式存储
File file = new File("c:/temp/tmp/c.xml");
int size = (int)file.length();
FileInputStream fis = new FileInputStream(file);
byte[] buff = new byte[size];
int readed = 0;
while (readed < size)
readed += fis.read(buff, readed, size-readed);
stmt.setBytes(1, buff);
stmt.executeUpdate();
|
我们还是通过例子来验证一下,在使用内部编码时,DB2 是如何处理的。首先准备一个正确的 xml 文件
清单 6. 一个正确的XML 文件
<?xml version="1.0" encoding="GBK"?>
<node>
你好
</node>
|
保证这个文件是 GBK 编码的,然后运行上面一段代码。可以验证,这个文档会被正常插入数据库。现在我们改变一下文件 c.xml。用 notepad 打开它,然后另存为 UTF-8 编码,再运行一次代码,会发现有 SQLException 产生,插入数据库失败。这是因为 DBMS 在检查内部代码时发现 BOM 所表示的编码 (UTF-8) 跟 XML 修饰行里面的 encoding 属性值
encoding="GBK"?>冲突。再进一步,我们用其他编辑工具打开 c.xml,把 BOM 去掉,然后再试一次,会发现插入成功,但是查询存入的数据,会发现数据变成了 清单 7. 改变编码后的 XML 文件
<?xml version="1.0" encoding="GBK"?>
<node>
浣犲ソ
</node>
|
这是因为原本按照三字节 UTF-8 编码的“你(0xE4BDA0) 好(0xE5A5BD)”,被当成双字节的 GBK 编码,就成了“浣(0xE4BD)犲(0xA0E5)ソ(0xA5BD)”
|
从数据库读取数据时,也有两种方式,一种是通过隐式的序列化操作来获取,另一种是显式的序列化操作来获取。
隐式序列化:在 java 程序中,使用 select c1 from qkk.t2,根据赋值时程序所用的数据类型,决定序列化的目标数据编码。如果赋值给字节流,比如rs.getBytes() 那么不存在编码转换的问题,因为在数据库中是 UTF-8 编码,因此得到的是 xml 的 UTF-8 的 byte 串。输出如下 3C6E6F64653E0AE4BDA0E5A5BD0A3C2F6E6F64653E 如果赋值给字符串类型,比如rs.getString(), 那么系列化过程中将进行 UTF-8 到 UTF-16 的编码转换,得到在 java 程序中的字符串。结果如下
清单 8. 隐式序列化 XML 文件
<node>
你好
</node>
|
显式序列化:SELECT XMLSERIALIZE(XMLCOL AS BLOB(100) EXCLUDING XMLDECLARATION) FROM T1 不进行字符转换,得到的字节数组依然是 3C6E6F64653E0AE4BDA0E5A5BD0A3C2F6E6F64653E
使用SELECT XMLSERIALIZE(XMLCOL AS CLOB(100) INCLUDING XMLDECLARATION) FROM T1 则会进行字符转换,系列化过程中将进行 UTF-8 到 UTF-16 的编码转换,同时添加 xml 修饰行,得到结果如下
清单 9. 显式序列化 XML 文件
<?xml version="1.0" encoding="GBK"?>
<node>
你好
</node>
|
|
XML 数据的编码可以从数据本身派生(称为内部编码数据),也可以从外部源派生(称为外部编码数据)。用来在应用程序与 XML 列之间交换 XML 数据的应用程序数据类型确定了编码的派生方式。
学习
- 在 XML 1.0 specification查看 XML 1.0 的详细信息。
- 在 DB2 V9 信息中心查看 DB2 V9 的相关产品信息。
- 在 developerWorks 中国网站 Information Management 专区中学习更多信息管理方面的知识。
获得产品和技术
- 下载 IBM 软件试用版,体验强大的 DB2®,Lotus®,Rational®,Tivoli® 和 WebSphere® 软件。
讨论
- 查看 developerWorks DB2 9 技术资源中心。
- Check out developerWorks blogs and get involved in the developerWorks community.
|
|
齐克科 2001年加入IBM,目前就职于中国开发中心,从事MBPS(Managed Business Process Services)相关的工作。 |
|
|
|
Elaine Zhan 中国开发中心 MBPS develope lead,负责CSDP common service 和 provisioning 的开发工作。 |
|
|
|
陈荔龙 2004年加入IBM,目前就职于中国开发中心,从事MBPS(Managed Business Process Services)相关的工作。 |
|
