共计 9798 个字符,预计需要花费 25 分钟才能阅读完成。
SpringBoot 整合 MyBatis
MyBatis 简介
MyBatis 官网所述:
MyBatis 是一款优良的长久层框架,它反对自定义 SQL、存储过程以及高级映射。MyBatis 罢黜了简直所有的 JDBC 代码以及设置参数和获取后果集的工作。MyBatis 能够通过简略的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Ordinary Java Objects,简略 Java 对象)为数据库中的记录。
MyBatis 的劣势
MyBatis 作为一款优良的长久层框架,具备如下长处:
- 玲珑并且简略易学;
- 相比于 JDBC 缩小了大量冗余的代码;
- 将 SQL 语句与程序代码进行拆散,升高了耦合,便于管理;
- 提供 XML 标签,反对编写动静 SQL 语句;
- 提供映射标签,反对 Java 对象与数据库 ORM 字段的映射关系。
MyBatis 的毛病
- SQL 语句编写工作量较大,尤其是字段和关联表比拟多时。
- SQL 语句依赖于数据库,导致数据库移植性差,不能随便更换数据库。
MyBatis 实际
创立 SpringBoot 我的项目,整合 MyBatis,实现简略 CRUD。
1. 引入依赖
POM 文件如下:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>springboot-mybatis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-mybatis</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<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>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
2. 配置 MySQL 和 MyBatis
application.yml 配置文件如下:
# 配置 MySQL
spring:
datasource:
url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# 配置 MyBatis
mybatis:
mapper-locations: classpath:mapper/*
type-aliases-package: com.example.entity
configuration:
map-underscore-to-camel-case: true
上述配置文件中,mapper-locations 用来指定 mapper 文件的门路;type-aliases-package 用来设置别名,它的作用是让 MyBatis 扫描咱们自定义的实体类,即 ‘com.example.entity’ 包下的所有类,这些类都会被注册到 TYPE_ALIASES 容器,这样在 mapper 文件中能够间接应用非限定类名来作为它的别名,如 ‘com.example.entity.User’ 可应用别名 ‘User’ 代替;map-underscore-to-camel-case 为 true 时示意开启驼峰命名主动映射,如将 user_name 映射为 userName。
3. 编写实体类
本文以 User 类为例:
package com.example.entity;
import lombok.Data;
import java.util.Date;
/**
* @Author john
* @Date 2021/11/14
*/
@Data
public class User {
private long id;
private String userName;
private int age;
private String address;
private Date createTime;
private Date updateTime;
}
User 类中封装了用户的 id、姓名、年龄、地址、创立工夫以及批改工夫等信息。
4. 编写 Mapper 类和 mapper 文件
首先编写 UserMapper 接口:
package com.example.mapper;
import com.example.entity.User;
/**
* @Author john
* @Date 2021/11/16
*/
public interface UserMapper {void insertUser(User user);
User findUserById(long id);
}
接口中定义了两个办法,insertUser 用来向数据表中插入一条记录;findUserById 用来通过 id 查问 User。
上述操作实现后,咱们在 resources 文件夹中创立 mapper/user-mapper.xml 文件(文件门路在上述配置文件 application.yml 中设置)。mapper 文件的内容如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper">
<sql id="insertFields">
user_name, age, address, gmt_create, gmt_modified
</sql>
<sql id="selectFields">
id, user_name, age, address, gmt_create, gmt_modified
</sql>
<resultMap id="UserMap" type="User">
<result column="id" jdbcType="INTEGER" property="id"/>
<result column="user_name" jdbcType="VARCHAR" property="userName"/>
<result column="age" jdbcType="INTEGER" property="age"/>
<result column="address" jdbcType="VARCHAR" property="address"/>
<result column="gmt_create" jdbcType="DATE" property="createTime" />
<result column="gmt_modified" jdbcType="DATE" property="updateTime" />
</resultMap>
<select id="findUserById" parameterType="Long" resultMap="UserMap">
select
<include refid="selectFields"></include>
from user
where id = #{id}
</select>
<insert id="insertUser" parameterType="User" keyProperty="id">
insert into user (<include refid="insertFields"></include>)
values(#{userName}, #{age}, #{address}, UTC_TIMESTAMP(), UTC_TIMESTAMP())
</insert>
</mapper>
mapper 文件须要与 Mapper 接口对应:Mapper 接口的全限定名,对应 mapper 文件的 namespace 值;接口的办法名,对应 mapper 文件 Statement 的 id 值;办法的参数,就是传递给 SQL 的参数;办法的返回值就是 SQL 返回的数据。
parameterType 和 resultType(本试验中未应用)别离用来指定参数和返回值的类型,因为咱们在配置文件中启用了别名,所以 parameterType 和 resultType 能够间接设置为 ‘User’ 或 ‘user’,而非全限定名 ‘com.example.entity.User’。对于别名的设置还有其余几种办法,这个咱们在后文探讨。
MyBatis 中 别名不辨别大小写。
mapper 文件中还有一个要害标签 resultMap,resultMap 次要用来创立自定义的映射关系。以查问为例,MyBatis 的映射规定是:依据查问到的列名找到 POJO 对应的属性名,而后调用该属性的 setter 办法进行赋值。本试验中,user 表的 id 会主动映射为 User 对象的 id,因为字段名和属性名是完全一致的;user 表的 user_name 也会主动映射为 User 对象的 userName,因为咱们开启了驼峰式命名映射。然而 gmt_create 不会映射到 createTime,因为字段名和属性名既不完全一致,也不合乎驼峰式命名映射的规定。所以这里咱们应用 resultMap 来创立新的映射关系,将 gmt_create 和 gmt_modified 别离映射到 createTime 和 updateTime,而后再将 resultType 替换为 resultMap(如果不须要自定义映射,本试验中的 resultMap=’UserMap’ 可替换为 resultType=’User’)。resultMap 还有一些其余性能,对于 resultMap 的应用办法能够参考我的另一篇博客
另外,本试验中,resultMap 标签也能够定义为:
<resultMap id="UserMap" type="User">
<result column="gmt_create" jdbcType="DATE" property="createTime" />
<result column="gmt_modified" jdbcType="DATE" property="updateTime" />
</resultMap>
因为其余字段会主动映射,不须要额定书写。
TODO
5. 编写 Service
创立 UserService:
package com.example.service;
import com.example.entity.User;
import com.example.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @Author john
* @Date 2021/11/16
*/
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public void insertUser(User user) {userMapper.insertUser(user);
}
public User findUserById(long id) {return userMapper.findUserById(id);
}
}
在 UserService 中注入 UserMapper 对象,并调用 UserMapper 的 insertUser()/findUserById() 办法来增加 / 查问 User。
为了可能失常注入 UserMapper 对象,咱们还须要再启动类上增加 @MapperScan 注解,用来指定 Mapper 接口的门路:
package com.example;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.mapper")
public class SpringbootMybatisApplication {public static void main(String[] args) {SpringApplication.run(SpringbootMybatisApplication.class, args);
}
}
上述代码中咱们指定 Mapper 接口的门路为 ‘com.example.mapper’ 包,该包下的所有 Mapper 接口都会被扫描。
除了在启动类上增加 @MapperScan 注解外,还能够在 Mapper 接口上间接增加 @Mapper 注解,这种办法绝对比拟麻烦,因为理论中咱们可能会有多个 Mapper 接口,这样就须要增加多个注解。
6. 创立 user 表
user 表字段设计如下(设置 id 自增):
7. 测试
编写测试接口:
package com.example;
import com.example.entity.User;
import com.example.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SpringbootMybatisApplicationTests {
@Autowired
private UserService service;
@Test
public void addUser(){User user = new User();
user.setUserName("John");
user.setAge(24);
user.setAddress("BUPT");
service.insertUser(user);
}
@Test
public void findUser(){System.out.println(service.findUserById(1));
}
}
首先执行 addUser() 办法,执行胜利后查问数据表,失去如下信息:
而后执行 findUser() 办法,执行后果如下:
至此,SpringBoot 整合 MyBatis 测试胜利!
8. MyBatis 设置别名的其余形式
形式一:在配置文件 application.yml 中增加配置。
map-underscore-to-camel-case: true
本试验中就应用此种形式(简略不便),默认状况下实体类的别名为其类名(严格来说是首字母小写的非限定类名,但别名不辨别大小写,所以 User、user、uSer 的成果都是雷同的),能够自定义别名吗,比方设置别名为 ‘hello’?当然能够,形式二介绍结束后咱们再探讨。
形式二:应用 MyBatis 的配置文件 filename.xml。
首先在 yml 文件中设置 MyBatis 配置文件的门路:
# 配置 MyBatis
mybatis:
mapper-locations: classpath:mapper/*
type-aliases-package: com.example.entity
config-location: classpath:mybatis/mybatis-config.xml #MyBatis 配置文件
而后在 resource 文件夹下创立 MyBatis 的配置文件 mapper/mybatis-config.xml(门路和文件名在 config-location 中设置),配置文件内容如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<typeAliases>
<package name="com.example.entity"/>
</typeAliases>
</configuration>
setting 标签中能够设置开启驼峰命名映射,其成果与在 yml 文件中配置 map-underscore-to-camel-case: true 是雷同的。
typeAliases 标签中,设置 package 能够让 MyBatis 扫描指定包下的实体类,其成果与在 yml 文件中配置 type-aliases-package: com.example.entity 是雷同的。
形式一和形式二实现成果是雷同的,本试验中实体类 ‘com.example.entity.User’ 可应用其别名 ‘User’ 或 ‘user’ 代替,如果心愿应用其余别名,能够搭配 @Alias 注解一起应用,即在实体类上增加该注解:
package com.example.entity;
import lombok.Data;
import org.apache.ibatis.type.Alias;
import java.util.Date;
/**
* @Author john
* @Date 2021/11/14
*/
@Data
@Alias("hello")
public class User {
private long id;
private String userName;
private int age;
private String address;
private Date createTime;
private Date updateTime;
}
这里咱们设置 User 类的别名为 ‘hello’,这样在 user-mapper.xml 文件中,将 type、parameterType 以及 resultType 替换为 ‘hello’,程序仍可失常运行,但此时如果持续应用 ‘User’ 或者 ‘user’,则会报别名解析谬误,因为 @Alias 注解会使默认的别名变得有效(形式一和形式二都可搭配 @Alias 注解一起应用)。
形式三:在 MyBatis 的配置文件中自定义别名。
与形式二类似,只不过这次咱们不应用 package 标签,而是应用 typeAlias 标签:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<typeAliases>
<typeAlias type="com.example.entity.User" alias="User"/>
<!-- <package name="com.example.entity"/>-->
</typeAliases>
</configuration>
应用 typeAlias 标签能够帮忙咱们 DIY 别名,且不须要应用注解 @Alias。应用此种形式定义别名时,如果有多个实体类,那么就须要为每个类都设置一个别名,较为繁琐。
值得注意的是,如果咱们曾经实现了形式一或形式二,那么咱们仍能够应用形式三增加别名,也就是说如果没有配置 @Alias 注解,那么 User 类的别名能够是默认的 ‘User’ 或形式三 DIY 的别名;如果配置了 @Alias 注解,那么 User 类的别名能够是 @Alias 指定的别名或形式三 DIY 的别名。
欢送批评指正!!!