Имеется Mybatis 3.5.13, БД Postgresql с колонкой типа bytea.
Прописываю в интерфейсе Mapper'а метод:
byte[] getContent(long id);
и запрос для него в xml:
<select id="getContent">
select content
from table1
where id = #{id}
limit 1
</select>
Получаю ошибку при выполнении: "Error attempting to get column 'content' from result set. Cause: org.postgresql.util.PSQLException: Bad value for type byte : \x504 ..."
Пробовал в xml прописывать resultType="_byte[]" — исключение меняется на "java.lang.IllegalArgumentException: argument type mismatch".
Если метод в интерфейсе поменять на:
byte[][] getContent(long id);
то отрабатывает нормально и можно данные забирать из result[0].
Как-то можно прописать, чтобы вариант с byte[] работал?
Здравствуйте, karbofos42, Вы писали:
K>Как-то можно прописать, чтобы вариант с byte[] работал?
Проблема здесь связана с тем, что MyBatis не знает, как правильно маппить столбец типа bytea в Postgresql на тип byte[] в Java. Вам нужно использовать org.apache.ibatis.type.TypeHandler для корректного маппинга bytea в byte[].
Далее, создайте класс, который реализует org.apache.ibatis.type.TypeHandler<byte[]> для маппинга столбцов типа bytea на массивы байтов byte[]:
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.postgresql.util.PGobject;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class ByteArrayTypeHandler extends BaseTypeHandler<byte[]> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, byte[] parameter, JdbcType jdbcType) throws SQLException {
PGobject pgObject = new PGobject();
pgObject.setType("bytea");
pgObject.setValue(new String(parameter));
ps.setObject(i, pgObject);
}
@Override
public byte[] getNullableResult(ResultSet rs, String columnName) throws SQLException {
PGobject pgObject = (PGobject) rs.getObject(columnName);
if (pgObject != null) {
return pgObject.getValue().getBytes();
}
return null;
}
@Override
public byte[] getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
PGobject pgObject = (PGobject) rs.getObject(columnIndex);
if (pgObject != null) {
return pgObject.getValue().getBytes();
}
return null;
}
@Override
public byte[] getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
PGobject pgObject = (PGobject) cs.getObject(columnIndex);
if (pgObject != null) {
return pgObject.getValue().getBytes();
}
return null;
}
}
Зарегистрируйте этот обработчик типов в вашем конфигурационном файле MyBatis (например, mybatis-config.xml):
Здравствуйте, r0nd, Вы писали:
R>Проблема здесь связана с тем, что MyBatis не знает, как правильно маппить столбец типа bytea в Postgresql на тип byte[] в Java. Вам нужно использовать org.apache.ibatis.type.TypeHandler для корректного маппинга bytea в byte[].
Ну, он же маппит как-то в byte[][]. Я предполагаю, что он целевой массив воспринимает как: мне нужно из БД вернуть множество записей, а потом не может в единственный byte засунуть содержимое столбца bytea.
Поэтому когда прописываю массив массивов, там всё у него получается. Первый массив — это для строк, а вложенные — это уже под строки.
С объектами и примитивами такой проблемы не было, т.к. они не являются коллекцией и библиотека чётко может понять, что нужно единственную запись взять.
R>С этими настройками MyBatis должен корректно маппить столбцы типа bytea на массивы байтов byte[].
В MyBatis есть стандартный ByteArrayTypeHadler, который несколько иначе работает, но прописывается в репозитории хендлеров.
Если я у запроса не пропишу resultType, то берётся стандартный хендлер, который падает. Если прописываю тип "_byte[]" и попадаю в предложенный самодельный, то возникает две проблемы:
1) rs.getObject(columnName) возвращает не PGobject, а byte[] (забавно, что rs.getBytes(columnName) падает с исключением), следовательно в исходном виде падает на попытке преобразования в PGobject
2) если я из методов без промежуточного PGobject возвращаю byte[] из getObject, то в библиотеке внутри что-то дальше падает с ошибкой IllegalArgument
Похоже, что проще забить и оставить костылик в виде byte[][].
Ну, либо делать класс-обёртку, чтобы он библиотекой как коллекция не воспринимался и нормально для него TypeHandler подхватывался без конфликтов со стандартными.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Это смотрел ?
Ага. Тоже костыльно как-то получается. В моём варианте прописывается byte[][] и потом возвращается нулевой элемент.
Там предлагают возвращать Object, в котором по сути будет лежать byte[].
Вариант по ссылке несколько оптимальнее будет, но конечно печально, что нормального решения похоже нет.
Здравствуйте, gyraboo, Вы писали:
G>Не связывайся с MyBatis, потом хуже будет.
Ну, сжатые сроки, руководство сверху рекомендовало эту библиотеку, а я Java в последний раз видел 15 лет назад, так что пока придётся с этим разбираться
В целом вроде жить можно, пока только с мелкими неудобствами сталкивался. Ну, и конечно вот эта смесь SQL и XML — нечто своеобразное.