Spring Boot 整合 MyBatis 之 注解版

本文导读

环境准备

新建项目

pom. xml 默认结构

<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>www.wmx.com</groupId>
    <artifactId>hippo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>hippo</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
        <relativePath/>
        <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!-- 引入 Spring Boot 封装的 jdbc,它会提供默认的数据源以及 JdbcTemplate  -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <!-- 引入web项目html页面的模板引擎 thymeleaf-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <!-- 引入的是 web 项目的启动器,web 项目必备-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 引入 myBatis,这是 MyBatis官方提供的适配 Spring Boot 的,而不是Spring Boot自己的-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>

        <!-- 引入 Mysql 数据库连接驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!-- 引入 Spring Boot 官方测试模块-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

Mysql 数据库

  • 这是本地的 Mysql 数据库,新建数据库 hippo,建表 user,默认内容如下,初始化一些数据:

全局配置文件

spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://localhost:3306/hippo?characterEncoding=UTF-8
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
  • 因为 Spring Boot 已经默认配置好了数据源,所以此时就可以测试一下获取数据源
package com.lct.wmx;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

@RunWith(SpringRunner.class)
@SpringBootTest
public class HippoApplicationTests {
	/**
	 * Spring Boot 默认已经配置好了数据源,程序员可以直接 DI 注入然后使用即可
	 * 数据源获取正常,能正常拿到数据库连接,则说明数据库连接成功
	 */
	@Resource
	DataSource dataSource;

	@Test
	public void contextLoads() throws SQLException {
		System.out.println("数据源>>>>>>" + dataSource.getClass());
		Connection connection = dataSource.getConnection();
		System.out.println("连接>>>>>>>>>" + connection);
		System.out.println("连接地址>>>>>" + connection.getMetaData().getURL());
		connection.close();
	}
}

数据源>>>>>>class com.zaxxer.hikari.HikariDataSource
2018-08-22 15:44:38.520  INFO 11944 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2018-08-22 15:44:39.246  INFO 11944 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
连接>>>>>>>>>HikariProxyConnection@2125903542 wrapping com.mysql.jdbc.JDBC4Connection@7ed9499e
连接地址>>>>>jdbc:mysql://localhost:3306/hippo?characterEncoding=UTF-8

Domain

  • 创建 User 的 Java Bean 实体来封装数据,到此环境准备完毕,之后就使用 MyBatis 操作数据库即可

package com.lct.wmx.domain;

import java.util.Date;

/**
 * Created by Administrator on 2018/8/22 0022.
 * 用户实体类
 */
public class User {
    private Integer uid;
    private String name;
    private Integer age;
    private Date birthday;
    private Float salary;

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Float getSalary() {
        return salary;
    }

    public void setSalary(Float salary) {
        this.salary = salary;
    }

    public Integer getUid() {
        return uid;
    }

    public void setUid(Integer uid) {
        this.uid = uid;
    }

    @Override
    public String toString() {
        return "User{" +
                "age=" + age +
                ", uid=" + uid +
                ", name='" + name + '\'' +
                ", birthday=" + birthday +
                ", salary=" + salary +
                '}';
    }
}

myBatis 注解版 CRUD

Mapper

  •  User 对应的 MyBatis 的操作数据库的 Mapper,具体作用以及写在注释上了

package com.lct.wmx.mapper;

import com.lct.wmx.domain.User;
import org.apache.ibatis.annotations.*;

import java.util.List;

/**
 * Created by Administrator on 2018/8/22 0022.
 * User 对应的 MyBatis 的操作数据库的 Mapper
 *
 * @Mapper : 表示本类是一个 MyBatis 的 Mapper,等价于以前 Spring 整合 MyBatis 时的 Mapper 接口
 * <p/>
 * Spring 整合 mybatis 时,一个 POJO 对应 MyBatis一个操作数据库的xml文件,每个xml文件又指向一个 mapper 接口
 * Spring Boot 则省略了 xml 文件这一环节,直接将以前xml文件中的sql写在了本类接口上
 * 以前在xml文件中写sql,现在使用注解直接写在接口上,所有sql注解都在:org.apache.ibatis.annotations 包中
 */

@Mapper
public interface UserMapper {

    /**
     * 根据用户 id 查询
     *
     * @param uid
     * @return :返回查询结果,不存在时返回 null
     * @Select :等价于以前 xml 形式时的 <select 标签,sql写法仍然和以前一样
     */
    @Select(value = {"select * from user where uid=#{uid}"})
    public User findUserById(Integer uid);

    /**
     * 查询所有用户
     *
     * @return :返回查询结果
     * @Select :等价于以前 xml 形式时的 <select 标签,sql写法仍然和以前一样
     */
    @Select(value = {"select * from user"})
    public List<User> findAllUsers();

    /**
     * 根据用户id删除用户
     *
     * @return :返回操作的行数,也可以不返回
     */
    @Delete("delete from user where uid = #{uid}")
    public Integer deleteUserById(Integer uid);

    /**
     * 添加用户
     *
     * @param user :因为主键 uid 自增,所以没设值
     * @return
     */
    @Insert("insert into user(name,age,birthday,salary) values(#{name},#{age},#{birthday},#{salary})")
    public Integer adduser(User user);

    /**
     * 根据用户 uid 修改用户
     *
     * @param user
     * @return
     */
    @Update("update user set name=#{name},age=#{age},birthday=#{birthday},salary=#{salary} where uid=#{uid}")
    public Integer updateUser(User user);
}

UserController

  • 用于浏览器请求后台,在注释中已经详细说明
package com.lct.wmx.controller;

import com.lct.wmx.domain.User;
import com.lct.wmx.mapper.UserMapper;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import java.util.List;

/**
 * Created by Administrator on 2018/8/22 0022.
 * 用户控制层
 * 因为主要是讲解 myBatis 操作数据库,所以省略 service 层与 dao 层
 */

@Controller
public class UserController {

    @Resource
    private UserMapper userMapper;

    /**
     * 根据用户 id 查询----直接将结果返回给用户页面
     *
     * @param uid
     * @return
     */
    @ResponseBody
    @GetMapping("/user/{uid}")
    public User findUserById(@PathVariable("uid") Integer uid) {
        System.out.println("------------findUserById >>uid>" + uid);
        User user = userMapper.findUserById(uid);
        System.out.println("------------findUserById >>user>" + user);
        return user;
    }

    /**
     * 查询所有用户----直接将结果返回给用户页面
     *
     * @return
     */
    @ResponseBody
    @GetMapping("/user")
    public List<User> findAllUsers() {
        System.out.println("------------findAllUsers >>>>>>");
        List<User> userList = userMapper.findAllUsers();
        System.out.println("------------findAllUsers >>>>userList>>" + userList);
        return userList;
    }

    /**
     * 添加用户--直接采用浏览器地址带参数的方式进行添加
     * localhost:8080/user/add?name=令狐冲&age=33&birthday=1897/08/25&salary=7000
     * 添加之后,重定向到查询所有
     *
     * @param user
     * @return
     */
    @GetMapping("/user/add")
    public String addUser(User user) {
        System.out.println("------------addUser >>>>user>>" + user);
        userMapper.adduser(user);
        return "redirect:/user";
    }


    /**
     * 修改用户----localhost:8080/user/update?uid=1&name=令狐冲&age=33&birthday=1897/08/25&salary=7000
     *
     * @param user
     * @return
     */
    @GetMapping("/user/update")
    public String updateUser(User user) {
        System.out.println("------------updateUser >>>>user>>" + user);
        userMapper.updateUser(user);
        return "redirect:/user";
    }

    /**
     * 删除用户
     *
     * @param uid
     * @return
     */
    @GetMapping("/user/del/{uid}")
    public String deleteUser(@PathVariable("uid") Integer uid) {
        System.out.println("------------deleteUser >>>>uid>>" + uid);
        userMapper.deleteUserById(uid);
        return "redirect:/user";
    }

}

CRUD 测试

  • 查询测试

  • 删除测试

  • 添加测试:

  • 修改测试:

MyBatis 自动配置原理

  • MyBatis 自动配置在 org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration 类中
  • 它会自动注入 数据源(DataSource) 创建 MyBatis 的 SqlSessionFactory,无需程序员插手
 @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()));
        }

        org.apache.ibatis.session.Configuration configuration = this.properties.getConfiguration();
        if(configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) {
            configuration = new org.apache.ibatis.session.Configuration();
        }

        if(configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) {
            Iterator var4 = this.configurationCustomizers.iterator();

            while(var4.hasNext()) {
                ConfigurationCustomizer customizer = (ConfigurationCustomizer)var4.next();
                customizer.customize(configuration);
            }
        }

        factory.setConfiguration(configuration);
        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(StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
            factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
        }

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

        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);
    }

自定义 MyBatis 配置

  • 以前使用 MyBatis 时,因为有 xml 文件,所以可以直接在文件中配置,但是 Spring Boot 内置的 myBatis 注解版时,需要程序员自己来配置组件
  • 上面的 org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration 类中创建 SqlSessionFactory 的时候使用了一个 ConfigurationCustomizers(配置定制器) ,我们自己如果想要修改 myBatis 配置时,只需要自己创建此组件然后添加到容器中即可
  • 下面以一个需求为例进行说明,修改数据库的 uid 字段名称为 "u_id",然后 UserMapper 中根据 id 查询的 sql 语句中也对应改为 u_id,其余所有内容不做改变。

    /**
     * 根据用户 id 查询
     *
     * @param uid
     * @return :返回查询结果,不存在时返回 null
     * @Select :等价于以前 xml 形式时的 <select 标签,sql写法仍然和以前一样
     */
    @Select(value = {"select * from user where u_id=#{uid}"})
    public User findUserById(Integer uid);
  • select * from user where u_id=#{uid} : "=" 号左边的 u_id 对应数据库字段,右边的 uid 对应 User 实体的属性,此时浏览器发送查询请求时结果如下:

  • 可以看到 uid 字段 封装结果失败!如果是以前是可以在配置文件中指定 myBatis 的驼峰命名的,现在注解版则使用  ConfigurationCustomizers 配置即可

  • ConfigurationCustomizers 配置定制器中还有其它许多配置项,如下所示只是其中一个
package com.lct.wmx.config;

import org.apache.ibatis.session.Configuration;
import org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer;
import org.springframework.context.annotation.Bean;

/**
 * Created by Administrator on 2018/8/22 0022.
 * MyBatis 配置类
 */

@org.springframework.context.annotation.Configuration
public class MyBatisConfig {

    /**
     * 将组建添加到容器中
     *
     * @return
     */
    @Bean
    public ConfigurationCustomizer configurationCustomizer() {
        return new ConfigurationCustomizer() {
            @Override
            public void customize(Configuration configuration) {
                /**
                 * 设置驼峰命名规则
                 * 即数据库的字段,如 aBc 中间要是存在"_" 时,则会自动转换匹配
                 */
                configuration.setMapUnderscoreToCamelCase(true);
            }
        };
    }
}

@MapperScan 批量扫描

  • 一个 POJO 对应一个 Mapper,实际项目中如果有许多的 POJO 时,同理就会有许多的 Mapper,方法一是每个 Mapper 上都添加 @Mapper 注解
  • 方法二是具体的 Mapper 上面可以不写 @Mapper ,使用 @MapperScan 注解来自动扫描
  •  @MapperScan 的位置通常放在应用启动类上,value是一个数组,可以扫描多个路径

package com.lct.wmx;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @MapperScan : 作用是扫描某些包下面所有的类作为 Mapper 类
 * 1)value是一个数组,可以扫描多个路径
 * 2)被扫描的包(com.lct.wmx.mapper)中的类可以不用再写@Mapper,因为全部会自动为它们添上
 * 3) @MapperScan的位置通常放在应用启动类上
 */

@MapperScan(value = {"com.lct.wmx.mapper"})
@SpringBootApplication
public class HippoApplication {

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

猜你喜欢

转载自blog.csdn.net/wangmx1993328/article/details/81900942