Mybatis 笔记 。Mybatis 整合spring

Mybattis 介绍

mybatis 本是apache 的一个开源项目,ibatis ,2010年这个项目由Apache software foundation 迁移到了good了code

,改名为Mybatis 2013年11月迁移到Github。

Mybatis 是一个优秀的持久层框架,他对于Jdbc 的操作数据库的过程进行封装使开发者只需要关注Sql 本身,而不需要在花费精力去处理例如注册驱动,创建connection ,创建statement ,手动设置参数,结果集检索等Jdbc 繁杂的过程代码。

mybatis 通过xml 或者注解的方式将要执行各种statement (statement、preparedStatemnt、CallableStatement)配

置起来并通过java 对象和statement中的sql 进行映射生成最终执行的sql 语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。

普通的jdbc 编程步骤

  1. 加载数据库驱动
  2. 创建并获取数据库链接
  3. 创建jdbc statement对象
  4. 设置sql语句
  5. 设置sql语句中的参数(使用preparedStatement)
  6. 通过statement执行sql并获取结果
  7. 对sql执行结果进行解析处理
  8. 释放资源(resultSet、preparedstatement、connection)

jdbc问题总结如下:

  1. 数据库连接创建、释放频繁造成系统资源浪费,从而影响系统性能。如果使用数据库连接池可解决此问题。
  2. Sql语句在代码中硬编码,造成代码不易维护,实际应用中sql变化的可能较大,sql变动需要改变java代码。
  3. 使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。
  4. 对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便。

Mybatis 框架

mybatis 配置

SqlMapconfig.xml 此文件作为mybatis 的全局配置文件配置了mybatis 的运行环境

mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。

  1. 通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂
  2. 由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
  3. mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
  4. Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
  5. Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。

Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,

  1. 输出结果映射过程相当于jdbc编程中对结果的解析处理过程。


第一个demo

SqlMapConfig.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>

    <!-- 和spring整合后 environments配置将废除 -->
    <environments default="development">
        <environment id="development">
            <!-- 使用jdbc事务管理 -->
            <transactionManager type="JDBC" />
            <!-- 数据库连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url"
                          value="jdbc:mysql://localhost:3306/fuxi?characterEncoding=utf-8" />
                <property name="username" value="root" />
                <property name="password" value="123456" />
            </dataSource>
        </environment>
    </environments>
<!--    映射-->
    <mappers>
<mapper resource="Mapper.xml"></mapper>

    </mappers>
</configuration>

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">
<!-- namespace:命名空间,用于隔离sql,还有一个很重要的作用,后面会讲 -->
<mapper namespace="test">
<!--    插入的-->
    <insert id="insert" parameterType="com.jj.pojo.Vip">

        insert into vip (name,pwd) values (#{name},#{pwd})
    </insert>
<!--    全查-->
    <select id="show" parameterType="com.jj.pojo.Vip" resultType="com.jj.pojo.Vip">

        select * from vip
    </select>
<!-- 修改   -->
    <update id="update" parameterType="com.jj.pojo.Vip">

        update vip set name=#{name} where id=#{id}
    </update>
<!--    删除-->
    <delete id="del" parameterType="int">
        delete from vip where id=#{id}
    </delete>
<!--    单查-->
    <select id="selectone" parameterType="int" resultType="com.jj.pojo.Vip">
        select * from vip where id=#{id}

    </select>
<!--    模糊查询-->
    <select id="selectlike" parameterType="string" resultType="com.jj.pojo.Vip">
        select * from vip where name like #{name}
    </select>
</mapper>

log4j.properties

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

Mybatisday01

package Demo;

import com.jj.pojo.Vip;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class Mybatisday01 {

   private SqlSession sqlSession;



    @Before
    public void text1() throws IOException {
        //        获取xml 的资源
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//        获取创建的工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//        创建工厂
        SqlSessionFactory session = builder.build(in);

//        获取到session
        sqlSession = session.openSession();
    }
    @Test
    public void demo() throws IOException {

//        调用方法
        int i = sqlSession.insert("test.insert", new Vip("jjj","111"));
        sqlSession.commit();
        sqlSession.close();
        if (i>0){
            System.out.println("添加成功!!");
        }

    }
    @Test
    public void demo2() throws IOException {

//        调用方法

        List<Vip> list = sqlSession.selectList("test.show", new Vip());
        System.out.println(list);
//        sqlSession.commit();
        sqlSession.close();
    }
//    修改
    @Test
    public void demo3() throws IOException {


//        调用方法
        int i = sqlSession.update("update", new Vip(26, "kiko"));
        if (i>0){
            System.out.println("修改成功");
        }
        sqlSession.commit();
        sqlSession.close();
    }
//删除
    @Test
    public void demo4(){
//        调用方法
        int i = sqlSession.delete("del", 5);
        if (i>0){
            System.out.println("删除成功!");
        }
        sqlSession.commit();
        sqlSession.close();
    }
//    单插
    @Test
    public void demo5(){
//        调用方法
        Vip selectone = sqlSession.selectOne("selectone", 26);
        System.out.println(selectone);
        sqlSession.close();
    }
//    模糊查询
    @Test
    public void demo6(){
//        调用方法
        List<Object> list = sqlSession.selectList("selectlike", "%憨%");
        System.out.println(list);
        sqlSession.close();

    }
}

Mybatis解决jdbc编程的问题

  1. 数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库连接池可解决此问题。

解决:在SqlMapConfig.xml中配置数据连接池,使用连接池管理数据库链接。

  1. Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。

解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。

  1. 向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。

解决:Mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型。

  1. 对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。

解决:Mybatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型。

mybatis与hibernate不同

Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。mybatis可以通过XML或注解方式灵活配置要运行的sql语句,并将java对象和sql语句映射生成最终执行的sql,最后将sql执行的结果再映射生成java对象。

Mybatis学习门槛低,简单易学,程序员直接编写原生态sql,可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。

Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件(例如需求固定的定制化软件)如果用hibernate开发可以节省很多代码,提高效率。但是Hibernate的学习门槛高,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡,以及怎样用好Hibernate需要具有很强的经验和能力才行。总之,按照用户的需求在有限的资源环境下只要能做出维护性、扩展性良好的软件架构都是好架构,所以框架只有适合才是最好。

#{}和${} 的区别

#{}表示一个占位符号,通过#{}可以实现preparedStatement 向占位符中设置值,

自动进行java类型和jdbc 类型转换。#{}可以有效防止sql 注入。#{}可以接收简单类型值或者pojo 属性值。如果parmerType 传输单个简单类型值。#{}括号中可以是value 或者其他名称

是以前servlect 项目中ps  会把sql 参数写成 ?,? 预编译

会把传入的参数(数据)当做一个字符串,会自动对传来的数据加上 "" 只有加 “” 才会更大程度上防止sql 注入

${} 表示拼接sql 串,通过${}可以将parameterType 传入放入内容拼接在sql 中且不进行jdbc 类型转换,${}可以接收简单类型值或者pojo属性如果parameterType传输单个简单类型值,${}括号中只能是value。

传入到数据库中,只会是一个没有加“” 直接 5 或者张三。 就不安全,不防止sql 注入

mybatis 在排序的时候order by 的时候会 用  ${} 而不用#{}

parameterType 和resultType

parameterType:指定输入参数类型,mybatis通过ognl 从输入对象中获取参数值拼接在sql 中

resultType:指定输入结果类型,mybatis 将sql查询结果的一行记录数据映射为resultype 指定类型的对象。如果有多条数据,则分别进行映射,并把对象放到容器List 中

selectone 和selectlist 区别

selectone 查询一条记录,如果使用selectone 查询多条记录抛出异常:

org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3

  at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:70)

selectlist 可以查询一条或者多条数据

原始的dao 开发出现的问题

dao方法体存在重复代码:通过sqlsessionFactory 创建sqlsession,调用sqlsession 的数据库操作方法

调用sqlsession 的数据库操作方法需要指定statement 的id ,这里存在硬编码,不得与开发维护

Mapper动态代理方式

开发规范

mapper 接口开发方法只需要写mapper 接口(相当于dao 接口),

由mybatis 框架根据接口定义创建接口的动态代理对象,代理对象的方法体实现类方法

Mapper 接口开发需要遵循以下规范:

  1. mapper.xml 文件中的namespace 与mapper 接口的类路径相同
  2. mapper 接口方法名和mapper.xml 中定义的方法名 的id 相同
  3. Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
  4. Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

Mapper1接口

package com.jj.mapper;

import com.jj.pojo.Vip;

import java.util.HashMap;
import java.util.List;

public interface Mapper1 {
//    添加
    int inser(Vip vip);
//    全查
    List<Vip> selectlist();
//    删除
    int del (int id);
//    修改
    int update(Vip vip);
//    模糊查询
    List<Vip>selectlike(String name);
//    分页查询
List<Vip>  pageselect(HashMap map);
//查询一条数据
   List<Vip> selectone(String name);
}

Mapper1.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">
<!-- namespace:命名空间,用于隔离sql,还有一个很重要的作用,后面会讲 -->
<mapper namespace="com.jj.mapper.Mapper1">
<!--    插入的-->
    <insert id="inser" parameterType="com.jj.pojo.Vip">

        insert into vip (name,pwd) values (#{name},#{pwd})
    </insert>
<!--全查的-->
    <select id="selectlist" parameterType="com.jj.pojo.Vip" resultType="com.jj.pojo.Vip">
        select * from vip
    </select>
<!--    删除的-->
    <delete id="del" parameterType="int">
        delete from vip where id=#{id}
    </delete>
<!--    修改-->
    <update id="update" parameterType="com.jj.pojo.Vip">
        update vip set name=#{name} where id=#{id}
    </update>
<!--  模糊查询  -->
    <select id="selectlike" parameterType="string" resultType="com.jj.pojo.Vip">
        select * from vip where name like #{name}
    </select>
<!--    分页查询-->
    <select id="pageselect" parameterType="hashmap" resultType="com.jj.pojo.Vip">
      select * from vip limit #{static},#{offset}
    </select>
<!--    查询一条数据-->
    <select id="selectone" resultType="com.jj.pojo.Vip" parameterType="String">
        select * from vip where name=#{name}
    </select>
</mapper>

测试类

package Demo;

import com.jj.mapper.Mapper1;
import com.jj.pojo.Vip;
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 org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;

public class Mybatisday02 {

   private SqlSession sqlSession;



    @Before
    public void text1() throws IOException {
        //        获取xml 的资源
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//        获取创建的工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//        创建工厂
        SqlSessionFactory session = builder.build(in);

//        获取到session
        sqlSession = session.openSession();
    }
//    插入
    @Test
    public void demo() throws IOException {

//        调用方法
        Mapper1 mapper = sqlSession.getMapper(Mapper1.class);
        int i = mapper.inser(new Vip("jj", "111"));
        if (i>0){
            System.out.println("添加成功!!");
        }
        sqlSession.commit();
        sqlSession.close();

    }
//全查
    @Test
    public void demo1(){
//        调用方法
        Mapper1 mapper = sqlSession.getMapper(Mapper1.class);
        List<Vip> list = mapper.selectlist();
        System.out.println(list);
        sqlSession.close();
    }
//    删除
@Test
public void demo2(){
//        调用方法
    Mapper1 mapper = sqlSession.getMapper(Mapper1.class);
    int i = mapper.del(24);
    if (i>0){
        System.out.println("删除成功!!!!");
    }
    sqlSession.commit();
    sqlSession.close();
}
//修改
@Test
public void demo3(){
//        调用方法
    Mapper1 mapper = sqlSession.getMapper(Mapper1.class);
    int i = mapper.update(new Vip(27, "冯娇娇"));
    if (i>0){
        System.out.println("修改成功!!!!");
    }
    sqlSession.commit();
    sqlSession.close();
}
//模糊查询
    @Test
    public void demo4(){
        //        调用方法
        Mapper1 mapper = sqlSession.getMapper(Mapper1.class);
        List<Vip> list = mapper.selectlike("%憨%");
        System.out.println(list);
        sqlSession.close();
    }
//    分页查询
    @Test
    public void demo5(){
        //        调用方法
        Mapper1 mapper = sqlSession.getMapper(Mapper1.class);
//        获取hashmap
        HashMap<String, Object> map = new HashMap<>();
        //        添加参数
        map.put("static",0);
        map.put("offset",6);
        List<Vip> list = mapper.pageselect(map);
        System.out.println(list);

        sqlSession.close();
    }
//    查询一条数据
    @Test
    public void demo6(){
        //        调用方法
        Mapper1 mapper = sqlSession.getMapper(Mapper1.class);
        List<Vip> list = mapper.selectone("冯娇娇");
        System.out.println(list);
        sqlSession.close();
    }
}

动态sql

通过mybatis 提供的各种标签方法实现动态拼接sql.

if 标签

<!--    动态sql   if  标签-->
    <select id="ifde" parameterType="vip" resultType="vip">
        select * from vip where 1=1
        <if test="name !=null and name !=''">
            and name=#{name}
        </if>
        <if test="pwd != null and pwd !=''">
            and pwd like '%${pwd}%'
        </if>
    </select>

接口

//   动态Sql if 的
    List<Vip> ifde (Vip vip);

测试类的

    //动态Sql if的
    @Test
    public void demo8(){
//        调用方法
        Mapper1 mapper = sqlSession.getMapper(Mapper1.class);
        Vip vip = new Vip();
        vip.setName("娇娇");
        vip.setPwd("12");
        List<Vip> list = mapper.wherede(vip);
        System.out.println(list);
        sqlSession.close();
    }

where 的

<!--    动态Sql where 标签-->
    <select id="wherede" parameterType="vip" resultType="vip">

        select * from vip
        <where>
        <if test="name !=null">
            and name=#{name}
        </if>
        <if test="pwd != null and pwd !=''">
            and pwd like '%${pwd}%'
        </if>
        </where>
    </select>

接口测试差不多

foreach标签

xml

<!--    foreach 标签 ,批量添加-->
    <insert id="insertbyid" parameterType="map">
        insert into vip (name,pwd) values
        <foreach collection="viplist" separator="," item="vip">
            (#{vip.name},#{vip.pwd})
        </foreach>
    </insert>

接口

 
//    批量添加
    int insertbyid(Map map);

测试类

//    批量添加
    @Test
    public void demo9(){
        //        调用方法
        Mapper1 mapper = sqlSession.getMapper(Mapper1.class);
        List<Vip> list = new ArrayList();
        for (int i = 0; i < 5; i++) {
            Vip vip = new Vip();
            vip.setName("娇娇"+i);
            vip.setPwd("1111"+i);
            list.add(vip);
        }
        HashMap map = new HashMap();
        map.put("viplist",list);
        int i = mapper.insertbyid(map);
        System.out.println(i);
        sqlSession.commit();
        sqlSession.close();
    }

mybatis 生命周期

生命周期作用域是至关重要的,因为错误的使用会导致非常严重的并发问题

SqlsessionFactoryBuilder:

一旦创建了SqlsessionFactory ,就不在需要他了,局部变量

SqlsessionFactory

可以想象为数据库连接池SqlsessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它,或重新创建另一个实例

因此他的最佳作用域是应用作用域

最简单的就是使用单例模式或者静态单例模式

Sqlsession:

连接到连接池的一个请求!

sqlsession 的实例不是线程安全的,因此是不能被共享的,所以他的最佳作用域是请求或方法作用域

用完记得关闭,避免资源的浪费

ResultMap

用来处理我们实体类字段与数据库不一致的时候用的

 

上面的方法是最笨的方法

我们也可以用resultMap

 

日志

第一种

这个是标准的日志

log4j 的使用

导入依赖

<!--    日志-->
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.17</version>
    </dependency>

写log4j.properties

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

实现mybatis 的分页

第一种limit 分页

sql 部分

<!--vipLimit  分页-->
    <select id="vipLimit" parameterType="map" resultMap="vipmap">

        select * from vip limit #{start},#{end}
    </select>

接口

//limit  分页
    List<Vip> vipLimit(Map<String,Integer> map);

测试类

//分页
    @Test
    public void demo1(){
        Mapper1 mapper = sqlSession.getMapper(Mapper1.class);
        Map<String, Integer> map = new HashMap<>();
        map.put("start",0);
        map.put("end",10);
        List<Vip> vips = mapper.vipLimit(map);
        for (Vip vip : vips) {
            System.out.println("vip = " + vip);
        }
        sqlSession.close();
    }

结果

RowBounds 分页 了解

sql

<!--    分页2-->
    <select id="RowBoundsLimit" resultMap="vipmap">
        select * from vip
    </select>

接口

//    RowbansLimit 分页
    List<Vip>  RowBoundsLimit();

测试类

    //分页
    @Test
    public void demo2(){

   //获取Rowbans
        RowBounds rowBounds = new RowBounds(0, 1);
        List<Vip> list = sqlSession.selectList("com.jj.mapper.Mapper1.RowBoundsLimit", null,rowBounds);
        for (Vip vip : list) {
            System.out.println("vip = " + vip);
        }
//        System.out.println("list = " + list);
        sqlSession.close();
    }

结果

分页插件,我在另一个博客写过了

分页插件使用

Mybatis 执行流程

多对一,一对多的

数据库的设计

实现的方式一

我们可以用子查询的理解来做,就是按照查询嵌套处理

实体类

Student

import lombok.*;

/**
 * @author fjj
 * @date 2021/1/28 15:02
 */
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Student {
    private int id;
    private String name;
    private int age;
    private teacher teacher;
}

teacher 的

package com.jj.pojo;

import lombok.*;

/**
 * @author fjj
 * @date 2021/1/28 15:00
 */
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class teacher {
    private int id;
    private String name;

}

我们的xml

    <select id="getStudent" resultMap="student1">
        select * from student
    </select>
    <resultMap id="student1" type="student">
        <result property="id" column="id"></result>
        <result property="name" column="name"></result>
        <result property="age" column="age"></result>
        <association property="teacher" column="tid" select="teacher"></association>
    </resultMap>
    <select id="teacher" resultType="teacher" parameterType="int">
        select * from teacher where id=#{id}
    </select>

这里我们的思路是,我们可以先查询出来Student 表的所有数据,然后再查询出来老师表的。大概就是用子查询的思想

接口

    //查询学生信息
    List<Student> getStudent();

测试类

    //多对一查询1
    @Test
    public void demo3(){
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> list = mapper.getStudent();
        for (Student student : list) {
            System.out.println("student = " + student);
        }
        sqlSession.close();
    }

结果的

方式2

按照结果查询

接口不变,唯一变得是我们得xml

<!--    多对一查询2 -->
    <select id="getStudent1" resultMap="getStudent1">
        select s.*,t.name tname from student s INNER JOIN teacher t on s.tid=t.id
    </select>
    <resultMap id="getStudent1" type="student">
        <result property="id" column="id"></result>
        <result property="name" column="name"></result>
        <result property="age" column="age"></result>
        <association property="teacher" javaType="teacher">
            <result property="name" column="tname"></result>
        </association>
    </resultMap>

结果

一对多得

方式一,根据结果查询

实体类

package com.jj.pojo;

import lombok.*;

import java.util.List;

/**
 * @author fjj
 * @date 2021/1/28 15:00
 */
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class teacher {
    private int id;
    private String name;
    private List<Student> students;
}
package com.jj.pojo;

import lombok.*;

/**
 * @author fjj
 * @date 2021/1/28 15:02
 */
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Student {
    private int id;
    private String name;
    private int age;
    private int tid;
//    private teacher teacher;
}

xml

 <select id="getStudent" resultMap="getStudent1">
        SELECT t.*,s.name ,s.age from teacher t inner JOIN student s on s.tid=t.id AND t.id=#{id}
    </select>
    <resultMap id="getStudent1" type="teacher">
        <result column="id" property="id"></result>
        <result column="name" property="name"></result>
        <collection  property="students" ofType="student">
            <result property="tid" column="tid"></result>
            <result property="name" column="name"></result>
            <result property="age" column="age"></result>
            <result property="id" column="id"></result>
        </collection>
    </resultMap>

接口

package com.jj.mapper;

import com.jj.pojo.Student;
import com.jj.pojo.teacher;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * @author fjj
 * @date 2021/1/28 15:13
 */
public interface teacherMapper {
    //获取学生
   List<teacher> getStudent(@Param("id") int id);
}

测试类

    //多一对多查询1
    @Test
    public void demo5(){
        teacherMapper mapper = sqlSession.getMapper(teacherMapper.class);
        List<teacher> list = mapper.getStudent(1);
        for (teacher teacher : list) {
            System.out.println(teacher+"\t");
        }
        sqlSession.close();
    }

结果

按照子查询得方式查询

xml

<!--    根据子查询得-->
    <select id="getStudent1" resultMap="getStudent2">
        select * from teacher where id=#{id}
    </select>
    <resultMap id="getStudent2" type="teacher">
        <collection property="students" ofType="student" javaType="ArrayList" column="id" select="student111">

        </collection>
    </resultMap>
    <select id="student111" resultType="student">
        select * from student where tid=#{id}
    </select>

其他得都一样,两个都可以用哪个比较顺手,就用那个就可以!

Mybatis 缓存

缓存得概念

存在内存中得临时数据

将用户经常查询得数据放到缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高效率,解决了高并发系统得性能问题

为什么使用缓存?

减少和数据库得交互次数,减少系统开销,提高系统效率

什么样得数据能使用缓存?

经常查询并且不经常改变得数据

Mybatis 缓存

Mybais 包含一个非常强大得查询缓存特性,它非常方便地定制和配置缓存,缓存可以极大得提升查询效率

Mybatis 系统中默认定义了两级缓存:一级缓存和二级缓存

默认情况下,只有一级缓存开启。(Sqlsession 级别得缓存,也称为本地缓存)

二级缓存需要手动开启和配置,他是基于namespace 级别得缓存

为了提高扩展性,Mybatis 定义了缓存接口Cache 我们可以通过实现Cache 接口来自定义二级缓存

一级缓存

当我们在执行一条查询语句得时候

一级缓存失效得几种方式

 

一,我们可以在中间加一个sqlSession.clearCache();

3,在中间加一个增删改得方法,

4,其他就是不在一个Mapper 得情况了

二级缓存

二级缓存也叫全局缓存,一级缓存得作用域太低了,所以诞生了二级缓存

基于namespace 级别得缓存,一个名称空间,对应一个二级缓存

工作机制

一个会话查询一条数据,这个数据就会被放在当前会话一级缓存中

如果当前会话关闭了,这个会话对应得一级缓存就死了,我们想要得是当一级缓存关闭了,一级缓存得数据会保存到二级缓存中

新的会话查询信息,就可以从二级缓存中获取内容

不同得mapper 查出得数据会放到自己对应得缓存中

我们先在配置文件里开启缓存

在mapper xml 里开启

测试类

结果

Mybatis整合spring

整合思路

  1. SqlSessionFactory对象应该放到spring容器中作为单例存在。
  2. 传统dao的开发方式中,应该从spring容器中获得sqlsession对象。
  3. Mapper代理形式中,应该从spring容器中直接获得mapper的代理对象。
  4. 数据库的连接以及数据库连接池事务管理都交给spring容器来完成。

导入需要的jar

  1. spring的jar包
  2. Mybatis的jar包
  3. Spring+mybatis的整合包。
  4. Mysql的数据库驱动jar包。
  5. 数据库连接池的jar包。
  6.  

加入配置文件

sqlmapConfig.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>
    <!-- 设置别名 -->
    <typeAliases>
        <!-- 2. 指定扫描包,会把包内所有的类都设置别名,别名的名称就是类名,大小写不敏感 -->
        <package name="com.jj.pojo" />
    </typeAliases>

</configuration>

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
	http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">

    <!-- 加载配置文件 -->
    <context:property-placeholder location="classpath:db.properties" />

    <!--使用c3p0连接池配置数据源-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <!--下面还可以配置连接数量等-->
    </bean>

    <!-- 配置SqlSessionFactory -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 配置mybatis核心配置文件 -->
        <property name="configLocation" value="classpath:sqlmapConfig.xml" />
        <!-- 配置数据源 -->
        <property name="dataSource" ref="dataSource" />
    </bean>
<!--    Mapper代理的方式开发方式一,配置 Mapper 代理对象-->
    <bean id="usermapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<!--配置mapper 接口-->
        <property name="mapperInterface" value="com.jj.dao.Vipmapper"/>
<!--        配置sqlsessionFactory-->
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>
</beans>

db.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///fuxi
jdbc.username=root
jdbc.password=123456

log4j.properties

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
      1. Mapper代理形式开发dao

Vipmapper.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.jj.dao.Vipmapper">
<!--查询-->
    <select id="selectall" resultType="vip">
        select * from vip
    </select>
<!--    添加-->
    <!--    foreach 标签 ,批量添加-->
    <insert id="insertbyid" parameterType="map">
        insert into vip (name,pwd) values
        <foreach collection="viplist" separator="," item="vip">
            (#{vip.name},#{vip.pwd})
        </foreach>
    </insert>
</mapper>

    Vipmapper

package com.jj.dao;

import com.jj.pojo.Vip;

import java.util.List;
import java.util.Map;

public interface Vipmapper {
    List<Vip> selectall();

    //    批量添加
    int insertbyid(Map map);
}

测试类

import com.jj.dao.Vipmapper;
import com.jj.pojo.Vip;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class Demo1 {
    private ApplicationContext context;
    @Before
    public void setUp() throws Exception {
        this.context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    }

    @Test
    public void springmybatis(){
//获取Mapper
        Vipmapper bean = this.context.getBean(Vipmapper.class);
        List<Vip> list = bean.selectall();
        System.out.println(list);

    }
    @Test
    public void springmybatis1(){
//获取Mapper
        Vipmapper bean = this.context.getBean(Vipmapper.class);
        List<Vip> list = new ArrayList();
        for (int i = 0; i < 5; i++) {
            Vip vip = new Vip();
            vip.setName("憨憨"+i);
            vip.setPwd("1111"+i);
            list.add(vip);
        }
        HashMap map = new HashMap();
        map.put("viplist",list);
        int i = bean.insertbyid(map);
        if (i>0){
            System.out.println("添加成功!!");
        }


    }
}

猜你喜欢

转载自blog.csdn.net/m0_46937429/article/details/110180553