使用自定义类型 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 实现SQLDatainterface的类可能看起来像这样:

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.Mapinterface的实例,在创建每个新连接时都会与它关联,因此您可以使用该类型 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对象,创建该对象的实例,并在后台执行其他许多操作以将ADDRESSMap 到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 都使用实现SQLDatainterface的类和类型 Map 中的条目进行设置即可。如果没有将类型 Map 传递给可以接受的方法,则驱动程序默认将使用与连接关联的类型 Map。

除了与连接关联的类型 Map 外,很少有其他情况需要使用类型 Map。例如,如果几个在 JDBC 应用程序上工作的程序员将他们的组件放在一起并使用同一连接,则可能需要为该方法提供类型 Map。如果两个或更多程序员为同一 SQL UDT 创建了自己的自定义 Map,则每个程序员都需要提供自己的类型 Map,从而覆盖连接的类型 Map。