You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MyBatis TypeHandler中OracleConnection.createOracleArray生成数组内部为空问题

解决MyBatis TypeHandler中Oracle数组datumArray全为null的问题

问题分析

核心问题是TypeHandler的setParameter方法中创建Oracle数组时,数组元素的字符串字段无法正确序列化,导致调试时datumArray全为null。根本原因有两点:

  1. CampoModificato的writeSQL方法未实现:该类实现了SQLData接口,但空实现的writeSQL导致Oracle JDBC驱动无法将Java对象属性写入SQL输出流,无法完成对象到SQL类型的转换。
  2. 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、ARRAY API不建议使用,官方推荐createOracleArray方法。

内容的提问来源于stack exchange,提问作者Emmanuele Guerriero

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 12:38:08