Spring Boot2 系列教程 (九) | SpringBoot 整合 Mybatis
前言
如题,今天介绍 SpringBoot 与 Mybatis 的整合以及 Mybatis 的使用,本文通过注解的形式实现。
什么是 Mybatis
MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以对配置和原生 Map 使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java 对象)映射成数据库中的记录。
优点:
- 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个 jar 文件+配置几个 sql 映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
- 灵活:mybatis 不会对应用程序或者数据库的现有设计强加任何影响。 sql 写在 xml 里,便于统一管理和优化。通过 sql 基本上可以实现我们不使用数据访问框架可以实现的所有功能,或许更多。
- 解除 sql 与程序代码的耦合:通过提供 DAL 层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql 和代码的分离,提高了可维护性。
- 提供映射标签,支持对象与数据库的 orm 字段关系映射
- 提供对象关系映射标签,支持对象关系组建维护
- 提供xml标签,支持编写动态 sql。
缺点:
- 编写 SQL 语句时工作量很大,尤其是字段多、关联表多时,更是如此。
- SQL 语句依赖于数据库,导致数据库移植性差,不能更换数据库。
- 框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改。
- 二级缓存机制不佳
准备工作
- IDEA
- JDK1.8
- SpringBoot 2.1.3
sql 语句,创建表,插入数据:
CREATE TABLE `student` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL, `age` double DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; INSERT INTO `student` VALUES ('1', 'aaa', '21'); INSERT INTO `student` VALUES ('2', 'bbb', '22'); INSERT INTO `student` VALUES ('3', 'ccc', '23');
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> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.nasus</groupId> <artifactId>mybatis</artifactId> <version>0.0.1-SNAPSHOT</version> <name>mybatis</name> <description>mybatis Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <!-- 启动 web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- mybatis 依赖 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.0.0</version> </dependency> <!-- mysql 连接类 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!-- druid 数据库连接池--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.9</version> </dependency> <!-- lombok 插件 用于简化实体代码 --> <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> <dependency> <groupId>org.hibernate.javax.persistence</groupId> <artifactId>hibernate-jpa-2.1-api</artifactId> <version>1.0.0.Final</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
application.yaml 配置文件
spring: datasource: url: jdbc:mysql://localhost:3306/test username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver
实体类
import javax.persistence.GeneratedValue; import javax.persistence.Id; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class Student { @Id @GeneratedValue private Integer id; private String name; private Integer age; }
使用了 lombok 简化了代码。
dao 层
import com.nasus.mybatis.domain.Student; import java.util.List; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; @Mapper public interface StudentMapper { @Insert("insert into student(name, age) values(#{name}, #{age})") int add(Student student); @Update("update student set name = #{name}, age = #{age} where id = #{id}") int update(@Param("name") String name, @Param("age") Integer age, @Param("id") Integer id); @Delete("delete from student where id = #{id}") int delete(int id); @Select("select id, name as name, age as age from student where id = #{id}") Student findStudentById(@Param("id") Integer id); @Select("select id, name as name, age as age from student") List<Student> findStudentList(); }
这里有必要解释一下,@Insert 、@Update、@Delete、@Select 这些注解中的每一个代表了执行的真实 SQL。 它们每一个都使用字符串数组 (或单独的字符串)。如果传递的是字符串数组,它们由每个分隔它们的单独空间串联起来。这就当用 Java 代码构建 SQL 时避免了“丢失空间”的问题。 然而,如果你喜欢,也欢迎你串联单独 的字符串。属性:value,这是字符串 数组用来组成单独的 SQL 语句。
@Param 如果你的映射方法的形参有多个,这个注解使用在映射方法的参数上就能为它们取自定义名字。若不给出自定义名字,多参数(不包括 RowBounds 参数)则先以 "param" 作前缀,再加上它们的参数位置作为参数别名。例如 #{param1},#{param2},这个是默认值。如果注解是 @Param("id"),那么参数就会被命名为 #{id}。
service 层
import com.nasus.mybatis.domain.Student; import java.util.List; public interface StudentService { int add(Student student); int update(String name, Integer age, Integer id); int delete(Integer id); Student findStudentById(Integer id); List<Student> findStudentList(); }
实现类:
import com.nasus.mybatis.dao.StudentMapper; import com.nasus.mybatis.domain.Student; import com.nasus.mybatis.service.StudentService; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class StudentServiceImpl implements StudentService { @Autowired private StudentMapper studentMapper; /** * 添加 Student * @param name * @param age * @return */ @Override public int add(Student student) { return studentMapper.add(student); } /** * 更新 Student * @param name * @param age * @param id * @return */ @Override public int update(String name, Integer age, Integer id) { return studentMapper.update(name,age,id); } /** * 删除 Student * @param id * @return */ @Override public int delete(Integer id) { return studentMapper.delete(id); } /** * 根据 id 查询 Student * @param id * @return */ @Override public Student findStudentById(Integer id) { return studentMapper.findStudentById(id); } /** * 查询所有的 Student * @return */ @Override public List<Student> findStudentList() { return studentMapper.findStudentList(); } }
controller 层构建 restful API
import com.nasus.mybatis.domain.Student; import com.nasus.mybatis.service.StudentService; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/Student") public class StudentController { @Autowired private StudentService studentService; @PostMapping("") public int add(@RequestBody Student student){ return studentService.add(student); } @PutMapping("/{id}") public int updateStudent(@PathVariable("id") Integer id, @RequestParam(value = "name", required = true) String name, @RequestParam(value = "age", required = true) Integer age){ return studentService.update(name,age,id); } @DeleteMapping("/{id}") public void deleteStudent(@PathVariable("id") Integer id){ studentService.delete(id); } @GetMapping("/{id}") public Student findStudentById(@PathVariable("id") Integer id){ return studentService.findStudentById(id); } @GetMapping("/list") public List<Student> findStudentList(){ return studentService.findStudentList(); } }
测试结果
其他接口已通过 postman 测试,无问题。
源码下载:github 地址
后语
以上为 SpringBoot 实战 (九) | 整合 Mybatis 的教程,除了注解方式实现以外,Mybatis 还提供了 XML 方式实现。想了解更多用法请移步官方文档。
如果看到这里,说明你喜欢这篇文章,请转发、点赞。微信搜索「一个优秀的废人」,关注后回复「1024」送你一套完整的 java 教程。