What the error looks like
When implementing automatic filling for common fields, calling updateById may suddenly fail with an exception like this:
1 2 3 4</th>
<th>org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException: ### Error updating database. Cause: java.lang.NullPointerException ### The error may exist in ...Mapper.xml ### Cause: java.lang.NullPointerException</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
</tr>
</tbody>
</table>
At first glance, it looks like a regular NullPointerException. But after checking the service logic, there may be no obvious null access in the business code at all.
Typical setup behind the issue
A common pattern is to use a custom annotation such as @AutoFill together with AOP to automatically populate shared entity fields like updateTime and updateUser.
Mapper layer
<table> <thead> <tr> <th>1 2 3 4 5 6 7</th>
<th>@Mapper public interface EmployeeMapper extends BaseMapper<Employee> { @Override @AutoFill(OperationType.UPDATE) int updateById(Employee entity); // 注意这里! }</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
</tr>
</tbody>
</table>
AOP aspect logic (simplified)
<table> <thead> <tr> <th>1 2 3 4 5 6 7 8 9 10 11 12 13 14</th>
<th>@Aspect @Component @Slf4j public class AutoFillAspect { @Pointcut("@annotation(top.zfmx.annotation.AutoFill)") public void autoFillPointCut() {} @Before("autoFillPointCut()") public void autoFill(JoinPoint joinPoint) { Object entity = joinPoint.getArgs()[0]; // 使用反射设置 updateTime、updateUser 等字段 } }</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
</tr>
</tbody>
</table>
Service layer call
<table> <thead> <tr> <th>1 2 3 4 5 6 7 8 9</th>
<th>@Override public void updateById(EmployeeVO employeeVO) { Employee employee = new Employee(); BeanUtils.copyProperties(employeeVO, employee); if (employee.getEmployeeId() == null) { throw new IllegalArgumentException("ID不能为空"); } baseMapper.updateById(employee); }</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
</tr>
</tbody>
</table>
The service code is straightforward: copy the incoming data into the entity, verify the ID is present, and then call baseMapper.updateById(employee). Nothing here directly explains the NPE.
Where the real problem comes from
The key is how MyBatis-Plus binds parameters internally when generating and executing update SQL.
When Wrapper-style parameter handling is involved, the entity object is typically referenced with the alias et, for example:
1 2 3 4</th>
<th><set> update_time = #{et.updateTime}, update_user = #{et.updateUser} </set></th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
</tr>
</tbody>
</table>
That means the SQL expects an object named et.
If you override updateById(Employee entity) in your own Mapper interface and add your custom annotation for AOP, but do not explicitly declare @Param("et"), then MyBatis-Plus cannot resolve et correctly during SQL parsing. The result is often this misleading null-related exception.
So although the stack trace points to a NullPointerException, the actual issue is parameter alias binding, not necessarily a bug in the update logic or in the field auto-fill itself.
Fix
Add the parameter annotation below to the Mapper method:
<table> <thead> <tr> <th>1</th>
<th>@Param("et")</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
</tr>
</tbody>
</table>
The final method definition should be:
<table> <thead> <tr> <th>1 2 3</th>
<th>@Override @AutoFill(OperationType.UPDATE) int updateById(@Param("et") Employee entity);</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
</tr>
</tbody>
</table>
What to remember
If you are using AOP and a custom annotation to auto-fill fields, especially when overriding built-in MyBatis-Plus methods such as updateById, the parameter alias must be declared explicitly.
@Param("et") is the critical part here. It tells MyBatis that the current method argument should be referenced as et inside the SQL. Without it, MyBatis may fail to bind properties correctly, which can lead to errors during update execution or prevent the auto-filled fields from being assigned as expected.