1

本教程主要详细讲解SpringBoot整合MyBatis进行数据库操作,本次讲解我们使用纯注解方式进行。

基础环境


技术 版本
Java 1.8+
SpringBoot 2.x.x
MyBatis 3.5.x

创建项目


  • 初始化项目
mvn archetype:generate -DgroupId=com.edurt.sli.slisma -DartifactId=spring-learn-integration-springboot-mybatis-annotations-DarchetypeArtifactId=maven-archetype-quickstart -Dversion=1.0.0 -DinteractiveMode=false
  • 修改pom.xml增加MyBatis
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <parent>
        <artifactId>spring-learn-integration-springboot-mybatis</artifactId>
        <groupId>com.edurt.sli</groupId>
        <version>1.0.0</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>

    <artifactId>spring-learn-integration-springboot-mybatis-annotations</artifactId>

    <name>SpringBoot整合MyBatis教程(注解版)</name>

    <properties>
        <system.java.version>1.8</system.java.version>
        <plugin.maven.compiler.version>3.3</plugin.maven.compiler.version>
        <springboot.common.version>2.1.3.RELEASE</springboot.common.version>
        <springboot.mybatis.common.version>2.1.1</springboot.mybatis.common.version>
        <mysql.version>5.1.47</mysql.version>
        <lombox.version>1.18.8</lombox.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${springboot.common.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>${springboot.common.version}</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>${springboot.mybatis.common.version}</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombox.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${springboot.common.version}</version>
                <configuration>
                    <fork>true</fork>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${plugin.maven.compiler.version}</version>
                <configuration>
                    <source>${system.java.version}</source>
                    <target>${system.java.version}</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

mybatis-spring-boot-starter:该starter是我们使用SpringBoot整合MyBatis的依赖整合包

  • src/main/java目录下新建com.edurt.sli.slisma目录并在该目录下新建SpringBootMyBatisIntegration类文件,在文件输入以下内容
package com.edurt.sli.slisma;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Component;

@SpringBootApplication
@Component(value = "com.edurt.sli.slisma")
public class SpringBootMyBatisIntegration {

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

}

构建基本使用的SQL文件


src/main目录下新建example.sql文件,键入以下内容

create database spring;

use spring;

drop table if exists user;
create table user (
    id       int(20) auto_increment,
    userName varchar(20),
    primary key (id)
)
    default charset 'utf8';

我们运行该sql文件进行创建数据库/数据表操作.

配置MyBatis数据源

  • /src/main/java/com/edurt/sli/slisma目录下创建config目录,并在该目录下新建MyBatisConfig配置类,键入以下代码
package com.edurt.sli.slisma.config;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;

@Configuration
@MapperScan(value = {"com.edurt.sli.slisma.mapper"})
public class MyBatisConfig {

    @Bean(name = "transactionManager")
    public DataSourceTransactionManager transactionManager(
            @Qualifier("dataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean(name = "sqlSessionFactory")
    @ConditionalOnMissingBean(name = "sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        return sessionFactory.getObject();
    }

    @Bean
    ConfigurationCustomizer mybatisConfigurationCustomizer() {
        return configuration -> {
            configuration.setMapUnderscoreToCamelCase(Boolean.TRUE);
            configuration.setLogPrefix("com.edurt.sli.slismat");
        };
    }

}

该代码中有3个Bean分别是:transactionManager(用于构建事务管理器),sqlSessionFactory(用于构建sqlSession工厂提供查询操作),mybatisConfigurationCustomizer(定制化MyBatis信息)

@MapperScan注解用于指定我们Mapper文件所在的位置

配置Mapper支持数据插入(@Insert)


  • /src/main/java/com/edurt/sli/slisma目录下创建model目录,并在该目录下新建UserModel实体类,键入以下代码
package com.edurt.sli.slisma.model;

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

@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class UserModel {

    private Integer id;
    private String userName;

}
  • /src/main/java/com/edurt/sli/slisma目录下创建mapper目录,并在该目录下新建UserMapper映射类,用于映射数据库和实体类,键入以下代码
package com.edurt.sli.slisma.mapper;

import com.edurt.sli.slisma.model.UserModel;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Param;

@Mapper
public interface UserMapper {

    @Insert("INSERT INTO user (username) VALUES (#{user.userName})")
    @Options(useGeneratedKeys = true, keyColumn = "id", keyProperty = "user.id")
    Integer insertModel(@Param(value = "user") UserModel model);

}

我们在Mapper中提供了一个添加数据方法,我们使用到了@Insert@Options注解

@Insert注解用于标志我们要进行数据插入操作

@Options该注解比较特殊,主要是用于标记我们对插入后返回数据的操作,比如我们指定了useGeneratedKeys=truekeyColumn = "id",这样的话我们插入数据的时候会自动生成主键,keyProperty = "user.id"标记着我们插入数据成功后返回当前插入数据库表中的id数据.需要注意的是我们如果在传递参数的时候使用@Param修饰参数后,那么keyProperty需要指定修饰的域名,如果未进行修饰的话,我们可以直接使用实体类中的字段名称.

  • 接下来我们在/src/test/java目录下新建com.edurt.sli.slisma目录,并在该目录下新建UserMapperTest测试文件,键入以下内容
package com.edurt.sli.slisma.mapper;

import com.edurt.sli.slisma.SpringBootMyBatisIntegration;
import com.edurt.sli.slisma.model.UserModel;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@SpringBootTest(
        classes = SpringBootMyBatisIntegration.class,
        webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
)
public class UserMapperTest {

    private UserModel user;
    private String value = "UserMapperTest";

    @Autowired
    private UserMapper userMapper;

    @Before
    public void before() {
        user = new UserModel();
        user.setUserName(value);
    }

    @After
    public void after() {

    }

    @Test
    public void testInsertModel() {
        Assert.assertTrue(this.userMapper.insertModel(user) > 0);
    }

}

我们在@Before中初始化了一个新的实体信息

然后使用testInsertModel方法进行测试我们UserMapper提供的插入数据方法是否有效

  • /src/main/resources资源目录下创建一个application.properties的配置文件,用于数据库连接配置,键入以下内容
server.port=8989
spring.datasource.url=jdbc:mysql://localhost:3306/spring?useSSL=false
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=123456

此时我们直接运行单元测试便可看到数据库表中新增的数据信息

数据查询操作(@Select)


  • UserMapper文件中键入以下内容支持查询操作
@Results(value = {
        @Result(property = "id", column = "id", id = true),
        @Result(property = "userName", column = "username")
})
@Select(value = "SELECT id, username FROM user WHERE username = #{userName}")
UserModel findByUserName(@Param(value = "userName") String userName);

将顶部引入的包import org.apache.ibatis.annotations.XXXX修改为import org.apache.ibatis.annotations.*

  • UserMapperTest文件中键入以下内容支持数据查询测试
@Test
public void testFindByUserName() {
    Assert.assertNotNull(this.userMapper.findByUserName(value));
}

然后使用testFindByUserName方法进行测试我们UserMapper提供的查询数据方法是否有效

数据查询操作(@Select)动态条件判断


我要想使用类似xml中的if-else的话我们需要用到<script></script>区间块标志.

  • 修改UserMapper文件中键入以下内容支持自定义script查询操作
@Results(value = {
        @Result(property = "id", column = "id", id = true),
        @Result(property = "userName", column = "username")
})
@Select(value = "<script>" +
        "SELECT id, username FROM user WHERE 1=1" +
        "<if test='userName != null'> and username=#{userName} </if>" +
        "</script>")
UserModel findByUserNameAndCustomScript(@Param(value = "userName") String userName);

我们在<script></script>区间块可以使用xml配置中的if语句

  • UserMapperTest文件中键入以下内容支持自定义脚本数据查询测试
@Test
public void testFindByUserNameAndCustomScript() {
    Assert.assertNotNull(this.userMapper.findByUserNameAndCustomScript(value));
}
注意: 如果字段类型是String的话test里面的字符串必需要转义,如果使用单引号的话是不支持的

数据查询操作(@Select)共享Results结果数据


在实际开发中很多时候我们在不同的方法中会返回相同的结果信息,那么这个时候我们就要使用到了共享Results结果数据,共享结果数据很简单,我们只需要修改@Results在里面增加id属性(该id值是唯一的)后期在其他方法中使用即可.

  • 修改UserMapper文件中的findByUserName方法在@Results中增加id属性,内容如下
@Results(id = "userRequiredResults", value = {
        @Result(property = "id", column = "id", id = true),
        @Result(property = "userName", column = "username")
})
@Select(value = "SELECT id, username FROM user WHERE username = #{userName}")
UserModel findByUserName(@Param(value = "userName") String userName);

我们定义了一个id为userRequiredResults的返回全局结果集

  • 修改UserMapper文件中键入以下内容支持共享结果查询操作
@ResultMap(value = "userRequiredResults")
@Select(value = "<script>" +
        "SELECT id, username FROM user WHERE 1=1" +
        "<if test='userName != null'> and username=#{userName} </if>" +
        "</script>")
UserModel findByUserNameAndCommonResult(@Param(value = "userName") String userName);

注意此时我们使用的是@ResultMap注解,该注解只有一个属性,那就是value,指定的是我们需要使用的是返回哪个数据结果集

  • UserMapperTest文件中键入以下内容支持共享结果集数据查询测试
    @Test
public void testFindByUserNameAndCommonResult() {
    Assert.assertNotNull(this.userMapper.findByUserNameAndCommonResult(value));
}

关于分页的功能,我们后续会有单独文章详解

数据修改操作(@Update)


  • UserMapper文件中键入以下内容支持修改操作
@Update(value = "UPDATE user SET userName = #{user.userName} WHERE id = #{user.id}")
void updateModel(@Param(value = "user") UserModel model);
  • UserMapperTest文件中键入以下内容支持数据修改测试
@Test
public void testUpdateModel() {
    user.setId(1);
    user.setUserName("Modify");
    this.userMapper.updateModel(user);
}

运行我们的测试示例,在此查询即可看到数据已经被修改

目前@Update值只支持返回受影响的行数,只需要修改返回值为Integer类型即可,不需要的话直接设置为void

数据删除操作(@Delete)


  • UserMapper文件中键入以下内容支持删除操作
@Delete(value = "DELETE FROM user WHERE id = #{id}")
Integer deleteModel(@Param(value = "id") Integer id);
  • UserMapperTest文件中键入以下内容支持数据删除测试
@Test
public void testDeleteModel() {
    this.userMapper.deleteModel(1);
}
目前@Delete值只支持返回受影响的行数,只需要修改返回值为Integer类型即可,不需要的话直接设置为void

在MyBatis中@Select, @Update, @Delete, @Insert都是支持自定义script的

打包文件部署


  • 打包数据
mvn clean package -Dmaven.test.skip=true -X

运行打包后的文件即可

java -jar target/spring-learn-integration-springboot-mybatis-annotations-1.0.0.jar

源码地址



qianmoQ
412 声望23 粉丝