Mybatis详解

框架 MYbatis

MyBatis简介:

MyaBtis 本来是apache的一个开源项目IBatis,2010年这个项目迁移到了 google Code 并改名为MyBatis 是一个Java的持久层框架。

优点:

1、与JDBC相比减少了50%以上的代码量

2、最简单的持久层框架,小巧

3、SQL代码与程序代码彻底分离(可重用)

4、提供XML标签,支持编写动态的SQL语句

5、提供映射标签,支持对象与数据库的ORM字段映射

缺点:

1、SQL语句的编写工作量比较大,对开发人员有一定的要求

2、数据库移植性差

MyBatis专注于SQL本身,是一个足够灵活的DAO层解决方案,适用于性能要求较高 或者 需求较多变的互联网项目

为什么使用MyBatis?

在传统的JDBC中,我们除了需要自己提供SQL之外,还必须操作Connection、Statment、ResultSet、为了访问不同的表,不同字段的数据,我们需要很多的雷同代码,

而我们使用了MyBatis之后 ,只需要提供sql语句就好了,好处:我们的“关注点可以集中在sql语句上”关注到增删查改这些操作层面上 并且MyBatis支持简单xml或注解配置和映射原生信息,将接口 和Java的POJO(Plain Old Java Objects普通的Java对象) 映射成数据库中的记录

mapper接口是怎么映射成sql语句的

使用xml来进行Mybatis的配置,包括Mybatis的核心配置和SQL映射配置(注解配置)。Xml本身只不过是一个元素的载体最终起作用的是MyBatis的核心类:

1、SqlSessionFactoryBuilder用来创建SqlSessionFactory的实例(对象)之后就没有用了,其生命周期知识在初识化时有做用

2、SqlSessionFactory,是MyBatis的基础类,用来创建会话(SqlSession)的实例(对象),其生命周期与整个系统的生命周期相同,在系统运行的任何时候都可以使用SqlSessionFactory来查询当前对数据库配置信息等。

3、SqlSession 真正和数据库之间的会话,线程不安全,其生命周期和其他线程相同

4、各种Mapper,承载了实际的业务逻辑,生命周期比较短,由SqlSession创建

MyBatis 本身就是一个简单的ORM框架,提供了SQL语句到方法、关系型数据表到对象的映射。实际使用中与开发相关的两个东西:

1、MyBatis 的核心配置

​ 缓存、数据源、日志等关系到MyBatis的本身行为一些配置

2、mapper接口的映射

​ 针对具体的业务逻辑的SQL映射

属性描述
id命名空间的标识符 》 接口名称
parameterType参数的类的全名或者别名 可选 默认为空
parameterMap
resultType返回结果的类型的全名或者 别名 。如果结果是集合 此类型表示的是集合的成员类型
resultMap使用resultMap来映射结果集,resultType和resultMap 只能选择一个用
flushCache如果为true,每次调用一级缓存和二级缓存都会回写,select中默认为false
useCache如果为true 结果将在二级缓存中缓存 select中默认为true
timeout设置超时,若超时抛出异常

更新语句(insert update delete)

属性描述
useGeneratedKeys将使用JDBC的getGeneratedKeys方法获取主键值 默认为false
keyProperty主键,MyBatis会将生成的主键赋给这个列
keyColumn特定数据库需要使用
association一对一的单向关联 查询的结果中包含有其他的对象 比如 学生集合中每一个学生的年级对象
collection一对多的关联 查询结果中包含有其他的集合 比如学生集合中包含了开始成绩 集合

maven的配置

Maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档项目管理工具软件。

Maven是一个项目管理工具,它包含了一个

项目对象模型 (Project Object Model),

一组标准集合,

一个项目生命周期(Project Lifecycle),

一个依赖管理系统(Dependency Management System)

Apache Maven 是一个软件项目管理工具。项目对象模型 (Project Object Model)的概念

Maven可以用来管理项目的依赖、编译、文档等信息

使用Maven管理项目时,项目的依赖的jar将不在包含在项目中,而是集中保存在本地

目录:C:\Users\Administrator \ .m2\目录

  • 国内镜像下载解压

  • 配置:

    • 在conf目录下找到settings.xml文件,设置镜像地址
      在这里插入图片描述

在这里插入图片描述

设置本地maven下载jar后默认的保存位置

在这里插入图片描述

使用mybatis

idea设置maven

在这里插入图片描述

设置maven文件夹存在地址与设置文件所在地址,如果设置了jar包存储仓库,会自动识别

在这里插入图片描述

新建一个项目,点击maven,如果使用maven,就把create from archetype勾打上,我们只是用mybatis框架因此不打勾,点击next

在这里插入图片描述

设置项目名称和保存项目路径
在这里插入图片描述

main中的resources存放配置文件;java存放java包、类、接口;test用于测试;pom.xml用来描述将要用到的信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9NJMebth-1607349675024)(C:\Users\scq\AppData\Roaming\Typora\typora-user-images\1606568479118.png)]

构建一个小mybatis项目,首先下载一个插件:mybatisCodeHelperPro用于sql提示,有代码提示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xks89BCg-1607349675025)(C:\Users\scq\AppData\Roaming\Typora\typora-user-images\1606568854094.png)]

连接数据库需要mybatis的配置定义文件,我们可以去网上找mybatis头部文件,复制头部配置

Mybatis xml文件头 - Actexpler - 博客园 (cnblogs.com)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jaYeq2zK-1607349675026)(C:\Users\scq\AppData\Roaming\Typora\typora-user-images\1606570172146.png)]

报红是因为maven没有引用关于mybatis的设置,我们要去https://mvnrepository.com/去搜索mybatis,将mybatis的jar包引用到pom.xml下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ounV8NH9-1607349675027)(C:\Users\scq\AppData\Roaming\Typora\typora-user-images\1606570371645.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7Rcc3wtp-1607349675028)(C:\Users\scq\AppData\Roaming\Typora\typora-user-images\1606570401130.png)]
在这里插入图片描述

将mybatis的jar包写到maven的pom.xml中,pom.xml添加各种jar包

在这里插入图片描述

接着添加mysql的jar包(5.1.0版本)、Junit jar包(单元测试)、log4j的jar包

在这里插入图片描述
resources中创建配置文件mybatis-config.xml,用于创建数据源,与数据库连接 ; 导入日志;导入数据库的配置文件database.properties ;mapper的xml文件的引用,更简单化创建一个包,告诉目录的位置即可

<?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE configuration
         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
       "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--mybatis对数据库信息定义-->
<configuration>
<!--引入database配置文件-->
 <properties resource="database.properties"></properties>

<!-- 配置mybatis的日志实现为log4j-->
 <settings>
  <setting name="logImpl" value="LOG4J"/>
 </settings>

<!-- 创建数据源,connection,JDBC来进行事务管理-->
 <environments default="development">
  <environment id="development">
<!--   配置事务管理 JDBC来进行事务管理-->
   <transactionManager type="JDBC"></transactionManager>
<!--   POOLED:mybatis自带的数据源,JNDI:基于tomcat的数据源-->
   <dataSource type="POOLED">
<!--    此处的value="${driver}"与数据库配置文件的属性一致-->
    <property name="driver" value="${driver}"/>
    <property name="url" value="${url}"/>
    <property name="user" value="${user}"/>
    <property name="password" value="${password}"/>
   </dataSource>
  </environment>
 </environments>
<!--将mapper的xml文件加入到mybatis配置文件中-->
 <mappers>
  <mapper resource="mapper/StudentMapper.xml"></mapper>
 </mappers>


</configuration>

resources中创建log4j的配置文件,用于存储日志的定义

resources中创建数据库的配置文件database.properties 存储数据库登录驱动信息
在这里插入图片描述

实现mybatis配置文件中对于xml文件的引用 : resources下新建一个文件夹mapper,mapper里面创建一个xml,xml文件用于写访问数据库的方法,起一个名,有要求,如果对student进行操作,就起名为StudentMapper.xml,此xml文件名与Dao层接口文件名一致,这个xml文件有格式的设置,需要我们从网上找:mybatis映射文件mapper.xml的写法

namespace表示当前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=""></mapper>

Dao层创建接口文件名为StudentMapper.java与要实现接口方法的xml文件名一致,StudentMapper.xml中的id就是用于对应接口文件写的方法名,因此接口方法必须与StudentMapper.xml中的一个id名称相同,才能匹配到,这样StudentMapper.xml就可以实现这个接口方法了

练习:对于学生表的操作

练习一:查询学生人数

  • Dao层接口文件StudentMapper.java,定义查询学生人数的方法:int getStudentCount();

  • StudentMapper.xml可以写一些数据库访问语句:id为接口文件定义的方法名 resultType表示返回值类型

<select id="getStudentCount" resultType="int">
    select count(1) from student;
</select>
  • 去mybatis-config.xml与mapper文件产生映射
<!--将mapper的xml文件加入到mybatis配置文件中-->
 <mappers>
  <mapper resource="mapper/StudentMapper.xml"></mapper>
 </mappers>
  • test中创建一个测试类,使用sqlsession访问数据库
public class StuTest {

    //加入日志
private Logger logger=Logger.getLogger(StuTest.class.getName());
    @Test
    public void testA() throws IOException {
        //使用mybatis,将mybatis配置文件转换为输入流,用于获取mybatis配置文件信息
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        //导入配置信息 获取sqlsessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//通过sqlsessionFactory获取sqlsession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //sqlSession可以用于执行数据库的访问操作
        Object count = sqlSession.selectOne("mapper.StudentMapper.getStudentCount");
        //日志保留访问数据库的结果
        logger.debug("学生人数为:"+count);
        //一定要关闭
        sqlSession.close();
    }

练习二:根据学生姓名进行模糊查询

  • 首先要在实体层中创建一个学生类,学生类属性与数据库表student的设计表属性顺序一致,实体层在main中的java下名为pojo

  • Dao层接口文件定义一个根据学生姓名进行模糊查询的方法List<Student> getStuName(String studentName); ,返回一个学生对象集合

  • StudentMapper.xml可以写一些数据库访问语句:id为接口文件定义的方法名 ,由于返回结果为学生对象集合,因此resultType设置为集合元素类型:学生对象

    <!--#{studentName}参数来自接口,接口的方法名与此处id一致-->
    <select id="getStuName" resultType="pojo.Student">
 select * from student where studentName like concat('%',#{studentName},'%');
    </select>
  • 测试:
   @Test
    public void testC() throws IOException {
        //使用mybatis,将mybatis配置文件转换为输入流,用于获取mybatis配置文件信息
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        //导入配置信息 获取sqlsessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//通过sqlsessionFactory获取sqlsession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //sqlSession可以用于执行数据库的访问操作 selectList返回一个集合
        //List<Student> studentlist = sqlSession.selectList("mapper.StudentMapper.getStuAll");//这样写由于接口存在值会指向接口不返回此处
        List<Student> studentlist = sqlSession.getMapper(StudentMapper.class).getStuName("李");//直接获取这个接口中的方法
        //日志保留访问数据库的结果
        for (Student stu:studentlist){
            logger.debug("学生名称为:"+stu.getStudentName());

        }
        //一定要关闭
        sqlSession.close();
    }

练习三:对象当作参数查询

  • 接口定义方法
    在这里插入图片描述

  • 为了简化xml中接口类型resultType的描述,在mybatis-config.xml配置文件中配置别名
    在这里插入图片描述

  • xml中实现接口方法
    在这里插入图片描述

  • 测试
    在这里插入图片描述

练习四:使用map集合当作参数

在这里插入图片描述

练习五:参数为list的查询

//使用List传参
    List<Student> QueryStudent_C(List<String> list);
    <!--    参数为List集合的查询 参数类型写全包名java.util.ArrayList List需要遍历 collection="接口参数名"  -->
    <select id="QueryStudent_C" resultType="Student" parameterType="java.util.ArrayList">
 select * from student
 where studentNo in(
 <foreach collection="list" item="stuNo" index="index" separator=",">
     #{stuNo}
 </foreach>
 )
    </select>
    @Test
    public void testG() throws IOException {
        //使用mybatis,将mybatis配置文件转换为输入流,用于获取mybatis配置文件信息
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        //导入配置信息 获取sqlsessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//通过sqlsessionFactory获取sqlsession
        SqlSession sqlSession = sqlSessionFactory.openSession();
     List<String> stuNos = new ArrayList<String>();
        stuNos.add("10001");
        stuNos.add("10005");
        stuNos.add("10008");
        List<Student> studentlist = sqlSession.getMapper(StudentMapper.class).QueryStudent_C(stuNos);//直接获取这个接口中的方法
        //日志保留访问数据库的结果
        for (Student stu:studentlist){
            logger.debug("学生名称为:"+stu.getStudentName());

        }
        //一定要关闭
        sqlSession.close();
    }

练习六:数组入参 需要加入注解

//使用数组传参 引用数据类型需要加入注解
    List<Student> QueryStudent_D(@Param("stuNos") int[] stuNos);
    <!--    参数为数组的查询 不用写参数类型-->
    <select id="QueryStudent_D" resultType="Student">
        select * from student
        where studentNo in(
        <foreach collection="stuNos" item="stuNo" index="index" separator=",">
            #{stuNo}
        </foreach>
        )
    </select>

描述如下:
在这里插入图片描述

   @Test
    public void testH() throws IOException {
        //使用mybatis,将mybatis配置文件转换为输入流,用于获取mybatis配置文件信息
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        //导入配置信息 获取sqlsessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//通过sqlsessionFactory获取sqlsession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        int[] stuNos={10001,10005,10008};
        List<Student> studentlist = sqlSession.getMapper(StudentMapper.class).QueryStudent_D(stuNos);//直接获取这个接口中的方法
        //日志保留访问数据库的结果
        for (Student stu:studentlist){
            logger.debug("学生名称为:"+stu.getStudentName());

        }
        //一定要关闭
        sqlSession.close();
    }

由于测试创建sqlsession有过多重复代码,因此简化一个工具类

package 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 sqlSessionFactory;

    public MyBatisUtil() {
    }

    public static void closeSqlSession(SqlSession sqlSession) {
        if (null != sqlSession) {
            sqlSession.close();
        }
    }

    static {
        System.out.println("创建SqlSessionFactory------------------------");
        try {
            InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
            //导入配置信息 获取sqlsessionFactory
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

        } catch (IOException e) {
            e.printStackTrace();
        }


    }

    public static SqlSession createSqlSession() {
        return sqlSessionFactory.openSession(false);//设置自动关闭 用于事务处理}
    }
}

练习:对于年级表的增删改

  • pojo实体层创建年级类

  • dAO中创建GradeMapper接口写方法
    在这里插入图片描述

  • mapper中创建GradeMapper.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="dao.GradeMapper">

    <insert id="addGrade" parameterType="String">
        insert into grade (gradeName)values (#{gradeName})
    </insert>

<delete id="deleteGrade" parameterType="int"
>
    delete from  grade where gradeId=#{gradeId}
</delete>

    <update id="updateGrade" parameterType="Grade">
        update grade set gradeName=#{gradeName} where gradeId=#{gradeID}
    </update>
</mapper>
  • 配置文件进行年级mapper文件映射
<!--将mapper的xml文件加入到mybatis配置文件中-->
 <mappers>
  <mapper resource="mapper/StudentMapper.xml"></mapper>
     <mapper resource="mapper/GradeMapper.xml"></mapper>

 </mappers>
  • 测试
  @Test
    public void testA(){
        SqlSession sqlSession = MyBatisUtil.createSqlSession();
        //int row = sqlSession.getMapper(GradeMapper.class).addGrade("初一");
        //int row = sqlSession.getMapper(GradeMapper.class).deleteGrade(4);

        int row = sqlSession.getMapper(GradeMapper.class).updateGrade(new Grade(5,"六年级"));
        if (row!=0){
            sqlSession.commit();
            System.out.println("success");
        }else{
            sqlSession.rollback();
            System.out.println("fail");
        }
        MyBatisUtil.closeSqlSession(sqlSession);


    }

由于每次创建mapper下的xml文件头部信息需要去网上查找或者复制,因此我们可以自动一个模板
在这里插入图片描述

  • 创建xml文件直接使用这个模板
    在这里插入图片描述

有难度的复杂查询动态SQL语句

练习一:查询学生表获取年级名称

年纪名称在年级实体类里面,查询学生需要用到年级实体类,查询一个学生,找到一个年级,学生与年级是一对一关系,学生表gradeId外键关联年级表gradeID

那么查询学生如何获取年级信息呢?

  • 首先创建学生实体类、年级实体类

  • 学生实体类中创建年级对象属性与get、set方法,通过映射将查询的信息保存到年级对象中。映射关系为:查询一个学生,找到一个年级,查询年级对象,找到一个学生集合
    在这里插入图片描述

  • 接口文件写查询方法


    //查询学生信息,获取学生年级名称
    List<Student> QueryStudent_E();
  • xml文件实现方法: 返回结果为自定义id的resultMap,resultMap中设置主键列id(表中的列名column(如果过长可以自己起一个名字)、实体对象属性名propertity、查询的是哪个对象,type就写这个对象的真实类型Student),需要的副键列,
  • 最重要的是在resultMap中描述学生与年级的关系association,学生实体中有一个年纪对象,设置实体类学生的属性名年级对象property,实体类学生的属性名的真实类型javaType(此处为实体类年级),association中写需要的年级主副键列(年级实体类的属性名pro perty与表列名column),如果不填就是全都都要
    在这里插入图片描述
  • 把返回结果为自定义id的resultMap设置到mapper映射中,查询到的年级信息就会保存到学生实体类中的年纪对象属性中,就可以通过查询年级对象获取年级名称属性值

在这里插入图片描述

  • 测试:做了映射后,查询到的年级信息就会保存到学生实体类中的年纪对象属性中
    在这里插入图片描述

练习二:查询学生表获取年级名称与学生考试成绩

一个学生可以考多次试,因此一个学生有多个考试成绩结果,学生与成绩是一对多关系,且学生表学生编号主键关联成绩表学生编号

在这里插入图片描述

  • 创建成绩实体类
  • 由于一个学生有多个考试成绩,因此学生实体类创建返回一个成绩实体类对象的集合、get set方法
//一个学生有多个成绩,因此一个学生对应多个成绩对象,一对多关系,创建成绩集合
private List<Result> resultList;
  • 查询的对象为学生实体类,学生与成绩为一对多关系,使用关系为collection,设置学生实体类属性名成绩集合property,与学生实体类属性名所在类型(成绩实体类)ofType

在这里插入图片描述

  • mapper做映射
    在这里插入图片描述

练习三:查询学生,查看学生成绩属于哪个科目

成绩表中外键subjectNo关联了科目表主键subjectNo,每一项成绩都可以查到所对应的科目,从成绩到科目是一对一关系,因此就可以通过查询学生来获取学生成绩属于哪个科目。

这是一种嵌套查询,首先通过学生表查询成绩表,再通过成绩表查询科目表。

  • 创建科目实体类,成绩实体类创建科目对象
    在这里插入图片描述
  • mapper中,学生成绩关系collection中嵌套查询科目,成绩与科目关系为association 一对一
    <sql id="sql_stu_resu_subj">
      select * from student
      join grade
      on grade.gradeID=student.gradeId
      join result
      on student.studentNo=result.studentNo
      join `subject`
      on result.subjectNo=`subject`.subjectNo
    </sql>
    <!-- 查询学生表获取年级名称 查询学生表返回学生对象集合,type为学生对象  -->
<!-- Type:查询学生表,此处为学生实体类,查询成绩表,此处为成绩实体类   -->
    <resultMap id="studentMap" type="Student">
        <id column="studentNo" property="studentNo"></id>
        <result column="studentName" property="studentName"></result>
        <result column="phone" property="phone"></result>
<!--  学生年级一对一 使用association关系 描述需要的年级表属性 property="grade" 实体类属性名       -->
        <association property="grade" javaType="pojo.Grade">
            <id column="gradeID" property="gradeID"></id>
            <result  column="gradeName" property="gradeName"></result>
        </association>
<!--学生成绩一对多 使用collection关系  描述需要的成绩表属性-->
        <collection property="resultList" ofType="pojo.Result">
            <result column="studentNo" property="studentNo"></result>
            <result column="subjectNo" property="subjectNo"></result>
            <result column="examDate" property="examDate"></result>
            <result column="studentResult" property="studentResult"></result>

<!--            嵌套查询科目表  科目表与成绩表主外键关联 -->
            <association property="subject" javaType="Subject">
                <id column="subjectNo" property="subjectNo"></id>
               <result column="subjectName" property="subjectName"></result>
               <result column="classHour" property="classHour"></result>
            </association>
        </collection>
    </resultMap>

在这里插入图片描述

  • 测试
    在这里插入图片描述

复杂查询总结:查询结果为对象使用的关系为association,查询结果为集合使用的关系为collection

多条件复杂动态SQL查询

例如按照如下多条件查询,有一种情况是所有条件值为空,就是全部查询;其余情况是满足其中一种条件的动态查询
在这里插入图片描述

  • 查询接口定义方法,传入参数类型为Map集合
  //查询学生信息,多条件if查询学生
    List<Student> QueryStudent_F(Map<String,String> map);

Mybatis提供的方式如下:多条件每一项要加入AND,mybatis会自动拼接和删除多余AND,如果每一次访问数据库的方法中都有重复的sql语句,可以抽取出来引用
在这里插入图片描述

 <select id="QueryStudent_F" resultMap="studentMap">
        <include refid="sql_stu_resu_subj">
        </include>
        <where>
            <if test="studentName!=''">
                AND student.studentName like concat('%',#{studentName},'%')
          </if>

          <if test="phone!=''">
              and student.phone=#{phone}
          </if>

          <if test="gradeName!=''">
              and grade.gradeName=#{gradeName}
          </if>

          <if test="subjectName!=''">
          and `subject`.subjectName=#{subjectName}
      </if>
      </where>


    </select>

在这里插入图片描述

  • 测试
    Map集合的键名必须与mapper.xml中传入的参数名一致,才能对应匹配查询该条件值是否存在,存在就填充SQL语句中查询
   @Test
    public void testJ() throws IOException {
        SqlSession sqlSession = MyBatisUtil.createSqlSession();


      Map<String, String> map = new HashMap<String, String>();
      map.put("studentName","李");
      map.put("phone","");
      map.put("gradeName","");
      map.put("subjectName","");
        List<Student> studentlist = sqlSession.getMapper(StudentMapper.class).QueryStudent_F(map);//直接获取这个接口中的方法
        //学生集合中遍历每一个学生,获取学生姓名、年级、成绩对象集合
        for (Student stu:studentlist){
            logger.debug("学生名称为:"+stu.getStudentName()+" 学生年级:"+stu.getGrade().getGradeName());
            for (Result result:stu.getResultList()){
                logger.debug("考试时间: "+result.getExamDate()+
                        "考试成绩: "+result.getStudentResult()+
                        "科目:"+result.getSubject().getSubjectName()); }

        }
        //一定要关闭
        MyBatisUtil.closeSqlSession(sqlSession);
    }

练习四:使用if-else来筛选多条件进行动态SQL查询

  • 接口定义方法
   //查询学生信息,多条件筛选if-else查询学生
    List<Student> QueryStudent_G(Map<String,String> map);

只要进入一个判断中其余判断均不进入
在这里插入图片描述

  • 测试
    在这里插入图片描述

练习五:对学生表的添加修改复杂动态sql语句

  • 接口定义方法
  //通过学生对象添加学生到数据库中,返回影响行数
    int addStudent(Student student);

    //通过学生对象修改学生到数据库中,返回影响行数
    int updateStudent(Student student);

  • mapper下:添加语句中有的列不允许为空,使用一个对象来写添加的值
<insert id="addStudent" parameterType="Student">
    INSERT INTO `student` (
	`studentNo`,
	`loginPwd`,
	`studentName`,
	`sex`,
	`gradeId`,
	`phone`,
	`address`,
	`bornDate`,
	`email`,
	`identityCard`
)
<trim prefix="VALUES (" suffix=");" prefixOverrides="," suffixOverrides=",">
    #{studentNo},
    #{loginPwd},
    #{studentName},
    #{sex},
    #{gradeId},
    #{phone},
    #{address},
    #{bornDate},
    #{email},
    #{identityCard},

</trim>
</insert>

在这里插入图片描述

  • 修改语句
    在这里插入图片描述
    利用前缀后缀标签来写修改SQL语句:
<update id="updateStudent" parameterType="Student">
    UPDATE  `student`
<!--  修改语句写法一:  <set></set><where></where>-->
<!--    修改语句使用前后缀写法二:-->
<trim prefix="set" suffix="WHERE(`studentNo` =#{studentNo})" suffixOverrides=",">
    <if test="loginPwd!=null and loginPwd!=''">
        `loginPwd` = #{loginPwd},
    </if>

    <if test="studentName!=null and studentName!=''">
        `studentName` = #{studentName},
    </if>

    <if test="sex!=null and sex!=''">
        `sex` = #{sex},
    </if>

    <if test="gradeId!=0">
        `gradeId` = #{gradeId},
    </if>

    <if test="phone!=null and phone!=''">
        `phone` = #{phone},
    </if>

    <if test="address!=null and address!=''">
        `address` = #{address},
    </if>
    <if test="bornDate!=null and bornDate!=''">
        `bornDate` = #{bornDate},
    </if>

    <if test="email!=null and email!=''">
        `email` = #{email},
    </if>

    <if test="identityCard!=null and identityCard!=''">
        `identityCard` = #{identityCard},
    </if>
</trim>
    </update>
  • 测试:
    @Test
    public void testL() throws IOException {
        SqlSession sqlSession = MyBatisUtil.createSqlSession();
        Student student=new Student(
                1119,
                "1111",
                "scq11",
                "女",
                1,
                "",
                "",
                "1901-9-8",
                "",
                "610103199609050028");

        int row = sqlSession.getMapper(StudentMapper.class).addStudent(student);//直接获取这个接口中的方法
     if (row!=0){sqlSession.commit();}
     else{sqlSession.rollback();}
        System.out.println(row==0?"失败":"成功");
        //一定要关闭
        MyBatisUtil.closeSqlSession(sqlSession);
    }
    @Test
    public void testM() throws IOException {
        //将30016这个学生性别修改为男
        SqlSession sqlSession = MyBatisUtil.createSqlSession();
        Student student=new Student();
        student.setStudentNo(30016);
       student.setSex("男");


        int row = sqlSession.getMapper(StudentMapper.class).updateStudent(student);//直接获取这个接口中的方法
        if (row!=0){sqlSession.commit();}
        else{sqlSession.rollback();}
        System.out.println(row==0?"失败":"成功");
        //一定要关闭
        MyBatisUtil.closeSqlSession(sqlSession);
    }
}

MyBatis缓存

MyBatis提供了一级缓存来减轻数据库压力但是一级缓存是SqlSession(会话)级别的缓存,

意味着一级缓存的适用范围比较小。

在一级缓存的基础上,MyBatis提供了二级缓存二级缓存是namaspace级别的缓存机制相对一一级缓存

二级缓存允许跨SqlSession工作,因此二级换的作用范围更大。

二级缓存的机制:

每个SqlSession在执行查询操作时,都会将查询的结果放在当前的会话(一级缓存中),如果当前会话关闭,一级缓存中的数据会被保存在二级缓存中。因此二级缓存是在一级缓存的基础上进行扩展的,不同的namaspace查出的数据都会将数据存在自己对应的缓存中,这些缓存信息使用map存储。

注意:MyBatis在开启二级缓存的清下,如果发出来一条SQL查询语句,会先向二级缓存中查询是否存在对应的缓存数据,如果没有 接着查询一级缓存中的数据,如果一级缓存中也没有对应的缓存数据,才会向数据库发送SQL语句。

实现:

1、在MyBatis全局配置(mybatis-config.xml)文件中开启二级缓存的配置(默认也是开启的)

2、在对应的SQL映射文件中加入 < cache / >标签。
在这里插入图片描述

3、将返回的JavaBean(实体类)实现序列化接口implements Serializable,序列化:将对象变成数据方便传输

在这里插入图片描述
测试:第一次查询完不关闭sqlsession进行二次查询,查询是从一级缓存中查询的
在这里插入图片描述
第一次查询完关闭sqlsession,查询结果保存到二级缓存中。第二次查询重新创建sqlsession,但是测试结果没有显示SQL语句,说明是从二级缓存中查询的

在这里插入图片描述
测试结果:第一次查询先去一级缓存,一级缓存没有去数据库查询,数据库查询后保存到一级缓存中,一级缓存在sqlsession关闭时保存到二级缓存中,第二次查询先去二级缓存查(不显示SQL语句),查询到后展示结果

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值