SpringBoot整合MyBatis

  1. SpringBoot整合MyBatis 【接口注解方式】

仅做配置记录,方便以后快速搭建粘贴,没有任何营养价值

1.0 创建表的Sql 脚本

CREATE TABLE User (
id bigint NOT NULL AUTO_INCREMENT,
name varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL,
age int DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci

1.1 需要Maven配置文件



4.0.0

org.springframework.boot
spring-boot-starter-parent
2.3.4.RELEASE

com.plumblossom
springboot-transaction
0.0.1-SNAPSHOT
springboot-transaction
Spring Transaction Knowledge


<java.version>1.8</java.version>


org.springframework.boot
spring-boot-starter-web



org.mybatis.spring.boot
mybatis-spring-boot-starter
2.1.3



mysql
mysql-connector-java



org.projectlombok
lombok
true


org.springframework.boot
spring-boot-starter-test
test


org.junit.vintage
junit-vintage-engine






org.springframework.boot
spring-boot-maven-plugin


1.2 Properties 配置文件内容

MyBatis 配置

spring.datasource.url=jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=UTF8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123321
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

上述配置有两点需要说明:

  1. 配置spring.datasource.url 的时候需要配置下时区不然运行的时候会抛出异常
  2. spring.datasource.driver-class-name 这个是因为 默认使用的是mysql8 的连接驱动所以和传统的比较多了个cj

1.3 User 对象的实体类

package com.plumblossom.springboottransaction.bean;

import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Data
@ToString
@NoArgsConstructor
public class User {

private Long id;
private String name;
private Integer age;

public User(Long id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
}

1.4 UserMapper 数据化持久层

package com.plumblossom.springboottransaction.mapper;

import com.plumblossom.springboottransaction.bean.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

@Mapper
public interface UserMapper {

// 查询指定姓名的用户
@Select("select * from user where name=#{name}")
User findUserByName(@Param("name") String n);

// 向数据库中插入用户
@Insert("insert into user(name,age) values(#{name},#{age})")
int insertUser(@Param("name") String name, @Param("age") Integer age);

}

1.5 编写测试用例对上面这种方式进行测试

package com.plumblossom.springboottransaction.mapper;

import com.plumblossom.springboottransaction.bean.User;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Rollback;

@Slf4j
@SpringBootTest
public class UserMapperTest {

@Autowired
private UserMapper userMapper;

@Test
@Rollback
public void testUserMapperInsert(){
userMapper.insertUser("张三", 23);
User user = userMapper.findUserByName("张三");
log.info(user.toString());
Assertions.assertThat(user.getAge()).isEqualTo(23);

}

}

执行代码日志打印结果

2020-09-28 16:37:25.288 INFO 5344 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2020-09-28 16:37:25.621 INFO 5344 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2020-09-28 16:37:25.805 INFO 5344 --- [ main] c.p.s.mapper.UserMapperTest : User(id=1, name=张三, age=23)

可以看到成功的执行了,但是此处还有一个注意点:

SpringBoot2.x 中默认使用的是hikari.HikariDataSource 数据源,SpringBoot1.x 网上说使用的是TomcatDataSource

拓展思考点: 如何更换数据源,还有这个数据源是怎么被SpringBoot 管理的

  1. SpringBoot整合MyBatis 【xml 配置文件方式】

2.1 application.properties 配置文件中的内容

MyBatis 配置

mybatis.type-aliases-package=com.plumblossom.springboottransaction.bean
# 指定Mybatis 配置文件,应该也可以使用Configuration 配置类的方式进行配置
mybatis.config-location=classpath:mybatis/mybatis-config.xml
# 指定Mapper配置文件的路径,也可以使用Configuration 配置类的方式进行配置
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml

数据库连接配置

spring.datasource.url=jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=UTF8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123321
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

2.2 mybatis-config.xml 配置文件












2.3 UserMapper配置文件








id, name, age

INSERT INTO
user
(name, age)
VALUES
( #{name}, #{age})

2.4 UserMapper.Java的文件内容

import com.plumblossom.springboottransaction.bean.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

@Mapper
public interface UserMapper {

User findUserByName(@Param("name") String n);

int insertUser(@Param("name") String name, @Param("age") Integer age);

}

2.5 使用测试用例执行测试

package com.plumblossom.springboottransaction.mapper;

import com.plumblossom.springboottransaction.bean.User;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Rollback;

@Slf4j
@SpringBootTest
public class UserMapperTest {

@Autowired
private UserMapper userMapper;

@Test
@Rollback
public void testUserMapperInsert(){
userMapper.insertUser("李四", 55);
User user = userMapper.findUserByName("李四");
log.info(user.toString());
Assertions.assertThat(user.getAge()).isEqualTo(55);

}

}

执行测试结果

2020-09-28 17:20:28.254 INFO 17148 --- [main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2020-09-28 17:20:28.527 INFO 17148 --- [main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2020-09-28 17:20:28.706 INFO 17148 --- [main] c.p.s.mapper.UserMapperTest : User(id=2, name=李四, age=55)

注意点: 这两种Dao 数据持久层的接口,我都使用了@Mapper 这个注解,他的作用就是在代码编译过后会生成相应的接口实现类,这种方式是官方推荐的。这里只有一个接口文件,如果有非常多的接口,在每一个上面标注上这个注解,也是一件麻烦的事情。所以还有另一个注解@MapperScan(packageName) 在SpringBoot的启动类上标注上这个注解,就会直接扫描指定包下的接口并生成实现类。

3 SpringBoot 整合MyBatis 原理

3.1 SpringBoot 能够整合MyBatis的原因

主要是org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration 这个类在起作用

在以前学习spring整合与mybatis整合的时候,需要我们自己配置两个Bean 一个是sqlSessionFactoryBean,还有一个是MapperScanner,在Springboot中这两个Bean不需要我们提供了,但并不是意味着这两个Bean不需要了

@Configuration
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties({MybatisProperties.class})
@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class})
public class MybatisAutoConfiguration implements InitializingBean {
private static final Logger logger = LoggerFactory.getLogger(MybatisAutoConfiguration.class);
private final MybatisProperties properties;
private final Interceptor[] interceptors;
private final TypeHandler[] typeHandlers;
private final LanguageDriver[] languageDrivers;
private final ResourceLoader resourceLoader;
private final DatabaseIdProvider databaseIdProvider;
private final List configurationCustomizers;

@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setVfs(SpringBootVFS.class);
if (StringUtils.hasText(this.properties.getConfigLocation())) {
factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
}

this.applyConfiguration(factory);
if (this.properties.getConfigurationProperties() != null) {
factory.setConfigurationProperties(this.properties.getConfigurationProperties());
}

if (!ObjectUtils.isEmpty(this.interceptors)) {
factory.setPlugins(this.interceptors);
}

if (this.databaseIdProvider != null) {
factory.setDatabaseIdProvider(this.databaseIdProvider);
}

if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
}

if (this.properties.getTypeAliasesSuperType() != null) {
factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());
}

if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
}

if (!ObjectUtils.isEmpty(this.typeHandlers)) {
factory.setTypeHandlers(this.typeHandlers);
}

if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
factory.setMapperLocations(this.properties.resolveMapperLocations());
}

Set factoryPropertyNames = (Set)Stream.of((new BeanWrapperImpl(SqlSessionFactoryBean.class)).getPropertyDescriptors()).map(FeatureDescriptor::getName).collect(Collectors.toSet());
Class<? extends LanguageDriver> defaultLanguageDriver = this.properties.getDefaultScriptingLanguageDriver();
if (factoryPropertyNames.contains("scriptingLanguageDrivers") && !ObjectUtils.isEmpty(this.languageDrivers)) {
factory.setScriptingLanguageDrivers(this.languageDrivers);
if (defaultLanguageDriver == null && this.languageDrivers.length == 1) {
defaultLanguageDriver = this.languageDrivers[0].getClass();
}
}

if (factoryPropertyNames.contains("defaultScriptingLanguageDriver")) {
factory.setDefaultScriptingLanguageDriver(defaultLanguageDriver);
}

return factory.getObject();
}

@Bean
@ConditionalOnMissingBean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
ExecutorType executorType = this.properties.getExecutorType();
return executorType != null ? new SqlSessionTemplate(sqlSessionFactory, executorType) : new SqlSessionTemplate(sqlSessionFactory);
}

@Configuration
@Import({MybatisAutoConfiguration.AutoConfiguredMapperScannerRegistrar.class})
@ConditionalOnMissingBean({MapperFactoryBean.class, MapperScannerConfigurer.class})
public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean {
public MapperScannerRegistrarNotFoundConfiguration() {
}

public void afterPropertiesSet() {
MybatisAutoConfiguration.logger.debug("Not found configuration for registering mapper bean using @MapperScan, MapperFactoryBean and MapperScannerConfigurer.");
}
}

}

未完。

posted @ 2020-09-28 21:47  梅花GG  阅读(386)  评论(0)    收藏  举报