Mybatis

MyBatis框架最新完整版视频教程(idea版)mybatis实战入门讲解_哔哩哔哩_bilibili

【尚硅谷】2022版MyBatis教程(细致全面,快速上手)_哔哩哔哩_bilibili

MyBatis 框架

第一章 框架的概述

1.三层架构

mvc:web开发中,使用mvc架构模式。 m:数据, v:视图, c:控制器。

      c控制器: 接收请求,调用service对象,显示请求的处理结果。 当前使用servlet作为控制器

      v视图: 现在使用jsp, html,css,js。 显示请求的处理结果,把m中数据显示出来。

      m数据: 来自数据库mysql, 来自文件,来自网络

mvc作用:

 1)实现解耦合。 

 2)让mvc 各负其职。  

 3)使的系统扩展更好。更容易维护。 

三层架构:

1.界面层(视图层):接收用户的请求,调用service, 显示请求的处理结果的。 包含了jsp,html,servlet等对象。 对应的包controller,

2.业务逻辑层:处理业务逻辑, 使用算法处理数据的。 把数据返回给界面层。 对应的是service包,和包中的很多的XXXService类。 例如: StudentService , OrderService, ShopService

3.持久层(数据库访问层):访问数据库,或者读取文件,访问网络。获取数据。 对应的包是dao。 dao包中很多的StudentDao, OrderDao, ShopDao等等。

2. 三层架构请求的处理流程

用户发起请求---->界面层----->业务逻辑层---->持久层---->数据库(mysql)

3. 为什么要使用三层?

1,结构清晰、耦合度低, 各层分工明确
2,可维护性高,可扩展性高
3,有利于标准化
4,开发人员可以只关注整个结构中的其中某一层的功能实现
5,有利于各层逻辑的复用

4. 三层架构模式和框架

每一层对应着一个框架

1)界面层---SpringMVC框架

2)业务层---Spring框架

3)持久层---MyBatis框架

5 .框架

  1. 什么是框架(framework)

框架:就是一个软件, 完成了部分的功能。 软件中的类和类之间的方法调用都已经规定好了。 通过这些可以完成某些功能。 框架看做是模版。

框架是可以升级的,改造的。 框架是安全的。

框架是对某一个方面有用的,不是全能的。

6. 框架解决的问题

1)框架能实现技术的整合。

2)提供开发的效率。 降低难度。

7. jdbc访问数据库的优缺点

优点:

  1. 直观,好理解

缺点:

  1. 创建很多对象 Connection ,Statement, ResultSet
  2. 注册驱动
  3. 执行sql语句
  4. 把ResultSet转为 Student , List集合。
  5. 关闭资源
  6. sql语句和业务逻辑代码混在一起

8 MyBatis框架

什么 mybatis: 是一个持久层框架, 原名是ibatis, 2013改名为 MyBatis. MyBatis可以操作数据库,对数据执行增删改查。 看做是高级的jdbc。 解决jdbc的缺点。

mybatis能做什么?

1) 注册驱动 。

2) 创建jdbc中使用的Connection, Statement,ResultSet

  1. 执行sql语句, 得到ResultSet

  2. 处理ResultSet, 把记录集中的数据转为java对象, 同时还能把java对象放入到List集合。

5)关闭资源

6)实现sql语句和java代码的解耦合。

mybatis的文档: https://mybatis.org/mybatis-3/zh/index.html

第二章 MyBatis入门

2.1 第一个例子

实现步骤:

创建student表(id,name,email,age)

CREATE TABLE `student` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

新建maven项目

修改pom.xml

  1. 加入依赖 mybatis依赖, mysql驱动, junit
  2. 加入资源插件

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>

  <groupId>com.bjpowernode</groupId>
  <artifactId>ch02-dao</artifactId>
  <version>1.0</version>


  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <!--依赖列表-->
  <dependencies>


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

    <!--mysql驱动-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.9</version>
    </dependency>


    <!--单元测试-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>

    <!--资源插件: 处理src/main/java目录中的xml-->
    <resources>
      <resource>
        <directory>src/main/java</directory><!--所在的目录-->
        <includes><!--包括目录下的.properties,.xml 文件都会扫描到target-->
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
      </resource>
    </resources>
  </build>
</project>

创建实体类Student,定义属性, 属性名和列名保持一致

Student.java

package com.dy.domain;

public class Student {
    //属性名和列名一样
    private Integer id;
    private String name;
    private String email;
    private Integer age;

    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 getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "学生实体的信息{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", age=" + age +
                '}';
    }
}

创建Dao接口, 定义操作数据库的方法

StudentDao.java

package com.dy.dao;

import com.dy.domain.Student;

public interface StudentDao {

    //查询一个学生
    Student selectStudentById(Integer id);

    //添加学生
    //返回值int:表示本次操作影响的数据库的行数
    int insertStudent(Student student);
}

创建xml文件(mapper文件), 写sql语句

StudentDao.xml

mybatis框架推荐是把sql语句和java代码分开

mapper文件:定义和dao接口在同一目录, 一个表一个mapper文件。

<?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.dy.dao.StudentDao">
<!--    <select id="selectBlog" resultType="Blog">-->
<!--    select * from Blog where id = #{id}-->
<!--  </select>-->

<!--    查询一个学生Student
            <select>:表示查询操作,里面是select语句
            id:要执行的sql语句的唯一标识,是一个自定义字符串
                推荐使用dao接口中的方法名称
            resultType:告诉mybatis,执行sql语句,把数据赋值给那个类型的java对象。
                resultType的值推荐使用的java对象的全限定名称。只有select的时候才能用

            #{studentId}:占位符,表示从java程序中传入过来的数据
-->

    <select id="selectStudentById" resultType="com.dy.domain.Student">
        select id,name,email,age from student where id=#{studentId};
    </select>

<!--    添加insert

        insert into student values(1003,"ds","gds@",34);

        如果传入给mybatis是一个java对象,使用#{属性名} 获取此属性的值。
        属性值放到 #{} 占位符的位置,mybatis执行此属性对应的getXxx()
        例如 #{id},执行 getId();

-->
    <insert id="insertStudent">
        insert into student values(#{id},#{name},#{email},#{age});
    </insert>
</mapper>


<!--
    1.约束文件
    http://mybatis.org/dtd/mybatis-3-mapper.dtd
    约束文件作用:定义和限制当前文件中可以使用的标签和属性,以及标签出现的顺序

    2.mapper是根标签
    namespace:命名空间,必须有值,不能为空。唯一值。
                推荐使用Dao接口的全限定名称。
    作用:参与识别sql语句的作用

    2.在mapper里面可以写<insert>,<update>,<delete>,<select>等标签。
    <insert> 里面是 insert 语句,表示执行的insert操作
    <update> 里面是 update 语句
    <delete> 里面是 delete 语句
    <select> 里面是select 语句

-->

创建mybatis的主配置文件(xml文件):有一个, 放在resources目录下

mybatis.xml

1)定义创建连接实例的数据源(DataSource)对象

  1. 指定其他mapper文件的位置
<?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>
    <!--设置日志-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <!--配置数据源: 创建Connection对象。-->
            <dataSource type="POOLED">
                <!--driver:驱动的内容-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <!--连接数据库的url-->
                <property name="url"
                          value="jdbc:mysql://dongye.games:3306/springdb?useUnicode=true&amp;characterEncoding=utf-8"/>
                <!--用户名-->
                <property name="username" value="root"/>
                <!--密码-->
                <property name="password" value="90"/>
            </dataSource>
        </environment>
    </environments>

    <!--指定其他mapper文件的位置:
        其他其他mapper文件目的是找到其他文件的sql语句
    -->
    <mappers>
<!--        使用mapper的resource属性指定mapper文件的路径
            这个路径是从target/classes 路径开启的
            使用注意:
                resource="mapper文件的路径,使用 / 分割路径"
                一个mapper resource 指定一个mapper文件
-->
        <mapper resource="com/dy/dao/StudentDao.xml"/>
    </mappers>
</configuration>

创建测试的内容

使用main方法,测试mybatis访问数据库
也可以使用junit 访问数据库

MyTest.java

package com.dy.mybatistest;

import com.dy.domain.Student;
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 MyTest {
    //测试mybatis执行sql语句
    public static void main(String[] args) throws IOException {
        //调用mybatis某个对象的方法,执行mapper文件中的sql语句
        //mybatis核心类:SqlSessionFactory

        //1.定义mybatis主配置文件的位置,从类路径开始的相对路径
//        String config="mybatis.xml";
//        2.读取主配置文件。使用mybatis框架中的Resources类
//        InputStream inputStream = Resources.getResourceAsStream(config);
//        3.创建SqlSessionFactory对象,使用SqlSessionFactoryBuilder类
//        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//
//        4.获取SqlSession对象
//        SqlSession session = factory.openSession();
//
//        5.指定要执行的sql语句的id
//        sql的id = namespace + "." + select|update|insert|delete 标签的id属性值
//        String sqlId = "com.dy.dao.StudentDao" + "." + "selectStudentById";
//        也可以
//        String sqlId = "com.dy.dao.StudentDao.selectStudentById";
//        6.通过SqlSession的方法,执行sql语句
//        Student student = session.selectOne(sqlId,"1001");
//        System.out.println("使用mybatis查询一个学生:" + student);
//
//        7.关闭SqlSession对象
//        session.close();


//        insert操作

        //1.定义mybatis主配置文件的位置,从类路径开始的相对路径
        String config="mybatis.xml";
        //2.读取主配置文件。使用mybatis框架中的Resources类
        InputStream inputStream = Resources.getResourceAsStream(config);
        //3.创建SqlSessionFactory对象,使用SqlSessionFactoryBuilder类
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);

        //4.获取SqlSession对象
        SqlSession session = factory.openSession();

        //5.指定要执行的sql语句的id
        //sql的id = namespace + "." + select|update|insert|delete 标签的id属性值
        String sqlId = "com.dy.dao.StudentDao" + "." + "insertStudent";
        //也可以
//        String sqlId = "com.dy.dao.StudentDao.selectStudentById";
        //6.通过SqlSession的方法,执行sql语句

//        int rows = session.insert(sqlId);
        Student student = new Student();
        student.setId(1004);
        student.setName("dg");
        student.setEmail("dgsad@");
        student.setAge(2);

        int rows = session.insert(sqlId,student);
        System.out.println("使用mybatis添加一个学生:rows=" + rows);

        //mybatis默认执行sql语句是,手工提交事务 模式,在做insert、update、delete后需要提交事务
        session.commit();
        //7.关闭SqlSession对象
        session.close();
    }
}

2.2 概念

1.自动提交:当你的 sql语句执行完毕后, 提交事务。 数据库更新操作之间保存到数据

2.手动(手工)提交事务:在你需要提交事务的位置, 执行方法,提交事务或者回顾事务。

2.3 MyBatis的一些重要对象

1) Resources : mybatis框架中的对象, 一个作用读取 主配置信息。

InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");

2)SqlSessionFactoryBuilder:负责创建SqlSessionFactory对象

SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);

3)SqlSessionFactory: 重要对象

SqlSessionFactory是重量级对象:创建此对象需要使用更多的资源和时间。 在项目中有一个就可以了。

SqlSessionFactory接口:作用是SqlSession的工厂, 就是创建SqlSession对象。

DefaultSqlSessionFactory实现类

public class DefaultSqlSessionFactory implements SqlSessionFactory { } 

SqlSessionFactory接口中的方法

openSession(): 获取一个默认的SqlSession对象, 默认是需要手工提交事务的。

openSession(boolean): boolean参数表示是否自动提交事务。

true: 创建一个自动提交事务的SqlSession
false:   等同于没有参数的openSession
  1. SqlSession对象

SqlSession对象是通过SqlSessionFactory获取的。 SqlSession本身是接口

DefaultSqlSession: 实现类

public class DefaultSqlSession implements SqlSession { }

SqlSession作用是提供了大量的执行sql语句的方法:

selectOne:执行sql语句,最多得到一行记录,多余1行是错误。
selectList:执行sql语句,返回多行数据
selectMap:执行sql语句的,得到一个Map结果
insert:执行insert语句
update:执行update语句
delete:执行delete语句
commit:提交事务
rollback:回顾事务

注意SqlSession对象不是线程安全的, 使用的步骤:

①:在方法的内部,执行sql语句之前,先获取SqlSession对象

②:调用SqlSession的方法,执行sql语句

③:关闭SqlSession对象,执行SqlSession.close()

2.4 使用模版

创建模版,mapper文件模版和mybatis主配置文件模版

创建模版的步骤:

创建模版文件:

创建文件选择使用的模版:

2.5 使用工具类

MyBatisUtil

package com.dy.utils;

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;

//工具类:创建SqlSession对象
public class MyBatisUtil {

    private static SqlSessionFactory factory = null;
    static {
        String config="mybatis.xml";
        try {
            InputStream inputStream = Resources.getResourceAsStream(config);
            factory = new SqlSessionFactoryBuilder().build(inputStream);
        }catch (IOException e) {
            e.printStackTrace();
        }
    }

    //创建方法,获取SqlSession对象
    public static SqlSession getSqlSession() {
        SqlSession session = null;
        if (factory != null) {
            session = factory.openSession(); //openSession(true);
        }
        return session;
    }

}

StudentDao

package com.dy.dao;

import com.dy.domain.Student;

import java.util.List;

public interface StudentDao {

    //查询一个学生
    Student selectStudentById(Integer id);

    //查询多个学生
    List<Student> selectStudents();

    //添加学生
    //返回值int:表示本次操作影响的数据库的行数
    int insertStudent(Student student);
}

StudentDao.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.dy.dao.StudentDao">

    <select id="selectStudentById" resultType="com.dy.domain.Student">
        select id,name,email,age from student where id=#{studentId}
    </select>

    <select id="selectStudents" resultType="com.dy.domain.Student">
        select id,name,email,age from student
    </select>

    <insert id="insertStudent">
        insert into student values(#{id},#{name},#{email},#{age})
    </insert>
</mapper>

测试类

package com.dy.mybatistest;

import com.dy.domain.Student;
import com.dy.utils.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;
import java.util.List;

public class MyTest {

    public static void main(String[] args) {
        //1.获取SqlSession
        SqlSession session = MyBatisUtil.getSqlSession();
        //2.指定sqlId
        String sqlId = "com.dy.dao.StudentDao.selectStudentById";
        //3.执行SqlSession的方法,表示执行sql语句
        Student student = session.selectOne(sqlId,1001);
        System.out.println("查询结果:" + student);
        //关闭SqlSession对象
        session.close();
    }

    @Test
    public void testSelectStudents() {
        //1.获取SqlSession
        SqlSession session = MyBatisUtil.getSqlSession();
        //2.指定sqlId
        String sqlId = "com.dy.dao.StudentDao.selectStudents";
        //3.执行SqlSession的方法,表示执行sql语句
        List<Student> students =  session.selectList(sqlId);
        for (Student stu:students) {
            System.out.println(stu);

        }
        //关闭SqlSession对象
        session.close();
    }

    @Test
    public void testInsertStudents() {
        //1.获取SqlSession
        SqlSession session = MyBatisUtil.getSqlSession();
        //2.指定sqlId
        String sqlId = "com.dy.dao.StudentDao.insertStudent";
        //3.执行SqlSession的方法,表示执行sql语句
        Student student = new Student();
        student.setId(1008);
        student.setName("du8");
        student.setEmail("435dfg");
        student.setAge(10);
        int rows = session.insert(sqlId, student);
        session.commit();
        System.out.println(rows);
        //关闭SqlSession对象
        session.close();
    }
}

实现Dao接口的方式

StudentDaoImpl

package com.dy.impl;

import com.dy.dao.StudentDao;
import com.dy.domain.Student;
import com.dy.utils.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;

import java.util.List;

public class StudentDaoImpl implements StudentDao {
    @Override
    public Student selectStudentById(Integer id) {
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        String sqlId = "com.dy.dao.StudentDao.selectStudentById";
        Student student = sqlSession.selectOne(sqlId,id);
        sqlSession.close();
        return student;
    }

    @Override
    public List<Student> selectStudents() {
        //1.获取SqlSession
        SqlSession session = MyBatisUtil.getSqlSession();
        //2.指定sqlId
        String sqlId = "com.dy.dao.StudentDao.selectStudents";
        //3.执行SqlSession的方法,表示执行sql语句
        List<Student> students =  session.selectList(sqlId);

        //关闭SqlSession对象
        session.close();
        return students;
    }

    @Override
    public int insertStudent(Student student) {
        //1.获取SqlSession
        SqlSession session = MyBatisUtil.getSqlSession();
        //2.指定sqlId
        String sqlId = "com.dy.dao.StudentDao.insertStudent";
        //3.执行SqlSession的方法,表示执行sql语句

        int rows = session.insert(sqlId, student);
        session.commit();
        System.out.println(rows);
        //关闭SqlSession对象
        session.close();
        return rows;
    }
}

测试类

package com.dy.mybatistest;

import com.dy.dao.StudentDao;
import com.dy.domain.Student;
import com.dy.impl.StudentDaoImpl;
import org.junit.jupiter.api.Test;

import java.util.List;

public class MyTest2 {

/*
    测试方法中:调用dao的方法
    Student student = dao.selectById(1002);

    1)  dao:通过反射能够得到 全限定类型名称
        dao是StudentDao 类型的,全限定名称 com.dy.dao.StudentDao
    2)  selectById:dao中的方法名称,方法名称就是mapper文件中标签的id
        通过dao.selectById() 能得到 sqlId="com.dy.dao.StudentDao.selectById";
    3)  确定调用SqlSession的那个方法
        1.根据dao接口的方法返回中,如果返回时一个对象,例如Student,调用SqlSession。selectOne();
            如果dao接口中的方法返回List,调用 SqlSession 的selectList();
        2.根据mapper文件中的标签,如果标签是<insert>,调用SqlSession.insert()方法

    mybatis框架,发现使用dao的方法调用能确定 执行sql语句的必要信息,mybatis简化dao对象的实现。
    由mybatis框架在程序执行期间,根据你的Dao接口,创建一个内存中的接口的实现类对象
    mybatis把这个技术叫做dao技术(动态代理,dao的动态代理)

    dao代理技术:由mybatis创建StudentDao接口的实现类Proxy(StudentDaoImpl)
    使用框架创建的StudentDaoImpl 代替 "你自己手工实现的StudentDaoImpl类的功能",
    不用开发人员写 dao 接口的实现类

    使用dao的代理要求:
    1.mapper 文件中的namespace:必须是dao接口的全限定名称
    2.mapper 文件中标签的id 是dao接口中的方法名称(一模一样的)
*/
    @Test
    public void testSelectOne(){
        //要使用dao的方法
        //接口类型  变量  = new 接口的实现类();
        StudentDao dao = new StudentDaoImpl();
        Student student = dao.selectStudentById(1001);
        System.out.println(student);
    }

    @Test
    public void testSelectStudents(){

        StudentDao dao = new StudentDaoImpl();
        List<Student> students = dao.selectStudents();
        students.forEach(stu -> System.out.println(stu));
    }


    @Test
    public void testInsert(){
        StudentDao dao = new StudentDaoImpl();

        Student student = new Student();
        student.setId(1009);
        student.setName("dsf");
        student.setEmail("dg4");
        student.setAge(10);
        dao.insertStudent(student);
    }
}

第三章 MyBatis的Dao代理

3.1 dao代理

3.1.1 mybatis提供代理:

mybatis创建Dao接口的实现类对象, 完成对sql语句的执行。 mybatis创建一个对象代替你的 dao实现类功能。

3.1.2 使用mybatis代理要求

1)mapper文件中的namespace 一定dao接口的全限定名称

2)mapper文件中 标签的id是dao接口方法名称

3.1.3 mybatis代理实现方式

使用SqlSession对象的方法 getMapper(dao.class)

例如: 现在有 StudentDao接口。

SqlSession session  = MyBatisUtils.getSqlSession();
StudentDao dao  = session.getMapper(StudentDao.class);
Student student = dao.selectById(1001);


//上面代码中
StudentDao dao  = session.getMapper(StudentDao.class);
等同于
StudentDao dao  = new StudentDaoImpl();

所以2.5中的测试方法可以写成


package com.dy.mybatistest;

import com.dy.dao.StudentDao;
import com.dy.domain.Student;
import com.dy.utils.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

import java.util.List;

public class MyTest3 {

    @Test
    public void testSelectOne(){
        //1,获取SqlSession
        SqlSession session = MyBatisUtil.getSqlSession();
        //2.获取dao的代理
        StudentDao dao = session.getMapper(StudentDao.class);
        Student student = dao.selectStudentById(1001);
        System.out.println("studnet = " + student);
        //3.关闭SqlSession对象
        session.close();
    }

    @Test
    public void testSelectStudents(){

        //1,获取SqlSession
        SqlSession session = MyBatisUtil.getSqlSession();
        //2.获取dao的代理
        StudentDao dao = session.getMapper(StudentDao.class);

        System.out.println("dao===" + dao.getClass().getName());//com.sun.proxy.$Proxy
        List<Student> students = dao.selectStudents();
        students.forEach(stu -> System.out.println("stu=" + stu));

        //3.关闭SqlSession对象
        session.close();
    }

}

3.2 理解参数

理解参数是: 通过java程序把数据传入到mapper文件中的sql语句。 参数主要是指dao接口方法的形参

3.2.1 parameterType

parameterType:表示参数的类型, 指定dao方法的形参数据类型。 这个形参的数据类型是给mybatis使用。 mybatis在给sql语句的参数赋值时使用。 PreparedStatement.setXXX( 位置, 值)

第一个用法: java类型的全限定类型名称   parameterType="java.lang.Integer"
第二个用法: mybatis定义的java类型的别名  parameterType="int"

parameterType:mybatis通过反射机制可以获取 dao接口方法参数的类型, 可以不写

<select id="selectById"  parameterType="integer"
                 resultType="com.bjpowernode.domain.Student">
   select id,name,email,age from student where id=#{studentId}
</select>

3.2.2 dao接口方法是一个简单类型的参数

可以通过${}#{}任意的名称获取参数值,但是需要注意${}的单引号问题

但是一般来说,不会使用任意的名称,还是会以传输过来的参数名去当名称(为了见名识义)

public interface StudentDao {

    //重载方法
    Student selectById(Integer id);

    //dao接口的方法形参是一个简单类型的
    //简单类型:java基本数据类型和String
    Student selectByEmail(String email);
}

<!--
   dao接口是一个简单类型的参数
   mapper文件,获取这个参数值,使用#{任意字符}
-->
<select id="selectByEmail" resultType="com.bjpowernode.domain.Student">
    select id,name,email,age from student where email=#{studentEmail}
</select>

3.2.3 dao接口方法有多个简单类型的参数,使用位置

此时MyBaits会将这些参数放在一个map集合中,以两种方式进行存储

  • 以 arg0、arg1……为键,以参数为值
  • 以 param0、param1……为键,以参数为值

因此只需要通过 #{}${}以键的方式访问值即可,但是需要注意 ${}的单引号问题

public interface StudentDao {

    //重载方法
    Student selectById(Integer id);

    //dao接口的方法形参是一个简单类型的
    //简单类型:java基本数据类型和String
    Student selectByEmail(String email);

    /*
  多个简单类型的参数
  使用@Param命名参数, 注解是mybatis提供的
  位置:在形参定义的前面
  属性:value 自定义的参数名称
 */
    List<Student> selectByNameOrAge(String name, Integer age);
}

<select id="selectByNameOrAge" resultType="com.bjpowernode.domain.Student">
    select id,name,email,age from student where name=#{arg0} or age=#{arg1}
</select>
    
或
<select id="selectByNameOrAge" resultType="com.bjpowernode.domain.Student">
    select id,name,email,age from student where name=#{param0} or age=#{param1}
</select>

或(不怕被打死的话)
<select id="selectByNameOrAge" resultType="com.bjpowernode.domain.Student">
    select id,name,email,age from student where name=#{arg0} or age=#{param1}
</select>

3.2.4 dao接口参数是一个Map

map作为dao接口的参数, 使用 key 获取参数值,mapper文件中,语法格式 #{key}

/*
   使用Map作为参数
 */
List<Student> selectStudentByMap(Map<String,Object> map);

mapper文件

<!--
   使用Map传递参数,
   在mapper文件中,获取map的值,是通过key获取的,语法:#{key}
-->
<select id="selectStudentByMap" resultType="com.bjpowernode.domain.Student">
     select id,name,email,age from student where name=#{myname} or age=#{myage}
</select>

测试,调用方法的位置

@Test
public void testSelectByMap(){
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    StudentDao dao  = sqlSession.getMapper(StudentDao.class);

    //使用map传递参数
    Map<String,Object> data = new HashMap<>();
    data.put("myname", "李思思");
    data.put("myage", 20);
    List<Student> students = dao.selectStudentByMap(data);

    students.forEach( stu-> System.out.println("stu="+stu));
    sqlSession.close();

}

3.2.5 dao接口方法使用一个对象作为参数

方法的形参是一个java对象。这个java对象表示多个参数。使用对象的属性值作为参数使用

java对象

public class Student {
    private Integer id;
    private String name;
    private String email;
    private Integer age;
    //set|get方法
    ...省略
}

public class QueryParam {
    private Object p1;
    private Object p2;
    //set|get方法
    ...省略
}

dao接口中的方法定义

/*
 * 一个java对象作为参数( 对象由属性, 每个属性有set,get方法)
 */
List<Student> selectByObject(Student student);

List<Student> selectByQueryParam(QueryParam param);

mapper文件

<!--
   一个java对象作为方法的参数,使用对象的属性作为参数值使用
   简单的语法: #{属性名} , mybatis调用此属性的getXXX()方法获取属性值
-->
<select id="selectByObject" resultType="com.bjpowernode.domain.Student">
    select id,name,email,age from student where name=#{name} or age=#{age}
</select>

<select id="selectByQueryParam" resultType="com.bjpowernode.domain.Student">
     select id,name,email,age from student where name=#{p1} or age=#{p2}
</select>

<!--负责的语法格式: #{属性名,javaType=java类型的全限定名称,jdbcType=mybatis中定义列的数据类型}-->
<select id="selectByObject" resultType="com.bjpowernode.domain.Student">
        select id,name,email,age from student where
        name=#{name,javaType=java.lang.String,jdbcType=VARCHAR}
        or
        age=#{age,javaType=java.lang.Integer,jdbcType=INTEGER}
</select>

3.2.6 使用@Param标识参数

此时 MyBatis 会将这些参数放在一个 map 集合中,以两种方式进行存储

  • 以@Param注解的值为键,以参数为值
  • 以 param1、param2……为键,以参数为值

dao接口,方法的定义

import com.dy.domain.Student;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface StudentDao {

    //重载方法
    Student selectById(Integer id);

    //dao接口的方法形参是一个简单类型的
    //简单类型:java基本数据类型和String
    Student selectByEmail(String email);

    /*
  多个简单类型的参数
  使用@Param命名参数, 注解是mybatis提供的
  位置:在形参定义的前面
  属性:value 自定义的参数名称
 */
    List<Student> selectByNameOrAge(@Param("myname") String name,
                                    @Param("myage") Integer age);
}

mapper文件

<!--
   多个简单类型的参数.
   当使用了@Param命名后,例如@Param("myname").
   在mapper中,使用#{命名的参数}, 例如 #{myname}
-->
<select id="selectByNameOrAge" resultType="com.bjpowernode.domain.Student">
    select id,name,email,age from student where name=#{myname} or age=#{myage}
</select>

也可以(以 param1、param2……为键)

<!--
   多个简单类型的参数.
   当使用了@Param命名后,例如@Param("myname").
   在mapper中,使用#{命名的参数}, 例如 #{myname}
-->
<select id="selectByNameOrAge" resultType="com.bjpowernode.domain.Student">
    select id,name,email,age from student where name=#{param1} or age=#{param2}
</select>

总结

建议分成两种情况进行处理

  1. 实体类类型的参数
  2. 使用@Param标识参数

3.3 #和$的区别

${}本质是字符串拼接

#{}本质是占位符赋值

3.3.1 # 占位符

语法: #{字符}

mybatis处理#{} 使用jdbc对象是 PrepareStatment对象

<select id="selectById"  parameterType="integer"
             resultType="com.bjpowernode.domain.Student">
    select id,name,email,age from student where id=#{studentId}
</select>

mybatis出创建PrepareStatement对象,执行sql语句
String sql=" select id,name,email,age from student where id=?";
PrepareStatement pst = conn.prepareStatement(sql);
pst.setInt(1,1001);  //传递参数
ResultSet rs  = pst.executeQuery(); //执行sql语句


#{}特点:

1)使用的PrepareStatement对象,执行sql语句,效率高。

2)使用的PrepareStatement对象,能避免sql注入, sql语句执行更安全。

3) #{}常常作为列值使用的, 位于等号的右侧, #{}位置的值和数据类型有关的。

3.3.2 $ 占位符

语法 : ${字符}

mybatis执行${}占位符的sql语句

<select id="selectById"  parameterType="integer"
             resultType="com.bjpowernode.domain.Student">
    select id,name,email,age from student where id=${studentId}
</select>	

${} 表示字符串连接, 把sql语句的其他内容和 ${}内容使用 字符串(+) 连接的方式连在一起
String sql="select id,name,email,age from student where id=" + "1001";

mybatis创建Statement对象, 执行sql语句。
Statement stmt  = conn.createStatement(sql);
ResultSet rs  = stmt.executeQuery();

${} 的特点

1)使用Statement对象,执行sql语句,效率低

2)${}占位符的值,使用的字符串连接方式, 有sql注入的风险。 有代码安全的问题

  1. ${} 数据是原样使用的, 不会区分数据类型。

4)${} 常用作 表名或者列名, 在能保证数据安全的情况下使用 ${}

3.3.3 区别

//${}占位符的使用,不管几个参数,都要使用@Param命名
List<Student> queryStudent(@Param("studentName") String name);
//由于原样使用,需要自己加 ''
@Test
public void testQueryStudent(){
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    StudentDao dao = sqlSession.getMapper(StudentDao.class);
    
    // 注意这里
    List<Student> students = dao.queryStudent("'李四'");
    
    students.forEach(stu -> System.out.println("stu" + stu));
    sqlSession.close();
}

3.3.4 $ 的用处

现在有一个需求,需要根据id、name、email等字段分别排序,如果分开写的话会有好几个重复的方法

如果用 #{},会有问题

List<Student> queryStudentOrderByColName(@Param('colName') String name);

<select id='queryStudentOrderByColName' resultType='com.dy.domain.Student'>
	select * from student order by #{colName}
</select>
@Test
public void testqueryStudentOrderByColName(){
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    StudentDao dao = sqlSession.getMapper(StudentDao.class);
    
    List<Student> students = dao.queryStudentOrderByColName("name");
    
    students.forEach(stu -> System.out.println("stu" + stu));
    sqlSession.close();
}

这里自动拼接完成后,select * from student order by 'name',并不能起到根据name排序的作用

得换成${}。以下是组合使用的一个例子

List<Student> queryStudentOrderByColName(@Param('myname') String name, @Param('colName') String colName);

<select id='queryStudentOrderByColName' resultType='com.dy.domain.Student'>
	select * from student where name=#{myname} order by #{colName} desc
</select>
@Test
public void testqueryStudentOrderByColName(){
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    StudentDao dao = sqlSession.getMapper(StudentDao.class);
    
    List<Student> students = dao.queryStudentOrderByColName("李四", "name");
    
    students.forEach(stu -> System.out.println("stu" + stu));
    sqlSession.close();
}

3.4 封装MyBatis输出结果

封装输出结果: MyBatis执行sql语句,得到ResultSet, 转为java对象。

讲两个 resultType, resultMap(不能同时使用)

resultType:设置默认的映射关系

resultMap:设置自定义的映射

默认的映射关系:当我们把实体类类型设置出来之后,会自动的把我们当前查询出来的结果的字段名来作为属性名为这个当前类中的属性进行赋值,如果能匹配到属性则赋值,如果匹配不到就不赋值。所以在默认的映射关系中,我们尽量要保证实体类中的属性名要跟我们数据库的表的字段包保持一致

自定义的映射:如果字段名跟属性名不一致的情况,用resultMap,或者多对一和一对多关系

3.4.1 resultType

resultType属性: 在执行select时使用, 作为<select>标签的属性出现的。

resultType:表示结果类型 , mysql执行sql语句,得到java对象的类型。 它的值有两种

  1. java类型的全限定名称

  2. 使用别名

resultType:表示java自定义对象

Student selectById(Integer id);

<select id="selectById"  parameterType="integer"
             resultType="com.bjpowernode.domain.Student">
    select id,name,email,age from student where id=#{studentId}
</select>

resultType:现在使用java类型的全限定名称。 表示的意思 mybatis执行sql,把ResultSet中的数据转为Student类型的对象。  mybatis会做以下操作:
1. 调用com.bjpowernode.domain.Student的无参数构造方法,创建对象。
    Student student = new Student(); //使用反射创建对象
2. 同名的列赋值给同名的属性。
    student.setId( rs.getInt("id"));
    student.setName(rs.getString("name"));
3. 得到java对象, 如果dao接口返回值是List集合, mybatis把student对象放入到List集合。


所以执行 Student mystudent = dao.selectById(1001); 得到 数据库中 id=1001这行数据, 
这行数据的列值, 付给了mystudent对象的属性。 你能得到mystudent对象。 就相当于是 id=1001这行数据。

resultType表示简单类型

dao方法

long countStudent();

mapper文件

<!--
  执行sql语句,得到是一个值(一行一列)
-->
<select id="countStudent" resultType="java.lang.Long">
    select count(*) from student
</select>

测试类

@Test
public void testCountStudent(){
    //1.获取SqlSession
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    //2.获取dao的代理
    StudentDao dao = sqlSession.getMapper(StudentDao.class);
    
    long nums = dao.countStudnet();
    System.out.println("nums" + nums)
    sqlSession.close();
}

resultType:表示一个map结构

dao方法

//查询结果返回是一个Map
Map<Object,Object> selectMap(@Param("stuid") Integer id);

mapper文件

<!--
   执行sql得到一个Map结构数据, mybatis执行sql,把ResultSet转为map
   sql执行结果, 列名做map的key , 列值作为value
   sql执行得到是一行记录,转为map结构是正确的。

   dao接口返回是一个map, sql语句最多能获取一行记录,多余一行是错误

-->
<select id="selectMap" resultType="java.util.HashMap">
    select id,name,email from student where id != #{stuid}
</select>

测试类

@Test
public void testCountStudent(){
    //1.获取SqlSession
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    //2.获取dao的代理
    StudentDao dao = sqlSession.getMapper(StudentDao.class);
    
    Map<Object,Object> map = dao.selectMap(1006);
    System.out.println("map===" + map);
    sqlSession.close();
    
    System.out.println("name=" + map.get("name"));
    System.out.println("id=" + map.get("id"));
}

练习题:

输入一个省份id ,得到 省份id ,省份name, 城市id,城市名称

例如输入 省份id=1

1 河北 1 石家庄

1 河北 2 秦皇岛

3.4.2 resultMap

resultMap: 结果映射。 自定义列名和java对象属性的对应关系。 常用在列名和属性名不同的情况。

用法:

  1. 先定义 resultMap标签, 指定列名和属性名称对应关系

  2. 在select标签使用resultMap属性,指定上面定义的resultMap的id值

<!--使用resultMap定义列和属性的关系-->
<!--定义resultMap
    id:给resultMap的映射关系起个名称,唯一值
    type:java类型的全限定名称
-->
<resultMap id="customMap" type="com.bjpowernode.vo.CustomObject">

    <!--定义列名和属性名的对应-->
    <!--主键类型使用id标签-->
    <id column="id" property="cid" />
    <!--非主键类型使用result标签-->
    <result column="name" property="cname" />
    <!--列名和属性名相同不用定义-->
    <result column="email" property="email" />
    <result column="age" property="age" />
</resultMap>

<!--使用resultMap属性,指定映射关系的id
    resultMap和resultType 不能同时使用, 二选一。
-->
<select id="selectById2" resultMap="customMap">
  select id,name,email,age from student where id=#{stuid}
</select>

3.5 自定义别名

mybatis提供的对java类型定义简短,好记名称。

自定义别名的步骤:

  1. 在mybatis主配置文件,使用 typeAliases标签声明别名
  2. 在mapper文件中, resultType="别名"

声明别名(mybatis主配置文件)

<typeAliases>
    <!--第一种语法格式
        type:java类型的全限定名称(自定义类型)
        alias:自定义别名
		
		优点:别名可以自定义
		缺点:每个类型必须单独定义
    -->
    <typeAlias type="com.bjpowernode.domain.Student" alias="stu" />
    
    <!--第二种语法格式
        name:包名,mybatis会把这个包中所有类名作为别名(不用区分大小写)
		
		优点:使用方便,一次给多个类定义别名
		缺点:别名不能自定义,必须是类名。(多个包由相同的类,会冲突报错)
    -->
    <package name="com.bjpowernode.domain" />
</typeAliases>

mapper文件中使用

<!-- 第一种别名 resultType="别名"-->
<select id="selectById"  parameterType="integer" resultType="stu">
    select id,name,email,age from student where id=#{studentId}
</select>

<!-- 第二种别名 resultType="类名",不区分大小写-->
<select id="selectById"  parameterType="integer" resultType="student">
    select id,name,email,age from student where id=#{studentId}
</select>

3.6 列名和java对象属性名称不一样解决方式

1) 使用resultMap: 自定义列名和属性名称对应关系

2)使用resultType: 使用列别名,让别名和java对象属性名称一样

<!--使用列别名,解决列名和属性名不同的问题-->
<select id="selectById3" resultType="com.dy.domain.CustomObject">
	select id as cid, name as cname,email,age from student where id=#{stuid}
</select>

3.7 like

第一种方式: 在java程序中,把like的内容组装好。 把这个内容传入到sql语句

//like第一种方式
List<Student> selectLikeOne(@Param("name") String name);

mapper

<!--like第一种方式-->
<select id="selectLikeOne" resultType="com.bjpowernode.domain.Student">
    select * from student where name like #{name}
</select>

执行like

@Test
public void testLikeOne(){
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    StudentDao dao  = sqlSession.getMapper(StudentDao.class);

    String name="%李%";
    List<Student> students = dao.selectLikeOne(name);

    sqlSession.close();

    students.forEach( stu-> System.out.println(stu));
}

第二种方式: 在sql语句,组织like的内容。

sql语句like的格式: where name like "%"空格#{name}空格"%"

//like第二种方式
List<Student> selectLikeTwo(@Param("name") String name);
<!--like第二种方式-->
<select id="selectLikeTwo" resultType="com.bjpowernode.domain.Student">
    select * from student where name like "%" #{name} "%"
</select>
@Test
public void testLikeTwo(){
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    StudentDao dao  = sqlSession.getMapper(StudentDao.class);

    String name="李";
    List<Student> students = dao.selectLikeTwo(name);

    sqlSession.close();

    students.forEach( stu-> System.out.println(stu));
}

总体上感觉,第一种方式更灵活一点

第四章 动态sql

动态 SQL,通过 MyBatis 提供的各种标签对条件作出判断以实现动态拼接 SQL 语句。这里的条件判断使用的表达式为 OGNL 表达式。常用的动态 SQL 标签有<if>/<where>/<choose>/<foreach>等。 MyBatis 的动态 SQL 语句,与 JSTL 中的语句非常相似。

动态 SQL,主要用于解决查询条件不确定的情况:在程序运行期间,根据 用户提交的查询条件进行查询。提交的查询条件不同,执行的 SQL 语句不同。 若将每种可能的情况均逐一列出,对所有条件进行排列组合,将会出现大量的 SQL 语句。此时,可使用动态 SQL 来解决这样的问题

在 mapper 的动态 SQL 中若出现大于号(>)、小于号(<)、大于等于 号(>=),小于等于号(<=)等符号,最好将其转换为实体符号。否则, XML 可能会出现解析出错问题。

特别是对于小于号(<),在 XML 中是绝不能出现的。否则解析 mapper 文件会出错。

实体符号表:

< 小于 &lt
> 大于 &gt
>= 大于等于 &gt=
<= 小于等于 &lt=

4.1 if 标签

对于该标签的执行,当 test 的值为 true 时,会将其包含的 SQL 片断拼接 到其所在的 SQL 语句中。

语法:


<if test="boolean判断结果">
   sql 代码
</if>


在mapper文件中
<select id="selectStudent" resultType="com.bjpwoernode.domain.Student">
      select *from student
      <if test="条件">
          sql语句
      </if>
      <if test="条件">
          sql语句
      </if>
</select>

例子:

List<Student> selectIf(Student student);
<!--if
    test: 使用对象的属性值作为条件
-->
<select id="selectIf" resultType="com.bjpowernode.domain.Student">
    select * from student
    where id=-1
    <if test="name !=null and name!=''">
       or  name = #{name}
    </if>

    <if test="age >0">
        or age &lt; #{age}
    </if>
</select>

4.2 where 标签

<if>标签的中存在一个比较麻烦的地方:需要在 where 后手工添加 1=1 的子句。因为,若 where 后的所有条件均为 false,而 where 后若又没 有 1=1 子句,则 SQL 中就会只剩下一个空的 where,SQL 出错。所以,在 where 后,需要添加永为真子句 1=1,以防止这种情况的发生。但当数据量很大时,会严重影响查询效率。

使用<where>标签,在有查询条件时,可以自动添加上 where 子句;没有查询条件时,不会添加 where 子句。需要注意的是,第一个<if>标签中的 SQL 片断,可以不包含 and。不过,写上 and 也不错,系统会将多出的 and 去掉。但其它<if>中 SQL 片断的 and,必须要求写上。否则 SQL 语句将拼接 出错

语法:

<where>
    <if test="条件1">sql语句1</if>
    <if test="条件2">sql语句2</if>
</where>

例子:

//where
List<Student> selectWhere(Student student);
<!--where-->
<select id="selectWhere" resultType="com.bjpowernode.domain.Student">
    select * from student
    <where>
        <if test="name !=null and name!=''">
            or  name = #{name}
        </if>

        <if test="age >0">
            or age &lt; #{age}
        </if>
    </where>

</select>

4.3 foreach 循环

<foreach>标签用于实现对于数组与集合的遍历。对其使用,需要注意:

  • collection 表示要遍历的集合类型, list ,array 等。
  • open、close、separator 为对遍历内容的 SQL 拼接。

语法:

< foreach collection="集合类型" open="开始的字符" close="结束的字符"
          item="集合中的成员" separator="集合成员之间的分隔符">
              #{item 的值}
</ foreach>

标签属性:
collection: 表示,循环的对象是 数组, 还是list集合。  如果dao接口方法的形参是 数组, 
             collection="array" ,如果dao接口形参是List, collection="list"

open:循环开始时的字符。  sql.append("(");
close:循环结束时字符。  sql.append(")");
item:集合成员, 自定义的变量。   Integer item  = idlist.get(i);// item是集合成员
separator:集合成员之间的分隔符。  sql.append(","); //集合成员之间的分隔符
#{item 的值}:获取集合成员的值。

手工写

public class MyTest() {
    @Test
    public void testFor() {
        List<Integer> idlist = new ArrayList<>();
        idlist.add(1001);
        idlist.add(1002);
        idlist.add(1003);

        //查询 id 在 idlist 中的 student
        // select * from student where id in (1001,1002,1003)

        StringBuffer sql = new StringBuffer("");
        sql.append("select * from student where id in ");

        //使用循环,把List数据追加到sql字符串中。
        //循环之前加入 (
        sql.append("(");
        for (int i = 0; i < idlist.size(); i++) {
            Integer item = idlist.get(i);  //item是集合成员
            sql.append(item); //添加成员到 sql 字符串
            sql.append(","); //集合成员之间的分隔符
        }

        //去掉 最后的 ,
        sql.deleteCharAt(sql.length() - 1);

        //循环之后加入 )
        sql.append(")");
    }
}

第一种方式(循环简单类型的List集合):

//foreach-1
List<Student> selectForeachOne(List<Integer> idlist);


<!--foreach第一种方式, 循环简单类型的List-->
<select id="selectForeachOne" resultType="com.bjpowernode.domain.Student">
      select * from student
        <if test="list !=null and list.size>0">
            where id in
            <foreach collection="list" open="(" close=")" separator="," item="myid">
                  #{myid}
            </foreach>
        </if>
</select>

@Test
public void testSelectForeachOne(){
        //1.获取SqlSession
        SqlSession session = MyBatisUtil.getSqlSession();
        //2.获取dao的代理
        StudentDao dao = session.getMapper(StudentDao.class);


        List<Integer> idlist = new ArrayList<>();
        idlist.add(1001);
        idlist.add(1002);
        idlist.add(1003);


        List<Student> students  = dao.selectForeachOne(idlist);

        students.forEach( stu-> System.out.println("stu=="+stu));
        //3.关闭SqlSession对象
        session.close();
    }

第二种方式(循环对象类型的List):

//foreach-2
List<Student> selectForeachTwo(List<Student> studentList);

<!--foreach第二种方式, 循环的List<Student>-->
<select id="selectForeachTwo" resultType="com.bjpowernode.domain.Student">
        select * from student
        <if test="list != null and list.size>0">
            where id in
            <foreach collection="list" open="(" close=")" separator="," item="stu">
                  #{stu.id}     //注意这里
            </foreach>
        </if>
</select>
            
 @Test
 public void testSelectForeachTwo(){
        //1.获取SqlSession
        SqlSession session = MyBatisUtil.getSqlSession();
        //2.获取dao的代理
        StudentDao dao = session.getMapper(StudentDao.class);


        List<Student> list  = new ArrayList<>();
        Student s1 = new Student();
        s1.setId(1001);

        Student s2 = new Student();
        s2.setId(1002);

        list.add(s1);
        list.add(s2);


        List<Student> students  = dao.selectForeachTwo(list);

        students.forEach( stu-> System.out.println("stu=="+stu));
        //3.关闭SqlSession对象
        session.close();
    }
            

4.4 sql标签

<sql/>标签用于定义 SQL 片断,以便其它 SQL 标签复用。而其它标签使 用该 SQL 片断,需要使用<include/>子标签。该<sql/>标签可以定义 SQL 语 句中的任何部分,所以<include/>子标签可以放在动态 SQL 的任何位置。

使用方式:

1) 在mapper文件中定义 sql代码片段 <sql id="唯一字符串">  部分sql语句  </sql>
2)在其他的位置,使用include标签引用某个代码片段

例如:

<!--定义代码片段-->
<sql id="selectStudent">
    select * from student
</sql>

<sql id="studentFieldList">
    id,name,email
</sql>

<select id="selectIf" resultType="com.bjpowernode.domain.Student">

        <include refid="selectStudent" />

        where id=-1
        <if test="name !=null and name!=''">
           or  name = #{name}
        </if>

        <if test="age >0">
            or age &lt; #{age}
        </if>
    </select>

    <!--where-->
    <select id="selectWhere" resultType="com.bjpowernode.domain.Student">
        select <include refid="studentFieldList"/> from student
        <where>
            <if test="name !=null and name!=''">
                or  name = #{name}
            </if>

            <if test="age >0">
                or age &lt; #{age}
            </if>
        </where>

    </select>

第五章 MyBatis配置文件

mybatis配置文件两大类: 1 mybatis主配置文件; 2 mybatis的mapper文件

  1. mybatis主配置文件,提供mybatis全局设置的。包含的内容 日志, 数据源,mapper文件位置
  2. mapper文件: 写sql语句的。 一个表一个mapper文件

5.1 settings部分

settings是mybatis的全局设置,影响整个mybatis的运行。 这个设置一般使用默认值就可以了。

<settings>
  <setting name="cacheEnabled" value="true"/>
  <setting name="lazyLoadingEnabled" value="true"/>
  <setting name="multipleResultSetsEnabled" value="true"/>
  <setting name="useColumnLabel" value="true"/>
  <setting name="useGeneratedKeys" value="false"/>
  <setting name="autoMappingBehavior" value="PARTIAL"/>
  <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
  <setting name="defaultExecutorType" value="SIMPLE"/>
  <setting name="defaultStatementTimeout" value="25"/>
  <setting name="defaultFetchSize" value="100"/>
  <setting name="safeRowBoundsEnabled" value="false"/>
  <setting name="mapUnderscoreToCamelCase" value="false"/>
  <setting name="localCacheScope" value="SESSION"/>
  <setting name="jdbcTypeForNull" value="OTHER"/>
  <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>

5.2 typeAliase 别名

设置别名

	<typeAliases>
        <!--第一种语法格式
            type:java类型的全限定名称(自定义类型)
            alias:自定义别名

            优点: 别名可以自定义
            缺点: 每个类型必须单独定义
        -->
        <typeAlias type="com.bjpowernode.domain.Student" alias="stu" />
        <typeAlias type="com.bjpowernode.vo.QueryParam" alias="qp" />

        <!--第二种方式
            name:包名, mybatis会把这个包中所有类名作为别名(不用区分大小写)
            优点:使用方便,一次给多个类定义别名
            缺点: 别名不能自定义,必须是类名。
        -->
        <package name="com.bjpowernode.domain" />
        <package name="com.bjpowernode.vo" />

    </typeAliases>

5.3 配置环境

environments: 环境标签, 在他里面可以配置多个environment
       属性: default ,必须是某个environment的id属性值。 表示mybatis默认连接的数据库
environment: 表示一个数据库的连接信息。
       属性: id 自定义的环境的标识。 唯一值。
transactionManager:事务管理器
       属性:  type 表示事务管理器的类型。
       属性值:1)JDBC: 使用Connection对象, 由mybatis自己完成事务的处理。
             2) MANAGED: 管理,表示把事务的处理交给容器实现(由其他软件完成事务的提交,回滚)
dataSource: 数据源,创建的Connection对象,连接数据库。
       属性:  type 数据源的类型
       属性值:1) POOLED, mybatis会在内存中创建PooledDataSource类,管理多个Connection连接对象,使                           用的连接池
             2) UNPOOLED ,不使用连接池, mybatis创建一个UnPooledDataSource这个类, 每次执行sql                           语句先创建Connection对象,再执行sql语句,最后关闭Connection
             3) JNDI : java的命名和目录服务。

<environments default="online">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <!--配置数据源: 创建Connection对象。-->
            <dataSource type="POOLED">
                <!--driver:驱动的内容-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <!--连接数据库的url-->
                <property name="url"
                          value="jdbc:mysql://localhost:3306/springdb"/>
                <!--用户名-->
                <property name="username" value="root"/>
                <!--密码-->
                <property name="password" value="123"/>
            </dataSource>
        </environment>
        <!-- 项目上线后使用的数据库 -->
        <environment id="online">
            <transactionManager type="JDBC"/>
            <!--配置数据源: 创建Connection对象。-->
            <dataSource type="POOLED">
                <!--driver:驱动的内容-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <!--连接数据库的url-->
                <property name="url"
                          value="jdbc:mysql://localhost:3306/springdb"/>
                <!--用户名-->
                <property name="username" value="admin"/>
                <!--密码-->
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

5.4 使用数据库属性配置文件(*)

需要把数据库的配置信息放到一个单独文件中, 独立管理。 这个文件扩展名是 properties. 在这个文件中,使用自定义的key=value的格式表示数据

使用步骤:

1.在resources目录中,创建xxxx.properties

2.在文件中,使用 key=value的格式定义数据。

例如 jdbc.url=jdbc:mysq://localhost:3306/springdb

3.在mybatis主配置文件, 使用properties标签引用外部的属性配置文件

4.在使用值的位置, 使用${key}获取key对应的value(等号右侧的值)

例子:

jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/springdb?useUnicode=true&amp;characterEncoding=utf-8
jdbc.username=root
jdbc.password=123

mybatis主配置文件

<!--使用外部属性配置文件
    resource:指定类路径下的某个属性配置文件
-->
<properties resource="jdbc.properties" />

<environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <!--配置数据源: 创建Connection对象。-->
            <dataSource type="POOLED">
                <!--driver:驱动的内容-->
                <property name="driver" value="${jdbc.driver}"/>
                <!--连接数据库的url-->
                <property name="url" value="${jdbc.url}"/>
                <!--用户名-->
                <property name="username" value="${jdbc.username}"/>
                <!--密码-->
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
         </environment>
</environments>

5.5 mapper 标签(*)

使用mapper指定其他mapper文件的位置,

mapper标签使用的格式有两个常用的方式:

<mappers>
    <!--第一种方式, resources="mapper文件的路径"
        优点:文件清晰。 加载的文件是明确的。
              文件的位置比较灵活。
        缺点:文件比较多, 代码量会比较大, 管理难度大
    -->
    <mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
    <mapper resource="com/bjpowernode/dao/OrderDao.xml"/>
    <!--
       第二种方式,使用<package>
       name:包名, mapper文件所在的包名。
       特点: 把这个包中的所有mapper文件,一次加载。

       使用要求:
        1. mapper文件和dao接口在同一目录
        2. mapper文件和dao接口名称完全一样。
    -->
    <package name="com.bjpowernode.dao" />
    <package name="com.bjpowernode.dao1" />
</mappers>

第六章 PageHelper

PageHelper做数据分页。 在你的select语句后面加入 分页的 sql 内容, 如果你使用的mysql数据库, 它就是在select * from student 后面加入 limit 语句。

使用步骤:

1.加入依赖pagehelper依赖

<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.10</version>
</dependency>

2.在mybatis主配置文件, 加入plugin声明

在<environments> 之前加入
<plugins>
   <plugin interceptor ="com.github.pagehelper.PageInterceptor" />
</plugins>    

3.springboot 配置

pagehelper.helperDialect=mysql
# 分页合理化参数,默认值为false。当该参数设置为 true 时,pageNum<=0 时会查询第一页, pageNum>pages(超过总数时),会查询最后一页
pagehelper.reasonable=true
# 支持通过 Mapper 接口参数来传递分页参数
pagehelper.supportMethodsArguments=true

4.在select语句之前,调用PageHelper.startPage(页码, 每页大小)

public PageInfoListResult queryRelationDataByDomainId(CompareInfoVO compareInfoVO, Long methodType) {

	PageHelper.startPage(1, 100);
    List<CodeRelationDto> codeRelationList = accurateInfoDao.queryRelationDataByDomainId(
		compareInfoVO.getDept(), compareInfoVO.getDomainId(), compareInfoVO.getUrl(), methodType);
    return xxx;

}
posted @ 2022-02-04 23:22  dongye95  阅读(69)  评论(0编辑  收藏  举报