Backend Development 9 min read

Custom SQL Injector Guide for MyBatis-Plus: Built‑in and User‑Defined Injectors

This article explains what SQL injectors are in MyBatis‑Plus, lists the built‑in extended injectors, shows how to configure them globally, demonstrates custom mapper creation, provides complete code examples and test cases, and guides readers through building their own SQL injector for full‑field updates and batch operations.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Custom SQL Injector Guide for MyBatis-Plus: Built‑in and User‑Defined Injectors

1. What is an SQL Injector

When using MyBatis‑Plus, the DAO layer inherits BaseMapper , which provides many methods; each method is essentially an SQL injector.

The core package of MyBatis‑Plus supplies default injectable methods (see image).

To customize an SQL injector, you can extend the default injector.

By default, updateById ignores null fields; sometimes you need to update fields to null values.

MyBatis‑Plus already provides several extended SQL injectors to support null updates.

2. Built‑in Extended SQL Injectors

1. Built‑in injectors

MyBatis‑Plus provides the following built‑in injectors (see image).

AlwaysUpdateSomeColumnById : updates all fields including nulls, unlike the default updateById which skips nulls.

InsertBatchSomeColumn : true batch insert, whereas saveBatch is a pseudo‑batch.

LogicDeleteBatchByIds : logical delete with fill fields such as update time and operator.

Upsert : insert a record with selected fields.

2. Global configuration of SQL injectors

@Component
public class MySqlInjector extends DefaultSqlInjector {
    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
        List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
        /**
         * Add two built‑in extended SQL injectors
         */
        methodList.add(new InsertBatchSomeColumn(i -> i.getFieldFill() != FieldFill.UPDATE));
        methodList.add(new AlwaysUpdateSomeColumnById(i -> i.getFieldFill() != FieldFill.INSERT));
        return methodList;
    }
}

3. Custom Mapper

public interface MyBaseMapper
extends BaseMapper
{
    /**
     * Full‑field update, will not ignore null values
     * @param entity entity object
     */
    int alwaysUpdateSomeColumnById(@Param("et") T entity);

    /**
     * Full batch insert, equivalent to insert
     * @param entityList entity collection
     */
    int insertBatchSomeColumn(List<T> entityList);
}

3. Example Test of Extended SQL Injectors

1. User table

CREATE TABLE `user` (
  `id` int unsigned AUTO_INCREMENT COMMENT 'primary key',
  `username` varchar(128) COMMENT 'username',
  `phone` varchar(32) COMMENT 'phone number',
  `sex` char(1) COMMENT 'gender',
  `create_time` datetime COMMENT 'creation time',
  `update_time` datetime COMMENT 'update time',
  `deleted` tinyint DEFAULT '0' COMMENT '1 deleted, 0 not deleted',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1;

2. Corresponding entity

@Data
@Accessors(chain = true)
@TableName("user")
public class UserDO implements Serializable {
    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    @TableField("username")
    private String username;

    @TableField("phone")
    private String phone;

    @TableField("sex")
    private String sex;

    @TableField(value = "create_time", fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;

    @TableField(value = "deleted", fill = FieldFill.INSERT)
    private Integer deleted;
}

Other related code omitted for brevity; see the project source.

3. Test code

@SpringBootTest
@RunWith(SpringRunner.class)
@ComponentScan("com.jincou.mybatisplus.dao")
public class SqlInjectorTest {

    @Autowired
    private UserMapper mapper;

    @Test
    public void alwaysUpdateSomeColumnById() {
        UserDO user = new UserDO();
        user.setUsername("小小");
        user.setPhone(null);
        user.setSex("女");
        user.setId(1);
        mapper.alwaysUpdateSomeColumnById(user);
    }

    @Test
    public void insertBatchSomeColumn() {
        UserDO user = new UserDO();
        user.setUsername("zhangsan");
        user.setPhone("13811111111");
        user.setSex("女");

        UserDO user1 = new UserDO();
        user1.setUsername("lisi");
        user1.setPhone("13822222222");
        user1.setSex("男");

        ArrayList
userDOS = Lists.newArrayList(user, user1);
        mapper.insertBatchSomeColumn(userDOS);
    }
}

Result screenshots show successful execution of alwaysUpdateSomeColumnById and insertBatchSomeColumn .

4. How to Create a Custom SQL Injector

When built‑in injectors do not satisfy requirements, you can define your own. The following example adds a simple findAll method.

1. Add findAll to MyBaseMapper

public interface MyBaseMapper
extends BaseMapper
{
    /**
     * Query all users
     */
    List
findAll();
}

2. Implement FindAll injector

public class FindAll extends AbstractMethod {
    public FindAll() { super("findAll"); }
    public FindAll(String methodName) { super(methodName); }
    @Override
    public MappedStatement injectMappedStatement(Class
mapperClass, Class
modelClass, TableInfo tableInfo) {
        // Execute SQL, dynamic SQL reference class SqlMethod
        String sql = "select * from " + tableInfo.getTableName();
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
        return this.addSelectMappedStatementForTable(mapperClass, sqlSource, tableInfo);
    }
}

3. Register injector in Spring container

@Component
public class MySqlInjector extends DefaultSqlInjector {
    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
        List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
        /**
         * Custom SQL injector registration
         */
        methodList.add(new FindAll());
        return methodList;
    }
}

4. Test findAll

@Test
public void findAll() {
    List
userDOS = mapper.findAll();
}

Result screenshot confirms success.

Finally, the author invites readers to like, follow, share, and subscribe to his knowledge community, offering premium content on Spring, MyBatis, distributed databases, DDD micro‑services, and more.

ORMMyBatis-PlusDatabase OperationsJava backendCustom MapperSQL Injector
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

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.