使用自定义类型映射
原文: https://docs.oracle.com/javase/tutorial/jdbc/basics/sqlcustommapping.html
注意:MySQL 目前不支持用户定义的类型。 MySQL 和 Java DB 目前不支持结构化类型或DISTINCT
SQL 数据类型。没有 JDBC 教程示例可用于演示本节中描述的功能。
随着业务的蓬勃发展,The Coffee Break 的所有者定期添加新商店并对数据库进行更改。所有者已决定使用结构化类型ADDRESS
的自定义映射。这使所有者能够对映射ADDRESS
类型的 Java 类进行更改。 Java 类将为ADDRESS
的每个属性提供一个字段。类的名称及其字段的名称可以是任何有效的 Java 标识符。
涵盖以下主题:
自定义映射所需的第一件事是创建一个实现接口SQLData
的类。
结构化类型ADDRESS
的 SQL 定义如下所示:
CREATE TYPE ADDRESS
(
NUM INTEGER,
STREET VARCHAR(40),
CITY VARCHAR(40),
STATE CHAR(2),
ZIP CHAR(5)
);
为ADDRESS
类型的自定义映射实现SQLData
接口的类可能如下所示:
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);
}
}
在编写实现接口SQLData
的类之后,设置自定义映射所需要做的唯一事情就是在类型映射中创建一个条目。例如,这意味着输入ADDRESS
类型的完全限定 SQL 名称和类Address
的Class
对象。类型映射(java.util.Map
接口的实例)在创建时与每个新连接相关联,因此您可以使用该连接。假设con
是活动连接,以下代码片段将 UDT ADDRESS
的条目添加到与con
关联的类型映射。
java.util.Map map = con.getTypeMap();
map.put("SchemaName.ADDRESS", Class.forName("Address"));
con.setTypeMap(map);
每当您调用getObject
方法来检索ADDRESS
类型的实例时,驱动程序将检查与该连接关联的类型映射,并看到它具有ADDRESS
的条目。驱动程序将记录Address
类的Class
对象,创建它的实例,并在后台执行许多其他操作以将ADDRESS
映射到Address
。除了为映射生成类之外,您不必执行任何操作,然后在类型映射中创建条目以使驱动程序知道存在自定义映射。司机将完成剩下的工作。
存储具有自定义映射的结构化类型的情况类似。当您调用方法setObject
时,驱动程序将检查要设置的值是否是实现接口SQLData
的类的实例。如果是(意味着存在自定义映射),则驱动程序将使用自定义映射将值转换为 SQL 对应项,然后再将其返回到数据库。同样,驱动程序在幕后进行自定义映射;您需要做的就是为方法setObject
提供一个具有自定义映射的参数。您将在本节后面看到此示例。
查看使用标准映射,Struct
对象和自定义映射(Java 编程语言中的类)之间的区别。以下代码片段显示了到Struct
对象的标准映射,该对象是驱动程序在连接的类型映射中没有条目时使用的映射。
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"
。
以下代码片段显示了在连接的类型映射中存在结构化类型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
的一个字段的当前值。请注意,在将getObject
方法分配给store_3
之前,必须记住将getObject
方法检索的对象转换为Address
对象。另请注意,store_3
必须是Address
对象。
比较使用Struct
对象来处理Address
类的实例。假设商店移动到邻近城镇的更好位置,因此您必须更新数据库。使用自定义映射,重置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
类型的实例。驱动程序检查连接的类型映射,并看到有一个条目链接ADDRESS
和类Address
,因此使用Address
中指示的自定义映射。当代码以变量_store_3_
作为第二个参数调用方法setObject
时,驱动程序检查并看到_store_3_
代表类Address
的实例,它实现结构化类型ADDRESS
的接口SQLData
,并再次自动使用自定义映射。
没有ADDRESS
的自定义映射,更新看起来会更像这样:
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;
到目前为止,您仅使用与连接关联的类型映射进行自定义映射。通常,这是大多数程序员将使用的唯一类型映射。但是,也可以创建类型映射并将其传递给某些方法,以便驱动程序将使用该类型映射而不是与连接关联的映射。这允许两个不同的映射用于相同的用户定义类型(UDT)。实际上,只要每个映射都使用实现SQLData
接口的类和类型映射中的条目设置,就可以为同一个 UDT 创建多个自定义映射。如果未将类型映射传递给可接受类型映射的方法,则驱动程序将默认使用与该连接关联的类型映射。
很少有情况要求使用除与连接关联的类型映射之外的类型映射。例如,如果在 JDBC 应用程序上工作的几个程序员将其组件组合在一起并使用相同的连接,则可能需要提供带有类型映射的方法。如果两个或多个程序员为同一个 SQL UDT 创建了自己的自定义映射,则每个程序员都需要提供他或她自己的类型映射,从而覆盖连接的类型映射。