Mybatis

MyBatis

使用框架的三大步骤

1.导入jar包

2.处理配置文件

3.开发业务处理

MyBatis的配置

MyBatis的依赖

<dependencies>
        <!--mysqlConnector-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.16</version>
        </dependency>
        <!--mybatis 核心jar包-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.3</version>
        </dependency>
        <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.1</version>
            <scope>test</scope>
        </dependency>
        <!--lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
​

MyBatis的核心配置文件

<?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>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/test?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <!--加载mapper映射文件-->
    <mappers>
            <!--这里放的是每个实体类所对应的配置文件-->
        <mapper resource="com/fjh/mapper/DeptMapper.xml"/>
    </mappers>
</configuration>

MyBatis的初次使用

项目结构

每个实体类所对应的配置文件都必须写在resources下,在resources文件下建立包com.fjh.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="aaa">
    <select id="findAll" resultType="com.fjh.pojo.Dept" >
        select * from dept
    </select>
</mapper>

业务实现

package com.fjh.test;
​
import com.fjh.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 org.junit.Test;
​
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
​
public class Test1 {
    @Test
    public void test(){
        //创建回话厂的工人
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
​
        //创建sql会话工厂的图纸
        InputStream resourceAsStream = null;
        try {
           resourceAsStream = Resources.getResourceAsStream("sqlMapContext.xml");
        } catch (IOException e) {
            e.printStackTrace();
        }
        //工人使用图纸建造工厂
        SqlSessionFactory factory= builder.build(resourceAsStream);
        //开启会话
        SqlSession sqlSession = factory.openSession();
        //执行业务
        List<Dept> depts = sqlSession.selectList("findAll");
        for (Dept dept : depts) {
            System.out.println(dept);
        }
    }
}
​

MyBatis日志配置

log4j1依赖

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

log4j1配置

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

log4j2依赖

log4j2
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.12.1</version>
</dependency>

log4j2配置

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="DEBUG">
    <Appenders>
        <Console name="Console" target="SYSTEM_ERR">
            <PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %msg%n" />
        </Console>
        <RollingFile name="RollingFile" filename="log/test.log"
                     filepattern="${logPath}/%d{YYYYMMddHHmmss}-fargo.log">
            <PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %msg%n" />
            <Policies>
                <SizeBasedTriggeringPolicy size="10 MB" />
            </Policies>
            <DefaultRolloverStrategy max="20" />
        </RollingFile>
    </Appenders>
    <Loggers>
        <Root level="INFO">
            <AppenderRef ref="Console" />
        </Root>
    </Loggers>
</Configuration>
​

SqlSession的三种查询方式

1.单个数据查询

<select id="findOne" resultType="com.fjh.pojo.Emp">   
    select *from  emp where  empno = 7521</select>
public void testFindOne(){  
Emp emp = sqlSession.selectOne("empMapper.findOne");  
System.out.println(emp);}

2.数据集合查找

<select id="findAll" resultType="com.fjh.pojo.Emp">    select * from emp;</select>
 @Test
    public void testFindAll(){
        if(sqlSession == null){
            System.out.println("sqlSession is null");
        }
        List<Emp> emps = sqlSession.selectList("empMapper.findAll");
        emps.forEach(System.out::println);
    }

3.数据mapper查询

<select id="findMapper" resultType="map">    select *from  emp</select>
    @Test
    public void testFindMapper(){
        Map<Integer, Emp> empMapper = sqlSession.selectMap("empMapper.findMapper", "EMPNO");
        Set<Integer> sets = empMapper.keySet();
        for (Integer set : sets) {
            System.out.println(""+set+": " + empMapper.get(set));
        }
    }

Sqlsession的三种传参方式

在对sql语句中进行参数的传递中,有两种占位符,一种是#{} 一种是${}

#{}相当于原生的jdbc使用用preparedStatement对象

${}相当于原生的JDBC使用Statement对象

一般使用#{}:因为可以防止SQL注入

1.只有一个参数

<!--
按照员工 工号进行查找员工信息
函数:public Emp findEmpByEmpNo(int empNo)
-->
    <select id="findEmpByEmpNo" resultType="com.fjh.pojo.Emp">
        select *from  emp where empno = ${empNo}
    </select>

因为只有一个参数,所以在占位符中所填写的内容就可以随便。但是一般要求见名知意

    public void testSingleArg(){
        Emp emp = sqlSession.selectOne("findEmpByEmpNo", 7521);
        System.out.println(emp);
    }

2参数是mapper集合

    <select id="findByDeptNoAndSal" resultType="com.fjh.pojo.Emp" parameterType="map">
        select * from emp where deptno = #{deptno} and sal &gt; #{sal}
    </select>

以mapper作为参数:就是将对应的函数的参数,以键值对的形式存入到mapper集合之中。在占位符中填写对应的参数的键值

    @Test
    public void testMapArg(){
      Map<String, Object>map = new HashMap<>();
      map.put("deptno",10);
      map.put("sal",1500.0);
      List<Emp> emps = sqlSession.selectList("findByDeptNoAndSal", map);
      emps.forEach(System.out::println);
    }

3以对象最作为参数

<!--
查找    查找10号部门中奖金大于30.0的员工信息
函数:public List<Emp> findByDeptNoAndComm
-->
    <select id="findByDeptNoAndComm" resultType="com.fjh.pojo.Emp" parameterType="com.fjh.pojo.Emp">
        select *from emp where deptno = #{deptNo} and comm &gt; 30.0
    </select>

以对象作为参数,就是将要传入的参数封装为对象,在占位符中要写,对象对应的属性名

    @Test
    public  void testObjectArg(){
      Emp arg = new Emp();
      arg.setDeptNo(10);
      arg.setComm(30.0);
      List<Emp> emps = sqlSession.selectList("findByDeptNoAndComm", arg);
      emps.forEach(System.out::println);
    }

sqlsession实现CRUD

在sqlsession对象实现insert updata 和 delete时,使用相对应的标签,在这些标签里面没有resultType,默认是int的返回

值。

因为Sqlsession对象在执行增删改的方法的时候默认是使用事务不提交的方式的,所以需要手动调用commit方法就行事务的提交,或者在sqlsessionFactory.OpenSession(ture)设置,事务自动提交

MyBatis基于接口代理开发

1.开发步骤

1.在mapper包下定义对实体类进行数据库相关操作的类,类名的规范写法为实体类的类名+Mapper

2.在resource目录下创建xml文件,用来对mapper包下接口中的方法进行重写,文件名必须和对应的接口名相同(不包含后缀)

3.在对应的点xml中利用标签书写对应方法的sql语句

<mapper namespace="com.fjh.mapper.EmpMapper">
<!--
查询所有员工信息
   List<Emp>findAll();
-->
    <select id="findAll" resultType="com.fjh.pojo.Emp">
        select *from  emp ;
    </select>

</mapper>

这里的命名空间必须是对应接口的的全路径 ,标签的id属性必须和接口中的方法名形同。参数的类型属性可以不写,MyBatis会自动补充

2参数问题

1.单个参数

单个参数函数: Emp findByEmpNo( int empNo);功能: 根据员工工号查询员工信息

<!--单个参数函数:    Emp findByEmpNo( int empNo);功能: 根据员工工号查询员工信息-->    <select id="findByEmpNo" resultType="com.fjh.pojo.Emp">        select * from  emp where empNo = #{empNo};    </select>

单个参数的时候可以传入任意的名称,规范编程使用对应方法的形参名

2.多个参数

多个参数 函数: List<Emp>findByDeptNoAndSal(int deptNo,double Sal); 功能: 根据员工的部们号和薪资下限查询员工信息 参数的传入放式: 1.arg* arg0 arg1 arg2 ... 数字表示下标 select * from emp where deptNo = #{arg0} and sal >#{arg1}

2.param* param1 param2 .... 数字表示第几个参数 select * from emp where deptNo = #{param1} and sal >#{param2}

3.使用别名 List<Emp>findByDeptNoAndSal(@Param("deptNo") int deptNo, @Param("sal") double Sal);

<!--
多个参数
函数:   List<Emp>findByDeptNoAndSal(int deptNo,double Sal);
功能: 根据员工的部们号和薪资下限查询员工信息
参数的传入放式:
1.arg* arg0 arg1 arg2 ... 数字表示下标    select * from emp where deptNo = #{arg0} and sal &gt;#{arg1}
2.param* param1 param2 .... 数字表示第几个参数  select * from emp where deptNo = #{param1} and sal &gt;#{param2}
3.使用别名     List<Emp>findByDeptNoAndSal(@Param("deptNo") int deptNo, @Param("sal") double Sal);
-->
    <select id="findByDeptNoAndSal" resultType="emp">
        select * from emp where deptNo = #{deptNo} and sal > #{sal}
    </select>

注意事项:

在使用别名之后,不能使用arg但是可以是用param

3.模糊查询

使用concat函数进行拼接

<!--
模糊查询
函数:    List<Emp>findByEname(String eName);
功能:对员工姓名进行模糊匹配
-->
    <select id="findByEname" resultType="emp">
        select *from emp where eName like concat ('%',#{eName},'%')
    </select>
  public void testFindByEname(){
        EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
        List<Emp> emps = empMapper.findByEname("a");
        emps.forEach(System.out::println);
    }

MyBatis多表查询

手动处理映射关系

当实体类中的属性名和数据库表中的列名不相同,就要进行手动的处理映射关系,否则就会出现不匹配的问题.

在SQL语句的标签的属性中,使用restMap属性

实体类

package com.fjh.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Emp implements Serializable {
    private Integer empNo;
    private String name;
    private String job;
    private int mgr;
    private Date heirDate;
    private Double sal;
    private Double comm;
    private Integer deptNo;
}

Mapper映射文件

    <resultMap id="empResultMap" type="emp">
        <result column="ename" property="name"></result>
    </resultMap>
<select id="findAll" resultMap="empResultMap">
    select * from  emp
</select>

column:数据库表中的列名

property:实体类中的属性名

多表查询一对一

业务:依据员工编号查询员工信息和该员工所在的部门信息

sql:select * from emp e left join dept d on e.deptno = d.deptno where empno = 7521

查询结果:

要想在Java代码中输出这个信息,那么必须在emp表中添加dept属性

实体类:

package com.fjh.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Emp implements Serializable {
    private Integer empNo;
    private String eName;
    private String job;
    private int mgr;
    private Date heirDate;
    private Double sal;
    private Double comm;
    private Integer deptNo;
    private Dept dept;
}

对应的映射文件

 <resultMap id="EmpJoinDeptResultMap" type="emp">
     必须对实体类中和数据库表中字段名相同的字段进行映射
        <id column="empNo" property="empNo"></id>
        <result column="eName" property="eName"></result>
        <result column="job" property="job"></result>
        <result column="mgr" property="mgr"></result>
        <result column="heirDate" property="heirDate"></result>
        <result column="sal" property="sal"></result>
        <result column="comm" property="comm"></result>
        <result column="deptNo" property="deptNo"></result>
        用association标签对实体类中的唯一一个其他类对象进行映射
        property :数据库表中的字段名
        JavaType:实体类中的属性名
        <association property="dept" javaType="dept">
            <id column="deptNo" property="deptNo"></id>
            <result column="dName" property="dName"></result>
            <result column="loc" property="loc"></result>
        </association>
    </resultMap>
<select id="findEmpJoinDeptByEmpno" resultMap="EmpJoinDeptResultMap">

select * from
emp e
 left join dept d
 on e.deptno = d.deptno
 where empno = #{empNo}
</select>

多表查询一对多

业务:依据部门号查询该部门的所有员工信息

sql:

select * from dept d left join emp e on d.deptno = e.deptno where
d.deptno = 20

查询结果:

实体类:

package com.fjh.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.List;

@AllArgsConstructor
@Data
@NoArgsConstructor
public class Dept implements Serializable {
    private Integer deptNo;
    private String  dName;
    private String loc;
    private List<Emp> empList;
}

映射文件:

  <resultMap id="DeptJoinEmps" type="dept">
        <id property="deptNo" column="deptNo"></id>
        <result property="dName" column="dName"></result>
      <result property="loc" column="loc"></result>
      一对多用collection 属性:ofType 多对应的数据类型 
        <collection property="empList" ofType="emp">
            <id column="empNo" property="empNo"></id>
            <result column="eName" property="eName"></result>
            <result column="job" property="job"></result>
            <result column="mgr" property="mgr"></result>
            <result column="heirDate" property="heirDate"></result>
            <result column="sal" property="sal"></result>
            <result column="comm" property="comm"></result>
            <result column="deptNo" property="deptNo"></result>
        </collection>
    </resultMap>
    <select id="findDeptJoinEmpByDeptNo" resultMap="DeptJoinEmps">xml
        
    

多表查询多对多

业务:根据项目编号查询做该项目的所有员工的信息

SQL:

select * from 
projects p
left join projectrecord pr 
on p.pid = pr.pid 
left join emp e 
on pr.empno = e.empno
where p.pid = 2

查询结果

实体类_project

package com.fjh.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@NoArgsConstructor
@AllArgsConstructor
@Data
public class Project {
    private Integer pid;
    private String pName;
    private Integer money;
    private List<ProjectRecord> projectRecordList;
}

实体类_ProjectRecord

package com.fjh.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ProjectRecord {
    private Integer empNo;
    private Integer pid;
    private Emp emp ;

}

映射文件:

<resultMap id="ProjectJoinEmp" type="project">
        <id property="pid" column="pid"></id>
        <result property="pName" column="pName"></result>
        <result property="money" column="money"></result>
        <collection property="projectRecordList" ofType="projectRecord">
            <id property="pid" column="pid"></id>
            <id property="empNo" column="empNo"></id>
            <association property="emp" javaType="emp">
                <id column="empNo" property="empNo"></id>
                <result column="eName" property="eName"></result>
                <result column="job" property="job"></result>
                <result column="mgr" property="mgr"></result>
                <result column="heirDate" property="heirDate"></result>
                <result column="sal" property="sal"></result>
                <result column="comm" property="comm"></result>
                <result column="deptNo" property="deptNo"></result>
            </association>
        </collection>
    </resultMap>
    <select id="findProjectJoinEmps" resultMap="ProjectJoinEmp">
        select * from
        projects p
        left join projectrecord pr
        on p.pid = pr.pid
        left join emp e
        on pr.empno = e.empno
        where p.pid = #{pid}
    </select>

级联查询积极加载

级联查询映射文件

<mapper namespace="com.fjh.mapper.DeptMapper">
    <!--    Dept findDeptJoinEmp(int deptNo);-->
    <resultMap id="DeptJoinEmp" type="dept">
        <id property="deptNo" column="deptNo"></id>
        <result property="dName" column="dName"></result>
        <result property="loc" column="loc"></result>
        <collection property="empList"
                   select="com.fjh.mapper.EmpMapper.findEmpByDeptNo"
                    javaType="list"
                    column="deptNo"
                    jdbcType="INTEGER"
                    fetchType="eager"
                    >
        </collection>
    </resultMap>
    <select id="findDeptJoinEmp" resultMap="DeptJoinEmp">
        select * from dept where deptNo = #{deptNo}
    </select>

缓存

一级缓存

一级缓存是sqlSession中的缓存,当执行一个sql语句后,在sqlSession中就会以键值对的形式查询的数据进行存储,默认是开启的

键是:命名空间+SQL的id+ 参数进过哈希算法得到

值为:查询的结果

因为一级缓存是在sqlSession中的缓存,所有只有在同一个sqlSession对象中适合

如果中间执行了commit方法就会清空缓存

二级缓存

二级缓存是以namespace为标记的缓存,可以是由一个SqlSessionFactory创建的SqlSession之间共享缓存数据。默认并不开启。下面的代码中创建了两个SqlSession,执行相同的SQL语句,尝试让第二个SqlSession使用第一个SqlSession查询后缓存的数据。要求实体类必须实现序列化接口

注意其中的commit(),执行该命令后才会将该SqlSession的查询结果从一级缓存中放入二级缓存,供其他SqlSession使用。另外执行SqlSession的close()也会将该SqlSession的查询结果从一级缓存中放入二级缓存。两种方式区别在当前SqlSession是否关闭了。

执行结果显示进行了两次对数据库的SQL查询,说明二级缓存并没有开启。需要进行如下步骤完成开启。

1) 全局开关:在sqlMapConfig.xml文件中的<settings>标签配置开启二级缓存

<settings>

<setting name="cacheEnabled" value="true"/>

</settings> cacheEnabled的默认值就是true,所以这步的设置可以省略。

2) 分开关:在要开启二级缓存的mapper文件中开启缓存:

<mapper namespace="com.msb.mapper.EmployeeMapper">

<cache/>

</mapper>

3) 二级缓存未必完全使用内存,有可能占用硬盘存储,缓存中存储的JavaBean对象必须实现序列化接口,

public class Emp implements Serializable { }

经过设置后,查询结果如图所示。发现第一个SqlSession会首先去二级缓存中查找,如果不存在,就查询数据库,在commit()或者close()的时候将数据放入到二级缓存。第二个SqlSession执行相同SQL语句查询时就直接从二级缓存中获取了。

注意:

1) MyBatis的二级缓存的缓存介质有多种多样,而并不一定是在内存中,所以需要对JavaBean对象实现序列化接口。

2) 二级缓存是以 namespace 为单位的,不同 namespace 下的操作互不影响

3) 加入Cache元素后,会对相应命名空间所有的select元素查询结果进行缓存,而其中的insert、update、delete在操作是会清空整个namespace的缓存。

4) cache 有一些可选的属性 type, eviction, flushInterval, size, readOnly, blocking。

<cache type="" readOnly="" eviction=""flushInterval=""size=""blocking=""/>

5) 如果在加入Cache元素的前提下让个别select 元素不使用缓存,可以使用useCache属性,设置为false。useCache控制当前sql语句是否启用缓存 flushCache控制当前sql执行一次后是否刷新缓存

<select id="findByEmpno" resultType="emp" useCache="true" flushCache="false">
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值