MyBatis Boolean vs Boolean: Unexpected 0 Value and Fix
Because MyBatis reads a primitive boolean field directly when no getter exists, the default false value is bound as 0, causing an unexpected zero in the MySQL tinyint column; changing the field to the Boolean wrapper (initialized to true) or fixing the update logic resolves the issue.
During a feature implementation a new MySQL column is_has_messages (unsigned tinyint, default 1) was added to record whether a session has messages. The corresponding POJO field was declared as private boolean hasMessages; following the Alibaba coding guidelines that forbid the is prefix on boolean variables.
After inserting a record the column unexpectedly stored 0 instead of 1 . Debugging revealed that MyBatis looks for a getter named getHasMessages() or a field named hasMessages . Because no getter exists, MyBatis reads the primitive field directly, whose default value is false , resulting in 0 in the database.
The SQL logged by a custom interceptor ( @Intercepts on StatementHandler.prepare ) shows the placeholder #{hasMessages} being bound to the primitive value:
@Slf4j
@Intercepts({
@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class MyBatisSqlInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler sh = (StatementHandler) invocation.getTarget();
String sql = sh.getBoundSql().getSql();
Object param = sh.getBoundSql().getParameterObject();
log.info("Executing SQL: {}", sql);
log.info("Parameters: {}", param);
return invocation.proceed();
}
// plugin and setProperties omitted for brevity
}The relevant part of MyBatis' DefaultParameterHandler extracts the property value:
public void setParameters(PreparedStatement ps) {
List
mappings = boundSql.getParameterMappings();
for (int i = 0; i < mappings.size(); i++) {
ParameterMapping pm = mappings.get(i);
String prop = pm.getProperty();
Object value = metaObject.getValue(prop);
TypeHandler handler = pm.getTypeHandler();
handler.setParameter(ps, i + 1, value, pm.getJdbcType());
}
}Because the primitive boolean defaults to false , the bound value becomes 0 . Moreover, a later xxxTalk update operation overwrites the column to 0 when the POJO field is still false .
Fixes:
Change the field type to Boolean and initialise it to Boolean.TRUE , ensuring the default value is 1 when not explicitly set.
Or adjust the update logic so that it does not reset the column unintentionally.
Final POJO snippet:
private Boolean hasMessages = Boolean.TRUE;This change makes MyBatis bind 1 correctly and resolves the intermittent “0” values observed during inserts and updates.
DaTaobao Tech
Official account of DaTaobao Technology
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.