[
{
"CountryName": "阿拉伯聯合酋長國",
"Province": [
{
"ProvinceName": "Bahrani",
"City": [ {"CityName": "迪拜"}, {"CityName": "沙迦"}, {"CityName": "拉斯海馬"} ]
},
{
"ProvinceName": "阿布扎比",
"City": [ {"CityName": "阿布扎比"} ]
}
]
},
...
]
CREATE TABLE Country (
Id INT PRIMARY KEY AUTO_INCREMENT,
Name VARCHAR(100) NOT NULL
);
CREATE TABLE Province (
Id INT PRIMARY KEY AUTO_INCREMENT,
CountryId INT NOT NULL,
Name VARCHAR(100) NOT NULL,
FOREIGN KEY (CountryId) REFERENCES Country(Id)
);
CREATE TABLE City (
Id INT PRIMARY KEY AUTO_INCREMENT,
ProvinceId INT NOT NULL,
Name VARCHAR(100) NOT NULL,
FOREIGN KEY (ProvinceId) REFERENCES Province(Id)
);
查詢策略:
CREATE TABLE RegionTree (
Id INT PRIMARY KEY,
Data JSON NOT NULL -- 直接儲存整棵 JSON
);
優點:讀取極快、無需 Join、結構彈性。
缺點:查詢/更新單一城市困難、無外鍵約束、索引支援有限。
public class Country {
private String countryName;
private List province; // JSON key "Province"
// getter/setter
}
public class Province {
private String provinceName;
private List city; // JSON key "City"
// getter/setter
}
public class City {
private String cityName;
// getter/setter
}
// 假設查詢得到扁平 DTO 列表
List flatList = jdbcTemplate.query(sql, new FlatRegionRowMapper());
// 使用 Map 依 ID 分組組裝
Map countryMap = new LinkedHashMap<>();
for (FlatRegion f : flatList) {
Country c = countryMap.computeIfAbsent(f.getCountryId(), id -> {
Country nc = new Country();
nc.setCountryName(f.getCountryName());
nc.setProvince(new ArrayList<>());
return nc;
});
Province p = c.getProvince().stream()
.filter(prov -> prov.getProvinceName().equals(f.getProvinceName()))
.findFirst()
.orElseGet(() -> {
Province np = new Province();
np.setProvinceName(f.getProvinceName());
np.setCity(new ArrayList<>());
c.getProvince().add(np);
return np;
});
p.getCity().add(new City(f.getCityName()));
}
List result = new ArrayList<>(countryMap.values());
// Jackson 序列化
String json = new ObjectMapper().writeValueAsString(result);
若堅持單表/單查詢直接序列化,需自訂 `ResultSetExtractor` 或使用 MyBatis `resultMap` 的 `collection`/`association` 嵌套映射,但效能與維護性通常不如「查扁平 + 記憶體組裝」。
標準做法:三表正規化 + 扁平 JOIN 查詢 + Java 端 Map 組裝樹狀結構 + Jackson 序列化。兼顧資料完整性、查詢效能、程式碼可維護性。若資料極少變動且結構固定,JSON 欄位儲存也是可行選項。