【SSM详细教程】-11-Mybatis注解开发

 精品专题:

01.《C语言从不挂科到高绩点》课程详细笔记

https://blog.csdn.net/yueyehuguang/category_12753294.html?spm=1001.2014.3001.5482

02. 《SpringBoot详细教程》课程详细笔记

https://blog.csdn.net/yueyehuguang/category_12789841.html?spm=1001.2014.3001.5482

03.《SpringBoot电脑商城项目》课程详细笔记

https://blog.csdn.net/yueyehuguang/category_12752883.html?spm=1001.2014.3001.5482

04.《VUE3.0 核心教程》课程详细笔记

https://blog.csdn.net/yueyehuguang/category_12769996.html?spm=1001.2014.3001.5482

================================

||     持续分享系列教程,关注一下不迷路 ||

||                视频教程:墨轩大楼               ||

================================

🌲 简介

MyBatis注解方式就是将SQL语句直接写在接口上,代替映射文件中的标签配置的SQL语句。这种方式的优点是,对于需求简单的系统,效率较高。缺点是,当SQL有变动时,修改重新编译代码。使用注解就是在接口方法基础上添加需要的注解,并写上SQL语句@Select、@Insert、@Update、@Delete这四个基本注解的参数可以是字符串数组。

🌲 环境准备

🌾 数据表

DROP TABLE IF EXISTS `emp`;
CREATE TABLE `emp` (
  `empno` int NOT NULL AUTO_INCREMENT,
  `ename` varchar(20) DEFAULT NULL,
  `job` varchar(20) DEFAULT NULL,
  `manager` int DEFAULT NULL,
  `hiredate` date DEFAULT NULL,
  `salary` double DEFAULT NULL,
  `comm` double DEFAULT NULL,
  `deptno` int DEFAULT NULL,
  PRIMARY KEY (`empno`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb3;

-- ----------------------------
-- Records of emp
-- ----------------------------
INSERT INTO `emp` VALUES ('1', '郭靖', 'clerk', '4', '2022-02-03', '7000', '2000', '2');
INSERT INTO `emp` VALUES ('2', '黄蓉', 'saleman', '4', '2023-02-01', '6000', '5000', '3');
INSERT INTO `emp` VALUES ('3', '江湖骗子', 'saleman', '4', '2023-02-18', '7000', '3000', '3');
INSERT INTO `emp` VALUES ('6', '孙尚香', '业务人员', '3', '2023-05-23', '5000', '0', null);
INSERT INTO `emp` VALUES ('7', '赵四', '舞者', '1', '2023-05-30', '5000', '5000', '4');
INSERT INTO `emp` VALUES ('8', '张飞', '开发', '1', '2023-05-30', '8000', '2000', '3');
INSERT INTO `emp` VALUES ('9', '关羽', '运维', '1', '2023-05-30', '6000', '4000', '3');

🌾 新建项目

🌾 导入依赖

需要将mybatis的依赖导入到pom.xml中,依赖如下:

    <dependencies>
        <!-- mybatis依赖-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>

        <!-- mysql依赖 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.26</version>
        </dependency>



        <!--lombok依赖-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
        </dependency>
        
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.3.0</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.6</version>
        </dependency>
    </dependencies>

🌾 创建包目录

在resources目录中创建mappers目录用来存放映射文件,在项目中新建entity包和dao包分别存放实体类和映射器接口,结构如下图:

图片中的log4j.properties日志文件暂时用不上,可以不用管它,也不用添加进来。

🌾 添加配置文件

在resources目录中添加链接数据库的数据源配置文件db.properties,内容如下:

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/study?serverTimezone=UTC
user=root
password=123456

在dao目录中新建映射器接口,EmpDao.java,内容如下:

package com.moxuan.mybatis_annotation.dao;

public interface EmpDao {
}

在resources下的mappers文件中添加映射器接口,内容如下:

<?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">
<!-- 此处的namespace需要对应上dao包中的数据操作接口-->
<mapper namespace="com.moxuan.mybatis_annotation.dao.EmpDao">


</mapper>

在entity包中新建Emp实体类,代码如下:

package com.moxuan.mybatis_annotation.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.sql.Date;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp {

    private Integer empno;
    private String ename;
    private String job;
    private Integer manager;
    private Date hiredate;
    private Double salary;
    private Double comm;
    private Integer deptno;
    
}

在resources目录中添加mybatis配置文件mybatis-config,内容如下:

<?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>
    <properties resource="db.properties"></properties>
    <!--常规配置-->
    <settings>
        <!--允许自动生成主键:配合映射文件-->
        <setting name="useGeneratedKeys" value="true"/>
        <setting name="logImpl" value="STDOUT_LOGGING" />
    </settings>
    
    <typeAliases>
        <package name="com.moxuan.mybatis_annotation.entity"/>
    </typeAliases>
    <!--配置分页插件-->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <!--指定数据库方言,可以不用配置,默认识别具体的数据库管理系统-->
            <property name="helperDialect" value="mysql"/>
            <!--
            pageSizeZero:默认值为 false,当该参数设置为 true 时,
            如果 pageSize=0 或者 RowBounds.limit = 0
            就会查询出全部的结果(相当于没有执行分页查询,但是返回结果仍然是 Page 类型)。
            -->
            <property name="pageSizeZero" value="true"/>
            <!--
            reasonable:分页合理化参数,默认值为false。当该参数设置为 true 时,
            pageNum<=0 时会查询第一页, pageNum>pages(超过总数时),
            会查询最后一页。默认false 时,直接根据参数进行查询。
            -->
            <property name="reasonable" value="true"/>
        </plugin>
    </plugins>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <!-- 数据源配置 -->
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${user}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="mappers\EmpMapper.xml"></mapper>
    </mappers>
</configuration>

🌲 具体实现

🌾 添加@Mapper注解

在映射器接口EmpDao上方添加@Mapper ,Mybatis注解主要是通过@Mapper 注解来实现的,添加了这个注解后,程序就会从这个接口中寻找对应的sql语句注解。代码如下:

package com.moxuan.mybatis_annotation.dao;

import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface EmpDao {
}

🌾 添加Mybatis工具类

package com.moxuan.mybatis_annotation.util;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

public class MyBatisUtil {
    private static SqlSessionFactory factory;

    static{
        // 在静态代码块下,factory只会被创建一次
        try {
            InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
            factory = new SqlSessionFactoryBuilder().build(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取sqlSession对象
     * @return
     */
    public static SqlSession getSession(){
        return factory.openSession(false);// true 为自动提交事务
    }

    /**
     * 关闭sqlSession对象
     * @param session
     */
    public static void closeSqlSession(SqlSession session){
        if(session!=null){
            session.close();
        }
    }
}

🌾 @Select 查询注解

在映射器接口的方法上添加@Select注解,写上对应的查询sql语句,当调用方法时会触发注解中的sql语句做查询操作,代码如下:

@Mapper
public interface EmpDao {

    @Select("select * from emp")
    List<Emp> findAll();

}

在test目录中编写测试类进行测试:

import com.moxuan.mybatis_annotation.dao.EmpDao;
import com.moxuan.mybatis_annotation.entity.Emp;
import com.moxuan.mybatis_annotation.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

import java.util.List;

public class MybatisTest {

    @Test
    public void test01(){
        SqlSession session = MyBatisUtil.getSession();
        EmpDao dao = session.getMapper(EmpDao.class);
        System.out.println("==========查询所有的员工信息===========");
        List<Emp> emps_01 = dao.findAll();
        for (Emp emp :emps_01){
            System.out.println(emp);
        }

    }
}

运行结果:

🌾 @Insert 注解添加数据

@Insert 注解可以用于在方法上添加向数据库新增数据的sql语句,在EmpDao中添加新增数据的方法,代码如下:

当sql语句中需要使用参数,而这些参数是方法参数对象的属性时,可以将方法参数对象用@Param 取一个别名,然后通过别名调用属性,来给sql语句设置参数

@Insert("insert into emp (ename,job) values(#{e.ename},#{e.job})")
void addEmp(@Param("e") Emp emp);

在test中添加测试方法:

@Test
public void testAdd(){
    SqlSession session = MyBatisUtil.getSession();
    EmpDao dao = session.getMapper(EmpDao.class);
    System.out.println("==========添加员工===========");
    Emp emp = new Emp();
    emp.setEname("狗蛋");
    emp.setJob("掏粪男孩");
    dao.addEmp(emp);
    session.commit();
    System.out.println("数据添加成功");
}

运行结果:

🌾 @Update 修改数据

@Update 注解可以用于在方法上添加修改数据库数据的sql语句,在EmpDao中添加修改数据的方法,代码如下:

@Update("update emp set job=#{e.job} where empno=#{e.empno}")
void updateEmp(@Param("e") Emp emp);

测试方法如下:

@Test
public void testUpdate(){
    SqlSession session = MyBatisUtil.getSession();
    EmpDao dao = session.getMapper(EmpDao.class);
    System.out.println("==========修改员工===========");
    Emp emp = new Emp();
    emp.setEmpno(9);
    emp.setJob("掏粪男孩");
    dao.addEmp(emp);
    session.commit();
    System.out.println("数据添加成功");
}

运行效果:

🌾 @Delete删除数据

@Delete 注解可以用于在方法上添加删除数据库数据的sql语句,在EmpDao中添加删除数据的方法,代码如下:

@Delete("delete from emp where empno=#{id}")
void deleteEmp(@Param("id")int empno);

测试方法如下:

@Test
public void testDelete(){
    SqlSession session = MyBatisUtil.getSession();
    EmpDao dao = session.getMapper(EmpDao.class);
    System.out.println("==========删除员工===========");
    int empno = 9;
    dao.deleteEmp(empno);
    session.commit();
    System.out.println("数据删除成功");
}

运行效果:

🌾 注解与映射文件搭配使用

由于注解开发是将所有的sql语句以字符串的形式写在方法的上面,有些情况就不适合放在注解中,比如动态sql的拼接以及关联映射、resultMap的配置等等。通常我们会将resultMap以及关联映射等相关信息配置到映射文件中,然后再使用注解去调用。

我们先看看使用注解在sql语句中拼接动态SQL是什么样的,比如下面我们想要实现一个动态修改的SQL语句注解,写法如下:

@Update({"<script>"+
                "update  emp " +
                " <set>" +
                "    <if test='e.ename!=null'> ename=#{e.ename},</if> " +
                "    <if test='e.job!=null'> job=#{e.job},</if> " +
                "    <if test='e.manager!=null'> manager=#{e.manager},</if> " +
                "    <if test='e.salary!=null'> salary=#{e.salary},</if> " +
                "    <if test='e.comm!=null'> comm=#{e.comm},</if> " +
                "    <if test='e.deptno!=null'> deptno=#{e.deptno},</if> " +
                " </set> " +
                "  where empno=#{e.empno} " +
            "</script>"})
void updateEmpSql(@Param("e")Emp emp);
  • 在注解中使用动态sql时需要添加需要将sql语句写在 { } 中
  • 在sql语句外面需要包裹一层<script></script>告诉mybatis这是一个动态sql脚本,而不是一个普通sql语句。

编写测试方法:

@Test
public void testUpdateEmp(){
        SqlSession session = MyBatisUtil.getSession();
        EmpDao dao = session.getMapper(EmpDao.class);
        Emp emp = new Emp();
        emp.setEmpno(3);
        emp.setEname("心肝小宝贝儿");
        System.out.println("====修改之前====");
        List<Emp> empList = dao.findAll();
        for(Emp e:empList){
            System.out.println(e);
        }

        dao.updateEmpSql(emp);
        session.commit();// 修改数据库数据之后,需要提交事务
        System.out.println("====修改之后====");
        empList = dao.findAll();
        for(Emp e:empList){
            System.out.println(e);
        }
}

可以看到这种方式虽然可以达到我们想要的效果,但是,拼接复杂,容易出错。

还有一种情况,当数据库字段和实体类属性不一致的时候,我们无法将数据查出来,这个时候就需要用到resultMap去做映射。这种情况在字符串中拼接也会比较麻烦,我们一般的做法,可以将resultmap相关映射写在映射文件中,然后再到映射器接口中使用@ResultMap注解引用。

比如:现在的employee对应emp表,其属性如下所示:

package com.moxuan.mybatis_annotation.entity;

import lombok.Data;

import java.sql.Date;

@Data
public class Employee {
    private Integer p_empno;
    private String p_ename;
    private String p_job;
    private Integer p_manager;
    private Date p_hiredate;
    private Double p_salary;
    private Double p_comm;
    private Integer p_deptno;

}

这个时候如果我们按照以前的方式编写sql语句,代码如下:

@Select("select * from emp")
List<Employee> getEmployees();

此时去测试程序

@Test
public void test02(){
    SqlSession session = MyBatisUtil.getSession();
    EmpDao dao = session.getMapper(EmpDao.class);
    System.out.println("==========查询所有的员工信息===========");
    List<Employee> emps_01 = dao.getEmployees();
    for (Employee emp :emps_01){
        System.out.println(emp);
    }

}

就会发现测试结果都为null,

此时,我们可以去映射文件中进行配置,使用resultMap让属性和字段对应起来,代码如下:

<?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">
<!-- 此处的namespace需要对应上dao包中的数据操作接口-->
<mapper namespace="com.moxuan.mybatis_annotation.dao.EmpDao">

    <resultMap id="empMap" type="employee">
        <id column="empno" property="p_empno"></id>
        <result column="ename" property="p_ename"></result>
        <result column="job" property="p_job"></result>
        <result column="manager" property="p_manager"></result>
        <result column="hiredate" property="p_hiredate"></result>
        <result column="salary" property="p_salary"></result>
        <result column="comm" property="p_comm"></result>
        <result column="deptno" property="p_deptno"></result>
    </resultMap>
</mapper>

上面我们将resultMap的id设置为了empMap,这个在映射器sql语句注解下使用@ResultMap("resultMap的id")去使用映射文件中对应的resultMap,代码如下:

@Select("select * from emp")
@ResultMap("empMap")
List<Employee> getEmployees();

再次运行,结果如下:

🌲 总结

  1. 注解方式适用于SQL语句简单时,复杂的动态SQL语句还是建议在映射文件中配置
  2. 使用注解方式时,如果sql语句中需要传参,那么需要在接口方法中使用@Param 去指定参数的名字
  3. 使用注解方式时,如果需要用到动态sql语句时,一定要使用 { "<script>sql语句</script>"}此种格式,将sql语句包裹,否则mybatis不会将其作为动态sql语句去解析。
  4. 注解方式和映射文件方式可以搭配使用,合理搭配能提升开发效率
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

听潮阁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值
>