使用MyBatis插入PostgreSQL bit(n)字段(对应Java byte[])报错求助
解决PostgreSQL bit(n)与Java byte[]的MyBatis Plus映射问题
问题回顾
向PostgreSQL插入数据时,因bit(n)字段与Javabyte[]类型不匹配报错:
org.postgresql.util.PSQLException: error: column "role" type is bit, but type of expression is bytea.
后续尝试自定义TypeHandler后,报错变为:
org.postgresql.util.PSQLException: error: column "role" type is bit, but type of expression is character varying.
核心原因
PostgreSQL的bit(n)类型需要传入固定长度的二进制格式字符串(如bit(2)对应'01'),但MyBatis默认将byte[]映射为bytea类型;错误的TypeHandler则将其转成了普通字符串,导致类型不匹配。
解决方案
1. 编写正确的TypeHandler
实现BaseTypeHandler,完成byte[]与PostgreSQLbit(n)的双向转换:
import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType; import java.sql.*; public class BitByteArrayTypeHandler extends BaseTypeHandler<byte[]> { @Override public void setNonNullParameter(PreparedStatement ps, int i, byte[] parameter, JdbcType jdbcType) throws SQLException { // 获取字段的bit长度(如bit(2)提取出2) ParameterMetaData metaData = ps.getParameterMetaData(); String typeName = metaData.getParameterTypeName(i); int bitLength = Integer.parseInt(typeName.substring(4, typeName.length() - 1)); // 将byte转成对应长度的二进制字符串 StringBuilder bitStrBuilder = new StringBuilder(); int value = parameter[0] & 0xFF; // 取第一个byte的无符号值 for (int j = bitLength - 1; j >= 0; j--) { bitStrBuilder.append((value >> j) & 1); } ps.setString(i, bitStrBuilder.toString()); } @Override public byte[] getNullableResult(ResultSet rs, String columnName) throws SQLException { return parseBitStrToByte(rs.getString(columnName)); } @Override public byte[] getNullableResult(ResultSet rs, int columnIndex) throws SQLException { return parseBitStrToByte(rs.getString(columnIndex)); } @Override public byte[] getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return parseBitStrToByte(cs.getString(columnIndex)); } // 将数据库返回的bit字符串转成byte[] private byte[] parseBitStrToByte(String bitStr) { if (bitStr == null) { return null; } int value = Integer.parseInt(bitStr, 2); return new byte[]{(byte) value}; } }
2. 配置DO类字段
在role和module字段上指定TypeHandler:
@TableName("agri_person_relation") @KeySequence("agri_person_relation_seq") @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor public class PersonRelationDO extends BaseDO { @TableId private Long id; private Long relatedTableId; @TableField(typeHandler = BitByteArrayTypeHandler.class) private byte[] role; @TableField(typeHandler = BitByteArrayTypeHandler.class) private byte[] module; private Long personId; }
3. 注册TypeHandler
确保MyBatis Plus能扫描到TypeHandler,有两种方式:
- 配置文件方式(application.yml):
mybatis-plus: type-handlers-package: com.yourproject.handler # 替换为TypeHandler所在包路径
- 代码配置方式:
import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.baomidou.mybatisplus.core.MybatisConfiguration; import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; @Configuration @MapperScan("com.yourproject.mapper") public class MyBatisPlusConfig { @Bean public MybatisSqlSessionFactoryBean sqlSessionFactory() { MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean(); // 配置数据源等其他信息... MybatisConfiguration configuration = new MybatisConfiguration(); configuration.getTypeHandlerRegistry().register(BitByteArrayTypeHandler.class); factoryBean.setConfiguration(configuration); return factoryBean; } }
验证逻辑
- 插入时:
byte[] role = new byte[]{1}(二进制00000001)会被转成'01',匹配bit(2)字段类型。 - 查询时:数据库返回的
'01'会被转成byte[]{1},实现双向兼容。
内容的提问来源于stack exchange,提问作者Paul
相关产品推荐
相关产品推荐

