MyBatis TypeHandler中OracleConnection.createOracleArray生成数组内部为空问题
解决MyBatis TypeHandler中Oracle数组datumArray全为null的问题
问题分析
核心问题是TypeHandler的setParameter方法中创建Oracle数组时,数组元素的字符串字段无法正确序列化,导致调试时datumArray全为null。根本原因有两点:
CampoModificato的writeSQL方法未实现:该类实现了SQLData接口,但空实现的writeSQL导致Oracle JDBC驱动无法将Java对象属性写入SQL输出流,无法完成对象到SQL类型的转换。ElencoCampiModificati不必要实现java.sql.Array:这个类只是封装数组的POJO,实现JDBC的Array接口不仅无意义,还可能造成逻辑混淆,且内部方法大多为空实现,无法提供有效功能。
解决方案
1. 完善CampoModificato的SQLData实现
补全writeSQL方法,按照Oracle自定义类型的字段顺序将属性写入SQLOutput,同时补全readSQL方法(若需从数据库读取该类型):
package com.ubiss.domain.logger; import java.io.Serializable; import java.sql.SQLData; import java.sql.SQLException; import java.sql.SQLInput; import java.sql.SQLOutput; public class CampoModificato implements SQLData, Serializable{ private static final long serialVersionUID = 1L; private String nome_campo; private String valore_old; private String valore_new; public CampoModificato() {} public CampoModificato(String nome_campo, String valore_old, String valore_new) { this.nome_campo = nome_campo; this.valore_old = valore_old; this.valore_new = valore_new; } // 保留原有getter、setter public String getNomeCampo() { return nome_campo; } public void setNomeCampo(String nome_campo) { this.nome_campo = nome_campo; } public String getValoreOld() { return valore_old; } public void setValoreOld(String valore_old) { this.valore_old = valore_old; } public String getValoreNew() { return valore_new; } public void setValoreNew(String valore_new) { this.valore_new = valore_new; } @Override public String getSQLTypeName() throws SQLException { // 指定完整Schema+类型名,与Oracle端定义一致 return "DYNAPP.TY_CAMPI_MODIFICATI"; } @Override public void readSQL(SQLInput stream, String typeName) throws SQLException { // 按Oracle类型字段顺序读取属性 nome_campo = stream.readString(); valore_old = stream.readString(); valore_new = stream.readString(); } @Override public void writeSQL(SQLOutput stream) throws SQLException { // 按Oracle类型字段顺序写入属性 stream.writeString(nome_campo); stream.writeString(valore_old); stream.writeString(valore_new); } }
2. 简化ElencoCampiModificati为普通POJO
去掉不必要的java.sql.Array实现,只保留数组封装功能:
package com.ubiss.domain.logger; public class ElencoCampiModificati { private CampoModificato[] campiModificati; public ElencoCampiModificati() {} public ElencoCampiModificati(CampoModificato[] campiModificati) { this.campiModificati = campiModificati; } public CampoModificato[] getCampiModificati() { return campiModificati; } public void setCampiModificati(CampoModificato[] campiModificati) { this.campiModificati = campiModificati; } }
3. 调整TypeHandler的setParameter方法
优化数组创建逻辑,增加空值判断:
public class ElencoCampiTypeHandler implements TypeHandler<ElencoCampiModificati> { @Override public void setParameter(PreparedStatement ps, int i, ElencoCampiModificati parameter, JdbcType jdbcType) throws SQLException { // 处理空值情况 if (parameter == null || parameter.getCampiModificati() == null) { ps.setNull(i, java.sql.Types.ARRAY, "DYNAPP.V_ELENCO_CAMPI_MODIFICATI"); return; } // 直接传入数组,驱动通过SQLData的writeSQL完成序列化 Array arr = ps.getConnection().unwrap(OracleConnection.class) .createOracleArray("DYNAPP.V_ELENCO_CAMPI_MODIFICATI", parameter.getCampiModificati()); ps.setArray(i, arr); } // 根据业务需求实现其他TypeHandler方法(getResult等) }
额外注意事项
- 确保Oracle端自定义类型
TY_CAMPI_MODIFICATI和数组类型V_ELENCO_CAMPI_MODIFICATI的字段顺序,与writeSQL/readSQL操作顺序完全一致。 - 使用兼容的Oracle JDBC驱动版本(推荐ojdbc8及以上),避免版本不兼容导致的序列化异常。
- 废弃的
ArrayDescriptor、ARRAYAPI不建议使用,官方推荐createOracleArray方法。
内容的提问来源于stack exchange,提问作者Emmanuele Guerriero
相关产品推荐
相关产品推荐

