当前位置:   article > 正文

Spring Boot 整合 MyBatis

Spring Boot 整合 MyBatis

ORM 框架的本质是简化操作数据库的编码工作,常用的框架有两个,一个是可以灵活执行动态 SQL 的 MyBatis;一个是崇尚不用写 SQL 的 Hibernate。前者互联网行业用的多,后者传统行业用的多。

Hibernate 的特点是所有的 SQL 通过 Java 代码生成,发展到最顶端的就是 Spring Data JPA,基本上根据方法名就可以生成对应的 SQL 了。gennerator

MyBatis 早些时候用起来比较繁琐,需要各种配置文件,需要实体类和 DAO 的映射关联,经过不断地演化和改进,可以通过 gennerator自 动生成实体类、配置文件和 DAO 层代码,简化了不少开发工作。

随着 MyBatis-Plus 的出现,又进一步加速了 MyBatis 的发展。经过 MyBatis-Plus 的增强,开发者只需要简单的配置,就可以快速进行单表的 CRUD 操作;同时,MyBatis-Plus又提供了代码生成、自动分页、逻辑删除、自动填充等丰富功能,进一步简化了开发工作。

整合 MyBatis

第一步,在 pom.xml 文件中引入 starter。

  1. <dependency>
  2. <groupId>org.mybatis.spring.boot</groupId>
  3. <artifactId>mybatis-spring-boot-starter</artifactId>
  4. <version>2.2.2</version>
  5. </dependency>

第二步,在 application.yml 文件中添加数据库连接配置

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 123**
    url: jdbc:mysql://localhost:3306/codingmore-mybatis?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false

第三步,导入 SQL 文件。

第四步,新建 User.java 实体类。

  1. @Data
  2. @Builder
  3. public class User {
  4. private Integer id;
  5. private Integer age;
  6. private String name;
  7. private String password;
  8. @Tolerate
  9. User() {}
  10. }

这里使用了 lombok 的

  • @Data 注解自动生成 getter/setter
  • @Builder 生成链式调用
  • 由于 @Data和@Builder 配合使用的时候会导致无参构造方法丢失,所以我们主动声明了无参构造方法,并使用 @Tolerate 注解来告诉 lombok 请允许我们的无参构造方法存在(没有无参构造方法的时候会导致 ORM 映射出错)

第五步,新建 UserMapper.java 接口:

  1. public interface UserMapper {
  2. @Select("SELECT * FROM user")
  3. List<User> getAll();
  4. @Select("SELECT * FROM user WHERE id = #{id}")
  5. User getOne(Integer id);
  6. @Insert("INSERT INTO user(name,password,age) VALUES(#{name}, #{password}, #{age})")
  7. void insert(User user);
  8. @Update("UPDATE user SET name=#{name},password=#{password},age=#{age} WHERE id =#{id}")
  9. void update(User user);
  10. @Delete("DELETE FROM user WHERE id =#{id}")
  11. void delete(Integer id);
  12. }

第六步,在启动类 CodingmoreMybatisApplication 上添加 @MapperScan 注解来扫描 mapper。

  1. @SpringBootApplication
  2. @MapperScan
  3. public class CodingmoreMybatisApplication {
  4. public static void main(String[] args) {
  5. SpringApplication.run(CodingmoreMybatisApplication.class, args);
  6. }
  7. }

  1. @Autowired
  2. private UserMapper userMapper;
  3. @Test
  4. void testInsert() {
  5. userMapper.insert(User.builder().age(18).name("张二").password("123456").build());
  6. userMapper.insert(User.builder().age(18).name("张三").password("123456").build());
  7. userMapper.insert(User.builder().age(18).name("张四").password("123456").build());
  8. log.info("查询所有:{}",userMapper.getAll().stream().toArray());
  9. }
  10. @Test
  11. List<User> testQuery() {
  12. List<User> all = userMapper.getAll();
  13. // log.info("查询所有:{}");
  14. // for (User user : all){
  15. // log.info(all.toString());
  16. // }
  17. return all;
  18. }
  19. @Test
  20. public void testqurqy11(){
  21. List<User> users = testQuery();
  22. for ( User user : users){
  23. log.info(String.valueOf(user));
  24. }
  25. }
  26. @Test
  27. void testUpdate() {
  28. //这里的id一定要输入存在的,写死的
  29. User one = userMapper.getOne(2);
  30. log.info("更新前{}", one);
  31. if (one == null){
  32. log.info("查询id为2的用户不存在");
  33. }
  34. one.setPassword("1123456");
  35. userMapper.update(one);
  36. log.info("更新后{}", userMapper.getOne(2));
  37. }
  38. @Test
  39. void testDelete() {
  40. log.info("删除前{}", userMapper.getAll().toArray().length);
  41. userMapper.delete(4);
  42. log.info("删除后{}", userMapper.getAll().toArray().length);
  43. }

极简 xml 版本

极简 xml 版本比较适合更加复杂的 SQL,接口层只定义空的方法,然后在 xml 中编写对应的 SQL。

第一步,新建 PostMapper。

  1. public interface PostMapper {
  2. List<Posts> getAll();
  3. Posts getOne(Long id);
  4. void insert(Posts post);
  5. void update(Posts post);
  6. void delete(Long id);
  7. }

第二步,在 resources 目录下新建 PostMapper.xml 文件。

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3. <mapper namespace="top.codingmore.mapper.PostMapper">
  4. <resultMap id="BaseResultMap" type="top.codingmore.entity.Posts">
  5. <id column="posts_id" property="postsId"/>
  6. <result column="post_author" property="postAuthor"/>
  7. <result column="post_content" property="postContent"/>
  8. <result column="post_title" property="postTitle"/>
  9. </resultMap>
  10. <sql id="Base_Column_List">
  11. posts_id, post_author, post_content, post_title
  12. </sql>
  13. <select id="getAll" resultMap="BaseResultMap">
  14. select
  15. <include refid="Base_Column_List" />
  16. from posts;
  17. </select>
  18. <select id="getOne" parameterType="java.lang.Long" resultMap="BaseResultMap" >
  19. SELECT
  20. <include refid="Base_Column_List" />
  21. FROM users
  22. WHERE id = #{id}
  23. </select>
  24. <insert id="insert" parameterType="top.codingmore.entity.Posts">
  25. insert into
  26. posts
  27. (post_author,post_content,post_title)
  28. values
  29. (#{postAuthor},#{postContent},#{postTitle});
  30. </insert>
  31. <update id="update" parameterType="top.codingmore.entity.Posts">
  32. update
  33. posts
  34. set
  35. <if test="postAuthor != null">post_author=#{postAuthor},</if>
  36. <if test="postContent != null">post_content=#{postContent},</if>
  37. post_title=#{postTitle}
  38. where id=#{id}
  39. </update>
  40. <delete id="delete">
  41. delete from
  42. posts
  43. where
  44. id=#{id}
  45. </delete>
  46. </mapper>

接口中方法对应的 SQL 直接写在 xml 文件中

也可以看文件放在和 PostMapper.java 接口同级的目录下,但是这样会带来一个问题,就是 Maven 打包的时候默认会忽略 xml 文件,所以为了避免这种情况发生,我们需要在 pom.xml 文件中添加配置:

  1. <build>
  2. <resources>
  3. <resource>
  4. <directory>src/main/java</directory>
  5. <includes>
  6. <include>**/*.xml</include>
  7. </includes>
  8. </resource>
  9. <resource>
  10. <directory>src/main/resources</directory>
  11. </resource>
  12. </resources>
  13. </build>

如果直接放在 resources 目录下,就不用担心打包时被忽略了,但放在 resources 目录下不会被  MyBatis 自动扫描到,所以需要在 application.yml 配置文件中告诉 MyBatis 具体的扫描路径:

  1. mybatis:
  2. mapper-locations: classpath:mapper/*.xml

第三步,在测试类中添加测试方法:

  1. @Test
  2. void testPostInsert() {
  3. postMapper.insert(Posts.builder()
  4. .postAuthor(1L)
  5. .postTitle("藏三")
  6. .postContent("123456")
  7. .build());
  8. log.info("查询所有:{}",postMapper.getAll().stream().toArray());
  9. }
  10. @Test
  11. List<Posts> testPostQuery() {
  12. List<Posts> all = postMapper.getAll();
  13. log.info("查询所有:{}",all.stream().toArray());
  14. return all;
  15. }
  16. @Test
  17. void testPostUpdate() {
  18. Posts one = postMapper.getOne(1L);
  19. log.info("更新前{}", one);
  20. one.setPostContent("藏三是沙比");
  21. postMapper.update(one);
  22. log.info("更新后{}", postMapper.getOne(1L));
  23. }
  24. @Test
  25. void testPostDelete() {
  26. log.info("删除前{}", postMapper.getAll().toArray());
  27. postMapper.delete(1L);
  28. log.info("删除后{}", postMapper.getAll().toArray());
  29. }

可以看得出,注解版比较适合简单的 SQL 语句,一旦遇到比较复杂的 SQL 查询,比如说多表查询,xml 中写 SQL 语句会容易实现。

实战项目中有一个分页查询(首页展示,需要查询标签、作者名、文章信息等等),涉及到多张表,那么此时,xml 版本就更适合。

 

  1. <select id="findByPageWithTagPaged" resultMap="PostsVoResultMapWithTagList">
  2. SELECT a.*, pt.description, ptr.post_tag_id
  3. FROM (
  4. SELECT
  5. <include refid="Base_Column_List_No_Content" />,
  6. b.term_taxonomy_id,
  7. c.user_nicename
  8. FROM
  9. posts a
  10. LEFT JOIN term_relationships b ON a.posts_id = b.term_relationships_id
  11. LEFT JOIN users c ON a.post_author = c.users_id
  12. WHERE 1=1
  13. <if test="searchTagId != null">
  14. and a.posts_id in (select post_id from post_tag_relation where post_tag_id=#{searchTagId})
  15. </if>
  16. and ${ew.sqlSegment}
  17. LIMIT #{pageStart}, #{pageSize}
  18. ) a
  19. LEFT JOIN post_tag_relation ptr on a.posts_id = ptr.post_id
  20. LEFT JOIN post_tag pt on pt.post_tag_id = ptr.post_tag_id
  21. </select>

细心的小伙伴应该可以看到 ${ew.sqlSegment} 这样的表达式,它属于 MyBatis-Plus 中的内容。

通过 MyBatis-Plus 增强

MyBatis 属于半自动的 ORM 框架,实现一些简单的 CRUD 也是需要编写 SQL 语句,那如果想省掉这些步骤的话选择国人开源的 MyBatis-Plus(简称 MP)

MP 提供了诸多优秀的特性,比如说:

  • 强大的 CRUD 操作:内置了通用的 mapper、service,可通过少量的配置实现大部分常用的 CRUD,不用再编写 SQL 语句。
  • 支持主键自动生成
  • 支持 ActiveRecord 模式:实体类只需继承 Model 类即可进行强大的 CRUD 操作
  • 代码生成器:可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码
  • 内置分页插件
  • 内置性能分析插件:可输出 SQL 语句以及其执行时间

我们直接进入实战。

第一步,在 pom.xml 文件中添加 MyBatis-Plus 的 starter。

  1. <dependency>
  2. <groupId>com.baomidou</groupId>
  3. <artifactId>mybatis-plus-boot-starter</artifactId>
  4. <version>3.4.2</version>
  5. </dependency>

第二步,新建 PostTag 实体类。

  1. @Data
  2. public class PostTag {
  3. private Long postTagId;
  4. private String description;
  5. }

对应的数据库表为 post-tag

可以看得出,类名 PostTag,字段名 postTagId 和数据库表 post_tag、字段名 post_tag_id 并不一致,但 mp 自动帮我们做了映射关联。

第二步,新建 PostTagMapper 继承 BaseMapper,继承该接口后,无需编写 mapper.xml 文件,即可获得CRUD功能

public interface PostTagMapper extends BaseMapper<PostTag> {}

BaseMapper里提供的方法如下:

第三步,在测试类中添加查询方法。

  1. @Test
  2. void testMybatisPlus() {
  3. List<PostTag> list = postTagMapper.selectList(null);
  4. list.forEach( e -> log.info("Mybatis-Plus 查询{}",e));
  5. }

selectList() 方法的参数为 MP 内置的条件封装器 Wrapper,不填写就是无任何条件,查询全部。来看一下查询结果:

总结

从整体上来讲,MyBatis 可以分为三层。

  • 接口层:SqlSession 是我们平时与 MyBatis 完成交互的核心接口;
  • 核心层:SqlSession 执行的方法,底层需要经过配置文件的解析、SQL 解析,以及执行 SQL 时的参数映射、SQL 执行、结果集映射等;
  • 支持层:核心层的功能实现,是基于底层的各个模块,共同协调完成的。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/341305
推荐阅读
相关标签
  

闽ICP备14008679号