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 文件如下:
<code class="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 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 配置文件如下:
<code class="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 类为例:
<code class="Java">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 接口:
<code class="Java">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 文件的内容如下:
<code class="XML"><?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 标签也能够定义为:
<code class="XML"><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:
<code class="Java">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 接口的门路:
<code class="Java">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. 测试
编写测试接口:
<code class="Java">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 中增加配置。
<code class="YML">map-underscore-to-camel-case: true
本试验中就应用此种形式(简略不便),默认状况下实体类的别名为其类名(严格来说是首字母小写的非限定类名,但别名不辨别大小写,所以 User、user、uSer 的成果都是雷同的),能够自定义别名吗,比方设置别名为 ‘hello’?当然能够,形式二介绍结束后咱们再探讨。
形式二:应用 MyBatis 的配置文件 filename.xml。
首先在 yml 文件中设置 MyBatis 配置文件的门路:
<code class="YML"># 配置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 中设置),配置文件内容如下:
<code class="XML"><?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 注解一起应用,即在实体类上增加该注解:
<code class="Java">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 标签:
<code class="XML"><?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 的别名。
欢送批评指正!!!