使用自定义类型 Map
注意 :MySQL 当前不支持用户定义的类型。 MySQL 和 Java DB 当前不支持结构化类型或DISTINCT
SQL 数据类型。没有 JDBC 教程示例可用来演示本节中描述的功能。
随着业务的蓬勃 Developing,The Coffee Break 的所有者会定期添加新 Store,并对数据库进行更改。所有者已决定对结构化类型ADDRESS
使用自定义 Map。这使所有者可以更改 MapADDRESS
类型的 Java 类。 Java 类的每个属性ADDRESS
都有一个字段。类的名称及其字段的名称可以是任何有效的 Java 标识符。
涵盖以下主题:
Implementing SQLData
定制 Map 所需的第一件事是创建一个实现interfaceSQLData
的类。
结构化类型ADDRESS
的 SQL 定义如下所示:
CREATE TYPE ADDRESS
(
NUM INTEGER,
STREET VARCHAR(40),
CITY VARCHAR(40),
STATE CHAR(2),
ZIP CHAR(5)
);
为ADDRESS
类型的自定义 Map 实现SQLData
interface的类可能看起来像这样:
public class Address implements SQLData {
public int num;
public String street;
public String city;
public String state;
public String zip;
private String sql_type;
public String getSQLTypeName() {
return sql_type;
}
public void readSQL(SQLInput stream, String type)
throws SQLException {
sql_type = type;
num = stream.readInt();
street = stream.readString();
city = stream.readString();
state = stream.readString();
zip = stream.readString();
}
public void writeSQL(SQLOutput stream)
throws SQLException {
stream.writeInt(num);
stream.writeString(street);
stream.writeString(city);
stream.writeString(state);
stream.writeString(zip);
}
}
使用连接的类型 Map
在编写了实现interfaceSQLData
的类之后,设置自定义 Map 所要做的另一件事就是在类型 Map 中创建一个条目。对于此示例,这意味着为ADDRESS
类型 Importing 完全限定的 SQL 名称,为Address
类 ImportingClass
对象。类型 Map 是java.util.Map
interface的实例,在创建每个新连接时都会与它关联,因此您可以使用该类型 Map。假设con
是活动连接,下面的代码片段将 UDT ADDRESS
的条目添加到与con
关联的类型 Map 中。
java.util.Map map = con.getTypeMap();
map.put("SchemaName.ADDRESS", Class.forName("Address"));
con.setTypeMap(map);
每当调用getObject
方法来检索ADDRESS
类型的实例时,驱动程序都会检查与连接关联的类型 Map,并查看它是否具有ADDRESS
的条目。驱动程序将记录Address
类的Class
对象,创建该对象的实例,并在后台执行其他许多操作以将ADDRESS
Map 到Address
。除了为 Map 生成类,然后在类型 Map 中创建一个条目以使驱动程序知道存在自定义 Map 外,您无需执行其他任何操作。驾驶员将完成所有其余的工作。
对于存储具有自定义 Map 的结构化类型,情况也是如此。当您调用方法setObject
时,驱动程序将检查要设置的值是否是实现interfaceSQLData
的类的实例。如果是(表示存在自定义 Map),驱动程序将使用该自定义 Map 将值转换为与其对应的 SQL,然后再将其返回数据库。再次,驱动程序在幕后进行自定义 Map。您需要做的就是为方法setObject
提供带有自定义 Map 的参数。您将在本节的后面看到一个示例。
查看使用标准 Map(Struct
对象)和定制 Map(Java 编程语言中的类)之间的区别。下面的代码片段显示了到Struct
对象的标准 Map,这是当连接的类型 Map 中没有条目时驱动程序使用的 Map。
ResultSet rs = stmt.executeQuery(
"SELECT LOCATION " +
"WHERE STORE_NO = 100003");
rs.next();
Struct address = (Struct)rs.getObject("LOCATION");
变量address
包含以下属性值:4344
,"First_Street"
,"Verona"
,"CA"
,"94545"
。
下面的代码片段显示了在连接的类型 Map 中有结构化类型ADDRESS
的条目时发生的情况。请记住,列LOCATION
存储类型为ADDRESS
的值。
ResultSet rs = stmt.executeQuery(
"SELECT LOCATION " +
"WHERE STORE_NO = 100003");
rs.next();
Address store_3 = (Address)rs.getObject("LOCATION");
变量store_3
现在是类Address
的实例,每个属性值都是Address
字段之一的当前值。请注意,在将其分配给store_3
之前,必须记住将getObject
方法检索的对象转换为Address
对象。还要注意store_3
必须是Address
对象。
将使用Struct
对象与使用Address
类的实例进行比较。假设 Store 搬到附近城镇的更好位置,因此您必须更新数据库。使用自定义 Map,重置store_3
的字段,如以下代码片段所示:
ResultSet rs = stmt.executeQuery(
"SELECT LOCATION " +
"WHERE STORE_NO = 100003");
rs.next();
Address store_3 = (Address)rs.getObject("LOCATION");
store_3.num = 1800;
store_3.street = "Artsy_Alley";
store_3.city = "Arden";
store_3.state = "CA";
store_3.zip = "94546";
PreparedStatement pstmt = con.prepareStatement(
"UPDATE STORES " +
"SET LOCATION = ? " +
"WHERE STORE_NO = 100003");
pstmt.setObject(1, store_3);
pstmt.executeUpdate();
LOCATION
列中的值是ADDRESS
类型的实例。驱动程序检查连接的类型 Map,发现有一个链接ADDRESS
与类Address
的条目,因此使用Address
中指示的自定义 Map。当代码以变量store_3
作为第二个参数调用方法setObject
时,驱动程序将检查并查看store_3
表示类Address
的实例,该类为结构化类型ADDRESS
实现interfaceSQLData
,并再次自动使用自定义 Map。
如果没有ADDRESS
的自定义 Map,则更新将更像这样:
PreparedStatement pstmt = con.prepareStatement(
"UPDATE STORES " +
"SET LOCATION.NUM = 1800, " +
"LOCATION.STREET = 'Artsy_Alley', " +
"LOCATION.CITY = 'Arden', " +
"LOCATION.STATE = 'CA', " +
"LOCATION.ZIP = '94546' " +
"WHERE STORE_NO = 100003");
pstmt.executeUpdate;
使用您自己的类型图
到目前为止,您仅使用了与连接关联的类型 Map 进行自定义 Map。通常,这是大多数程序员都将使用的唯一类型 Map。但是,也可以创建类型 Map 并将其传递给某些方法,以便驱动程序将使用该类型 Map,而不是与连接关联的类型 Map。这允许针对同一用户定义类型(UDT)进行两种不同的 Map。实际上,对于同一个 UDT,可能有多个自定义 Map,只要每个 Map 都使用实现SQLData
interface的类和类型 Map 中的条目进行设置即可。如果没有将类型 Map 传递给可以接受的方法,则驱动程序默认将使用与连接关联的类型 Map。
除了与连接关联的类型 Map 外,很少有其他情况需要使用类型 Map。例如,如果几个在 JDBC 应用程序上工作的程序员将他们的组件放在一起并使用同一连接,则可能需要为该方法提供类型 Map。如果两个或更多程序员为同一 SQL UDT 创建了自己的自定义 Map,则每个程序员都需要提供自己的类型 Map,从而覆盖连接的类型 Map。