Mybatis框架

官网: https://mybatis.org/mybatis-3/zh/index.html

Mybatis框架介绍

MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了 google code,并且改名为MyBatis 。2013年11月迁移到Github。 iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框 架包括SQL Maps和Data Access Objects(DAO) MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的 JDBC代码和参数的手工设置以及对结果集的检索封装。MyBatis可以使用简单的XML或注解用于配置和 原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。

简单概括:

更加简化jdbc代码,简化持久层,sql语句从代码中分离,利用反射,将表中数据与java bean 属性一一 映射 即 ORM(Object Relational Mapping 对象关系映射)

Mybatis功能架构图

从上面我们可以看到mybatis的功能架构分为三层: API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层接收到调用请 求就会调用数据处理层来完成具体的数据处理。 数据处理层:负责具体的SQL查 找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据 调用的请求完成一次数据库操作。 基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用 的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。

Mybatis环境搭建

1.新建项目,配置jar包
mybatis核心jar包
mybatis依赖的jar包
数据库的驱动包
2.编写核心配置文件
3.编写SQl映射文件,编写实体类
4.测试

  1. 配置jar包

  1. 编写核心配置文件

<?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">
<!-- mybatis的全局配置文件 -->
<configuration>
    <!--
    用于指明使用哪一个开发环境
    default : 用于指定使用的环境的id属性值
    -->
    <environments default="ev">
        <!-- 用户配置开发环境 id: 环境的唯一标识 -->
        <environment id="ev">
            <!--
            事务管理器
            JBDC : 表示采用JDBC一样的事务管理方式
            -->
            <transactionManager type="JDBC"/>
            <!--
            用于配置数据库连接吃和数据库连接参数
            POOLED : 表示mybatis采用连接池技术
            -->
            <dataSource type="POOLED">
                <property name="driver"
                          value="oracle.jdbc.driver.OracleDriver"/>
                <property name="url"
                          value="jdbc:oracle:thin:@localhost:1521:XE"/>
                <property name="username" value="SCOTT"/>
                <property name="password" value="TIGER"/>
            </dataSource>
        </environment>
    </environments>
    <!-- SQL映射文件配置 -->
    <mappers>
        <!-- 指明SQL映射文件路径 resource : 包路径 com/.../xxxMapper.xml-->
        <mapper resource="com/yjxxt/mappers/DeptMapper.xml"/>
    </mappers>
</configuration>

  1. 编写sql映射文件,编写实体类

sql映射文件

<?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: 命名空间
要求:唯一的,SQL映射文件唯一标识
定义方式:
    1.随意定义,只要不重复即可,不推荐,不便于后期维护
    2.推荐使用包名.文件名
-->
<mapper namespace="com.yjxxt.mappers.DeptMapper">
    <!--
    查询标签: select 用于编写查询语句
    id : 当前文件中保证唯一
    resultType : 结果的类型
    parameterType : 入参类型
    -->
    <select id="queryDept" resultType="com.yjxxt.pojo.Dept">
select * from dept
    </select>
<!--根据部门编号查询部门信息-->
    <select id="quaryDeptById" resultType="com.yjxxt.pojo.Dept" parameterType="int">
        select * from dept where deptno=#{ID}
    </select>
<!--根据部门位置查询部门信息-->
    <select id="quaryDeptByLoc" resultType="com.yjxxt.pojo.Dept" parameterType="String">
        select * from dept where loc=#{loc}
    </select>
</mapper>

实体类

package com.yjxxt.pojo;

public class Dept {
    private int deptno;
    private String dname;
    private String loc;

    public Dept(int deptno, String dname, String loc) {
        this.deptno = deptno;
        this.dname = dname;
        this.loc = loc;
    }

    public Dept() {
    }

    /**
     * 获取
     * @return deptno
     */
    public int getDeptno() {
        return deptno;
    }

    /**
     * 设置
     * @param deptno
     */
    public void setDeptno(int deptno) {
        this.deptno = deptno;
    }

    /**
     * 获取
     * @return dname
     */
    public String getDname() {
        return dname;
    }

    /**
     * 设置
     * @param dname
     */
    public void setDname(String dname) {
        this.dname = dname;
    }

    /**
     * 获取
     * @return loc
     */
    public String getLoc() {
        return loc;
    }

    /**
     * 设置
     * @param loc
     */
    public void setLoc(String loc) {
        this.loc = loc;
    }

    public String toString() {
        return "Dept{deptno = " + deptno + ", dname = " + dname + ", loc = " + loc + "}";
    }
}

  1. 测试

package com.yjxxt.test;

import com.yjxxt.pojo.Dept;
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;
import java.util.Map;
public class Class002_Method {
    public static void main(String[] args) throws IOException {
        //1.加载核心文件
        InputStream is= Resources.getResourceAsStream("mybatis.xml");
        //2.构建SqlSessionFactory实例
        SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(is);
        //3.获取会话
        SqlSession session=factory.openSession();
        //4.执行Sql
        //selectList("命名空间.id");
        List<Dept> list=session.selectList("com.yjxxt.mappers.DeptMapper.queryDept");

        //测试使用selectOne("命名空间.id",入参)
        Dept dept=session.selectOne("com.yjxxt.mappers.DeptMapper.quaryDeptById",10);
        System.out.println(dept);

        System.out.println("-----------------------");
        //测试selectList("命名空间.id");
        List<Dept> list2=session.selectList("com.yjxxt.mappers.DeptMapper.quaryDeptByLoc","NEW YORK");
        list2.forEach(System.out::println);

        System.out.println("--------------------------");
        //selectMap("命名空间.id","作为key的字段名")
        //selectMap("命名空间.id",入参,"作为key的字段名")
        Map<Integer,Dept> map =session.selectMap("com.yjxxt.mappers.DeptMapper.quaryDeptByLoc","NEW YORK","deptno");
        System.out.println(map);

        //5.处理结果
        System.out.println("-------------------");
        list.forEach(System.out::println);
        //6.关闭会话
        session.close();
    }
}

运行结果:

数据库查询结果:

Log4j日志

在apache网站: jakarta.apache.org/log4j 可以免费下载到Log4j最新版本的软件包。

日志级别

分为五个级别: DEBUG(人为调试信息)、INFO(普通信息)、WARN(警告)、ERROR(错误)和FATAL(系统错误) 这五个级别是有顺序的,DEBUG < INFO < WARN < ERROR < FATAL,分别用来指定这条日志信息的重 要程度,明白这一点很重要,Log4j有一个规则:只输出级别不低于设定级别的日志信息,Logger 级别设定为INFO,则INFO、WARN、ERROR和FATAL级别的日志信息都会输出,而级别比INFO低的 DEBUG则不会输出。

log4j使用

  1. 导包

  1. 配置文件

在src目录下创建properties配置文件,内容如下

# Set root category priority to INFO and its only appender to CONSOLE.
log4j.rootCategory=INFO, CONSOLE
# log4j.rootCategory=INFO, CONSOLE, LOGFILE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=- %m %c %l %d{yyyy-MM-dd HH:mm:ss}%n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:/test.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=- %m %l%n

  1. 日志格式输出

  1. 进行测试

package com.yjxxt.test;

//注意要获取apache包下面的Logger类
import org.apache.log4j.Logger;

public class Class003_log4j {
    public static void main(String[] args) {
        //获取一个日志对象
        Logger logger = Logger.getLogger(Class003_log4j.class);

        //测试武功和日志级别
        logger.fatal("致命的。。系统错误");
        logger.error("错误。。。。");
        logger.warn("警告。。。。");
        logger.info("日志信息。。。。");
        logger.debug("用户调试信息。。。。");

    }
}

输出结果:

配置文件中写明了info,故只显示info及以上的警告级别的日志信息

Mybatis对Log4j的支持

测试代码

package com.yjxxt.test;

import com.yjxxt.pojo.Dept;
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 Class001_Dept {
    public static void main(String[] args) throws IOException {
        //1.加载核心文件
        InputStream is= Resources.getResourceAsStream("mybatis.xml");
        //2.构建SqlSessionFactory实例
        SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(is);
        //3.获取会话
        SqlSession session=factory.openSession();
        //4.执行Sql
        //selectList("命名空间.id");
        List<Dept> list=session.selectList("com.yjxxt.mappers.DeptMapper.queryDept");
        //5.处理结果
        list.forEach(System.out::println);
        //6.关闭会话
        session.close();
    }
}
  1. 通过setting标签开始对log4j的支持

通过查看mybatis官网,对log4j的支持,配置在mybatis的核心配置文件中

通过查看configuration查看setting配置位置

修改后的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">
<!-- mybatis的全局配置文件 -->
<configuration>
    <!-- settings标签 -->
    <settings>
        <!-- 设置MyBatis使用log4j日志支持 -->
        <setting name="logImpl" value="LOG4J"/>
    </settings>
    <!--
    用于指明使用哪一个开发环境
    default : 用于指定使用的环境的id属性值
    -->
    <environments default="ev">
        <!-- 用户配置开发环境 id: 环境的唯一标识 -->
        <environment id="ev">
            <!--
            事务管理器
            JBDC : 表示采用JDBC一样的事务管理方式
            -->
            <transactionManager type="JDBC"/>
            <!--
            用于配置数据库连接吃和数据库连接参数
            POOLED : 表示mybatis采用连接池技术
            -->
            <dataSource type="POOLED">
                <property name="driver"
                          value="oracle.jdbc.driver.OracleDriver"/>
                <property name="url"
                          value="jdbc:oracle:thin:@localhost:1521:XE"/>
                <property name="username" value="SCOTT"/>
                <property name="password" value="TIGER"/>
            </dataSource>
        </environment>
    </environments>
    <!-- SQL映射文件配置 -->
    <mappers>
        <!-- 指明SQL映射文件路径 resource : 包路径 com/.../xxxMapper.xml-->
        <mapper resource="com/yjxxt/mappers/DeptMapper.xml"/>
    </mappers>
</configuration>
  1. 不同日志级别下的输出

log4j.rootCategory=DEBUG, CONSOLE
log4j.rootCategory=INFO, CONSOLE

注意:上诉两种级别设定都不能满足,保留SQl语句的信息的同时,不显示一些非重要语句

  1. 单独设置SQL语句输出级别为DEBUG

a.注释单个SQL语句为DEBUG

修改 log4j.properties

#单独设置SQL语句输出级别为DEBUG
#方法级别设置(SQL语句--每一个SQL语句其实就是一个方法
log4j.logger.com.yjxxt.mappers.DeptMapper.queryDept=DEBUG

输出结果:保留了SQL语句的输出

b.类级别的等级设置

#修改 log4j.properties
#类级别设置(SQL文件
log4j.logger.com.yjxxt.mappers.DeptMapper=DEBUG

测试代码:

public class Class002_Method {
    public static void main(String[] args) throws IOException {
        //1.加载核心文件
        InputStream is= Resources.getResourceAsStream("mybatis.xml");
        //2.构建SqlSessionFactory实例
        SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(is);
        //3.获取会话
        SqlSession session=factory.openSession();
        //4.执行Sql
        //selectList("命名空间.id");
        List<Dept> list=session.selectList("com.yjxxt.mappers.DeptMapper.queryDept");

        //测试使用selectOne("命名空间.id",入参)
        Dept dept=session.selectOne("com.yjxxt.mappers.DeptMapper.quaryDeptById",10);
        System.out.println(dept);

        System.out.println("-----------------------");
        //测试selectList("命名空间.id");
        List<Dept> list2=session.selectList("com.yjxxt.mappers.DeptMapper.quaryDeptByLoc","NEW YORK");
        list2.forEach(System.out::println);

        System.out.println("--------------------------");
        //selectMap("命名空间.id","作为key的字段名")
        //selectMap("命名空间.id",入参,"作为key的字段名")
        Map<Integer,Dept> map =session.selectMap("com.yjxxt.mappers.DeptMapper.quaryDeptByLoc","NEW YORK","deptno");
        System.out.println(map);

        //5.处理结果
        System.out.println("-------------------");
        list.forEach(System.out::println);
        //6.关闭会话
        session.close();
    }
}

c.包级别下的设置

#包级别设置
log4j.logger.com.yjxxt.mappers=DEBUG

通过properties标签实现软编码

  1. src下配置properties文件

driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:XE
username=SCOTT
password=TIGER

  1. 在mybatis中配置properties标签

    <!-- 加载外部的properties文件 -->
    <properties resource="db.properties" />

位置在settingsconfiguration

  1. 使用方式

typeAliases标签

用于给java类型定义别名,方便在配置文件中使用

在mybatis官网下查看

使用方式:(为com.yjxxt.pojo.Dept设置别名

    <typeAliases>
<!--        <typeAlias alias="D" type="com.yjxxt.pojo.Dept"/>-->
<!--        别名默认为类名Dept-->
        <typeAlias type="com.yjxxt.pojo.Dept"/>
<!--        为一个包中的所有类型设置别名,默认为类名不区分-->
        <package name="com.yjxxt.pojo"/> 
    </typeAliases>

Mybatis內键别名

parameterType入参类型

如果执行的是条件查询,DML,需要在调用方法的时候传递参数,此时, 可以在sql标签中通过 parameterType属性指定参数的类型(别名|权限定名). 而在sql语句,通过#{}的方式获取参数
  1. 基本数据类型|包装类

<!-- 基本数据类型|包装类   根据员工编号查看员工信息-->
    <select id="queryEmpId" parameterType="int" resultType="emp">
        select * from emp where empno=#{empno}
    </select>
 // 基本数据类型|包装类
        Emp emp=session.selectOne("com.yjxxt.mappers.EmpMapper.queryEmpId",7369);
        System.out.println(emp);

包装类Date

<!-- Date   根据员工入职日期查看员工信息-->
    <select id="queryEmpByDate" parameterType="Date" resultType="emp">
        select * from emp where hiredate=#{hiredate}
    </select>
System.out.println("======Date   根据员工入职日期查看员工信息===========");
        list=session.selectList("com.yjxxt.mappers.EmpMapper.queryEmpByDate",new SimpleDateFormat("yyyy/MM/dd").parse("1981/12/3"));
        list.forEach(System.out::println);
  1. String

    <!-- String   根据员工姓名查看员工信息-->
    <select id="queryEmpByName" parameterType="String" resultType="emp">
        select * from emp where ename=#{ename}
    </select>
System.out.println("======String   根据员工姓名查看员工信息===========");
        List<Emp> list=session.selectList("com.yjxxt.mappers.EmpMapper.queryEmpByName","SMITH");
        list.forEach(System.out::println);

  1. Map

    <!-- Map   根据员工薪资与员工的部门编号查看员工信息-->
    <select id="queryEmpBySalDeptno" parameterType="map" resultType="emp">
        select * from emp where sal=#{sal} or deptno=${deptno}
    </select>
System.out.println("======Map   根据员工薪资与员工的部门编号查看员工信息===========");
        //创建一个员工实例
        Map map=new HashMap<>();
        map.put("deptno",10);
        map.put("sal",1500);

        list=session.selectList("com.yjxxt.mappers.EmpMapper.queryEmpBySalDeptno",map);
        list.forEach(System.out::println);
  1. 数组List

    <!-- 数组   根据员工薪资与员工的部门编号查看员工信息-->
    <select id="queryEmpByNoSome"  resultType="emp">
        select * from emp where empno in(
        <foreach collection="array" separator="," item="item">
            #{item}
        </foreach>
        )
    </select>
System.out.println("======数组   根据员工薪资与员工的部门编号查看员工信息===========");
        //创建一个员工实例
        int[] arr={7369,7499,9999};
        list=session.selectList("com.yjxxt.mappers.EmpMapper.queryEmpByNoSome",arr);
        list.forEach(System.out::println);
        //3.关闭会话
        session.close();
  1. JavaBean

    <!-- JavaBean   根据员工姓名与员工薪资查看员工信息-->
    <!-- sql 中的占位符的名字匹配入参对象的属性名,根据属性名匹配属性值-->
    <select id="queryEmpByNameSal" parameterType="emp" resultType="emp">
        select * from emp where ename=#{ename} and sal=${sal}
    </select>
System.out.println("======JavaBean   根据员工姓名和薪资查看员工信息===========");
        //创建一个员工实例
        Emp e=new Emp();
        e.setDeptno(8888);
        e.setEname("SMITH");
        e.setSal(800);
        list=session.selectList("com.yjxxt.mappers.EmpMapper.queryEmpByNameSal",e);
        list.forEach(System.out::println);

工具类的封装

package com.yjxxt.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 SessionUtils {
    private static SqlSessionFactory factory=null;

    static{
        try {
            factory =new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis.xml"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static SqlSession getSession(){
        SqlSession session=null;
        if(factory!=null){
            session=factory.openSession();
        }
        return session;
    }
}

测试代码

public class Class003_Test {
    public static void main(String[] args) throws IOException {
//        //1.加载核心文件
//        InputStream is= Resources.getResourceAsStream("mybatis.xml");
//        //2.构建SqlSessionFactory实例
//        SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(is);
        //3.获取会话
        SqlSession session=SessionUtils.getSession();
        //4.执行Sql
        //selectList("命名空间.id");
        List<Dept> list=session.selectList("com.yjxxt.mappers.DeptMapper.queryDept");
        //5.处理结果
        list.forEach(System.out::println);
        //6.关闭会话
        session.close();
    }
}

运行结果:

事务

1. 事务是数据库操作的最小单位,有着ACID的特性,应该保证一个事务下的多条SQL语句要么都成功,要 么都失败.

2. Mybatis中配置了事务管理器,type属性设置JDBC,表示Mybatis采用和原生JDBC相同的事务管理机 制

3.在Myabatis执行操作的开始,将自动提交功能关闭了,需要我们在执行DML操作时候,手动提交设置| 设置自动提交

创建会话的时候设置自动提交

在包装的工具类里面,创建会话的时候就设置自动提交(通过参数true

    public static SqlSession getSession(){
        SqlSession session=null;
        if(factory!=null){
            //()手动提交  true自动提交
            //session=factory.openSession(true);
            session=factory.openSession();
        }
        return session;
    }

在测试代码中设置手动提交

int rows=session.delete("com.yjxxt.mappers.DeptMapper.deleteDept",70);
        if(rows>0){
            //添加成功,手动提交
            session.commit();
        }else{
            //添加失败,回滚
            session.rollback();
        }

结果类型

注意返回List集合的时候要返回泛型的类型

数据库查询结果

  1. 基本数据类型|包装类

<!--    基本数据类型|包装类 根据员工编号查看员工薪资-->
    <select id="querySalByNo" parameterType="int" resultType="double">
        select sal from emp where empno=#{empno}
    </select>
System.out.println("<!--    基本数据类型|包装类 根据员工编号查看员工薪资-->");
double d=session.selectOne("com.yjxxt.mappers.EmpMapper.querySalByNo",7369);
System.out.println(d);

  1. String

<!--    String 根据员工编号查看员工姓名-->
    <select id="queryNameByNo" parameterType="int" resultType="String">
        select ename from emp where empno=#{empno}
    </select>
System.out.println("<!--    String 根据员工编号查看员工姓名-->");
String str=session.selectOne("com.yjxxt.mappers.EmpMapper.queryNameByNo",7369);
System.out.println(str);

  1. Date

<!--    Date 根据员工编号查询员工入职日期-->
    <select id="queryDateByNo" parameterType="int" resultType="Date">
        select hiredate from emp where empno=#{empno}
    </select>
System.out.println("<!--    Date 根据员工编号查询员工入职日期-->");
Date date=session.selectOne("com.yjxxt.mappers.EmpMapper.queryDateByNo",7369);
System.out.println(date);

  1. Map

<!--    Map 根据员工编号,查询员工信息-->
    <select id="queryEmpByNo" parameterType="int" resultType="Map">
        select * from emp where empno=#{empno}
    </select>
System.out.println("<!--    Map 根据员工编号,查询员工信息-->");
Map<String,Object> map=session.selectOne("com.yjxxt.mappers.EmpMapper.queryEmpByNo",7369);
System.out.println(map);

  1. List<Map>

<!--    List<Map> 根据员工姓名模糊查询-->
    <select id="queryEmpByNoLike" parameterType="String" resultType="map">
        select * from emp where ename like '%'||#{ename}||'%'
    </select>
System.out.println("<!--    List<Map> 根据员工姓名模糊查询-->");
List<Map<String,Object>> list1=session.selectList("com.yjxxt.mappers.EmpMapper.queryEmpByNoLike","A");
list1.forEach(System.out::println);

接口绑定方案

Mybatis
1.定义接口的实现类
2.重写接口当中的抽象方法
3.找到相应的SQL语句
4.创建实现类对象

Myabtis中,提供了一套接口绑定方案,程序员可以提供一个接口,然后提供一个与接口所对应的 mapper.xml文件

Myabaits会自动讲接口与xml文件进行绑定,实际上就是Mybatis互根据接口和对应的xml文件创建一个接 口的实现类,换言之,就是可以得到接口实现类的一个对象,方便方法的调用

实现步骤:

1.定义接口,定义抽象功能
2.定义与接口绑定的SQL文件,定义SQL语句,按照要求进行定义
3.核心配置文件中通过Mapper扫描接口
4.在java代码中通过获取接口实现类对象调用功能
  1. 定义接口,定义抽象功能

/*
接口绑定方案下的接口
 */
public interface DeptMapper {
    //查询所有的部门信息
    public List<Dept> qureyAll();
}

  1. 定义与接口绑定的SQL文件,定义SQL语句,按照要求进行定义

定义要求

1.接口与SQl映射文件名要保持一致,并且放在同一个包下

2.SQl映射文件名的命名空间namespaces定义为与之绑定的接口包名.类名

3.SQl标签的ID属性值要与接口当中所对应的抽象方法的方法名保持一致

4.SQl语句的参数与返回值要与对应的抽象方法的参数和返回值保持一致

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.yjxxt.mappers.DeptMapper">
    <select id="qureyAll" resultType="Dept">
        select * from Dept
    </select>
</mapper>

  1. 核心配置文件中通过Mapper扫描接口

<!-- 扫描接口,接口绑定方案-->
    <mappers>
        <mapper class="com.yjxxt.mappers.DeptMapper"/>
    </mappers>

4.在java代码中通过获取接口实现类对象调用功能

public class Class001_InterfaceBind {
    public static void main(String[] args) {
        //1获取会话
        SqlSession session= SessionUtils.getSession();
        //2.获取接口实现类对象--》指定哪一个接口
        DeptMapper mapper =session.getMapper(DeptMapper.class);
        //3.调用方法
        List<Dept> list=mapper.qureyAll();
        list.forEach(System.out::println);
        //4.关闭会话
        session.close();
    }
}

通过接口绑定解决多参数传递方案

测试类

public class Class002_Param {
    public static void main(String[] args) {
        //1获取会话
        SqlSession session= SessionUtils.getSession();
        //2.获取接口实现类对象--》指定哪一个接口
        EmpMapper mapper =session.getMapper(EmpMapper.class);
        //3.调用方法
        System.out.println("<!--一个参数 根据部门编号查看员工信息-->");
        Emp emp=mapper.queryEmpById(7369);
        System.out.println(emp);

        //多个参数
        System.out.println("<!--多个参数 根据薪资与部门一起查询-->");
        List<Emp> list=mapper.queryEmpSalDeptno(1500,30);
        list.forEach(System.out::println);
        //4.关闭会话
        session.close();
    }
}

方法一 使用args 或者param

映射文件

<!--多个参数 根据薪资与部门一起查询-->
    <select id="queryEmpSalDeptno"  resultType="Emp">
        select * from emp where sal>#{arg0} and deptno=#{arg1}
        select * from emp where sal>#{param1} and deptno=#{param2}
    </select>

对应的接口

    //根据薪资与部门一起查询
    List<Emp> queryEmpSalDeptno(@Param("sal") double sal, int deptno);

方法二 使用注解@Param

映射文件

        select * from emp where sal>#{sal} and deptno=#{deptno}

对应的接口

//根据薪资与部门一起查询
    List<Emp> queryEmpSalDeptno(@Param("sal") double sal, @Param("deptno") int deptno);

运行结果:

接口代理开发(CRUD)

  1. insert

<!--    insert 插入一个部门信息-->
    <insert id="insertDept" parameterType="dept">
        insert into dept values(#{deptno},#{dname},#{loc})
    </insert>
        System.out.println("<!--一个参数 根据部门编号查看员工信息-->");
        int rows=mapper.insertDept(new Dept(66,"六部","上海"));
        System.out.println(rows>0?"操作成功":"失败");

数据库查询结果:

  1. update

<!--    update 根据部门编号修改部门名称-->
    <update id="updateDept" >
        update dept set dname =#{dname} where deptno=#{deptno}
    </update>

        System.out.println("<!--    update 根据部门编号修改部门名称-->");
        int rows=mapper.updateDept(66,"liu");
        System.out.println(rows);
  1. delete

<!--delete    根据部门编号删除部门信息-->
    <delete id="deleteDept" parameterType="int">
        delete from dept where deptno=#{deptno}
    </delete>

        System.out.println("<!--delete    根据部门编号删除部门信息-->");
        int rows=mapper.deleteDept(66);
        System.out.println(rows);

动态Sql

通过条件SQl语句随之发生改变

动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同 条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个 列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。 使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显 著地提升了这一特性的易用性。

  1. if ( 相当于if单选择

用于进行条件判断, test 属性用于指定判断条件. 为了拼接条件, 在 SQL 语句后强行添加 1=1 的恒成立条 件

  1. where

  1. choose...when...otherwise(相当于Switch条件判断

  1. set

  1. trim

  1. bind

  1. foreach

  1. sql_include

Mybatis缓存机制

列名与属性名不一致问题

如果查询时使用 resultType 属性, 表示采用 MyBatis 的Auto-Mapping(自动映射)机制, 即相同的列名和 属性名会自动匹配. 因此, 当数据库表的列名和类的属性名不一致时, 会导致查不到数据
//Dept实体类
/*
测试字段名与属性名不一致的问题

 */
public class Dept {
    private int no;
    private String name;
    private String loc;

    public Dept(int deptno, String dname, String loc) {
        this.no = deptno;
        this.name = dname;
        this.loc = loc;
    }

    public Dept() {
    }


    @Override
    public String toString() {
        return "Dept{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", loc='" + loc + '\'' +
                '}';
    }
}
    <select id="qureyAll" resultType="Dept">
        select deptno,dname,loc from Dept
    </select>

解决办法:

使用resultMap标签

自定义表与javaBean类型的映射情况

不同字段名必须手动设置映射关系

同名的字段名可以不设置,默认会根据自动映射机制找同名

<mapper namespace="com.yjxxt.mappers.DeptMapper">
<!--    自定义结果映射关系-->
    <resultMap id="deptMap" type="Dept">
<!--     主键字段与属性的映射关系-->
        <id column="deptno" property="no"/>
<!--     非主键字段与属性的映射关系-->
        <result column="dname" property="name"/>
    </resultMap>
    <select id="qureyAll" resultMap="deptMap" >
        select deptno,dname,loc from Dept
    </select>
</mapper>

为字段起别名

要求字段别名与类型对应的属性名保持一致

<!--    用别名实现-->
    <select id="qureyAll" resultType="Dept" >
        select deptno no,dname name,loc from Dept
    </select>

resultMap 的关联方式实现多表查询(一对一|多对一)

1.多表查询所有员工信息和部门信息

<mapper namespace="com.yjxxt.mappers.EmpMapper">
<!--    自定义结果集中的字段与javaBean中属性的映射关系-->
    <resultMap id="EmpDept" type="Emp">
        <id column="empno" property="empno"/>
        <result column="ename" property="ename"/>
        <result column="sal" property="sal"/>
        <result column="job" property="job"/>
        <result column="comm" property="comm"/>
        <result column="mgr" property="mgr"/>
        <result column="hiredate" property="hiredate"/>
        <result column="deptno" property="deptno"/>
<!-- association 定义javabean类型属性的映射关系       -->
        <association property="dept" javaType="Dept">
            <id column="deptno" property="no"></id>
            <result column="dname" property="name"></result>
            <result column="loc" property="loc"></result>
        </association>
    </resultMap>
    <select id="queryEmpDept" resultMap="EmpDept">
        select empno,ename,job,mgr,hiredate,sal,comm,emp.deptno,dname,loc from emp join dept on emp.deptno=dept.deptno
    </select>
</mapper>

在Emp实体类中定义

    //定义一个属性表示部门信息
    private Dept dept;

测试类:

public class Class002_EmpDeptTest {
    public static void main(String[] args) {
        //1获取会话
        SqlSession session= SessionUtils.getSession();
        //2.获取接口实现类对象--》指定哪一个接口
        EmpMapper mapper =session.getMapper(EmpMapper.class);
        //3.调用方法
        List<Emp> list=mapper.queryEmpDept();
        list.forEach(System.out::println);
        //4.关闭会话
        session.close();
    }
}

运行结果:

2.查询一对多 查询每个部门和这个部门里面的员工信息

<mapper namespace="com.yjxxt.mappers.DeptMapper">
<!--    自定义结果映射关系-->
    <resultMap id="deptMap" type="Dept">
<!--     主键字段与属性的映射关系-->
        <id column="deptno" property="no"/>
<!--     非主键字段与属性的映射关系-->
        <result column="dname" property="name"/>
        <result column="loc" property="loc"></result>
<!--        当类中的属性为List集合,使用collection标签定义-->
        <collection property="empList" javaType="List"
                    ofType="Emp">
            <id column="empno" property="empno"/>
            <result column="ename" property="ename"/>
            <result column="sal" property="sal"/>
            <result column="job" property="job"/>
            <result column="comm" property="comm"/>
            <result column="mgr" property="mgr"/>
            <result column="hiredate" property="hiredate"/>
            <result column="deptno" property="deptno"/>
        </collection>
    </resultMap>

    <select id="qureyAll" resultMap="deptMap" >
        select dept.deptno,dname,loc,empno,ename,job,mgr,hiredate,sal,comm from dept left join emp on emp.deptno=dept.deptno
    </select>
</mapper>

public class Dept {
    private int no;
    private String name;
    private String loc;

    //定义一个集合存储该部门里面的员工信息
    private List<Emp> empList;

    public Dept(int deptno, String dname, String loc) {
        this.no = deptno;
        this.name = dname;
        this.loc = loc;
    }

    public Dept() {
    }
    
    @Override
    public String toString() {
        return "Dept{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", loc='" + loc + '\'' +
                ", empList=" + empList +
                '}';
    }
}

测试类:

public class Class001_InterfaceBind {
    public static void main(String[] args) {
        //1获取会话
        SqlSession session= SessionUtils.getSession();
        //2.获取接口实现类对象--》指定哪一个接口
        DeptMapper mapper =session.getMapper(DeptMapper.class);
        //3.调用方法
        List<Dept> list=mapper.qureyAll();
        list.forEach(System.out::println);
        //4.关闭会话
        session.close();
    }
}

运行结果

Mybatis缓存机制

一级缓存

1. 默认开启. 线程级别的缓存, SqlSession 的缓存; 2. 在一个 SqlSession 生命周期中有效. SqlSession 关闭,缓存清空; 3. 在同一个 SqlSession 中, Mybatis 会把执行的方法和参数通过算法生成缓存的键值, 将键值和结果 存放在一个 Map 中, 如果后续的键值一样, 则直接从 Map 中获取数据; 4. 不同的 SqlSession 之间的缓存是相互隔离的; 5. 用一个 SqlSession, 可以通过配置使得在查询前清空缓存;flushCache="true" 6. 任何的 UPDATE, INSERT, DELETE 语句都会清空缓存。

二级缓存

1. 进程级别的缓存, SqlSessionFactory 的缓存 2. 在一个SqlSessionFactory生命周期中有效. 可以在多个SqlSession 生命中期中共享. 3. 默认关闭, 需要使用的时候, 要为某个命名空间开启二级缓存(在 mapper.xml 中配置cache).

<!-- 开启二级缓存, 要求实体类进行序列化 -->
<cache />

在核心配置文件中开启二级缓存之后,再在相应的映射文件中开启缓存 4. 由于在更新时会刷新缓存, 因此需要注意使用场合:查询频率很高, 更新频率很低时使用, 即经 常使用 select, 相对较少使用delete, insert, update。 5. 缓存是以 namespace 为单位的,不同 namespace 下的操作互不影响。但刷新缓存是刷新整个 namespace 的缓存, 也就是你 update 了一个, 则整个缓存都刷新了。 6. 最好在 「只有单表操作」 的表的 namespace 使用缓存, 而且对该表的操作都在这个 namespace 中。 否则可能会出现数据不一致的情况。

注解开发

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值