你好MyBatis 中级篇

时间:2022-07-24
本文章向大家介绍你好MyBatis 中级篇,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

MyBatis中级篇

如约而至,MyBatis的中级篇;小伙伴们对昨天的中级篇的代码掌握了嘛!在程序猿这里,程序这条路没有捷径,只有怀着对技术的热枕砥砺前行,多写多练,才能使自己的技术更进一步!如果你真的想掌握MyBatis的使用,就把这几篇所有讲到的代码吃透,保证无论是你自己写demo,还是企业中的实际开发,在使用MyBatis的时候都没有任何问题!如果有问题的话可以加我微信号,文末我会贴上自己的微信号,有问题的话我会第一时间回复你。

本章节我将继续讲述MyBatis,会对上一章节的一些代码进行简化和重构,使整个程序看起来更加优雅,易扩展。

提取数据连接配置

思考一个问题 ,上节课讲到,我们将关于数据库的一些配置全部都配置在了一个全局配置文件上,我们能否将配置信息拿出来,单独放置在一个文件里?将数据库连接信息提取到外部.properties文件,Resources文件夹下建立properties文件夹,并创建db.properties`文件

mysql.driver=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://127.0.0.1:3306/testmybatis
mysql.username=root
mysql.password=hr

完整的配置文件信息如下

<?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="properties/db.properties"></properties>
    <!--配置默认使用那个环境变量  以id作为标志-->
    <environments default="test">
        <!--配置连接环境-->
        <environment id="test">
            <!--事务管理器使用JDBC-->
            <transactionManager type="JDBC"/>
            <!--数据源   连接池使用该POOLED-->
            <dataSource type="POOLED">
                <property name="driver" value="${mysql.driver}"/>
                <property name="url" value="${mysql.url}"/>
                <property name="username" value="${mysql.username}"/>
                <property name="password" value="${mysql.password}"/>
            </dataSource>
        </environment>
    </environments>
    <!--将Mapper文件在这里注册-->
    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>
</configuration> 

将配置信息文件导入全局配置文件mybatis-config.xml;在mybatis-config.xml中配置一下配置。

<properties resource="properties/db.properties"></properties>

思考:如果配置文件缺失,能否再缺失配置文件的情况下保证程序正常运行呢?引申出下面的概念,给配置信息增加默认值。

首先我们需要开启MyBatis对配置文件默认值的支持

<properties resource="properties/db.properties">
        <!--开启配置文件配置默认值-->
        <property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/>
</properties>

其次,在进行注入数据时加上 :分割,具体注入操作如下;

 <!--数据源   连接池使用该POOLED-->
<dataSource type="POOLED">
     <property name="driver" value="${mysql.driver:com.mysql.jdbc.Driver}"/>
     <property name="url" value="${mysql.url:jdbc:mysql://127.0.0.1:3306/testmybatis}"/>
     <property name="username" value="${mysql.username:root}"/>
     <property name="password" value="${mysql.password:hr}"/>
</dataSource>

当你注入配置文件时,就使用配置文件注入,当不使用配置文件时就是用默认数据库。

MyBatis自带动态代理执行sql语句

首先大概介绍一下什么叫做动态代理类动态代理类必须实现InvocationHandler,覆盖invoke方法!通过new ProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler invocationHandler )返回一个实例,这个实例就是代理对象,使用ClassLoader来动态的生成代理对象,通过反射拿到目标类的构造函数,从而调用目标类的方法,其唯一参数类型是调用处理器接口类型! 想详细了解动态代理类详情请移步我以前的一篇博客设计模式之代理模式

https://blog.csdn.net/qq_37561309/article/details/86693714

复制到浏览器查看文章

根据上面的说法,我们如果想要使用动态代理类就必须提供类对象以及方法名字和参数;相同MyBatis想要使用动态代理类也必须知道这几个先决条件! 下面,我们去看如何去使用动态代理吧。为了区分上一节课,我们重新建立一个数据库表(依旧可以直接复制)

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

DROP TABLE IF EXISTS `student`;
CREATE TABLE `student`  (
  `id` int(7) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `clazzname` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

INSERT INTO `student` VALUES (1, '张三', '计算机网络技术01班');

SET FOREIGN_KEY_CHECKS = 1;

老规矩还是先建立实体类

package com.recommend.entity;

/**
 * @author 皇甫
 */
public class Student {
    private Integer id;
    private String name;
    private String clazzName;

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + ''' +
                ", clazzName='" + clazzName + ''' +
                '}';
    }

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getClazzName() {
        return clazzName;
    }

    public void setClazzName(String clazzName) {
        this.clazzName = clazzName;
    }

    public Student(Integer id, String name, String clazzName) {
        this.id = id;
        this.name = name;
        this.clazzName = clazzName;
    }

    public Student() {
    }
}

建立DAO接口

package com.recommend.dao;

import com.recommend.entity.Student;

import java.util.List;

/**
 * @author 皇甫
 */
public interface StudentDao {
    /**
     * 查询所有学生信息
     * @return
     */
    public List<Student> findAllStudent();
}

配置Mapper文件;此时,请注意,使用动态代理类最关键的一点是 必须提供类对象 方法名 ,类对象可以通过全限定名获取,故在配置Mapper的namespace时,所使用的命名必须时要映射的Dao接口的全限定名;在设置增删改查的id时必须时方法名称;请关注我划重点的地方,这是整个MyBatis使用动态代理的核心点。具体实现如下:

<?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.recommend.dao.StudentDao">
    <select id="findAllStudent" resultType="com.recommend.entity.Student">
        select * from student
    </select>
</mapper>

下面我将重点圈起来

最重要的一步,别忘了将Mapper注入到全局配置文件

此时就完成了动态代理类的使用,我们此时可将Dao实现类省略,有动态代理来隐式生成实现类;省略实现类,直接测试如下:

package com.recommend.testmybatis;

import com.complete.util.MyBatisUtil;
import com.recommend.dao.StudentDao;
import com.recommend.entity.Student;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

/**
 * @author 皇甫
 */
public class MybatisTest {
    private SqlSession sqlSession= null;
    public MybatisTest() {
        //使用工具类获取SqlSession
        sqlSession = MyBatisUtil.openSqlSession();
    }

    @Test
    public void findAll(){
        //将Dao接口注入到sqlSession,动态生成DaoImpl对象
        StudentDao mapper = sqlSession.getMapper(StudentDao.class);
        //执行查询
        List<Student> students = mapper.findAllStudent();
        for (Student student : students) {
            System.out.println(student.getName());
        }
    }
}
动态代理总结
>1. namespace的名字必须同映射Dao接口的全限定名相同
>2. sql所定义的id必须同方法名字相同
>3. sqlSession.getMapper(Clazz<T> clazz)  参数必须为所要映射的Dao的类对象
MyBatis中的多参数查询

如果你想使用班级和名字去查询一个人的信息,此时你应该怎么去设计sql以及Dao接口

 /**
     * 根据名字和班级查询
     * @param name
     * @param clazz
     * @return
     */
    public List<Student> findStudentByNameAndClazz(String name,String clazz);

Mapper文件为

    <select id="findStudentByNameAndClazz" resultType="com.recommend.entity.Student">
        select * from student where name=#{name} and clazzname = #{clazzName}
    </select>

测试执行报错,报错信息如下

报错信息说找不到name,可是我明明有啊!原来是因为在多个参数的情况下,系统并不知道你要把值注入给谁,需要你手动去指定!

使用注解@Param("对应sql注入的名字")
 /**
     * 根据名字和班级查询
     * @Param内部参数对应着你sql语句中#{name},#{clazzName} 名字必须一致
     * @param name
     * @param clazz
     * @return
     */
        public List<Student> findStudentByNameAndClazz(@Param("name") String name, @Param("clazzName") String clazz);

再次运行就OK了!

Mapper文件中 ${id} #{id}的区别

在我们前面的使用中一直使用的都是#{id}取值,还有另外一种取值方式${id},他们两个的区别为,#{id}为注入参数,${id}为拼接参数!#{id}不可进行运算;${id}可以进行运算!当我们使用${id}进行注入时,此时会报错,但是我们可以观看它的日志详情

<select id="findStudentByNameAndClazz" resultType="com.recommend.entity.Student">
        select * from student where name=${name} and clazzname = ${clazzName}
 </select>

那么{id}报错的情况也就很容易解释了,因为字符串条件是需要加''的,直接拼接的没有所以报错,它一般应用在什么情况下呢!上面说到了,{}支持运算,当你想分页时可以使用!

<select id="findAllStudent" resultType="com.recommend.entity.Student">
        select * from student limit 0,${1*2}
    </select>

当你想根据某些条件查询不同的表时也可以使用

<select id="findAllStudent" resultType="com.recommend.entity.Student">
        select * from ${table_name}
    </select>

以上就是中级篇的内容,下期高级篇主要讲述知识点为:

  1. MyBatis的动态SQL
  2. MyBatis的缓存策略
  3. MyBatis的多表连接查询映射即MySql的高级查询
  4. Spring整合MyBatis如何整合