mybatis 关联查询

关联查询

创立订单表和用户表:
订单表:
mybatis 关联查询
用户表:
mybatis 关联查询
一个用户可以有多个订单,一个订单对应一个用户,所以用户对订单是一对多关系,订单对用户是一对一关系。

一对一关系:
在数据库中的sql语句:
mybatis 关联查询
方式一:使用resultType实现

(a)改造POJO:目前已经拥有的实体,没有一个能够映射所有的字段,需要重新创建一个POJO类
创建一个类,继承字段多的POJO类
(b)OrdersMapper接口
(b)OrdersMapper.xml

方式二:使用resultMap实现

需求:根据用户id查询订单。
(a)改造POJO
mybatis 关联查询
定义Mapper接口:
mybatis 关联查询
Mapper.xml中配置:
mybatis 关联查询
结果:
mybatis 关联查询
总结:
实现一对一查询
ResultType:
使用resultType比较简单,如果没有对应POJO,就创建一个对应POJO即可。
如果,查询结果没有特殊性的要求,就建议使用ResultType
ResultMap:
需要单独定义ResultMap,实现有些麻烦,
如果 对查询的结果有特殊要求(指定结果)使用ResultMap,将关联查询的结果映射到POJO的属性中。

另外,ResultMap可以实现延迟加载,ResultType无法实现延迟加载。
延迟加载就是先执行一个statement,根据需要再去执行另一个statement,sql的实现多数是用子查询语句
使用标签中的 select 指定子statement, 使用column指定关联的列,用的是父statement中的列。

实现一对多关系:
一对多的关系,只能用ResultMap实现,无法使用resultType实现。

sql:
mybatis 关联查询
改造POJO:
mybatis 关联查询
Mapper接口:
mybatis 关联查询
Mapper.xml:
mybatis 关联查询
Mybatis使用resultMap的collection对关联插入的多条记录映射到一个List集合属性中。
使用ResultType也能实现,但是数据需要自己处理,并且使用双重循环遍历,合并记录。

多对多
多对多的关系,需要借助第三表来存储这个关系,无论是添加、还是删除、查询,本质都是对第三张表进行的操作。
商品和订单的关系
用户和角色的关系
用户和权限的关系

延迟加载
ResultMap可以实现高级映射(使用collection和association),collection和association具有延迟加载的功能。
需求:查询订单并且关联用户信息,如果先查询订单信息可以满足要求,当我们需要使用到 用户信息的时候,再去查询用户信息。把 用户信息 按需 查询就是延迟加载。
延迟加载:先从单表查询,需要的时候,再去关联的表查询,大大提升了数据库的性能,因为单表查询肯定比关联查询更快。

(a)修改配置:在config.xml中:
mybatis 关联查询
(b)mapper接口:
mybatis 关联查询

(c)mapper.xml:
mybatis 关联查询

查询缓存:

正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持
一级缓存是SQLSession级别的缓存,在操作数据库是需要构建SQLSession对象,在对象有有一个数据接口(hashMap)用于存储缓存数据,不同的SQLSession之间缓存数据区域(hashMap)是互补影响。
二级缓存是Mapper基本的缓存,多个SQLSession去操作同一个Mapper的SQL语句,多个SQLSession可以共用二级缓存,二级缓存是跨SQLSession的。。
  3. 对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。

一级缓存:
当第一次查询id为1的用户时,就会在sqlsession中记录该条数据。当第二次访问该对象是,只需要从缓存区域读取就行,不需要在访问数据库。如果执行了增,删,改的操作,那么就会清空缓存区。

实现:

读取两次同一个id的用户。
mybatis 关联查询
mybatis 关联查询
这里可以看出只运行了一次数据库。

当在两次查询中添加一次删除。
mybatis 关联查询
mybatis 关联查询
sql语句执行了三次。
过程:
第一次发起查询用户id为1的用户信息,先去找缓冲中是否有id为1的用户信息,如果没有,从数据库中查询用户,
得到用户信息,将用户信息存储到一级缓存中。
如果SQLSession执行了commit操作(插入、更新、删除),情况SQLSession中的一级缓存,这样做的目的:为了让缓存存储最新的数据,避免脏读。
第二次发起查询用户id为1的用户信息,先去找缓冲中是否有id为1的用户信息,直接从缓存中获取用户信息。

Mybatis 默认支持的是一级缓存,不需要进行配置。

二级缓存
Mybatis二级缓存细粒度的数据级别的缓存实现不好。比如,对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次查询都能查询到最新的商品信息,此时如果使用mybatis的二级缓存就无法实现当有一个商品变化时只刷新该商品的缓存,而不是全部商品信息。
因为mybatis的二级缓存区域以Mapper为单位划分的,当有一个商品信息变化,会将所有的商品信息的缓存全部清空。解决此类问题,在业务层根据需求对数据有针对性的缓存。

使用内存数据库来做缓存
Redis、memcache

Mybatis****

mybatis官方提供了一个****包,可以针对数据库表自动生成mybatis执行所需要的Pojo、Mapper xml文件、Mapper Interface接口文件。

****需要加载mysql-connector-java-5.1.38.jar包。
mybatis 关联查询
com文件夹是需要自动生成的。
generatorConfig.xml配置:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <!-- (1)配置mysql 驱动jar包路径.用了绝对路径 -->
    <classPathEntry location="C:\Users\zhuliyang\Desktop\mybatis\mysql-connector-java-5.1.38.jar" />
    <context id="scm_mysql_tables" targetRuntime="MyBatis3">
        <!-- 防止生成的代码中有很多注释,加入下面的配置控制 -->
        <commentGenerator>
            <property name="suppressAllComments" value="true" />
            <property name="suppressDate" value="true" />
        </commentGenerator>
        <!-- (2)数据库连接 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/mybatis01"
                        userId="root"
                        password="123">
        </jdbcConnection>
        <javaTypeResolver >
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>
        <!-- (3)数据表对应的model层  -->
        <javaModelGenerator targetPackage="com.hd.po"
                            targetProject="src/main/java">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true" />
        </javaModelGenerator>
        <!-- (4)sql mapper 映射配置文件 -->
        <sqlMapGenerator targetPackage="com.hd.mapper"
                         targetProject="src/main/java">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>
        <!-- (5)mybatis3中的mapper接口 -->
        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="com.hd.mapper"
                             targetProject="src/main/java">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>
        <!-- (5)数据表进行生成操作 schema:相当于库名; tableName:表名;
            domainObjectName:对应的DO
        -->
        <table schema="mybatis" tableName="user" domainObjectName="User"
               enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false">
        </table>
        <table schema="mybatis" tableName="orders" domainObjectName="Orders"
               enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false">
        </table>
    </context>
</generatorConfiguration>

pom.xml配置:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.34</version>
</dependency>