Skip to content

How to Perform CRUD Operations with MyBatis-Flex BaseMapper

I needed to implement basic database operations for a new project, but I dreaded writing the same repetitive SQL statements for every table. I wanted something that would handle CRUD operations automatically without sacrificing flexibility.

That’s when I discovered MyBatis-Flex’s BaseMapper interface.

The Problem

Traditional MyBatis requires writing XML mapper files or annotations for even the simplest operations. Need to insert a record? Write SQL. Want to select by ID? Write SQL. Update a field? You guessed it—more SQL.

This leads to bloated mapper files filled with boilerplate code that’s essentially the same across all entities.

BaseMapper to the Rescue

MyBatis-Flex solves this by providing a BaseMapper interface with built-in CRUD methods. You just extend it, and you get insert, select, update, and delete operations without writing any SQL.

Let me show you how each operation works.

INSERT: Creating New Records

The insert() method persists a new entity and automatically populates the generated ID back into your object.

AccountMapperTest.java
@SpringBootTest
class AccountMapperTest {
@Autowired
private AccountMapper accountMapper;
@Test
@Transactional
void testInsert() {
Account account = new Account();
account.setUserName("john_doe");
account.setAge(28);
account.setStatus(1);
int rows = accountMapper.insert(account);
assertThat(rows).isEqualTo(1);
assertThat(account.getId()).isNotNull(); // ID populated automatically
}
}

The entity uses standard JPA annotations:

Account.java
@Table("tb_account")
public class Account {
@Id(keyType = KeyType.Auto)
private Long id;
private String userName;
private Integer age;
private Integer status;
// getters and setters
}

Your mapper interface simply extends BaseMapper:

AccountMapper.java
public interface AccountMapper extends BaseMapper<Account> {
// No SQL needed - all CRUD methods inherited
}

READ: Retrieving Records

The selectOneById() method fetches a single record by its primary key. It returns null when no record exists instead of throwing an exception.

AccountMapperTest.java
@Test
void testSelectOneById() {
Account account = accountMapper.selectOneById(1L);
assertThat(account).isNotNull();
assertThat(account.getUserName()).isEqualTo("john_doe");
assertThat(account.getAge()).isEqualTo(28);
}
@Test
void testSelectOneByIdNotFound() {
Account account = accountMapper.selectOneById(999L);
assertThat(account).isNull(); // Returns null, not an exception
}

For more complex queries, you can use the QueryWrapper:

AccountMapperTest.java
@Test
void testSelectByCondition() {
List<Account> accounts = accountMapper.selectListByQuery(
QueryWrapper.create()
.where(Account::getAge).ge(25)
.and(Account::getStatus).eq(1)
);
assertThat(accounts).isNotEmpty();
}

UPDATE: Modifying Existing Records

The update() method modifies an existing entity. You typically load the entity first, modify it, then save.

AccountMapperTest.java
@Test
@Transactional
void testUpdate() {
// Load existing record
Account account = accountMapper.selectOneById(1L);
assertThat(account).isNotNull();
// Modify fields
account.setStatus(0);
// Persist changes
int rows = accountMapper.update(account);
assertThat(rows).isEqualTo(1);
// Verify the change
Account updated = accountMapper.selectOneById(1L);
assertThat(updated.getStatus()).isEqualTo(0);
}

You can also update specific columns without loading the entire entity:

AccountMapperTest.java
@Test
@Transactional
void testUpdateSpecificColumns() {
Account account = new Account();
account.setId(1L);
account.setStatus(0);
int rows = accountMapper.update(account);
assertThat(rows).isEqualTo(1);
}

DELETE: Removing Records

The deleteById() method removes a record by its primary key.

AccountMapperTest.java
@Test
@Transactional
void testDelete() {
// First, verify record exists
Account before = accountMapper.selectOneById(2L);
assertThat(before).isNotNull();
// Delete the record
int rows = accountMapper.deleteById(2L);
assertThat(rows).isEqualTo(1);
// Verify deletion
Account after = accountMapper.selectOneById(2L);
assertThat(after).isNull();
}

Batch deletion is equally straightforward:

AccountMapperTest.java
@Test
@Transactional
void testBatchDelete() {
int rows = accountMapper.deleteByIds(Arrays.asList(1L, 2L, 3L));
assertThat(rows).isEqualTo(3);
}

Why This Matters

With traditional MyBatis, implementing CRUD for a single entity might require:

  • 4+ XML mapper methods
  • Corresponding SQL statements
  • Parameter type definitions
  • Result mapping configuration

With MyBatis-Flex BaseMapper, you get all of this by simply extending an interface:

AccountMapper.java
public interface AccountMapper extends BaseMapper<Account> {
// That's it - you're done
}

The @Transactional annotation in the tests ensures each test runs in isolation, rolling back changes after completion. This keeps your test database clean.

Summary

In this post, I showed you how to perform CRUD operations using MyBatis-Flex BaseMapper. The insert() method creates records and populates generated IDs, selectOneById() retrieves records by primary key, update() modifies existing entities, and deleteById() removes records. All without writing a single SQL statement.

If you’re starting a new project with MyBatis-Flex, BaseMapper should be your first choice for standard CRUD operations. Write custom SQL only when you need something beyond basic persistence patterns.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments