MyBatis框架

一、概述

三层架构

三层

1、界面层:和用户打交道,接受用户的请求参数,显示处理结果。(jsp、html、servlet)
2、业务逻辑层:接受页面层传递的数据,计算逻辑,调用数据库,获取数据。
3、数据访问层:就是访问数据库,对数据库中的数据增删改查。

三层架构对应的包

1、界面层:controller包(servlet)
2、业务逻辑层:service包(XXXServicelei)
3、数据访问层:dao包(XXXDao类)

三层中类的交互

用户使用界面层---->业务逻辑层–>数据访问层(持久层)–>数据库

三层对应的处理框架

界面层:servlet----springmvc(框架)
业务逻辑层:service类----spring(框架)
数据访问层:dao类----MyBatis(框架)

框架

框架是一个舞台,一个模板。
1、框架中定义了一些功能。这些功能是可用的。
2、可以加入项目中自己的功能,这些功能可以利用框架中写好的功能。

框架是一个软件,半成品软件,定义好了一些功能,需要加入自己所需的功能就完整了。
基础功能是可重复使用的,可升级的。

框架特点

1、框架不是全能的,不能做所有事情
2、框架是针对某一领域有效。
3、框架是一个半成品软件。

JDBC缺陷

大量的代码重复,核心就只是sql语句,效率低。
需要关注Connection,Statement,ResultSet对象的创建和关闭。
对查询结果ResultSet需要自己封装成List
业务代码和数据库操作混在一起

MyBatis框架概述

减轻使用JDBC的复杂性,不用编写重复的创建Connection,Statement;不用编写关闭资源代码。直接使用java对象,表示结果数据。
可以完成:
1、注册数据库驱动。
2、创建JDBC必须使用的Connection,Statement,ResultSet对象。
3、从xml中获取sql,并执行sql语句,把ResultSet结果转换成java对象。
4、

主要功能

1、sql mapper

sql映射。可以把表中的一行数据映射为一个java对象。一行数据可以看作一个java数据。操作这个对象相当于操作表中的数据。

2、Data Access Objects

DAOs 数据访问。对数据库执行增删改查。

MyBatis提供功能

1、创建Connection,Statement,ResultSet的能力,不需要开发人员创建。
2、提供了执行sql语句的能力
3、提供了循环sql,把sql结果转为java对象,List集合的能力
4、提供了资源关闭的能力。

达到开发人员只需提供sql语句,MyBatis处理sql,开发人员得到List集合或Java对象。

二、入门

准备工作

配置日志功能

mybatis.xml文件中加入日志配置:可以在控制台输出执行的sql语句和参数
settings:控制mybatis全局行为的。

<settings>
	<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

基本步骤

本地文件实例:D:\JAVACODE\MyBatis\ch01

1、加入maven依赖

pom.xml 中加入mybatis依赖

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

pom.xml 中加入mysql驱动依赖

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

2、创建Dao接口

定义了操作数据的方法
创建dao包,在此包下创建XXXDao接口

package com.daihan.dao;

import com.daihan.domain.Student;

import java.util.List;

//接口,操作Student表
public interface StudentDao {
    //查询student表所有数据
    public List<Student> selectStudent();
       
    //插入方法
    //参数student表示插入到数据库的数据
    //返回值表示执行insert之后,影响数据库的行数
    public int insertStudent(Student student);
}

3、创建mapper文件

也叫做sql映射文件:写sql语句的,和接口中方法对应的sql语句。
注:mapper文件与Dao接口在想同包下(dao包),且文件名相同,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.daihan.dao.StudentDao">

    <!--
        select:表示查询操作
        id:要执行的sql语句的唯一标识,mybatis会使用这个id值来找到要执行的sql语句
            可以自定义,但要求使用接口中的方法名
        resultType:表示结果类型的,是sql语句执行结束之后得到的ResultSet得到Java对象的类型
            值写的是类型的全限定名称
    -->
    <select id="selectStudent" resultType="com.daihan.domain.Student">
        select id,name,email,age from student order by id
    </select>

	<!--例2 插入操作-->
    <insert id="insertStudent">
        <!--#{属性名} 表示占位符,到时候去实例对象中取具体值-->
        insert into student values(#{id},#{name},#{email},#{age})
    </insert>
</mapper>
<!--
    sql映射文件(sql mapper):是写sql语句的,mybatis会执行这些sql
    1、指定约束文件
        <!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

        mybatis-3-mapper.dtd是约束文件的名称,扩展名是dtd
    2、约束文件的作用:
        限制、检查在当前文件中出现的标签,属性必须符合mybatis的要求。
    3、mapper 是当前文件的根标签,必须的。
        namespace:叫做命名空间,唯一值,可以是自定义的字符串
            要求使用dao接口的全限定名称。
    4、在当前文件中,可以使用特定的标签,表示数据库的操作
        <select>:表示执行查询
        <update>:表示执行更新
        <delete>:表示执行删除
        <insert>:表示执行插入

-->

4、创建mybatis的主配置文件

作用:
1、连接数据库
2、指定mapper文件的位置
位置:
main/resources目录下的xml文件

<?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>
    <!--
        环境配置:数据库的连接信息
        default:必须和某个environment的id值一样。
        告诉mybatis使用哪个数据库的连接信息。也就是访问哪个数据库
    -->
    <environments default="mydev">
        <!-- environment:一个数据库信息的配置,环境
            id是个唯一值,自定义的,表示环境名称,用于说明当前使用的库。
            通过改动对应值,切换数据库。
         -->

        <!--开发使用的库-->
        <environment id="mydev">
            <!--
                transactionManager:mybatis的事务类型
                    type:JDBC(表示使用JDBC中的Connection对象的commit,rolllback)
            -->
            <transactionManager type="JDBC"/>
            <!--
                dataSource:表示数据源,连接数据库的
                    type:表示数据源类型,POOLED表示使用连接池
            -->
            <dataSource type="POOLED">
                <!--
                    driver,url,username,password是固定的,不能随意改
                -->
                <!--数据库的驱动类名-->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <!--连接数据库的url字符串-->
                <property name="url" value="jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC"/>
                <!--访问数据库的用户名-->
                <property name="username" value="root"/>
                <!--访问数据库的密码-->
                <property name="password" value="a123b456"/>
            </dataSource>
        </environment>

        <!--表示线上的数据库,是项目真实使用的库-->
        <environment id="online">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC"/>
                <property name="username" value="root"/>
                <property name="password" value="a123b456"/>
            </dataSource>
        </environment>
    </environments>


    <!--sql mapper(sql映射文件)的位置-->
    <mappers>
        <!--
            一个mapper标签指定一个文件的位置
            从类路径开始的路径信息。target/classes(类路径)
        -->
        <mapper resource="com/daihan/dao/StudentDao.xml"/>
    </mappers>
</configuration>
<!--
    这是mybatis的主配置文件:主要定义了数据库的配置信息,sql映射文件的位置

    1、约束文件
        <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
        mybatis-3-config.dtd:约束文件的名称
    2、<configuration>根标签
-->

5、使用mybatis对象

使用mybatis对象SqlSession,通过它的方法执行sql语句
例1,执行查询

public class MyApp {
    public static void main(String[] args) throws IOException {
        //访问MyBatis读取student数据
        //1、定义MyBatis主配置文件的名称,从类路径根开始(target/classes)
        String config = "mybatis.xml";
        //2、读取这个文件
        InputStream in = Resources.getResourceAsStream(config);
        //3、创建sqlSessionFactoryBuilder
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //4、创建SqlSessionFactory对象
        SqlSessionFactory factory = builder.build(in);
        //5、【重要】获取SqlSession对象,从SqlSessionFactory中获取
        SqlSession sqlSession = factory.openSession();
        //6、【重要】指定要执行的sql语句的标识.使用sql映射文件中的namespace+"."+标签的id值
        String sqlid = "com.daihan.dao.StudentDao" + "." + "selectStudent";
        
        //7、执行sql语句,通过sqlid找到语句
        List<Student> studentList = sqlSession.selectList(sqlid);
        //8、输出结果
        studentList.forEach(student -> System.out.println(student));
        //9、关闭SqlSession对象
        sqlSession.close();
    }
}

例2,执行插入

	public void testInsert() throws IOException {
        //访问MyBatis读取student数据
        //1、定义MyBatis主配置文件的名称,从类路径根开始(target/classes)
        String config = "mybatis.xml";
        //2、读取这个文件
        InputStream in = Resources.getResourceAsStream(config);
        //3、创建sqlSessionFactoryBuilder
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //4、创建SqlSessionFactory对象
        SqlSessionFactory factory = builder.build(in);
        //5、【重要】获取SqlSession对象,从SqlSessionFactory中获取
        SqlSession sqlSession = factory.openSession();
        //6、【重要】指定要执行的sql语句的标识.使用sql映射文件中的namespace+"."+标签的id值
        String sqlid = "com.daihan.dao.StudentDao" + "." + "insertStudent";
        //7、执行sql语句,通过sqlid找到语句
        Student student1 = new Student();
        student1.setId(1003);
        student1.setName("张飞");
        student1.setEmail("zhangfei@163.com");
        student1.setAge(20);
        int nums = sqlSession.insert(sqlid,student1);
        //mybatis默认是不会提交事务,在insert,update,delete后需要手动提交
        sqlSession.commit();
        //8、输出结果
        System.out.println("执行insert的结果:"+nums);
        //9、关闭SqlSession对象
        sqlSession.close();
    }

使用工具类(进阶)

因为核心是获取SqlSession

com.daihan下创建新的package:MyBatisUtil

package com.daihan.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;

public class MyBatisUtil {

    private static SqlSessionFactory factory=null ;

    static {
        String config="mybatis.xml";//需要和项目名对应
        try {
            InputStream in=Resources.getResourceAsStream(config);
            //创建SqlSessionFactory对象,使用SqlSessionFactoryBuild
            factory=new SqlSessionFactoryBuilder().build(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //获取SqlSession的方法
    public static SqlSession getSqlSession(){
        SqlSession sqlSession=null;
        if (factory!=null){
            sqlSession=factory.openSession();//非自动提交事务
        }
        return sqlSession;
    }
}

主函数可以改为:

package com.daihan;


import com.daihan.domain.Student;
import com.daihan.utils.MyBatisUtil;
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;
import java.util.List;

public class MyApp2 {
    public static void main(String[] args) throws IOException {

        //【重要】获取SqlSession对象,从SqlSessionFactory中获取
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        //【重要】指定要执行的sql语句的标识.使用sql映射文件中的namespace+"."+标签的id值
        String sqlid = "com.daihan.dao.StudentDao" + "." + "selectStudent";
        //执行sql语句,通过sqlid找到语句
        List<Student> studentList = sqlSession.selectList(sqlid);
        //输出结果
        studentList.forEach(student -> System.out.println(student));
        //关闭SqlSession对象
        sqlSession.close();
    }
}

主要的类介绍

1、Resources

mybatis中的一个类,负责读取主配置文件
InputStream in = Resources.getResourceAsStream("mybatis.xml");

2、SqlSessionFactoryBuilder

用来创建SqlSessionFactory对象
一、创建SqlSessionFactoryBuilderSqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
二、使用builder创建SqlSessionFactory对象SqlSessionFactory factory = builder.build(in);

3、SqlSessionFactory(重要)

重量级对象,程序创建这个对象耗时长,使用资源多,在整个项目中有一个就够了。

SqlSessionFactory是一个接口,接口默认实现类:DefaultSqlSessionFactory,
SqlSessionFactory作用:获取SqlSession对象。SqlSession sqlSession = factory.openSession();
openSession()方法说明:
1、openSession()无参数,获取非自动提交事务的SqlSession对象
2、openSession(boolean):参数true时,是获取自动提交事务的SqlSession;参数false时,是获取非自动提交事务的SqlSession对象。

SqlSession(重要)

SqlSession是接口,定义了操作数据库的方法,例如:selectONe(),selectList(),insert(),update(),delete(),commit(),rollback()。
SqlSession接口实现类DefaultSqlSession,
使用要求:SqlSession对象不是线程安全的,需要在方法内部使用,在执行sql语句之前要使用openSession()获取SqlSession对象,在执行sql语句之后,需要关闭它,执行SqlSession.close();这样保证线程安全。

MyBatis使用传统Dao开发

本地文件位置:D:\JAVACODE\MyBatis\ch02-nybatis-dao
规律:

资源配置文件

main下新建resources目录
创建mybatis.xml文件

<?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>
        <!--设置mybatis打印日志-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <environments default="mydev">
        <environment id="mydev">

            <transactionManager type="JDBC"/>

            <dataSource type="POOLED">

                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>

                <property name="url" value="jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC"/>

                <property name="username" value="root"/>

                <property name="password" value="a123b456"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="com/daihan/dao/StudentDao.xml"/>
    </mappers>
</configuration>

创建dao包

1、定义接口

package com.daihan.dao;

import com.daihan.domain.Student;

import java.util.List;

public interface StudentDao {
    List<Student> selectStudents();

    int insertStudent(Student student);
}

2、dao下子包定义接口实现类

package com.daihan.dao.impl;

import com.daihan.domain.Student;
import com.daihan.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;

import java.util.List;

public class StudentDaoImpl implements com.daihan.dao.StudentDao {
    @Override
    public List<Student> selectStudents() {
        //1、获取SqlSession对象
        SqlSession sqlSession= MyBatisUtil.getSqlSession();
        String sqlId="com.daihan.dao.StudentDao"+'.'+"selectStudents";

        //2、执行sql语句,使用SqlSession类的方法
        List<Student> students=sqlSession.selectList(sqlId);

        //3、关闭
        sqlSession.close();
        return students;
    }

    @Override
    public int insertStudent(Student student) {
        //1、获取SqlSession对象
        SqlSession sqlSession= MyBatisUtil.getSqlSession();
        String sqlId="com.daihan.dao.StudentDao"+'.'+"insertStudent";

        //2、执行sql语句,使用SqlSession类的方法
        int nums=sqlSession.insert(sqlId,student);
        //提交事务
        sqlSession.commit();


        //3、关闭
        sqlSession.close();
        return nums;
    }
}

3、dao接口同名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.daihan.dao.StudentDao">
    <select id="selectStudents" resultType="com.daihan.domain.Student">
        select id,name,email,age from student order by id
    </select>

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

创建domain包下实体类

package com.daihan.domain;

public class Student {
    //定义属性,目前属性名和列名一致
    private Integer id;
    private String name;
    private String email;
    private Integer age;

    public Student() {

    }

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

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

创建工具包util

package com.daihan.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=null ;

    static {
        String config="mybatis.xml";//需要和项目名对应
        try {
            InputStream in=Resources.getResourceAsStream(config);
            //创建SqlSessionFactory对象,使用SqlSessionFactoryBuild
            factory=new SqlSessionFactoryBuilder().build(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //获取SqlSession的方法
    public static SqlSession getSqlSession(){
        SqlSession sqlSession=null;
        if (factory!=null){
            sqlSession=factory.openSession();//非自动提交事务
        }
        return sqlSession;
    }
}

主程序

在test/java/com/daihan/新建主程序

package com.daihan;

import com.daihan.dao.StudentDao;
import com.daihan.dao.impl.StudentDaoImpl;
import com.daihan.domain.Student;
import org.junit.Test;

import java.util.List;

public class TestMyBatis {
    @Test
    public void testSelectStudent(){
        StudentDao dao = new StudentDaoImpl();
        List<Student> studentList=dao.selectStudents();

        for(Student stu:studentList){
            System.out.println(stu);
        }
    }

    @Test
    public  void testInsertStudent(){
        StudentDao dao = new StudentDaoImpl();
        int nums= dao.insertStudent(new Student(1004,"王五","wangwu@163.com",20));
        System.out.println("添加对象:"+nums);
    }
}

三、Dao代理(核心)

1、MyBatis动态代理机制(重点)

本地文件位置:D:\JAVACODE\MyBatis\ch03-proxy-dao
重点是:使用sqlSession.getMapper(dao接口.class) ,获取这个dao接口的对象

     1、dao对象,类型是StudentDao,全限定名称:com.daihan.dao.StudentDao
    全限定名称和namespace一致
    
     2、方法名称,selectStudents,这个方法就是mapper文件的id值
    
     通过dao方法中的返回值也可以确定MyBatis要调用的SqlSession方法
     如果返回值是List,调用的是SqlSession.selectList()方法
     如果返回值是int,看mapper中的标签是<insert>或是<update>...
    
     mybatis动态代理:mybatis根基dao方法调用,获取执行sql语句的信息。
     根据dao接口创建dao接口的实现类,并创建个类对象,完成SqlSession调用,访问数据库

使用动态代理机制,不再需要实现dao包下XXXDao接口中的方法。
主程序

package com.daihan;

import com.daihan.dao.StudentDao;
import com.daihan.domain.Student;
import com.daihan.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class TestMyBatis {
    @Test
    public void testSelectStudent(){
        /*
        使用mybatis的动态代理机制,使用SqlSession.getMapper(dao接口)
        getMapper能获取dao接口对应的实现类对象
         */
        SqlSession sqlSession= MyBatisUtil.getSqlSession();
        StudentDao dao=sqlSession.getMapper(StudentDao.class);
        //底层自动生成实现类
        System.out.println("类"+dao.getClass().getName());
        //调用dao方法,执行数据库的操作
        List<Student> studentList = dao.selectStudents();
        for(Student stu:studentList){
            System.out.println(stu);
        }
    }

    @Test
    public  void testInsertStudent(){
        SqlSession sqlSession= MyBatisUtil.getSqlSession();
        StudentDao dao=sqlSession.getMapper(StudentDao.class);
        调用dao方法,执行数据库的操作
        int nums= dao.insertStudent(new Student(1005,"关羽","guanyu@163.com",20));
        sqlSession.commit();
        System.out.println("添加对象:"+nums);
    }
}

2、深入理解参数(重点)

从Java代码中把参数传到xml文件中。

1、parametType

写在mapper文件中的一个属性。表示dao接口中方法的参数的数据类型。
例如StudentDao接口

public Student selectStudentById(Integer id)

2、传入一个简单类型的参数:

在mapper文件获取简单类型的一个参数的值,使用#{任意字符串}
接口:public Student selectStudentById(Integer id);
mapper:select id,name,email,age from student where id=#{id}

3、传入多个参数(掌握前两个)

1)使用@Param(重要)

当Dao接口方法多个参数,需要通过名称使用参数。在方法形参前面加入@Param(“自定义参数名”),mapper文件使用#{自定义参数名}
例如:定义List<Studnet> selectStudent( @Param("personName") String name,Integer age)
mapper文件 select * from student where name=#{personName}
例如:
dao包下StudentDao接口中

package com.daihan.dao;

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

import java.util.List;

public interface StudentDao {
        /*
        传入一个简单类型的参数:
        在mapper文件获取简单类型的一个参数的值,使用#{任意字符串}
         */
        public Student selectStudentById(Integer id);

        /*
        多个参数:命名参数,在形参定义前面加入@Param("自定义参数名称")
         */
        List<Student> selectMultiParam(@Param("myname")String name,
                                       @Param("myage")Integer age);
}

dao包下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.daihan.dao.StudentDao">
    <select id="selectStudentById" parameterType="java.lang.Integer" resultType="com.daihan.domain.Student">
        select id,name,email,age from student where id=#{id}
    </select>

    <!--多个参数,使用@Param命名-->
    <select id="selectMultiParam" resultType="com.daihan.domain.Student">
        select id,name,email,age from student where name=#{myname} or age=#{myage}
    </select>
</mapper>

实体类和工具类同上,省略
测试主程序:

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

        List<Student> students = dao.selectMultiParam("关羽",20);
        for(Student stu:students){
            System.out.println("学生:"+stu);
        }
    }
}
2)使用对象传参(使用最多)

新建包vo,新建实体类:
(也可以不新增实体类,继续用已有的,例如Student类)

package com.daihan.vo;

public class QueryParam {
    private String paramName;
    private Integer paramAge;

    public String getParamName() {
        return paramName;
    }

    public Integer getParamAge() {
        return paramAge;
    }

    public void setParamName(String paramName) {
        this.paramName = paramName;
    }

    public void setParamAge(Integer paramAge) {
        this.paramAge = paramAge;
    }
}

dao包下StudentDao接口中新建方法:

        /*
        多个参数,使用java对象作为接口中方法的参数
         */
        List<Student> selectMultiObject(QueryParam param);

dao包下StudentDao.xml中新增:

    <!--
        多个参数,使用java对象的属性值,作为参数实际值
        使用对象语法:#{属性名,javaType=类型名称,jdbcType=数据库类型}
            javaType:指java中的属性数据类型
            jdbcType:在数据库中的数据类型
            例如:#{paramName,javaType=java.lang.String,jdbcType=varchar}
        简化:
            #{属性名},javaType,jdbcType的值mybatis发射能获取。不用提供
    -->
    <!--<select id="selectMultiObject" resultType="com.daihan.domain.Student">
        select id,name,email,age from student where
        name=#{paramName,javaType=java.lang.String,jdbcType=VARCHAR}
        or age=#{paramAge,javaType=java.lang.Integer,jdbcType=INTEGER}
    </select>-->
    <select id="selectMultiObject" resultType="com.daihan.domain.Student">
        select id,name,email,age from student where
        name=#{paramName}
        or age=#{paramAge}
    </select>

测试程序增加测试方法:

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

        QueryParam param = new QueryParam();
        param.setParamAge(20);
        param.setParamName("李四");
        List<Student> students = dao.selectMultiObject(param);
        for(Student stu:students){
            System.out.println("学生:"+stu);
        }
    }
3)按位置传参(不建议)

从0开始,计算位置。
传的是简单类型的参数
语法:
接口方法中:参数列表(参数类型 参数名,…)
xml文件中:#{arg0}、#{arg1}...

4)Map传参 (不建议)

xml文件中#{key1},#{key2}…通过key传参
缺点:可读性差,map中key的值改动,xml文件#{key}也要改

#和$区别

#(首选)

告诉mybatis使用实际的参数值替代。并使用PrepareStatement对象执行sql语句,#{…}代替sql语句中的“?”。

$

告诉mybatis使用$包含的字符串替换所在位置。使用Statement把sql语句和${}的内容连接起来。主要用在替换表名,列名,不同列排序等操作。

区别

1、#使用?在sql语句中做占位符,使用PrepareStatement对象执行sql语句,效率高。并且能防注入
2、$不使用占位符,是字符串拼接方式,使用Statement执行sql语句,效率低。有注入风险。
3、$可以替换表名或列名

3、封装MyBatis输出结果

MyBatis输出结果:MyBatis执行了sql语句,得到Java对象。
resultType和resultMap不能同时使用。

1)resultType

resultType:执行sql得到ResultSet转换的类型,使用类型的完全限定名或别名。注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。
处理方式:

1、mybatis执行sql语句,然后mybatis调用类的无参构造方法,创建对象。
2、mybatis把ResultSet指定列值付给同名属性。

2)定义别名

1、在mybatis主配置文件中定义,使用<typeAlias>定义别名
2、可以在resultType中使用别名

例如:

<typeAliases>
	<!--
		第一种方式
		可以指定一个类型一个别名
		type是要自定以别名的类的全限定名称
		alias是自定义别名
	-->
	<typeAlias type="com.daihan.domain.Student1" alias="stu1"/>
	<typeAlias type="com.daihan.domain.Student2" alias="stu2"/>
	...

	<!--
		第二种方式
		<package name>name是包名,这个包中所有类,类名就是别名(不区分大小写)
	-->
	<package name="com.daihan.domain"/>
	<package name="com.daihan.vo"/>
	...
</typeAliases>

3)查询返回Map(用的少)

dao包下接口XXXDao的方法:

Map<Object,Object> selectMapById(Integer id){};

dao包下XXXDao.xml文件

	<!--
		返回Map
		1、属性名是Map的key,属性值是Map的value
		2、返回Map的时候,最多返回一行记录
	-->
    <select id="selectMapById" resultType="java.util.Map">
        select id,name,email,age from student where id=#{id}
    </select>

test/java/com/daihan/Test主程序中新增方法

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

		Map<Okbject,Object> map=dao.selectMapById(1001);
        for(Student stu:students){
            System.out.println("学生:"+stu);
        }
    }

4)resultMap 结果映射

指定列名(属性名)和java对象的属性对应关系。
resultMap和resultType不能同时使用,二选一。

1、自定义列值赋值给哪个属性(原本默认赋值给同名的属性)
2、当列名和属性名不一样时,一定要使用result

dao包下XXXDao接口中,增加方法

        //使用resultMap定义映射关系
        List<Student> selectAllStudents();

dao包下XXXDao.xml,增加

    <!--
        使用resultMap
        1、先定义resultMap
        2、在select标签,使用resultMap来引用1定义的resultMap
    -->
    <!--
        id:自定义的名称,表示自定义的这个resultMap
        type:java类型的全限定名称
    -->
    <resultMap id="studentMap" type="com.daihan.domain.Student">
        <!--
            定义列名和java属性的关系
            column:列名
            property:java属性名
            主键列用id;非主键列使用result
        -->
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="email" property="email"/>
        <result column="age" property="age"/>
    </resultMap>
    <select id="selectAllStudents" resultMap="studentMap">
        select id,name,email,age from student
    </select>

测试主方法:略

列名属性名不同第二种解决方案

新增实体类MyStudent:略

dao包下XXXDao接口中,增加方法

        //使用resultMap定义映射关系
        List<MyStudent> selectDifferentColumnProperty();

dao包下XXXDao.xml,增加

    <!--
		resultType默认原则是:同名的列赋值给同名的属性,使用列别名(java对象属性名)
	-->
    <select id="selectDifferentColumnProperty" resultType="studentMap">
        select id as stuId,name as stuName,email as stuEmail,age as stuAge from student
    </select>

测试主方法:略

模糊Like

第一种方式(推荐)

在java代码中指定like内容
dao包下XXXDao接口中,增加方法

        //第一种模糊查询,在java代码中指定like内容
        List<Student> selectLikeOne(String name);

dao包下XXXDao.xml,增加

    <!--第一种like,java代码中指定like内容-->
    <select id="selectLikeOne" resultType="com.daihan.domain.Student">
        select id,name,email,age from student where name like #{name}
    </select>

测试主方法:

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

        //准备like内容
        String name="%李%";
        List<Student> students = dao.selectLikeOne(name);
        for(Student stu:students){
            System.out.println("学生:"+stu);
        }
    }

第二种方式

在mapper文件中拼接like内容
dao包下XXXDao接口中,增加方法

        //第二种模糊查询,在mapper中拼接 "%"+"李"+"%"
        List<Student> selectLikeTwo(String name);

dao包下XXXDao.xml,增加

    <!--第二种like,mapper中拼接,注意'%' #{} '%'之间有空格."%"或'%'不影响-->
    <select id="selectLikeTwo" resultType="com.daihan.domain.Student">
        select id,name,email,age from student where name like "%" #{name} "%"
    </select>

注: 上述情况有时会”@P0“巴拉巴拉错误,应使用如下语句。

    <!--第三种like,mapper中拼接,注意'%${}%'之间没有有空格。占位符需要$-->
    <select id="selectLikeTwo" resultType="com.daihan.domain.Student">
        select id,name,email,age from student where name like '%${name}%'
    </select>

测试主方法:

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

        //准备like内容
        String name="李";
        List<Student> students = dao.selectLikeTwo(name);
        for(Student stu:students){
            System.out.println("学生:"+stu);
        }
    }

四、动态SQL(重点)

动态SQL:sql内容是变化的,可以根据条件获取不同的sql语句。主要是where部分发生变化。
动态SQL实现:使用的是MyBatis提供的标签,<if> ,<where>, <foreach>

1)if

if是判断条件的
语法:

<if test="判断一个Java对象的属性值">
	<!--部分sql语句-->
</if>

dao包下XXXDao接口新增方法:

public interface StudentDao {
    //动态sql,传参使用java对象
    //if的使用
    List<Student> selectStudentIf(Student student);
}

dao包下XXXDao.xml,增加

    <!--
        if
        <if test="使用参数java对象的属性值做判断条件">
            语句
        </if>
        满足if test条件时,把语句加到where后面
    -->
    <select id="selectStudentIf" resultType="com.daihan.domain.Student">
        select id,name,email,age from student
        where 1=1
        <if test="name !=null and name !=''">
            and name=#{name}
        </if>
        <if test="age>0">
            or age>#{age}
        </if>
    </select>

测试程序:

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

        List<Student> students = dao.selectStudentIf(new Student(1003, "李四", "123@163.com", 18));
        for(Student stu:students){
            System.out.println(stu);
        }
    }

2)where

where是用来包含多个if的,当多个if有一个成立的时候,where会自动增加一个where关键字,并去掉if中多余的and,or之类的。
dao包下XXXDao接口新增方法:

    //where的使用
    List<Student> selectStudentWhere(Student student);

dao包下XXXDao.xml,增加

    <!--
        where:<where><if>...</if></where>
    -->
    <select id="selectStudentWhere" resultType="com.daihan.domain.Student">
        select id,name,email,age from student
        <where>
            <if test="name !=null and name !=''">
                name=#{name}
            </if>
            <if test="age>0">
                or age>#{age}
            </if>
        </where>
    </select>

测试程序:

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

        Student student = new Student();
        student.setAge(18);
        List<Student> students = dao.selectStudentWhere(student);
        for(Student stu:students){
            System.out.println(stu);
        }
    }

3)choose、when

4)foreach

底层是字符串的拼接

集合中是基本数据类型

循环java中的数组,List集合的。主要用在sql的in语句中。
例如需要执行以下语句:select * from student where id in (1001,1002,1003)
dao包下XXXDao接口新增方法:

    //foreach的使用
    List<Student> selectForeachOne(List<Integer> idList);

dao包下XXXDao.xml,增加

    <!--foreach使用:1、List<integer>-->
    <select id="selectForeachOne" resultType="com.daihan.domain.Student">
        select * from student where id in
        <!--
            collection,用来表示接口中方法参数类型,数组写array,List集合写list
            item,自定义的表示数组和集合成员的变量
            open,循环开始是字符
            close,循环结束时字符
            separator,集合成员之间的分割符
        -->
        <foreach collection="list" item="myid" open="(" close=")" separator=",">
            #{myid}
        </foreach>
    </select>

测试程序:

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

        List<Integer> list = new ArrayList<>();
        list.add(1001);
        list.add(1002);
        list.add(1003);
        List<Student> students = dao.selectForeachOne(list);
        for(Student stu:students){
            System.out.println(stu);
        }
    }

集合中是对象

dao包下XXXDao接口新增方法:

    //foreach的使用2
    List<Student> selectForeachTwo(List<Student> stuList);

dao包下XXXDao.xml,增加
重点是使用#{stu.id}

    <select id="selectForeachTwo" resultType="com.daihan.domain.Student">
        select * from student where id in
        <foreach collection="list" item="stu" open="(" close=")" separator=",">
            #{stu.id}
        </foreach>
    </select>

测试程序:

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

        List<Student> stuList = new ArrayList<Student>();
        for (int i=0;i<3;i++){
            Student student = new Student();
            student.setId(1001+i);
            stuList.add(student);
        }
        List<Student> students = dao.selectForeachTwo(stuList);
        for(Student stu:students){
            System.out.println(stu);
        }
    }

代码片段

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

<sql id="studentSql">
	语句
</sql>

使用:

<include refid="studentSql"/>

五、配置文件(了解)

主配置文件

文件中,顺序:properties、setings、typeAliases、plugins、environments
位置:模块-src-main-resources-mybatis.xml文件。

<?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>
        <!--设置mybatis打印日志-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <environments default="mydev">
        <environment id="mydev">

            <transactionManager type="JDBC"/>
			
			<!--
				dataSource type指定数据源类型:POOLED、UPOOLED、JNDI

			-->
            <dataSource type="POOLED">

                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>

                <property name="url" value="jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC"/>

                <property name="username" value="root"/>

                <property name="password" value="a123b456"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="com/daihan/dao/StudentDao.xml"/>
    </mappers>
</configuration>

使用属性配置文件管理连接数据

数据库的属性配置文件:把数据库连接信息放到单独一个文件中。和mybatis主配置文件分开。目的是便于修改,保存,处理多个数据库信息。
1、在resources目录中定义一个属性配置文件,xxx.properties
key一般使用多级目录,例如jdbc.mysql.driver
2、在mybatis的主配置文件中,使用<property>指定文件位置
在需要使用值的地方,${}

主配置文件中:先指定properties文件路径,再使用文件

<?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文件的位置,从类的根路径开始-->
    <properties resource="jdbc.properties"/>

    <settings>
        <!--设置mybatis打印日志-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <environments default="mydev">
        <environment id="mydev">

            <transactionManager type="JDBC"/>

            <dataSource type="POOLED">

                <property name="driver" value="${jdbc.driver}"/>

                <property name="url" value="${jdbc.url}"/>

                <property name="username" value="${jdbc.user}"/>

                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="com/daihan/dao/StudentDao.xml"/>
    </mappers>
</configuration>

多个mapper文件

第一种方式

    <mappers>
        <mapper resource="com/daihan/dao/StudentDao.xml"/>
        <mapper resource="com/daihan/dao/StudentDao.xml"/>
        ...
    </mappers>

第二种方式,使用包名
name:xml文件所在包名

<package name="com.daihan.dao">

使用要求:
1、mapper文件名称需要和接口一样
2、mapper文件和dao接口需要在同一目录

六、扩展 ——PageHelper

做数据分页的。原本需要limit语句
使用步骤:
1、pom中加入maven依赖

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

2、加入plugin配置,在<enviroments>之前加入

<plugins>
	<plugin interceptor="com.github.pagehelper.PageInterceptor">
</plugins>

具体使用:
调用dao接口方法查找前,先调用PageHelper静态方法starPage(x,y);显示第x页(从1开始),每页y个

PageHelper.starPage(1,3);
List<Student> studentList=studentDao.selectStudents();

处理枚举类型

参考文章

注:

1、常见问题

  1. dao中的接口,于xml文件中的mapper的namespace对应
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值