[SpringBoot + Mybatis series] Several ways of Mapper interface registration

In the SpringBoot project, using Mybatis to operate the database is not unfamiliar to most of the small partners of the java technology stack; we know that when using Mybatis, there are generally the following

  • Entity: database entity class
  • Mapper: db operation interface
  • Service: Service class

The comments in the blog post of this film are placed on Mapper. Do you know that there are several ways to register Mapper (this question does not seem to have several ways of writing the word "Fen" 😬)

<!-- more -->

I. Environmental preparation

1. Database Preparation

Use mysql as the instance database of this article, add a new table

CREATE TABLE `money` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL DEFAULT '' COMMENT '用户名',
  `money` int(26) NOT NULL DEFAULT '0' COMMENT '钱',
  `is_deleted` tinyint(1) NOT NULL DEFAULT '0',
  `create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;

2. Project environment

This article is developed with the help of SpringBoot 2.2.1.RELEASE + maven 3.5.3 + IDEA

pom dependencies are as follows

<dependencies>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.2.0</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
</dependencies>

db configuration information application.yml

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/story?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password:

II. Demonstration

The previous basic environment is set up, and then I will prepare the basic classes such as Mybatis's Entity, Mapper, etc.

1. Entity class, Mapper class

Database entity class MoneyPo

@Data
public class MoneyPo {
    private Integer id;

    private String name;

    private Long money;

    private Integer isDeleted;

    private Timestamp createAt;

    private Timestamp updateAt;
}

Corresponding Mapper interface (here, use annotations directly to implement CURD)

public interface MoneyMapper {

    /**
     * 保存数据,并保存主键id
     *
     * @param po
     * @return int
     */
    @Options(useGeneratedKeys = true, keyProperty = "po.id", keyColumn = "id")
    @Insert("insert into money (name, money, is_deleted) values (#{po.name}, #{po.money}, #{po.isDeleted})")
    int save(@Param("po") MoneyPo po);

    /**
     * 更新
     *
     * @param id    id
     * @param money 钱
     * @return int
     */
    @Update("update money set `money`=#{money} where id = #{id}")
    int update(@Param("id") int id, @Param("money") long money);

    /**
     * 删除数据
     *
     * @param id id
     * @return int
     */
    @Delete("delete from money where id = #{id}")
    int delete(@Param("id") int id);

    /**
     * 主键查询
     *
     * @param id id
     * @return {@link MoneyPo}
     */
    @Select("select * from money where id = #{id}")
    @Results(id = "moneyResultMap", value = {
            @Result(property = "id", column = "id", id = true, jdbcType = JdbcType.INTEGER),
            @Result(property = "name", column = "name", jdbcType = JdbcType.VARCHAR),
            @Result(property = "money", column = "money", jdbcType = JdbcType.INTEGER),
            @Result(property = "isDeleted", column = "is_deleted", jdbcType = JdbcType.TINYINT),
            @Result(property = "createAt", column = "create_at", jdbcType = JdbcType.TIMESTAMP),
            @Result(property = "updateAt", column = "update_at", jdbcType = JdbcType.TIMESTAMP)})
    MoneyPo getById(@Param("id") int id);
}

Corresponding Service class

@Slf4j
@Service
public class MoneyService {
    @Autowired
    private MoneyMapper moneyMapper;

    public void basicTest() {
        int id = save();
        log.info("save {}", getById(id));
        boolean update = update(id, 202L);
        log.info("update {}, {}", update, getById(id));
        boolean delete = delete(id);
        log.info("delete {}, {}", delete, getById(id));
    }

    private int save() {
        MoneyPo po = new MoneyPo();
        po.setName("一灰灰blog");
        po.setMoney(101L);
        po.setIsDeleted(0);
        moneyMapper.save(po);
        return po.getId();
    }

    private boolean update(int id, long newMoney) {
        int ans = moneyMapper.update(id, newMoney);
        return ans > 0;
    }

    private boolean delete(int id) {
        return moneyMapper.delete(id) > 0;
    }

    private MoneyPo getById(int id) {
        return moneyMapper.getById(id);
    }
}

2. Registration method

Note that after writing the above, if you do not register the Mapper interface through the following methods, the project will fail to start, prompting that the bean corresponding to MoneyMapper cannot be found

Field moneyMapper in com.git.hui.boot.mybatis.service.MoneyService required a bean of type 'com.git.hui.boot.mybatis.mapper.MoneyMapper' that could not be found.

2.1 @MapperScan registration method

On the configuration class or the startup class, add the @MapperScan annotation to specify the package path of the Mapper interface, so as to realize the registration of the Mapper interface

@MapperScan(basePackages = "com.git.hui.boot.mybatis.mapper")
@SpringBootApplication
public class Application {

    public Application(MoneyService moneyService) {
        moneyService.basicTest();
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }
}

The output after execution is as follows

2021-07-06 19:12:57.984  INFO 1876 --- [           main] c.g.h.boot.mybatis.service.MoneyService  : save MoneyPo(id=557, name=一灰灰blog, money=101, isDeleted=0, createAt=2021-07-06 19:12:57.0, updateAt=2021-07-06 19:12:57.0)
2021-07-06 19:12:58.011  INFO 1876 --- [           main] c.g.h.boot.mybatis.service.MoneyService  : update true, MoneyPo(id=557, name=一灰灰blog, money=202, isDeleted=0, createAt=2021-07-06 19:12:57.0, updateAt=2021-07-06 19:12:57.0)
2021-07-06 19:12:58.039  INFO 1876 --- [           main] c.g.h.boot.mybatis.service.MoneyService  : delete true, null

Notice:

  • basePackages: The package path passed in to the Mapper, an array, you can pass in multiple
  • The package path supports regular, such as com.git.hui.boot.*.mapper

    • The above method can avoid putting all our mappers under one package path, which will lead to unfriendly reading

2.2 @Mapper registration method

The previous @MapperScan specifies the package path of the mapper, and this annotation is placed directly on the Mapper interface

@Mapper
public interface MoneyMapper {
...
}

Test output omitted...

2.3 MapperScannerConfigurer registration method

Use MapperScannerConfigurer to implement mapper interface registration. Long ago, when Spring's xml was used for bean declaration, mybatis's mapper was like this

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="xxx"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>

The corresponding java code is as follows:

@Configuration
public class AutoConfig {
    @Bean(name = "sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setMapperLocations(
                // 设置mybatis的xml所在位置,这里使用mybatis注解方式,没有配置xml文件
                new PathMatchingResourcePatternResolver().getResources("classpath*:mapping/*.xml"));
        return bean.getObject();
    }

    @Bean("sqlSessionTemplate")
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory storySqlSessionFactory) {
        return new SqlSessionTemplate(storySqlSessionFactory);
    }

    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setBasePackage("com.git.hui.boot.mybatis.mapper");
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
        mapperScannerConfigurer.setSqlSessionTemplateBeanName("sqlSessionTemplate");
        return mapperScannerConfigurer;
    }
}

Test output omitted

3. Summary

This article mainly introduces the three registration methods of the Mapper interface in Mybatis, of which two common annotation methods

  • @MapperScan : Specify the package path of the Mapper interface
  • @Mapper : put on the mapper interface
  • MapperScannerConfigurer : Register programmatically

So the question is, why should we introduce these three methods? In our actual business development, the first two are basically satisfied; what scenarios will use the third method?

  • Such as writing a general Mapper (similar to BaseMapper in Mybatis-Plus)
  • Such as a Mapper, a scenario with multiple data sources (such as master-slave library, hot and cold library, db operation mapper is the same, but the underlying data source is different)

This is the end of this article. Regarding the example cases of the above two scenarios, I will add them later when I have time. I am a ash gray, and goodbye bye (welcome to the public a ash gray blog of Changcao)

III. Source code and related knowledge points not to be missed

0. Project

1. A Grey Blog

It is not as good as the letter. The above content is purely a family statement. Due to limited personal ability, it is inevitable that there will be omissions and errors. If you find a bug or have better suggestions, criticisms and corrections are welcome, and I am grateful.

The following is a gray personal blog, which records all the blog posts in study and work. Welcome everyone to visit

一灰灰blog


小灰灰Blog
251 声望46 粉丝