Databases 9 min read

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.

DaTaobao Tech
DaTaobao Tech
DaTaobao Tech
MyBatis Boolean vs Boolean: Unexpected 0 Value and Fix

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.

debuggingJavaDatabaseMyBatisORMBoolean
DaTaobao Tech
Written by

DaTaobao Tech

Official account of DaTaobao Technology

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.