03-SpringBoot工程中MyBatis应用实践

MyBatis环境初始化

概述

Mybatis是一个优秀的持久层(数据层)框架,底层基于JDBC实现与数据库的交互。并在JDBC操作的基础上做了封装和优化,它借助灵活的动态SQL,参数及结果集的映射方式,更好的适应了当前互联网技术的发展。Mybatis框架的简单应用架构,如图所示:

在当今的互联网应用中项目,mybatis框架通常会由spring框架进行资源整合,作为数据层技术实现数据交互操作。

创建项目模块

在spr-boot工程下创建项目moudle,名字为spr-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 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.3.2.RELEASE</version>
	</parent>
	
	<groupId>com.cy</groupId>
	<artifactId>spr-mybatis</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>03-mybatis</name>
	<description>Demo project for Spring Boot</description>
	
	<properties>
		<java.version>1.8</java.version>
	</properties>
</project>

添加项目依赖

mysql数据库驱动依赖,例如:

<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<scope>runtime</scope>
</dependency>

添加mybatis依赖(参考官方),例如:

<dependency>
	<groupId>org.mybatis.spring.boot</groupId>
	<artifactId>mybatis-spring-boot-starter</artifactId>
	<version>2.2.0</version>
</dependency>

我们添加了mybatis依赖以后,spring框架启动时会对mybatis进行自动配置。例如SqlSessionFactory工厂对象的创建。

Mybatis简易配置实现。

假如需要对mybatis框架进行简易配置,可以创建并打开application.properties文件,在此文件中进行基本配置(可选,暂时可以不配置),例如:


#设置连接数据库的url、username、password,这三部分不能省略
spring.datasource.url=jdbc:mysql://localhost:3306/jy-blog?serverTimezone=Asia/Shanghai&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=root
#设置池中最小连接数
spring.datasource.hikari.minimum-idle=5
#设置池中最大连接数
spring.datasource.hikari.maximum-pool-size=15
#设置事务自动提交
spring.datasource.hikari.auto-commit=true
#设置空间链接多长时间后被释放
spring.datasource.hikari.idle-timeout=30000
#设置连接池的名字
spring.datasource.hikari.pool-name=JyHikariCP
#设置连接超时时间(客户端一直请求不到连接时,在这个时间以后会抛出连接超时)
spring.datasource.hikari.connection-timeout=30000
#连接测试
spring.datasource.hikari.connection-test-query=SELECT 1


mybatis.configuration.default-statement-timeout=30
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.mapper-locations=classpath:/mapper/*.xml

配置mybatis中的sql日志的输出:(com.cy为我们写的项目的根包)

logging.level.com.spring=DEBUG

创建项目启动类

创建项目启动类,代码如下:

package com.spring;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyBatisApplication {//Application.class
  public static void main(String[] args) {//Main Thread
    SpringApplication.run(MyBatisApplication .class, args);
  }
}

环境测试代码实现

在src/test/java目录中添加测试类,对mybatis框架整合进行基本测试,代码如下:

package com.spring;

import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

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

@SpringBootTest
public class ConnectionTests {
    @Autowired
    private DataSource dataSource;
    @Test
    void testGetConnection() throws SQLException {
        Connection conn = dataSource.getConnection();
        System.out.println(conn);
    }
}
package com.spring;

@SpringBootTest
public class SqlSessionTests {
	   @Autowired
	   private SqlSession sqlSession;
	   @Test
	   public void testGetConnection() {
		   Connection conn=sqlSession.getConnection();
		   System.out.println("connection="+conn);
	   }
}

在SpringBoot脚手架工程中,Spring框架会基于MyBatis框架底层配置,创建SqlSessionFactory对象,然后再通过此工厂对象创建SqlSession,最后基于Springku框架为测试类注入SqlSession对象,接下来,我们可以通过SqlSession对象实现与数据库的会话了。如图所示:
在这里插入图片描述

课堂练习

基于mybatis实现一个简易的查询映射,从数据库查询一条记录存储到map对象。
第一步:定义sql映射文件(这个文件中按照mybatis语法结构定义我们的sql映射元素,参考官方mybatis.org/mybatis-3)

在项目的resources目录下创建mapper目录,并在此目录中创建NoticeEgMapper.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.spring.dao.NoticeMapper">
    <!--这里的每个sql元素都会在服务启动时进行解析,并将解析的结果存储到MappedStatement对象-->
    <select id="selectById" resultType="map">
        select *
        from tb_sys_notices
        where id = #{id}
    </select>
</mapper>

第二步:确定springboot配置文件(application.properties)中指定了sql映射文件的路径

mybatis.mapper-locations=classpath:/mapper/*.xml

第三步:编写测试类,基于sqlSession对象查询数据库数据。

在项目的test目录下创建单元测试类,进行功能测试,代码如下:

package com.spring;

import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.sql.Connection;

@SpringBootTest
public class SqlSessionTests {
    /**
     * SqlSession是MyBatis官方提供的一个与数据库进行会话的接口。
     * 在springboot工程中假如添加了mybatis-spring-boot-starter依赖,
     * 项目中就有了这个接口,并且在服务启动时可以为我们创建一个SqlSession
     * 对象(?)
     */
    @Autowired
    private SqlSession sqlSession;//SqlSessionTemplate

    @Test
    void testGetConnection(){
        Connection connection = sqlSession.getConnection();//底层还是通过DataSource对象获取连接
        System.out.println(connection);
    }

    @Test
    void testSelectNotice(){
        //1.定义statement对象(命名空间+元素id),系统底层会基于这个key找到sql
        String statement="com.spring.dao.NoticeMapper.selectById";
        //2.基于sqlSession实现与数据库的会话,这里表示查询一条记录
        Object result = sqlSession.selectOne(statement,1);
        System.out.println(result);
        System.out.println(result.getClass());
    }
}

系统公告综合实践

业务描述

基于SpringBoot脚手架工程对MyBatis框架进行整合,然后实现对通知模块数据的基本操作,通过这个实践帮助我们在业务的基础上掌握mybatis的基本应用(例如API的应用,工作机制,动态SQL-基于条件动态构建sql语句)

Pojo类设计

创建Notice类,借助此类对象封装公告(通知)数据。

package com.spring.pojo;
public class Notice {
    private Long id;
    private String title;
    private String type;
    private String content;
    private String status;
    private Long userId;
    private Date createdTime;
    private Date modifiedTime;
    private String remark;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public Date getCreatedTime() {
        return createdTime;
    }

    public void setCreatedTime(Date createdTime) {
        this.createdTime = createdTime;
    }

    public Date getModifiedTime() {
        return modifiedTime;
    }

    public void setModifiedTime(Date modifiedTime) {
        this.modifiedTime = modifiedTime;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }

    @Override
    public String toString() {//alt+insert
        return "Notice{" +
                "id=" + id +
                ", title='" + title + '\'' +
                ", type='" + type + '\'' +
                ", content='" + content + '\'' +
                ", status='" + status + '\'' +
                ", userId=" + userId +
                ", createdTime=" + createdTime +
                ", modifiedTime=" + modifiedTime +
                ", remark='" + remark + '\'' +
                '}';
    }

Dao接口及方法

第一步:定义通告业务数据层接口及业务方法。借助此类型的对象基于MyBatis技术实现与数据库的交互。

package com.spring.dao;

@Mapper
public interface NoticeDao {
    /**
     * 基于id查询notice对象
     * @param id 公告唯一标识id
     * @return 基于id查询到结果
     * 建议:简单sql映射语句可以直接写到接口方法上,复杂sql还是推荐写到xml映射文件
     */
    @Select("select * from tb_sys_notices where id=#{id}")
    Notice selectById(Long id);

    /**
     * 基于条件查询公告信息
     * @param notice 用于封装查询参数
     * @return 基于查询条件查询到结果
     */
    List<Notice> selectNotices(Notice notice);

    /**
     * 基于id删除公告信息
     * @param id
     * @return 删除了几行
     * 说明:在jdk8之前,对于接口方法,假如参数有多个或者参数是数组,是不可以
     * 直接在sql映射文件中使用参数名的,需要通过@Param这个注解定义参数名,然后
     * 在sql映射语句中使用@Param注解中的名字获取参数数据。对于数组而言在sql映射
     * 中可以直接使用array进行接收也可以。
     */
    int deleteById(@Param("ids") Long... id);//array
    
    /**
     * 持久化notice对象数据
     * @param notice (封装了要更新的数据)
     * @return 返回更新的行数。
     */
    int updateNotice(Notice notice);

    /**
     * 持久化notice对象数据
     * @param notice (封装了要写入的数据)
     * @return 返回写入的行数。
     */
    int insertNotice(Notice notice);

}

其中:@Mapper是由MyBatis框架中定义的一个描述数据层接口的的注解(所有的注解只起到一个描述性的作用),当系统启动时,会对启动类所在包以及子包中的类进行扫描,假如发现接口上有@Mapper注解(mybatis提供),系统底层会基于接口创建其实现类(借助反射包中Proxy类进行创建)的对象,并将对象交给spring管理。在实现类的内部,底层会又基于sqlsession对象(SqlSessionTemplate)实现数据访问和操作。

第二步:创建NoticeDao接口对应的SQL映射文件,名字为NoticeDaoMapper.xml,存储在resources/mapper目录下,同时定义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.spring.dao.NoticeDao">
  
</mapper>

第三步:在映射文件中添加对应的sql映射,关键代码如下:


    <!--假如Dao接口方法上写了sql映射,映射文件中就不需要再写sql映射了-->

    <!--
    <select id="selectById" resultType="com.spring.pojo.Notice">
        select id,title,type,content,status,user_id userId,
               created_time createdTime,modified_time modifiedTime,remark
        from tb_sys_notices
        where id=#{id}
    </select>
    -->

    <!--动态sql应用(sql语句可以根据查询条件进行动态构建)-->
    <select id="selectNotices"
            parameterType="com.spring.pojo.Notice"
            resultType="com.spring.pojo.Notice">
        select id,title,type,content,status,user_id ,
               created_time,modified_time,remark
        from tb_sys_notices
        <where>
            <if test="title!=null and title!=''">
                 title like concat("%",#{title},"%")
            </if>
            <if test="status==1 or status==0">
                and status=#{status}
            </if>
        </where>
    </select>
     <!--基于元素id执行删除操作-->
    <delete id="deleteById">
          delete from tb_sys_notices
          <where>
          <choose>
              <when test="ids!=null and ids.length>0">
                  id in <!--(1,2,3,4)-->
                  <foreach collection="ids" open="(" close=")" item="id" separator=",">
                      #{id}
                  </foreach>
              </when>
              <otherwise>
                  1=2
              </otherwise>
          </choose>
          </where>
    </delete>

  <!--更新Notice对象-->
    <update id="updateNotice" parameterType="com.spring.pojo.Notice">
        update tb_sys_notices
        <set>
            <if test="status==1 or status==0">status=#{status},</if>
            <if test="content!=null and content!=''">content=#{content},</if>
            <if test="modifiedTime==null">modified_time=now(),</if>
        </set>
        where id=#{id}
    </update>

  <!-- 添加新的notice-->
    <insert id="insertNotice"  parameterType="com.spring.pojo.Notice">

         insert into tb_sys_notices
         (title,type,content,status,user_id,created_time,modified_time,remark)
         values
         (#{title},#{type},#{content},#{status},#{userId},now(),now(),#{remark})

    </insert>

单元测试实现及分析

在src/java/test目录下定义单元测试类,对NoticeDao对象进行应用测试。

package com.spring;

import com.spring.dao.NoticeDao;
import com.spring.pojo.Notice;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
public class NoticeDaoTests {

    @Autowired
    private NoticeDao noticeDao;

    @Test
    void testSelectById(){
        Notice notice = noticeDao.selectById(1L);
        System.out.println(notice);
    }
    /**
     * 基于多个条件查询notice信息
     */
    @Test
    void testSelectNotices(){
        Notice notice=new Notice();
        //notice.setTitle("title-");
        //notice.setStatus("0");
        List<Notice> notices = noticeDao.selectNotices(notice);
        for(Notice n:notices){
            System.out.println(n);
        }
    }
 @Test
    void testDeleteById(){
        int rows = noticeDao.deleteById(100L,200L);
        System.out.println(rows);
    }

    @Test
    void testUpdateNotice(){
        Notice notice = noticeDao.selectById(5L);
        notice.setContent("Content-E");
        notice.setStatus("0");
        notice.setModifiedTime(new Date());
        noticeDao.updateNotice(notice);
    }

    @Test
    void testInsertNotice(){
       Notice notice=new Notice();
       notice.setTitle("Title-X");
       notice.setContent("Content-Y");
       notice.setStatus("1");
       notice.setType("1");
       notice.setUserId(102L);
       notice.setCreatedTime(new Date());
       notice.setModifiedTime(new Date());
       noticeDao.insertNotice(notice);
    }
}

文章标签综合实践

业务描述

我们发布文章或者发布一个问题,一般都会指定一个标签(Tag),在这个实践中我们就基于标签做一个CRUD业务的实践。
通过这个业务实践,强化单表的增删改查的操作,同时掌握基于注解方式的SQL映射实现(@Select,@Insert,@Update,@Delete)。

Tag表设计

create table tb_sys_tags
(
    id bigint(20) unsigned auto_increment,
    name varchar(50) default 'java',
    remark varchar(100) default '',
    created_time datetime,
    modified_time datetime,
    primary key (id)
);

Pojo对象

创建Tag对象用于封装标签信息

package com.spring.pojo;

import java.util.Date;

/**
 * 创建一个文章标签对象
 */
public class Tag {
    private Long id;
    private String name;
    private String remark;
    private Date createdTime;
    private Date modifiedTime;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }

    public Date getCreatedTime() {
        return createdTime;
    }

    public void setCreatedTime(Date createdTime) {
        this.createdTime = createdTime;
    }

    public Date getModifiedTime() {
        return modifiedTime;
    }

    public void setModifiedTime(Date modifiedTime) {
        this.modifiedTime = modifiedTime;
    }

    @Override
    public String toString() {
        return "Tag{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", remark='" + remark + '\'' +
                ", createdTime=" + createdTime +
                ", modifiedTime=" + modifiedTime +
                '}';
    }
}

Dao接口对象

创建Dao接口封装Tag的数据访问操作。

package com.spring.dao;

import com.spring.pojo.Tag;
import org.apache.ibatis.annotations.*;

import java.util.List;

@Mapper
public interface TagDao {

    @Select("select * from tb_sys_tags")
    List<Tag> list();

    @Insert("insert into tb_sys_tags (name,remark,created_time,modified_time) " +
            "values (#{name},#{remark},#{createdTime},#{modifiedTime})")
    int insert(Tag tag);

    @Update("update tb_sys_tags set name=#{name},remark=#{remark},modified_time=#{modifiedTime} " +
            "where id=#{id}")
    int update(Tag tag);

    @Delete("delete from tb_sys_tags where id=#{id}")
    int deleteById(Long id);
}

单元测试分析与实践

编写TagDao接口的单元类,针对TagDao接口中的具体数据操作方法进行单元测试。

package com.spring;

import com.spring.dao.TagDao;
import com.spring.pojo.Tag;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.Date;
import java.util.List;

@SpringBootTest
public class TagDaoTests {
    @Autowired
    private TagDao tagDao;
     @Test
     void testInsert(){
         Tag tag=new Tag();
         tag.setName("mysql");
         tag.setRemark("mysql...");
         tag.setCreatedTime(new Date());
         tag.setModifiedTime(new Date());
         tagDao.insert(tag);
     }
     @Test
     void testList(){
         List<Tag> list = tagDao.list();
         System.out.println(list.size());
     }

    @Test
    void testUpdate(){
        Tag tag=new Tag();
        tag.setId(2L);
        tag.setName("TiDB");
        tag.setRemark("TiDB...");
        tag.setModifiedTime(new Date());
        tagDao.update(tag);
    }
    @Test
    void testDeleteById(){
       tagDao.deleteById(2L);
    }
}

博客文章综合实践

业务描述

基于需求实现文章的发布和查询,要求在发布文章时,要给文章指定标签,还有在查询文章时,将文章所有的标签也要查询出来。通过这个案例掌握mybatis中的一些更加高级应用技巧。

Article表设计

基于业务创建文章表,例如:

create table tb_sys_articles
(
    id             bigint(20)     unsigned auto_increment    comment 'ID',
    title          varchar(50)    not null          comment '标题',
    type           char(1)        not null          comment '类型(1 原创 2 转载 3翻译)',
    content        varchar(500)   default null      comment '文章内容',
    status         char(1)        default '0'       comment '状态(1审核  2通过  3关闭)',
    user_id        bigint(20)     unsigned not null comment '用户id',
    created_time   datetime                         comment '创建时间',
    modified_time  datetime                         comment '更新时间',
    remark        varchar(255)                      comment '备注',
    primary key (id)
) engine=innodb auto_increment=1 comment = '通知公告表';

基于业务创建文章、标签关系表(文章和标签是一种多对多的关系,这种关系需要一张关系表。)

create table tb_article_tags
(
    id    bigint(20)     unsigned auto_increment    comment 'ID',
    article_id bigint(20)  unsigned comment '文章 ID',
    tag_id bigint(20)  unsigned comment '标签 ID',
    created_time   datetime          comment '创建时间',
    modified_time  datetime            comment '更新时间',
    primary  key (id)
)

Pojo类的设计

package com.spring.pojo;

import java.util.Date;
import java.util.List;

public class Article {
    private Long id;
    private String title;
    private String type;
    private String status;
    private String content;
    private Long userId;
    private Date createdTime;
    private Date modifiedTime;
    private String remark;
    private List<Tag> tags;

    public List<Tag> getTags() {
        return tags;
    }

    public void setTags(List<Tag> tags) {
        this.tags = tags;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public Date getCreatedTime() {
        return createdTime;
    }

    public void setCreatedTime(Date createdTime) {
        this.createdTime = createdTime;
    }

    public Date getModifiedTime() {
        return modifiedTime;
    }

    public void setModifiedTime(Date modifiedTime) {
        this.modifiedTime = modifiedTime;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }

    @Override
    public String toString() {
        return "Article{" +
                "id=" + id +
                ", title='" + title + '\'' +
                ", type='" + type + '\'' +
                ", status='" + status + '\'' +
                ", content='" + content + '\'' +
                ", userId=" + userId +
                ", createdTime=" + createdTime +
                ", modifiedTime=" + modifiedTime +
                ", remark='" + remark + '\'' +
                ", tags=" + tags +
                '}';
    }
}

Dao接口的设计

第一步:定义ArticleDao接口及sql映射设计(对应文章表的数据操作)。

package com.spring.dao;

import com.spring.pojo.Article;
import org.apache.ibatis.annotations.Mapper;

/**
 * 定义文章dao
 */
@Mapper
public interface ArticleDao {
    int insertArticle(Article article);
    Article selectById(Long id);
}

ArticleDao接口对应的Sql映射文件ArticleDaoMapper.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.spring.dao.ArticleDao">

    <insert id="insertArticle"
            parameterType="com.spring.pojo.Article"
            useGeneratedKeys="true"
            keyProperty="id">

        insert into tb_sys_articles
        (title,type,content,status,user_id,created_time,modified_time,remark)
        values
        (#{title},#{type},#{content},#{status},#{userId},now(),now(),#{remark})

    </insert>
  <!--ResultMap是高级的ResultType,ResultMap可以自己定制映射规则-->
    <resultMap id="articleMap" type="com.spring.pojo.Article">
        <id property="id" column="id"></id>
        <result property="title" column="title"></result>
        <result property="type" column="type"></result>
        <result property="content" column="content"></result>
        <result property="status" column="status"></result>
        <result property="userId" column="user_id"></result>
        <result property="createdTime" column="created_time"></result>
        <result property="modifiedTime" column="modified_time"></result>
        <result property="remark" column="remark"></result>

        <collection property="tags" ofType="com.spring.pojo.Tag">
              <id property="id" column="tagId"></result>
              <result property="name" column="tagName"></result>
        </collection>
    </resultMap>

    <select id="selectById" resultMap="articleMap">
        select a.id,a.title,a.type,a.content,a.status,a.user_id,
               a.created_time,a.modified_time,a.remark,t.id tagId,t.name tagName
        from tb_sys_articles a left join tb_article_tags at
             on a.id=at.article_id left join tb_sys_tags t
             on at.tag_id=t.id
        where a.id=#{id}
    </select>
    
</mapper>

第二步:定义ArticleTagDao 接口及sql映射设计(对应文章标签关系表的数据操作)

package com.spring.dao;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

@Mapper
public interface ArticleTagDao {

    int insertArticleTag(@Param("articleId") Long articleId,
                         @Param("tagIds") Long[]tagIds);

}

ArticleTagDao 对应的sql映射文件ArticalTagDaoMapper.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.spring.dao.ArticleTagDao">

    <!--博客文章与标签的关系表中写入数据-->
    <insert id="insertArticleTag">
        insert into tb_article_tags
        (article_id,tag_id)
        values <!--(1,2),(1,3),(1,4)-->
        <foreach collection="tagIds" separator="," item="tagId">
            (#{articleId},#{tagId})
        </foreach>
    </insert>

</mapper>

单元测试分析和实践

构建单元测试类,对文章模块进行单元测试。

package com.spring;

import com.spring.dao.ArticleDao;
import com.spring.dao.ArticleTagDao;
import com.spring.pojo.Article;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.Date;

@SpringBootTest
public class ArticleDaoTests {

    @Autowired
    private ArticleDao articleDao;

    @Autowired
    private ArticleTagDao articleTagDao;

    @Test
    void testAddArticle(){
       //1.文章要写入到数据库
        Article art=new Article();
        art.setTitle("Blog-Title-A");
        art.setContent("Blog-Content-A");
        art.setType("2");
        art.setStatus("1");
        art.setRemark("..");
        art.setUserId(101L);
        art.setCreatedTime(new Date());
        art.setModifiedTime(new Date());
        articleDao.insertArticle(art);
        System.out.println(art);
       //2.文件和标签的关系也要写入数据库
        articleTagDao.insertArticleTag(art.getId(), new Long[]{1L,3L});
    }
    @Test
    void testSelectById(){
        Article article = articleDao.selectById(4L);
        System.out.println(article);
    }
}

总结(Summary)

重难点分析

  • MyBatis框架核心优势(简单、灵活、功能强大)
  • MyBatis框架应用架构及核心API(SqlSessionFactory,SqlSession,…)
  • MyBatis框架在SpringBoot工程中的整合(参考官网)
  • MyBatis框架与数据库会话的入口及会话过程
  • MyBatis框架中的动态SQL应用

FAQ分析

  • MyBatis是什么?(持久层框架,半成品-只解决了数据的持久化问题)
  • 为什么选择MyBatis?(开源,简单,功能强大,灵活,稳定,…)
  • MyBatis应用场景?(互联网软件应用都倾向于使用mybatis做数据持久化)
  • MyBatis框架实现与数据库交互的入口对象?SqlSession
  • SqlSession对象是如何创建的?SqlSessionFactory
  • 你了解哪些具体的SqlSession对象呢?(DefaultSqlSession,SqlSessionTemplate)
  • @Mapper注解的作用是什么?
  • MyBatis为我们的Dao接口创建的实现类及其方法内部做了什么?

BUG分析

  • BindingException
  • BadSqlGrammarException
  • SqlSyntaxErrorException
  • UnstatisfiedDependencyException
  • BeanInstantiationException
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值