mybatis 从 0 到 1

112 阅读8分钟

mybatis从0到1

前沿

本文主要介绍mybatis的学习,用惯了springboot的快速搭建,似乎都忘了mybatis的一开始的原始搭建。这边重新学习一下,主要为了给自己巩固,为了更好的理解springboot到底帮你做了啥,能够更好的理解springboot的底层源码。如果是初学的你,也希望给你一个指引。

基础: 至少了解过maven

准备工作

  1. 使用idea,点击file->new->project->maven项目

    结果:

image-20220811230708065.png

2.必须加载jar包

mysql-connector-java: 下载合适版本

mybatis

辅助工具包:

lombok: 实体类友好

junit: 测试包

maven查询包网址

个人的下载版本: 可以做参考

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
​
    <groupId>com.duncan</groupId>
    <artifactId>mybatis-myself</artifactId>
    <version>1.0-SNAPSHOT</version>
​
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
​
    <dependencies>
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
​
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
        </dependency>
​
        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
            <scope>provided</scope>
        </dependency>
​
        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.1</version>
            <scope>test</scope>
        </dependency>
​
    </dependencies></project>

入门

关键网址: mybatis中文网

配置文件

  • 在resources的目录下创建SqlMapperConfig.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>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>  <!-- 驱动 -->
        <property name="url" value="${url}"/>       <!-- 数据库信息 -->
        <property name="username" value="${username}"/> <!-- 用户名 -->
        <property name="password" value="${password}"/><!-- 密码 -->
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>  <!-- 映射的文件,这个之后都不是手动添加,这里一定记得改,而且是 / -->
  </mappers>
</configuration>

数据库准备

现有数据库表 Teacher: id name(数据库方面不会的话可以去看mysql的教程)

创建pojo

package com.duncan.pojo;
​
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
​
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
    private Integer id;
    private String name;
}

创建查询xml

目录:

image-20220811232539325.png

上面的目录,最好逐级创建,不要直接 com.duncan.mapper到底

xml内容:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="aaa">
    <select id="selectTeacher" resultType="com.duncan.pojo.Teacher">
        select `id`,`name` from teacher
    </select>
</mapper>

测试查询

利用junit测试类,和sqlsession进行测试(以后不用手动写sqlsession)

  • 编写测试类
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
​
public class MybatisTestDemo1 {
​
    @Before
    public void init() {
        // 获取sql_session
    }
​
    @Test
    public void selectTeacher() {
        // 具体逻辑
    }
​
    @After
    public void release() {
        // 释放
    }
}
  • 编写测试代码
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
​
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
​
public class MybatisTestDemo1 {
​
    private SqlSession session = null;
    @Before
    public void init() throws IOException {
        // 获取sql_session
        // 创建一个工厂
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        InputStream inputStream = null;
        inputStream = Resources.getResourceAsStream("SqlMapperConfig.xml"); //  加载配置文件 // 需要抛出异常
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); // 流加载,将配置加载
        session = sqlSessionFactory.openSession();
​
    }
​
    @Test
    public void selectTeacher() {
        // 具体逻辑
        List<Teacher> list = session.selectList("selectTeacher"); // 配置文件中的id
        for(Teacher l : list) {
            System.out.println(l.getId() + ": " + l.getName());
        }
    }
​
    @After
    public void release() {
        // 释放
        session.close();
    }
}

测试结果:

image-20220811234420929.png

日志

日志配置-log4j

1.log4j1

maven的配置文件

<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
  • 在resources的目录下配置log4j.properties(必须这么命名)
# 日志的级别 error,warn,info,debug
log4j.rootLogger=debug,stdout
​
#log4j.rootLogger=debug,logfile  日志输出到文件
​
​
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout
​
​
​
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=/duncan/mybatis.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd   HH:mm:ss} %l %F %p %m%n
​
  • 测试结果(红色的就是日志的输出)

image-20220814223559320.png

2.log4j2

maven的配置文件

<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-core</artifactId>
  <version>2.17.1</version>
</dependency>
  • 在resources的目录下配置log4j2.xml
<?xml version="1.0" encoding="UTF-8" ?>
<configuration status="debug" monitorInterval="5">
    <properties>
        <property name="LOG_HOME">/duncan</property>
    </properties>
​
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] [%-5level] %c{36}:%L --- %m%n" />
        </Console><!--        <File name="file" fileName="${LOG_HOME}/myfile.log">-->
<!--            <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %m%n" />-->
<!--        </File>--><!--        <RandomAccessFile name="accessFile" fileName="${LOG_HOME}/myAcclog.log">-->
<!--            <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %m%n" />-->
<!--        </RandomAccessFile>--><!--        <RollingFile name="rollingFile" fileName="${LOG_HOME}/myrollog.log"-->
<!--                     filePattern="E:/logs/$${date:yyyy-MM-dd}/myrollog-%d{yyyy-MM-dd-HH-mm}-%i.log">-->
<!--            <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY" />-->
<!--            <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %msg%n" />-->
<!--            <Policies>-->
<!--                <OnStartupTriggeringPolicy />-->
<!--                <SizeBasedTriggeringPolicy size="10 MB" />-->
<!--                <TimeBasedTriggeringPolicy />-->
<!--            </Policies>-->
<!--            <DefaultRolloverStrategy max="30" />-->
<!--        </RollingFile>-->
​
    </Appenders>
​
    <Loggers>
        <Root level="debug">
            <AppenderRef ref="Console" />
            <!--  这边可以修改输出的类型选择          -->
        </Root>
    </Loggers>
</configuration>
  • 测试结果

image-20220814224938872.png

制定日志类型

  • 在SqlMapperConfig.xml中设置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
   <!-- 添加下面的 -->
    <settings>
        <setting name="logImpl" value="LOG4J2"/>
    </settings>
  <!-- =============== -->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:8889/health?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/duncan/mapper/TeacherMapper.xml"/>
    </mappers>
</configuration>

事务的配置

<!-- 这个type的类型还包括 JDBC -->
<transactionManager type="MANAGED">  
  <property name="closeConnection" value="false"/>
</transactionManager>

类型别名的配置

<typeAliases>
  <typeAlias alias="teacher" type="com.duncan.pojo.Teacher"/>
  <typeAlias alias="blog" type="com.duncan.pojo.Blog"/>
</typeAliases>

如果实体的类特别多可以用 的标签

<typeAliases>
  <package name="com.duncan.pojo"/>  
</typeAliases>

外部链接配置

为了对某些配置解偶,增强模块的内聚性: 例如springboot中我们直接在yml配置数据库的信息

  • 已数据库链接为例:在resources目录下创建 jdbc.properties
mysql_driver=com.mysql.jdbc.Driver
mysql_url=jdbc:mysql://localhost:8889/health?useSSL=false&useUnicode=true&characterEncoding=UTF-8
mysql_username=root
mysql_password=root
  • 在SqlMapperConfig.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>
  <!-- 加的这个 也可以在这边直接定义,但是就没有解偶,所以不建议 -->
    <properties resource="jdbc.properties"/>
    <settings>
        <setting name="logImpl" value="LOG4J"/>
    </settings>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${mysql_driver}"/>  
                <property name="url" value="${mysql_url}"/>
                <property name="username" value="${mysql_username}"/>
                <property name="password" value="${mysql_password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/duncan/mapper/TeacherMapper.xml"/>
    </mappers>
</configuration>

普通模式

查询,有参,无参

这个部分结果图就不贴了,可以自行测试

xml的配置,resultType: 定义返回的类型,parameterType: 定义传入的参数,多个参数可以用map和对象的方式

<select id="selectTeacher" resultType="Teacher">
    select `id`,`name` from teacher
</select>
​
<select id="selectTeacherToMap" resultType="map">
    select `id`,`name` from teacher
</select>
​
<select id="selectOneTeacher" resultType="Teacher">
    select `id`,`name` from teacher LIMIT 1
</select>
​
<select id="selectOneTeacherById" resultType="Teacher" parameterType="Long">
    select `id`,`name` from teacher where id = #{id}
</select>
​
<select id="selectOneTeacherByMapId" resultType="Teacher" parameterType="map">
    select `id`,`name` from teacher where id = #{id}
</select>
​
<select id="selectOneTeacherByObjectId" resultType="Teacher" parameterType="Teacher">
    select `id`,`name` from teacher where id = ${id}
</select>

测试代码(接着之前的sqlsession写的)

 @Test
    public void selectTeacher() {
        // 具体逻辑
        List<Teacher> list = session.selectList("selectTeacher"); // 配置文件中的id
        for(Teacher l : list) {
            System.out.println(l.getId() + ": " + l.getName());
        }
    }
​
    @Test
    public void selectOneTeacher() {
        Teacher teacher = session.selectOne("selectOneTeacher");
        System.out.println("selectOneTeacher --> " + teacher.getName());
    }
​
    @Test
    public void selectTeacherToMap() {
        Map<Long, Teacher> map = session.selectMap("selectTeacherToMap", "id");
        Iterator<Map.Entry<Long, Teacher>> iterator = map.entrySet().iterator();
        System.out.println();
        while (iterator.hasNext()) {
            Map.Entry<Long, Teacher> m = iterator.next();
            System.out.println(m.getKey() + ": " + m.getValue());
        }
​
//        Set<Map.Entry<Long, Teacher>> entrySet = map.entrySet();
//        for(Map.Entry<Long, Teacher> entry : entrySet) {
//            System.out.println(entry.getKey() + ": " + entry.getValue());
//        }
//
//        /**
//         * 这种形式有些版本不支持
//         */
//        map.forEach((key, value) -> {
//            System.out.println(key + ":" + value);
//        });
    }
​
    @Test
    public void selectOneTeacherById() {
        Teacher t = session.selectOne("selectOneTeacherById", (long)9);
        System.out.println("selectOneTeacherById: " + t);
    }
​
    @Test
    public void selectOneTeacherByMapId() {
        Map<String, Long> map = new HashMap();
        map.put("id", (long)9);
        Teacher t = session.selectOne("selectOneTeacherByMapId", map);
        System.out.println("selectOneTeacherByMapId: " + t);
    }
​
    @Test
    public void selectOneTeacherByObjectId() {
        Teacher param = new Teacher();
        param.setId(9l);
        Teacher t = session.selectOne("selectOneTeacherByObjectId", param);
        System.out.println("selectOneTeacherByObjectId: " + t);
    }

插入,删除,更新

xml的配置,增删改,返回值都是int

<!--   插入数据 -->
    <insert id="addTeacher" parameterType="teacher">
        insert into teacher (`id`, `name`) values(#{id}, #{name})
    </insert>
​
    <!--  更新数据  -->
    <update id="updateTeacher" parameterType="teacher">
        update teacher set `name`=#{name} where `id`=#{id}
    </update>
​
    <!--   删除数据 -->
    <delete id="deleteTeacher" parameterType="long">
        delete from teacher where id=#{id}
    </delete>

Java测试代码

@Test
public void addTeacher() {
  Teacher teacher = new Teacher(null, "test");
  int rows = session.insert("addTeacher", teacher);
  System.out.println(rows);
  // 这边mybatis默认不是自动提交的,如果需要自动提交,session = sqlSessionFactory.openSession(true); 初始化的时候加 true
  session.commit();
}
​
@Test
public void updateTeacher() {
  Teacher teacher = new Teacher(11l, "test_update");
  int rows = session.update("updateTeacher", teacher);
  System.out.println(rows);
  // 这边mybatis默认不是自动提交的,如果需要自动提交,session = sqlSessionFactory.openSession(true); 初始化的时候加 true
  session.commit();
}
​
@Test
public void delTeacher() {
  int rows = session.delete("deleteTeacher", 11l);
  System.out.println(rows);
  // 这边mybatis默认不是自动提交的,如果需要自动提交,session = sqlSessionFactory.openSession(true); 初始化的时候加 true
  session.commit();
}

代理模式开发

为了进一步的解偶,减少sqlsession的使用,不用区使用sqlsession.update,selectOne,insert等,这边使用接口去代替,用代理模式,如果你有一些反射的基础,将更好的理解这个开发,而且这个模式更加符合我们现在常用的的开发模式,后面还会进一步的解偶

  1. 创建接口文件

image-20220816142920087.png

2.接口文件的代码

package com.duncan.mapper;
import com.duncan.pojo.Teacher;
import java.util.List;
public interface TeacherMapper {
    // 这个方法名字必须和底下的那个id名字一致,因为反射通过这个id去获取方法
    // package 和 底下的namespace必须保持一致
    public List<Teacher> selectTeacher();
}
​
​

3.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.duncan.mapper.TeacherMapper">
    <select id="selectTeacher" resultType="Teacher">
        select `id`,`name` from teacher
    </select>
</mapper>
  1. 编写测试代码使用
@Test
public void getTeachers() {
  TeacherMapper mapper = session.getMapper(TeacherMapper.class); // 这边代理会去自动实现这个接口
  List<Teacher> ts = mapper.selectTeacher();  // 直接使用我们定义好的方法就行,就不需要去sqlsession.select/update...
  ts.forEach(System.out::println);
}
  1. 测试的结果

image-20220816143754382.png

这边其实主要是文件的一致性弄对就可以了

查询的参数传递

  • 通过arg*获取

xml的代码

<!-- 0,1代表的是索引值 --> 
<select id="getTeacherByArgs" resultType="Teacher">
    select `id`,`name` from teacher where `id`=#{arg0} AND `name`=#{arg1} 
</select>

java的代码

public Teacher getTeacherByArgs(long id,String name);

测试代码

@Test
public void getTeacher() {
  TeacherMapper mapper = session.getMapper(TeacherMapper.class); // 自己会去实现这个接口
  Teacher ts = mapper.getTeacherByArgs(9l, "sun");
  System.out.println(ts);
}
  • 通过param*获取

xml的代码

<select id="getTeacherByParam" resultType="Teacher">
     select `id`,`name` from teacher where `id`=#{param1} AND `name`=#{param2}
 </select>

java的代码

public Teacher getTeacherByParam(long id,String name);

测试代码

public void getTeacher() {
  TeacherMapper mapper = session.getMapper(TeacherMapper.class); // 自己会去实现这个接口
  Teacher ts = mapper.getTeacherByParam(9l, "sun");
  System.out.println(ts);
}
  • 通过@param别名获取

xml代码

<select id="getTeacherByParams" resultType="Teacher">
        select `id`,`name` from teacher where `id`=#{id} AND `name`=#{name}
</select>

java代码

public Teacher getTeacherByParams(@Param("id") long id, @Param("name") String name);
​

测试代码

 @Test
public void getTeacher() {
  TeacherMapper mapper = session.getMapper(TeacherMapper.class); // 自己会去实现这个接口
  Teacher ts = mapper.getTeacherByParams(9l, "sun");
  System.out.println(ts);
}

以上就是三种传值的方式,如果是对象,object.property 这种方式获取

需要回传自增的id

xml的配置

<insert id="addTeacherHasId" keyProperty="id" useGeneratedKeys="true">
    insert into teacher (`name`) values (#{name})
</insert>

动态sql

IF

主要是不确定查询条件是有的时候

<select id="getDairys" resultType="dairy">
        select `id`,`text`,`sleephour`,`mood`,`cigarette`, `weight`,`pressure`,`bphigh`,`bplow`,`bs`,`teacher_id` from `dairy`
        where 1 = 1
        <if test="id != null">
            and `id`=#{id}
        </if>
        <if test="mood != null and mood != ''">
            and `mood`=#{mood}
        </if>
        <if test="pressure != null">
            and `pressure` like concat('%', #{pressure}, '%')
        </if>
</select>

where/when

  • where标签主要是为了减少1=1的操作,如果只有一个查询条件会自动把and去掉

xml的使用,和上面的结果一样

<select id="getDairys1" resultType="dairy">
        select `id`,`text`,`sleephour`,`mood`,`cigarette`, `weight`,`pressure`,`bphigh`,`bplow`,`bs`,`teacher_id` from `dairy`
        <where>
            <if test="id != null">
                and `id`=#{id}
            </if>
            <if test="mood != null and mood != ''">
                and `mood`=#{mood}
            </if>
            <if test="pressure != null">
                and `pressure` like concat('%', #{pressure}, '%')
            </if>
        </where>
    </select>
  • when标签,这个一般配合着choose这个标签一起用,其实可以理解为switch case,不过需要注意的是,它只会满足一个条件,就会直接break
<select id="getDairys2" resultType="dairy">
        select `id`,`text`,`sleephour`,`mood`,`cigarette`, `weight`,`pressure`,`bphigh`,`bplow`,`bs`,`teacher_id` from `dairy`
        <where>
            <choose>
                <when test="id != null">
                    and `id`=#{id}
                </when>
                <when test="mood != null and mood != ''">
                    and `mood`=#{mood}
                </when>
                <when test="pressure != null">
                    and `pressure` like concat('%', #{pressure}, '%')
                </when>
            </choose>
        </where>
    </select>

set

  • 这个set标签主要是用于数据更新的时候用法类似于where主要是用于自己不知道需要更新啥的做一个统一的配置

具体的配置问津啊

<update id="updateByset" parameterType="dairy">
  update `dairy`
  <set>
    <if test="mood != null and mood != ''">
      ,`mood`=#{mood}
    </if>
    <if test="pressure != null">
      ,`pressure`=#{pressure}
    </if>
  </set>
  where id=#{id}
</update>

trim

  • 这个标签其实是可以进行整个拼接字符串的前缀后缀的替换,比如可以替换set
<!-- 语法 -->
<trim prefix="" prefixOverrides="" suffix="" suffixOverrides></trim><update id="updateByTrim" parameterType="dairy">
        update `dairy`
        <trim prefix="set" prefixOverrides=",">
            <if test="mood != null and mood != ''">
                ,`mood`=#{mood}
            </if>
            <if test="pressure != null">
                ,`pressure`=#{pressure}
            </if>
        </trim>
        where id=#{id}
</update>

sql片段

  • 秉持着多次使用就封装的原则/提取原则这边可以将常用的sql语句进行提取

xml的例子

<!-- 定义 -->
<sql id="columnDairy">`id`,`text`,`sleephour`,`mood`,`cigarette`, `weight`,`pressure`,`bphigh`,`bplow`,`bs`,`teacher_id`</sql>
​
​
<!-- 使用 <include refid=""></include> -->
<select id="getDairys2" resultType="dairy">
  select <include refid="columnDairy"></include> from `dairy`
  <where>
    <choose>
      <when test="id != null">
        and `id`=#{id}
      </when>
      <when test="mood != null and mood != ''">
        and `mood`=#{mood}
      </when>
      <when test="pressure != null">
        and `pressure` like concat('%', #{pressure}, '%')
      </when>
    </choose>
  </where>
</select>

foreach

  • 这个标签一般用于in语句中,可以支持array,list

具体的语法

<select id="selectDairyByForeach">
  <!-- 类似于 select ... from dairy where `id` in (1,2,3) -->
  select <include refid="columnDairy"></include> from `dairy` WHERE `id` in
  <foreach collection="array" separator="," open="(" close=")" item="id">
    #{id}
  </foreach>
​
  <!-- collection 还可以等于 list -->
</select>

多表查询

手动映射

  • 如果实体类的属性值和那个mysql的字段值不一致,这个时候可以使用 resultMap做一个配置

具体语法

<resultMap id="dairyMap" type="dairy">
        <id column="id" property="id"></id>
        <result column="name" property="javaName"/>
</resultMap>
<select id="getDairyInfo" resultMap="dairyMap">
  select id,name from dairy
</select>

一对一

  • 这个是表示在java实体类中有另外的一个实体类怎么办,可以用association,进行关联
<resultMap id="dairyMap" type="dairy">
    <id column="id" property="id"></id>
    <result column="name" property="javaName"/>
    <association property="teacher" javaType="com.duncan.pojo.Teacher">
        <result column="tname" property="name"></result>
    </association>
</resultMap>
<select id="getDairyInfoJoinTeacher" resultMap="dairyMap">
    select a.id,a.`name`,b.`name` as `tname` from dairy a left join teacher b on a.teacher_id=b.id
</select>

Dairy的实体类修改

public class Dairy {
    private Long id;
    private String text;
    private Double sleephour;
    private String mood;
    private Integer cigarette;
    private Double weight;
    private String pressure;
    private Double bphigh;
    private Double bplow;
    private Double bs;
    private Long teacherId;
    //新增加属性
    private Teacher teacher;
}
### 一对多

在java中一对多怎么体现,多其实就是一个集合,所以说只要在实体里面加个集合就好,这边用classroom和teacher来表示,一个教室对应多个老师

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Classroom {
    private Long id;
    private String name;
    
    private List<Teacher> teachers;
}

那么在xml中如何表示呢?和之前的resultMap是一样的,这边用的标签用的是集合标签 collection,具体案例

<resultMap id="classroomTeacherMap" type="classroom">
        <id column="id" property="id"></id>
        <result column="name" property="name"/>
        <collection property="teachers" ofType="com.duncan.pojo.Teacher">
            <id column="t_id" property="id"/>
            <result column="tname" property="name"></result>
        </collection>
    </resultMap>
    <select id="classroomJoinTeacher" resultMap="classroomTeacherMap">
        select a.id,a.`name`,b.id as t_id ,b.`name` as `tname` from classroom a left join teacher b on b.class_id=a.id where a.id = 1
    </select>

结果

image-20220818100115510.png

多对多

其实多对多是一对一和一对多的集大成,只要记住 1对1 用的就是association,1对多就可以用collection(这里用的是ofType)

如果实在不知道的话,可以联系我

级联查询

这边其实完成的也是一个多表的查询,但是级联查询有个延迟加载,这个时候可以有效的减少一些资源的开销,主要的控制参数其实就是fetchType

<resultMap id="getTeachersByClassId" type="classroom">
        <id column="id" property="id"/>
        <result property="name" column="name"/>
        <!--
         select: 需要关联的数据库语言
         fetchType: 获取的方式
         jdbcType: 参数的类型
         column: 需要传的值,和上面的列想对应
         -->
        <collection property="teachers" select="com.duncan.mapper.TeacherMapper.getTeachersByClassId" fetchType="eager"
                    jdbcType="INTEGER"
                    javaType="list"
                    column="id"
        ></collection>
    </resultMap>
  • 延迟加载

这边需要fetchType要变为lazy,同时需要开启这个延迟加载,具体的xml的配置是

<resultMap id="getTeachersByClassId" type="classroom">
        <id column="id" property="id"/>
        <result property="name" column="name"/>
        <collection property="teachers" select="com.duncan.mapper.TeacherMapper.getTeachersByClassId" fetchType="lazy"
                    jdbcType="INTEGER"
                    javaType="list"
                    column="id"
        ></collection>
    </resultMap>

一级缓存

这个是默认开启的,其实这个和mysql底层默认的是一样的,假如两条sql语句是一模一样的,且没有被修改过row, 那么会直接用走缓存,增加效率,它是属于内存级的缓存。其中sqlsession和namespace是一致的

二级缓存

这个不是默认的缓存,不是默认开启的。这里的粒度只要namespace一致就行了,不过这个必须实例化

开启二级缓存

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

在mapper中要开启两个

<mapper namespace="com.duncan.mapper.ClassroomMapper">
    <cache/>  <!-- 这边一个 -->
    <select id="classroomJoinTeacher" resultMap="classroomTeacherMap" useCache="true"> <!-- 这边一个 -->
        select a.id,a.`name`,b.id as t_id ,b.`name` as `tname` from classroom a left join teacher b on b.class_id=a.id where a.id = 1
    </select>
</mapper>