[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 interfaceMapperScannerConfigurer
: 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
- Engineering: https://github.com/liuyueyi/spring-boot-demo
- Source code: https://github.com/liuyueyi/spring-boot-demo/tree/master/spring-boot/104-mybatis-ano
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 Personal blog 160fe729ad359c https://blog.hhui.top
- Blog-Spring Special Blog 160fe729ad35df http://spring.hhui.top
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。