The Java Tutorials have been written for JDK 8.Java教程是为JDK 8编写的。Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available.本页中描述的示例和实践没有利用后续版本中引入的改进,并且可能使用不再可用的技术。See Java Language Changes for a summary of updated language features in Java SE 9 and subsequent releases.有关Java SE 9及其后续版本中更新的语言特性的摘要,请参阅Java语言更改。
See JDK Release Notes for information about new features, enhancements, and removed or deprecated options for all JDK releases.有关所有JDK版本的新功能、增强功能以及已删除或不推荐的选项的信息,请参阅JDK发行说明。
Note: MySQL currently does not support user-defined types. 注意:MySQL目前不支持用户定义的类型。MySQL and Java DB currently do not support structured types, or the MySQL和JavaDB目前不支持结构化类型,也不支持DISTINCT
SQL data type. DISTINCT
SQL数据类型。No JDBC tutorial example is available to demonstrate the features described in this section.没有JDBC教程示例可用于演示本节中描述的功能。
With business booming, the owner of The Coffee Break is regularly adding new stores and making changes to the database. 随着业务的蓬勃发展,咖啡休息时间的所有者定期增加新店,并对数据库进行更改。The owner has decided to use a custom mapping for the structured type 所有者已决定对结构化类型ADDRESS
. ADDRESS
使用自定义映射。This enables the owner to make changes to the Java class that maps the 这使所有者能够对映射ADDRESS
type. ADDRESS
类型的Java类进行更改。The Java class will have a field for each attribute of Java类将为ADDRESS
. ADDRESS
的每个属性都有一个字段。The name of the class and the names of its fields can be any valid Java identifier.类的名称及其字段的名称可以是任何有效的Java标识符。
The following topics are covered:涵盖以下主题:
The first thing required for a custom mapping is to create a class that implements the interface 自定义映射所需的第一件事是创建一个实现接口SQLData
.SQLData
的类。
The SQL definition of the structured type 结构化类型ADDRESS
looks like this:ADDRESS
的SQL定义如下所示:
CREATE TYPE ADDRESS ( NUM INTEGER, STREET VARCHAR(40), CITY VARCHAR(40), STATE CHAR(2), ZIP CHAR(5) );
A class that implements the 为SQLData
interface for the custom mapping of the ADDRESS
type might look like this: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); } }
After writing a class that implements the interface 在编写实现接口SQLData
, the only other thing you have to do to set up a custom mapping is to make an entry in a type map. SQLData
的类之后,设置自定义映射所需做的唯一其他事情是在类型映射中创建一个条目。For the example, this means entering the fully qualified SQL name for the 例如,这意味着为ADDRESS
type and the Class
object for the class Address
. ADDRESS
类型输入完全限定的SQL名称,为类ADDRESS
输入Class
对象。A type map, an instance of the 类型映射是java.util.Map
interface, is associated with every new connection when it is created, so you use that one. java.util.map
接口的一个实例,它在创建每个新连接时都与之关联,因此您可以使用该类型映射。Assuming that 假设con
is the active connection, the following code fragment adds an entry for the UDT ADDRESS
to the type map associated with con
.con
是活动连接,下面的代码片段将UDTADDRESS
的条目添加到与con
关联的类型映射中。
java.util.Map map = con.getTypeMap(); map.put("SchemaName.ADDRESS", Class.forName("Address")); con.setTypeMap(map);
Whenever you call the 无论何时调用getObject
method to retrieve an instance of the ADDRESS
type, the driver will check the type map associated with the connection and see that it has an entry for ADDRESS
. getObject
方法来检索ADDRESS
类型的实例,驱动程序都将检查与连接关联的类型映射,并查看它是否有ADDRESS
条目。The driver will note the 驱动程序将记录Class
object for the Address
class, create an instance of it, and do many other things in the background to map ADDRESS
to Address
. Address
类的Class
对象,创建其实例,并在后台执行许多其他操作以将ADDRESS
映射到Address
。You do not have to do anything more than generate the class for the mapping and then make an entry in a type map to let the driver know that there is a custom mapping. The driver will do all the rest.您不必做任何事情,只需为映射生成类,然后在类型映射中创建一个条目,让驱动程序知道存在自定义映射。其余的事都由司机来做。
The situation is similar for storing a structured type that has a custom mapping. 存储具有自定义映射的结构化类型的情况类似。When you call the method 调用方法setObject
, the driver will check to see if the value to be set is an instance of a class that implements the interface SQLData
. setObject
时,驱动程序将检查要设置的值是否是实现接口SQLData
的类的实例。If it is (meaning that there is a custom mapping), the driver will use the custom mapping to convert the value to its SQL counterpart before returning it to the database. 如果是(意味着存在自定义映射),驱动程序将使用自定义映射将值转换为SQL对应值,然后再将其返回到数据库。Again, the driver does the custom mapping behind the scenes; all you need to do is supply the method 同样,驱动程序在幕后进行自定义映射;您只需为方法setObject
with a parameter that has a custom mapping. setObject
提供一个具有自定义映射的参数。You will see an example of this later in this section.您将在本节后面看到一个示例。
Look at the difference between working with the standard mapping, a 看看使用标准映射(Struct
object, and the custom mapping, a class in the Java programming language. Struct
对象)和自定义映射(Java编程语言中的类)之间的区别。The following code fragment shows the standard mapping to a 下面的代码片段显示了到Struct
object, which is the mapping the driver uses when there is no entry in the connection's type map.Struct
对象的标准映射,这是当连接的类型映射中没有条目时驱动程序使用的映射。
ResultSet rs = stmt.executeQuery( "SELECT LOCATION " + "WHERE STORE_NO = 100003"); rs.next(); Struct address = (Struct)rs.getObject("LOCATION");
The variable 变量address
contains the following attribute values: 4344
, "First_Street"
, "Verona"
, "CA"
, "94545"
.address
包含以下属性值:4344
、"First_Street"
、"Verona"
、"CA"
、"94545"
。
The following code fragment shows what happens when there is an entry for the structured type 下面的代码片段显示了当连接的类型映射中存在结构化类型ADDRESS
in the connection's type map. ADDRESS
的条目时会发生什么。Remember that the column 请记住,列LOCATION
stores values of type ADDRESS
.LOCATION
存储ADDRESS
类型的值。
ResultSet rs = stmt.executeQuery( "SELECT LOCATION " + "WHERE STORE_NO = 100003"); rs.next(); Address store_3 = (Address)rs.getObject("LOCATION");
The variable 变量store_3
is now an instance of the class Address
, with each attribute value being the current value of one of the fields of Address
. store_3
现在是类Address
的实例,每个属性值都是Address
字段之一的当前值。Note that you must remember to convert the object retrieved by the 请注意,在将getObject
method to an Address
object before assigning it to store_3
. getObject
方法检索到的对象分配给store_3
之前,必须记住将其转换为Address
对象。Note also that 还请注意,store_3
must be an Address
object.store_3
必须是Address
对象。
Compare working with the 将使用Struct
object to working with the instance of the Address
class. Struct
对象与使用Address
类的实例进行比较。Suppose the store moved to a better location in the neighboring town and therefore you must update the database. 假设商店搬到了邻近城镇的一个更好的位置,因此您必须更新数据库。With the custom mapping, reset the fields of 使用自定义映射,重置store_3
, as in the following code fragment: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();
Values in the column 列LOCATION
are instances of the ADDRESS
type. LOCATION
中的值是ADDRESS
类型的实例。The driver checks the connection's type map and sees that there is an entry linking 驱动程序检查连接的类型映射,发现有一个条目链接ADDRESS
with the class Address
and consequently uses the custom mapping indicated in Address
. ADDRESS
与类ADDRESS
,因此使用ADDRESS
中指示的自定义映射。When the code calls the method 当代码以变量setObject
with the variable store_3
as the second parameter, the driver checks and sees that store_3
represents an instance of the class Address
, which implements the interface SQLData
for the structured type ADDRESS
, and again automatically uses the custom mapping.store_3
作为第二个参数调用方法setObject
时,驱动程序检查并看到store_3
表示类Address
的实例,该实例实现了结构化类型ADDRESS
的接口SQLData
,并再次自动使用自定义映射。
Without a custom mapping for 如果没有ADDRESS
, the update would look more like this: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;
Up to this point, you have used only the type map associated with a connection for custom mapping. 到目前为止,您只使用了与自定义映射的连接关联的类型映射。Ordinarily, that is the only type map most programmers will use. 通常,这是大多数程序员将使用的唯一类型映射。However, it is also possible to create a type map and pass it to certain methods so that the driver will use that type map instead of the one associated with the connection. 但是,也可以创建类型映射并将其传递给某些方法,以便驱动程序使用该类型映射,而不是与连接关联的类型映射。This allows two different mappings for the same user-defined type (UDT). 这允许对同一用户定义类型(UDT)进行两种不同的映射。In fact, it is possible to have multiple custom mappings for the same UDT, just as long as each mapping is set up with a class implementing the 事实上,对于同一个UDT,可以有多个自定义映射,只要每个映射都使用实现SQLData
interface and an entry in a type map. SQLData
接口的类和类型映射中的条目进行设置。If you do not pass a type map to a method that can accept one, the driver will by default use the type map associated with the connection.如果未将类型映射传递给可接受类型映射的方法,则驱动程序将默认使用与连接关联的类型映射。
There are very few situations that call for using a type map other than the one associated with a connection. 除了与连接关联的类型映射之外,很少有其他情况需要使用类型映射。It could be necessary to supply a method with a type map if, for instance, several programmers working on a JDBC application brought their components together and were using the same connection. 例如,如果几个在JDBC应用程序上工作的程序员将他们的组件放在一起并使用相同的连接,则可能需要提供一个带有类型映射的方法。If two or more programmers had created their own custom mappings for the same SQL UDT, each would need to supply his or her own type map, thus overriding the connection's type map.如果两个或多个程序员为同一个SQLUDT创建了自己的自定义映射,那么每个人都需要提供自己的类型映射,从而覆盖连接的类型映射。