本次使用的Library数据库访问在实现MyBatis之前访问的设置

Spring Boot 实践系列,Spring Boot + MyBatis。

目的

将 MyBatis 与 Spring Boot 应用程序一起使用来访问数据库。

这次使用的图书馆数据库访问权限

在实现 MyBatis 之前,首先要设置 DB 访问权限。

数据库访问定义

DataSourceSpring Boot 自动定义访问 DB 等 bean。

默认情况下它访问内存中的 H2 数据库,因此您需要将 h2 添加到您的依赖项中。

pom.xml

    
        
            com.h2database
            h2
            runtime
        
    

注意

:您可以通过更改 Spring Boot 配置文件中的驱动程序和连接目标来访问另一个 DB。 (需要添加依赖对应的驱动)

src/main/resources/application.yml

spring:
  datasource:
    driver-class-name: org.postgresql.Driver
    url: jdbc:postgresql://localhost:5432/testdb
    username: postgres
    password: postgres

如果直接在src/main/resources下创建如下SQL文件,也可以在应用启动时自动初始化数据库。

默认识别的SQL文件如下。

如您所见,我们在 schema.sql 中定义了 DDL,在 data.sql 中定义了 DML。

注意

${platform}:spring.datasource.platform 在属性中指定。

看来您可以使用 H2 进行单元测试,使用 Postgresql 进行集成测试。

这一次,创建 schema.sql 并创建一个表。

src/main/resources/schema.sql

create table if not exists todo (

图片[1]-本次使用的Library数据库访问在实现MyBatis之前访问的设置-唐朝资源网

todo_id identity, todo_title varchar(30), finished boolean, created_at timestamp );

mybatis-spring-boot-starter

它是使用 MyBatis 和 Spring Boot 的入门者。

通过使用 Spring Boot 的 Auto Configuration 机制,在 Spring Boot 应用程序中使用 MyBatis 的 bean 定义是自动完成的。开发者只需要将 mybatis-spring-boot-starter 添加到他们的依赖项中即可。

pom.xml

    
        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
            2.0.1
        
    

src/main/java/*/Application.java

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

主类不会更改 Spring Boot 应用程序中的默认值。

领域类

映射 DB 数据的域类适用于普通 Java Bean。

在下文中,Lombok 用于省略 Getter 和 Setter 的实现 @Data。

src/main/java/*/domain/Todo.java

@Data
public class Todo {
    private String todoId;
    private String todoTitle;
    private boolean finished;

图片[2]-本次使用的Library数据库访问在实现MyBatis之前访问的设置-唐朝资源网

private LocalDateTime createdAt; }

存储库接口

MyBatis 的 Mapper 对应 Spring 的 Repository 接口。

MyBatis 的 Mapper 可以通过以下任意一种方式实现。

这次我将使用MyBatis的Mapper,基于注解库Spring Boot实现@Mapper。

src/main/java/*/repository/TodoRepository.java

@Mapper // (1)
public interface TodoRepository {
    // (2)
    @Select("SELECT todo_id, todo_title, finished, created_at FROM todo WHERE todo_id = #{todoId}")
    Optional findById(String todoId);
    @Select("SELECT todo_id, todo_title, finished, created_at FROM todo")
    Collection findAll();
    @Insert("INSERT INTO todo (todo_title, finished, created_at) VALUES (#{todoTitle}, #{finished}, #{createdAt})")
    @Options(useGeneratedKeys = true, keyProperty = "todoId") // (3)
    void create(Todo todo);
    @Update("UPDATE todo SET todo_title = #{todoTitle}, finished = #{finished}, created_at = #{createdAt} WHERE todo_id = #{todoId}")
    boolean updateById(Todo todo);
    @Delete("DELETE FROM todo WHERE todo_id = #{todoId}")
    void deleteById(Todo todo);
    @Select("SELECT COUNT(*) FROM todo WHERE finished = #{finished}")
    long countByFinished(boolean finished);
}

(1)如果添加到Repository接口@Mapper,MyBatis会自动扫描并注册到Mapper。我们把Repository接口放在主类下的一个包中。

(2) 在给方法的…中实现要执行的SQL。由于在SQL中使用了参数,因此比XML更容易理解,因为它是在同一个文件中描述的。 @Select @Insert@Update@Delete#{}

(3)@Options在需要执行异常设置的SQL时给出。这里由于表的关键项是IDENTITY列,所以在DB端自动编号,但是@您可以使用的选项 使用自动编号的 ID。

多行 SQL

虽然上面的SQL是一行描述的,但是由于不可读,建议多行。

它比 XML 更难看,因为它是这样的字符串连接形式。

    @Select("SELECT"
            + " todo_id,"
            + " todo_title,"
            + " finished,"
            + " created_at"
            + " FROM todo"
            + " WHERE"
            + " todo_id = #{todoId}")
    Optional findById(String todoId);

选择结果的自动和手动映射

选择结果映射失败,因为图示的 Select 语句的结果列名称与 Todo 类的属性名称不同。 (todo_title 等 todoTitle)

以下方法之一可以解决此问题。

就个人而言,命名属性是一个好主意,以便自动映射可用,并且仅在偏离规则时才进行手动映射。

自动映射

如果下划线分隔的列名匹配驼峰式的属性名,它们可以被MyBatis的命名规则自动映射。

将以下设置添加到 Spring Boot 配置文件中。

src/main/resources/application.yml

mybatis:
  configuration:
    map-underscore-to-camel-case: true

注意

mybatis.configuration.*:您可以在属性中更改MyBatis的设置。

手动映射

如果列名和属性名不匹配,@Results 需要@ResultMap 为每个 SQL 定义手动映射。

    @Select("SELECT todo_id, todo_title, finished, created_at FROM todo WHERE todo_id = #{todoId}")
    @Results(id = "todo", value = {
            @Result(column = "todo_id", property = "todoId"),
            @Result(column = "todo_title", property = "todoTitle"),
            @Result(column = "finished", property = "finished"),
            @Result(column = "created_at", property = "createdAt") })

    Optional findById(String todoId);
    @Select("SELECT todo_id, todo_title, finished, created_at FROM todo")
    @ResultMap("todo")
    Collection findAll();

与动态 SQL 共通

Mapper XML 可以实现的动态 SQL() 和 Generic() 现在通过 SqlProvider 实现。

    // (2)
    @SelectProvider(type = TodoSqlProvider.class, method = "find")
    Optional findById(String todoId);
    @SelectProvider(type = TodoSqlProvider.class, method = "find")
    Collection findAll();
    // (1)
    public class TodoSqlProvider {
        public String find(String todoId) {
            return new SQL() {{
                SELECT("todo_id", "todo_title", "finished", "created_at");
                FROM("todo");
                if (todoId != null) {
                    WHERE("todo_id = #{todoId}");
                }
            }}.toString();
        }
    }

(1)实现SqlProvider类,在方法中使用new SQL()组装SQL。示例使用实例初始化器(new SQL() {{ココ}}),当然你也可以在方法链中也正常写。

注意

:可以直接在WHERE子句中嵌入参数,但必须使用#{}。

#{} 防止 SQL 注入。

(2)通过分配@Select而不是@SelectProvider方法来指定实现的SqlProvider类和方法。

注意

:接口默认方法不能是SqlProvider方法。你需要上课。

这是因为当您使用 SqlProvider 方法时,会创建一个 SqlProvider 类的实例。

mybatis-spring-boot-starter-test

使用 Spring Boot 测试 MyBatis 的入门。

通过使用 Spring Boot Auto Configuration 机制,Spring Boot 应用程序会自动定义一个 bean 用于测试 MyBatis Mapper。开发者只需要将mybatis-spring-boot-starter-test添加到自己的依赖中并进行一些设置即可。

pom.xml

    
        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter-test
            2.0.1
        
    

JUnit 测试用例

在 JUnit 测试用例中,您所要做的就是提供类并 @MyBatisTest 使存储库 @Autowired 进行测试。

src/test/java/*/repository/TodoRepositoryTest.java

@MybatisTest
class TodoRepositoryTest {
    @Autowired
    TodoRepository todoRepository;
    @Test
    @Sql(statements = "INSERT INTO todo (todo_title, finished, created_at) VALUES ('sample todo', false, '2019-01-01')")
    void testFindAll() {
        // execute
        Collection todos = todoRepository.findAll();
        // assert
        assertThat(todos)
                .hasSize(1)
                .extracting(Todo::getTodoTitle, Todo::isFinished, Todo::getCreatedAt)
                .containsExactly(tuple("sample todo", false, LocalDate.of(2019, 1, 1).atStartOfDay()));
    }

@MyBatisTestDataSource 会自动定义使用 MyBatis、访问 DB 等的 bean,但 @Transactional 也会添加更多。

@Transactional@Sql 测试完成后,测试中执行的 SQL 会回滚。这是安全的,因为即使在访问和测试不在内存中的实际数据库时也能保持测试独立性。

© 版权声明
THE END
喜欢就支持一下吧
点赞297 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片