如何在实现SQLData的Java类Country中映射嵌套表CITY UDT?
实现Oracle嵌套表UDT到Java SQLData类的映射
首先明确数据库端的UDT定义(请确保与你的实际定义一致):
-- 定义CITY对象类型 CREATE TYPE CITY AS OBJECT ( city_id NUMBER, city_name VARCHAR2(100) ); / -- 定义嵌套表类型,用于存储多个CITY CREATE TYPE CITY_LIST AS TABLE OF CITY; / -- 定义COUNTRY对象类型,包含嵌套表属性 CREATE TYPE COUNTRY AS OBJECT ( country_id NUMBER, country_name VARCHAR2(100), cities CITY_LIST ); /
接下来分两步实现Java类的映射:
1. 实现CITY UDT对应的Java类
嵌套表的元素是CITY UDT,需先创建实现SQLData接口的City类,用于单个城市对象的映射:
import java.sql.SQLData; import java.sql.SQLException; import java.sql.SQLInput; import java.sql.SQLOutput; public class City implements SQLData { private Integer cityId; private String cityName; // 必须和数据库中CITY UDT的名称完全一致 private static final String SQL_TYPE = "CITY"; @Override public String getSQLTypeName() throws SQLException { return SQL_TYPE; } @Override public void readSQL(SQLInput stream, String typeName) throws SQLException { // 严格按照数据库UDT定义的属性顺序读取 cityId = stream.readInt(); cityName = stream.readString(); } @Override public void writeSQL(SQLOutput stream) throws SQLException { // 严格按照数据库UDT定义的属性顺序写入 stream.writeInt(cityId); stream.writeString(cityName); } // 构造方法、Getter/Setter public City() {} public City(Integer cityId, String cityName) { this.cityId = cityId; this.cityName = cityName; } public Integer getCityId() { return cityId; } public void setCityId(Integer cityId) { this.cityId = cityId; } public String getCityName() { return cityName; } public void setCityName(String cityName) { this.cityName = cityName; } }
2. 实现COUNTRY UDT对应的Java类,处理嵌套表属性
在Country类中用List<City>存储嵌套的城市数据,通过java.sql.Array完成与数据库嵌套表的转换:
import java.sql.*; import java.util.ArrayList; import java.util.List; public class Country implements SQLData { private Integer countryId; private String countryName; // 存储嵌套城市的List private List<City> cities; // 数据库中COUNTRY UDT的名称 private static final String SQL_TYPE = "COUNTRY"; // 数据库中嵌套表类型CITY_LIST的名称 private static final String CITY_LIST_TYPE = "CITY_LIST"; @Override public String getSQLTypeName() throws SQLException { return SQL_TYPE; } @Override public void readSQL(SQLInput stream, String typeName) throws SQLException { // 按UDT属性顺序读取 countryId = stream.readInt(); countryName = stream.readString(); // 读取嵌套表为Array对象 Array cityArray = stream.readArray(); if (cityArray != null) { // 将Array转换为City数组,再转为List Object[] cityObjs = (Object[]) cityArray.getArray(); cities = new ArrayList<>(); for (Object obj : cityObjs) { cities.add((City) obj); } // 释放Array资源 cityArray.free(); } else { cities = new ArrayList<>(); } } @Override public void writeSQL(SQLOutput stream) throws SQLException { // 按UDT属性顺序写入 stream.writeInt(countryId); stream.writeString(countryName); if (cities != null && !cities.isEmpty()) { // 获取数据库连接(若使用连接池,应从池获取并归还,不要直接关闭) Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@//your-host:port/your-service", "user", "password"); // 将List<City>转为Oracle Array,指定嵌套表类型名称 Array cityArray = conn.createArrayOf(CITY_LIST_TYPE, cities.toArray()); stream.writeArray(cityArray); // 释放资源 cityArray.free(); conn.close(); } else { // 写入空嵌套表 stream.writeArray(null); } } // 构造方法、Getter/Setter public Country() {} public Country(Integer countryId, String countryName, List<City> cities) { this.countryId = countryId; this.countryName = countryName; this.cities = cities; } public Integer getCountryId() { return countryId; } public void setCountryId(Integer countryId) { this.countryId = countryId; } public String getCountryName() { return countryName; } public void setCountryName(String countryName) { this.countryName = countryName; } public List<City> getCities() { return cities; } public void setCities(List<City> cities) { this.cities = cities; } }
关键注意事项
- UDT名称匹配:Java类中定义的
SQL_TYPE必须和数据库中UDT的名称完全一致,大小写敏感(若数据库用双引号创建了区分大小写的UDT,需严格对应)。 - 属性顺序一致:
readSQL和writeSQL中读写属性的顺序必须和数据库UDT定义的属性顺序完全相同,否则会导致数据错位。 - 连接管理:写入嵌套表时获取Connection,若使用连接池,不要直接调用
close(),应将连接归还到池子里,避免资源泄漏。 - 驱动兼容性:确保使用的Oracle JDBC驱动(ojdbc8及以上版本)和数据库版本兼容,避免出现类型转换异常。
内容的提问来源于stack exchange,提问作者errorrelativo
相关产品推荐
相关产品推荐

