万字大章学习MyBatis

本文详细介绍了MyBatis的搭建流程,包括核心配置文件的设置、数据库环境配置、类型别名、动态SQL、查询策略(一对一、一对多、多对多)、分页查询以及缓存和延迟加载的实践。还涵盖了逆向工程的使用,帮助开发者快速生成Mapper和实体类。
摘要由CSDN通过智能技术生成

MyBatis

基于Java的数据持久层(ORM)框架。把实体类和SQL语句之间建立了映射关系,是一种半自动化的ORM实现。

(1)ORM对象关系映射,一种数据持久化技术。
		O:Object	对象===java中的实体类---对象
		R:Relation	关系===关系型数据库---表
		M:Mapping	映射===提供一种映射的机制
		
(2)半自动化:在映射过程中需要写一些SQL语句才能完成指定功能

搭建

  1. 创建Maven工程。

  2. 添加项目依赖。

<!--MyBatis项目依赖包-->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.6</version>
</dependency>
<!-- Mysql驱动包 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.16</version>
</dependency>
<!-- junit测试包 -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>
<!-- 日志包 -->
<dependency>
	<groupId>log4j</groupId>
	<artifactId>log4j</artifactId>
	<version>1.2.17</version>
</dependency>
  1. 创建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.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/ssm_db"/>
                <property name="username" value="root"/>
                <property name="password" value="rootstart"/>
            </dataSource>
        </environment>
    </environments>
  <!--加载mapper映射文件-->
    <mappers>
        <mapper resource="org/mybatis/example/BlogMapper.xml"/>
    </mappers>
</configuration>
  1. 创建实体类。

  2. 创建sql映射文件。

<?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.cwd.mybatisdemo.userDao">
    <select id="selectBlog" resultType="com.cwd.mybatisdemo.User">
        select *
        from Blog
        where id = #{id}
  </select>
</mapper>
  1. 测试。

核心配置文件

核心配置文件下载地址

<!ELEMENT configuration (properties?, settings?, typeAliases?, typeHandlers?, objectFactory?, objectWrapperFactory?, reflectorFactory?, plugins?, environments?, databaseIdProvider?, mappers?)>

核心配置文件sqlMapperConfig中的标签顺序应按照上面👆的顺序:properties—>mappers

数据库环境配置
<!--环境-->
    <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://127.0.0.1:3306/ssm_db"/>
                <property name="username" value="root"/>
                <property name="password" value="rootstart"/>
            </dataSource>
        </environment>
    </environments>
属性设置

1.在属性中配置对应的数据。

 <!--属性引用-->
    <properties>
        <property name="driver" value="com.mysql.jdbc.Driver"/>
    </properties>
    
<!--环境-->
    <environments default="development">
        <environment id="development">
          <!--事务管理-->
            <transactionManager type="JDBC"/>
          <!--数据源设置-->
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/ssm_db"/>
                <property name="username" value="root"/>
                <property name="password" value="rootstart"/>
            </dataSource>
        </environment>
    </environments>

2.提取属性到一个全新的文件(jdbc.properties)进行引用

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/ssm_db
username=root
password=rootstart
<configuration>
    <!--属性引用-->
    <properties resource="jdbc.properties">
      
    </properties>
  
  <!--环境-->
    <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>

</configuration>

3.赋默认值(以password为例)

<configuration>
    <!--属性引用-->
    <properties resource="jdbc.properties">
    		<!--开启默认值-->
        <property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/>
    </properties>


  <!--环境-->
    <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:rootstart}"/>
            </dataSource>
        </environment>
    </environments>
</configuration>
设置setting
<!--设置-->
    <settings>
        <!--开启log4j日志-->
        <setting name="logImpl" value="LOG4J"/>
        <!--开启二级缓存-->
        <setting name="cacheEnabled" value="true"/>
        <!--开启延迟加载/懒加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
    </settings>
类型别名

1.标签设置,依次设置

<typeAliases>
     <typeAlias type="com.cwd.mybatisdemo.User" alias="user"/>
</typeAliases>

2.直接设置一个包

<!--类型别名-->
<typeAliases>
		<package name="com.cwd.mybatisdemo"/>
</typeAliases>
其它配置项
  1. 类型处理器 typeHandlers
  2. 对象工厂 objectFactory
  3. 插件 plugins
  4. 映射器 mappers
<!--加载mapper映射文件-->
<mappers>
		<mapper resource="UserDao.xml"/>
</mappers>

逆向工程

​ Mybatis需要自己编写SQL,若是表太多的话难免会麻烦,所以官方提供了一种逆向工程,可以针对单个表自动生成Mybatis执行所需要的代码(包括Mapper.xml、mapper.java、pojo)。一搬我们在开发中常用的逆向工程是通过数据库的表生成代码。

创建逆向工程
  1. 新建一个maven工程。
  2. 添加依赖的jar包。
<!-- Mysql驱动包 -->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>8.0.16</version>
</dependency>

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

<!--代码生成工具-->
<!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-core -->
<dependency>
    <groupId>org.mybatis.generator</groupId>
    <artifactId>mybatis-generator-core</artifactId>
    <version>1.3.7</version>
</dependency>

  1. 添加配置文件generatorConfig.xml文件,用于设置数据库驱动,配置,包名,文件保存位置,表名等等。
  2. 定义GeneratorSqlmap类,调用MyBatis自动创建接口,在main方法执行自动创建。

使用为主!!!

使用逆向工程
  1. 添加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>
    <context id="testTables" targetRuntime="MyBatis3">
        <commentGenerator>
            <!-- 是否去除自动生成的注释 true:是 : false:否 -->
            <property name="suppressAllComments" value="true" />
        </commentGenerator>

        <!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/ssm_db"
                        userId="root"
                        password="rootstart">
        </jdbcConnection>

        <!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL
            和 NUMERIC 类型解析为java.math.BigDecimal -->
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>

        <!-- targetProject:生成PO类的位置
            注意:mac电脑写的地址是./src
                windows电脑写的是.\src
        -->
        <javaModelGenerator targetPackage="main.java.com.cwd.mybatisdemo"
                            targetProject="./src">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
            <!-- 从数据库返回的值被清理前后的空格 -->
            <property name="trimStrings" value="true" />
        </javaModelGenerator>

        <!-- targetProject:mapper映射文件生成的位置
            注意:mac电脑写的地址是./src
                windows电脑写的是.\src
        -->
        <sqlMapGenerator targetPackage="main.resources.mapper"
                         targetProject="./src">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
        </sqlMapGenerator>

        <!-- targetPackage:mapper接口生成的位置
            注意:mac电脑写的地址是./src
                windows电脑写的是.\src
        -->
        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="main.java.com.cwd.mybatisdemo" targetProject="./src">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
        </javaClientGenerator>

        <!-- 指定数据库表
            tableName   表名
            domainObjectName 生成实体类对应的名称
        -->
        <table tableName="t_role" domainObjectName="Role" enableCountByExample="false"
            enableUpdateByExample="false" enableDeleteByExample="false"
            enableSelectByExample="false" selectByPrimaryKeyQueryId="false"
        >
            <columnOverride column="id" javaType="Integer"/>
        </table>


    </context>
</generatorConfiguration>
  1. 运行逆向工程的服务程序
public class GeneratorSqlmap {
    public void generator() throws Exception {
        List<String> warnings = new ArrayList<>();
        boolean overwrite = true;

        //加载核心配置文件
        File configFile = new File("/Users/caiweidong/IdeaProjects/myCode/mybatisDemo/src/main/resources/generatorConfig.xml");
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(configFile);
        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        MyBatisGenerator mybatisGenerator = new MyBatisGenerator(config, callback, warnings);
        mybatisGenerator.generate(null);
    }

    //程序入口^o^
    public static void main(String[] args) throws Exception {
        GeneratorSqlmap generatorSqlmap = new GeneratorSqlmap();
        generatorSqlmap.generator();
    }
}

动态SQL

​ 动态SQL可以解决JDBC或其它类似框架根据不同条件拼接SQL语句时需要注意各种规则的问题,例如拼接时需要注意空格、去掉列表最后一个列名逗号等等这些问题。

MyBatis提供了各种标签对条件作出判断可以实现动态拼接SQL语句。

  1. if标签(实现查询)

​ if进行判断,test的内容是表达式,使用like进行模糊查询,%作为占位符, 进 行 拼 接 查 询 , c o n c a t ( ) 表 示 字 符 串 拼 接 , {}进行拼接查询,concat()表示字符串拼接, concat{}无法被识别为字符串,因此要加单引号,#{}可以被识别为字符串,无需加单引号。由于在mapper文件中<会被识别成一个标签的开始,因此我们的< <= 是没有办法直接写的,因此需要转译:<![CDATA[ < ]]>

select * from t_role where id > #{id}
	<if test="name != null">
      and name like "%${name}%"
  </if>
  
select * from t_role where id>#{id}
  <if test="name != null">
      and name like concat('%','${name}','%')
  </if>
  
select * from t_role where id<![CDATA[<]]>#{id}
  <if test="name != null">
      and name like concat('%',#{name},'%')
  </if>
  1. if-where标签(实现查询)

​ 当我们无法判断是否有条件时,使用where标签框架会自动判断我们是否需要where,如果所有条件都不满足就会查询出所有的记录,并且可以自动消除第一个and和or。

select * from t_role
 <where>
     <if test="id != null">
         and id<![CDATA[<]]>#{id}
     </if>
     <if test="name != null">
         and name like concat('%',#{name},'%')
     </if>
 </where>
  1. choose-when-otherwise标签(实现查询)

​ 当我们不想使用所有的条件,只是想从多个条件中选择一个使用时,我们可以选择choose标签,类似于switch语句。choose标签可以按照顺序判断when标签中的条件是否成立,有一个成立时choose就会结束。当when的所有条件都不满足时,会执行otherwise中的语句。类比switch语句,chooseswitch,whencase,otherwise==default。

select * from t_role where
<choose>
    <when test="id != null">
        id<![CDATA[<]]>#{id}
    </when>
    <when test="name != null">
        and name like concat('%',#{name},'%')
    </when>
    <otherwise>
        userid = #{userid}
    </otherwise>
</choose>
  1. trim-if标签(实现添加)

​ trim标签可以在在自己包含的内容前加上某些前缀,也可以在其后加上某些后缀,与之对应的属性是prefix和suffix。或将包含内容的首部(或尾部)某些内容覆盖,对应的属性是prefixOverrides和suffixOverrides。

/*insert into 表名(列名,列名,列名) values(值,值,值)*/
insert into t_role
<trim prefix="(" suffix=")" suffixOverrides=",">
    <if test="name != null">
        name,
    </if>
    <if test="userid != null">
        userid,
    </if>
    <if test="operTime != null">
        oper_time,
    </if>
</trim>
values
<trim prefix="(" suffix=")" suffixOverrides=",">
    <if test="name != null">
        #{name},
    </if>
    <if test="userid != null">
        #{userid},
    </if>
    <if test="operTime != null">
        #{operTime},
    </if>
</trim>
  1. set-if-where标签(实现修改)

set标签用在修改的操作,作用和where差不多,使用set标签可以在包含的语句前面输出一个set,若包含的语句以逗号结尾会将逗号省略

<update id="updateRole" parameterType="role">
    /*update t_role set 列1=值1,列2=值2 where 列1=值1 and 列2=值2*/
    update t_role
    <set>
        <if test="name != null">
            name = #{name},
        </if>
        <if test="userid != null">
            userid = #{userid},
        </if>
        <if test="operTime != null">
            oper_time = #{operTime},
        </if>
    </set>
    <where>
        <if test="id != null">
            and id = #{id}
        </if>
        <if test="id == null">
            and id = -1
        </if>
    </where>
</update>
  1. foreach标签-构建in条件

    foreach标签用于构建in条件,在SQL语句中进行迭代一个集合。

    foreach标签的属性主要有:

属性作用
item表示迭代集合中每一个元素的别名。
index指定一个名字表示在迭代过程中每次迭代到的位置。
open表示语句以什么开始。
separator表示每次迭代以什么符号作为分割符。
close表示语句以什么为结束。
collection单参且参数类型为List,属性为list;单参且类型为数组,属性为array;多参为Map。

实际如果在传入参数的时候,在MyBatis里面也会把他封装成一个Map的,Map的key就是参数名,所以在这个时候collection属性值就是传入的List或Array对象在自己封装的Map里面的Key。

<!--第一种,直接使用foreach标签-->
<select id="selectRoleById" parameterType="java.util.List" resultType="com.cwd.mybatisSQL.bean.Role">
    select * from t_role
    <where>
        <foreach collection="list" open="(" close=")" item="roleId" separator="or">
            id = #{roleId}
        </foreach>
    </where>
</select>

<!--第二种,通过foreach标签构建in-->
<select id="selectRoleById" parameterType="java.util.List" resultType="com.cwd.mybatisSQL.bean.Role">
    select * from t_role where id in
        <foreach collection="list" open="(" close=")" item="roleId" separator=",">
            #{roleId}
        </foreach>
</select>

<!--第三种,集合类型为array-->
<select id="selectRoleById" parameterType="java.util.List" resultType="com.cwd.mybatisSQL.bean.Role">
    select * from t_role where id in
    <where>
        <foreach collection="array" open="(" close=")" item="roleId" separator=",">
            id = #{roleId}
        </foreach>
    </where>
</select>

<!--第四种,参数转换为Map集合,map的key为roleIds,一般有多条复杂查询时使用Map集合-->
<select id="selectRoleByMap" parameterType="java.util.Map" resultType="com.cwd.mybatisSQL.bean.Role">
    select * from t_role where id in
    <foreach collection="roleIds" open="(" close=")" item="roleId" separator=",">
        #{roleId}
    </foreach>
</select>

  1. SQL片段(重复利用相同的SQL片段)
<sql id = "sqlid">
    select * from t_role
</sql>

<select id="selectRoleById" parameterType="java.util.List" resultType="com.cwd.mybatisSQL.bean.Role">
     <include refid="sqlid"></include>
     where id in
        <foreach collection="list" open="(" close=")" item="roleId" separator="or">
            #{roleId}
        </foreach>
</select>

<select id="selectRoleByMap" parameterType="java.util.Map" resultType="com.cwd.mybatisSQL.bean.Role">
    <include refid="sqlid"></include>
    where id in
    <foreach collection="roleIds" open="(" close=")" item="roleId" separator=",">
        #{roleId}
    </foreach>
</select>
  1. bind标签

    允许在OGNL表达式外创建一个变量,并将其绑定在当前的上下文。

<!--以模糊查询为例-->
<select id="selectRoleByIdName" parameterType="role" resultType="role">
    <bind name="name" value=" '%'+name+'%' "/>
    select * from t_role
    <where>
        <if test="id != null">
            and id<![CDATA[<]]>#{id}
        </if>
        <if test="name != null">
            and name like #{name}
        </if>
    </where>
</select>

MyBatis查询

​ MyBatis进行select映射时,返回类型可以用resultType,也可以使用resultMap。resultType是直接表示返回类型的(即我们的model对象中的实体);而resultMap则是对外部ResultMap的引用(即提前定义了数据库和实体类之间的映射key-value关系),两者不能同时存在。

​ 在MyBatis中进行查询映射时,查询的每一个属性都是放在一个对应的Map中的,其中key是属性名,value是对应的值。(1)返回类型是resultType时,MyBatis会将Map里面的键值对取出来赋给resultType所指定的对象对应的属性。所以其实MyBatis的每一个查询映射的返回类型都是ResultMap,只是当提供的返回类型属性时resultType时,MyBatis会自动的把对应的质感赋给resultType所指定对象的属性;(2)当返回值类型是resultMap时,因为Map不能很好的表示领域模型,就需要自己再进一步的把它转化为对应的对象,这常常在复杂查询中很有作用。

一对一关联查询

查询所有员工信息及员工对应的部门信息。

  1. 使用resultType属性。

    (1)创建包含员工和部门信息的一个实体类。

    (2)创建实体类对应的mapper接口。

    (3)创建mapper.xml映射文件。

    (4)编写测试类。

    (5)存在问题:多创建了一组实体类及其对应的mapper文件。

  2. 使用resultMap属性。

    (1)分别创建员工和部门信息的实体类,在其中一个类中添加另一个类作为属性。

public class User {
    private Integer id;

    private String account;

    private String password;

    private Integer type;

    private String fileName;

    private Role role;
}


public class Role {
    private Integer id;

    private String name;

    private Integer userid;

    private Date operTime;
}

​ (2)创建对应的mapper接口。

​ (3)创建对应的Mapper.xml文件。

<resultMap id="userAndRole" type="user">
    <id column="u.id" property="id"/>
    <result column="u.account" property="account"/>
    <result column="u.password" property="password"/>
    <result column="u.type" property="type"/>
    <result column="u.file_name" property="fileName"/>
    <association property="role" javaType="role">
        <id column="r.id" property="id"/>
        <result column="r.name" property="name"/>
        <result column="r.userid" property="userid"/>
        <result column="r.oper_time" property="operTime"/>
    </association>
</resultMap>
<select id="selectAllUsers" resultMap="userAndRole">
 	sql语句
</select>
一对多关联查询

​ 使用resultMap。

public class User {
    private Integer id;

    private String account;

    private String password;

    private Integer type;

    private String fileName;

    private List<Role> roles;
}


public class Role {
    private Integer id;

    private String name;

    private Integer userid;

    private Date operTime;
}
<!--
​ 1.collection标签用于封装查询到的多条数据信息。

​ 2.collection标签中的property属性是java类中集合属性所对应的对象名。

​ 3.collection标签中的javaType属性是所用集合的类型,如list或者set等。

​ 4.collection标签中的ofType属性是集合封装的对象类型。
-->
<resultMap id="userAndRole" type="com.cwd.mybatisSelect.bean.User">
    <id column="uid" property="id"></id>
    <result column="uaccount" property="account"></result>
    <result column="upassword" property="password"></result>
    <result column="utype" property="type"></result>
    <result column="ufilename" property="fileName"></result>
  
    <collection property="roles" ofType="com.cwd.mybatisSelect.bean.Role" javaType="list">
        <id column="rid" property="id"></id>
        <result column="rname" property="name"></result>
        <result column="ruserid" property="userid"></result>
        <result column="ropertime" property="operTime"></result>
    </collection>
</resultMap>

<select id="selectUserAndRole" resultMap="userAndRole" parameterType="integer">
    SELECT
        u.id as uid,
        u.account as uaccount,
        u.PASSWORD as upassword,
        u.type as utype,
        u.file_name as ufilename,
        r.id as rid,
        r.NAME as rname,
        r.userid as ruserid,
        r.oper_time as ropertime
    FROM
        t_user AS u
            INNER JOIN user_role AS ur ON u.id = ur.userid
            INNER JOIN t_role AS r ON ur.roleid = r.id
    WHERE
        u.id = #{userId}
</select>
多对多关联查询

​ 准备表

--用户表
CREATE table users(
 uid int(4) not null,
 uname VARCHAR(20) DEFAULT null,
 sex VARCHAR(3) DEFAULT null,
 birthday date default null,
 address VARCHAR(100) default null,
 PRIMARY Key(uid)
)

--订单表
create table orders(
	oid int(4) not null,
	userid int(4) default null,
	orderid VARCHAR(20) DEFAULT null,
	createtime date default null,
	status varchar(10) default null,
	primary key(oid)
)

--订单详情表
create table orderdetail(
	odid int(4) not null PRIMARY key,
	orderid VARCHAR(20) DEFAULT null,
	itemid int(4) DEFAULT null,
	itemnum int(4) DEFAULT null
)

--商品表
CREATE TABLE items(
	iid int(4) not null,
	name VARCHAR(30) DEFAULT NULL,
	detail VARCHAR(50) DEFAULT NULL,
	price DOUBLE(5,2) DEFAULT NULL,
	PRIMARY KEY(iid)
)

​ 问题:获得所有用户的所有订单里的所有商品信息!

​ (1)创建四张表对应的四个实体类。

​ (2)创建对应的mapper接口。

​ (3)创建对应的mapper.xml文件。

<!--resultMap嵌套-->
<resultMap id="infoAll" type="users">
    <id column="uid" property="uid"/>
    <result column="uname" property="uname"/>
    <result column="sex" property="sex"/>
    <result column="birthday" property="birthday"/>
    <result column="address" property="address"/>
    <collection property="orders" ofType="orders" javaType="list">
        <id column="oid" property="oid"/>
        <result column="orderid" property="orderid"/>
        <result column="createtime" property="createtime"/>
        <result column="status" property="status"/>
        <collection property="ods" ofType="orderDetail" javaType="list">
            <id column="odid" property="odid"/>
            <result column="itemnum" property="itemnum"/>
            <association property="items" javaType="items">
                <id column="iid" property="iid"/>
                <result column="name" property="name"/>
                <result column="detail" property="detail"/>
                <result column="price" property="price"/>
            </association>
        </collection>
    </collection>
</resultMap>

<select id="selectInfoById" parameterType="int" resultMap="infoAll">
    SELECT
        u.uid,
        u.uname,
        u.sex,
        u.birthday,
        u.address,
        o.oid,
        o.orderid,
        o.createtime,
        o.STATUS,
        od.odid,
        od.itemnum,
        i.iid,
        i.NAME,
        i.detail,
        i.price
    FROM
        users AS u
            INNER JOIN orders AS o ON u.uid = o.userid
            INNER JOIN orderdetail AS od ON o.orderid = od.orderid
            INNER JOIN items AS i ON od.itemid = i.iid
    WHERE
        u.uid = #{uid}
</select>
分页查询
方案一:使用Page工具类
  1. 创建util工具类page
public class Page<T> {
    //获得表里一共有多少条数据
    private Integer dataCount;

    //每页显示多少条数据
    private Integer showData;

    //一共分成多少页
    private Integer pageCount;

    //当前是第几页
    private Integer pageIndex;

    //当前页面显示的集合信息
    private List<T> list;

    public Integer getDataCount() {
        return dataCount;
    }

    public void setDataCount(Integer dataCount) {
        this.dataCount = dataCount;
    }

    public Integer getShowData() {
        return showData;
    }

    public void setShowData(Integer showData) {
        this.showData = showData;
    }

    public Integer getPageCount() {
        //数据库的总条数如果能除尽每页显示的条数就直接赋值,若不能则除数取整+1
        return this.pageCount = this.dataCount%this.showData==0 ? this.dataCount/this.showData:this.dataCount/this.showData+1;
    }

    public Integer getPageIndex() {
        return pageIndex;
    }

    public void setPageIndex(Integer pageIndex) {
        this.pageIndex = pageIndex;
    }

    public List<T> getList() {
        return list;
    }

    public void setList(List<T> list) {
        this.list = list;
    }
}
  1. 创建接口方法,获取数据库总条数和第x列的数据集合
//分页获得一共有多少条数据
int selectCount() throws Exception;

//获得当前页显示的集合信息
List<Users> selectUsersByPage(Page<Users> page) throws Exception;
  1. 创建两个方法对应的xml文件
<!--用于分页,一共有多少条数据-->
<select id="selectCount" resultType="java.lang.Integer">
    select count(uid) from users;
</select>

<!--用于分页,获得当前页显示的集合信息-->
<select id="selectUsersByPage" parameterType="com.cwd.mybatisSelect.util.Page" resultType="com.cwd.mybatisSelect.bean.Users">
    <bind name="beginIndex" value="(pageIndex-1)*showData+1"/>
    select * from users order by uid limit #{beginIndex},#{showData}
</select>
  1. 调用方法进行使用
public class test {

    private SqlSessionFactory factory;

    @Before
    public void init() throws IOException {
        InputStream res = Resources.getResourceAsStream("sqlMapperConfig.xml");
        SqlSessionFactoryBuilder fac = new SqlSessionFactoryBuilder();
        factory = fac.build(res);
    }

    @Test
    public  void test2() throws Exception {
        SqlSession sqlSession = factory.openSession();
        UsersMapper mapper = sqlSession.getMapper(UsersMapper.class);
        Page<Users> page = new Page<>();
        //一共有多少条数据
        int dataCount = mapper.selectCount();
        System.out.println(dataCount);
        page.setDataCount(dataCount);
        page.setShowData(2);
        page.setPageIndex(1);
        //获取对应页的数据集合
        List<Users> users = mapper.selectUsersByPage(page);
        System.out.println(users);
        page.setList(users);
        sqlSession.close();
        for (Users user : page.getList()) {
            System.out.println(users);
        }
    }
}
方案二:使用RowBounds插件
  1. 创建实体类.
  2. 创建接口,参数使用RowBounds
//RowBounds插件,分页插件
List<Items> selectItems(RowBounds rb) throws Exception;
  1. 创建对应的xml文件
<select id="selectItems" resultType="com.cwd.mybatisSelect.bean.Items">
    select * from items;
</select>
  1. 测试使用
@Test
public  void test3() throws Exception {
    SqlSession sqlSession = factory.openSession();
    UsersMapper mapper = sqlSession.getMapper(UsersMapper.class);
    //new RowBounds(从第几个下标开始查,查多少条数据);
    RowBounds rb = new RowBounds(3,2);
    List<Items> items = mapper.selectItems(rb);
    sqlSession.close();
    System.out.println(items);
}

延迟加载(Lazy Load)

​ 在数据与对象进行mapping映射操作是,只有在真正使用到该对象时,才进行mapping操作,这样可以减少数据库查询的开销,提升系统的性能。但是Lazy Load也是有缺点的,在按需加载时会多次连接数据库,会增加数据库的压力,所以我们需要在现实中斟酌使用。resultMap可以实现高级映射,association、collection都具备延迟加载的功能。

延迟加载配置
  1. myBatis默认没有开启延迟加载,需要在MyBatis的核心配置文件中的setting进行配置。
<settings>
    <!--开启延迟加载/懒加载 默认为false-->
    <setting name="lazyLoadingEnabled" value="true"/>
</settings>
  1. aggressiveLazyLoading:value为true,延迟加载开启时,访问一个对象中的懒对象属性时,将完全加载这个对象的所有懒对象属性。value为false,延迟加载开启时,按需加载对象属性。
<settings>
    <!--开启延迟加载/懒加载-->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!--将积极加载改为消极加载 既按需加载-->
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>
实现延迟加载
  1. 准备实体类OrserDetail(订单详情)和Items(商品信息)。
public class OrderDetail {
    private Integer odid;

    private String orderid;

    //private Integer itemid;

    private Integer itemnum;

    private Items items;
}

public class Items {
    private Integer iid;

    private String name;

    private String detail;

    private Double price;
}
  1. 准备两个mapper接口
public interface OrderDetailMapper {

    OrderDetail selectOrserDatailLazyLoad(int odid) throws Exception;
    
}


public interface ItemsMapper {

    Items selectItemsById(int id) throws Exception;

}
  1. 准备两个mapper映射文件
<!--OderDeatilmapper.xml文件-->
<resultMap id="OrderDetailItemLazyLoad" type="orderDetail">
    <id column="odid" property="odid"/>
    <result column="orderid" property="orderid"/>
    <result column="itemnum" property="itemnum"/>
    <association property="items" javaType="items" 
                 select="com.cwd.mybatisSelect.dao.ItemsMapper.selectItemsById" 
                 column="itemid"/>
</resultMap>

<select id="selectOrserDatailLazyLoad" resultMap="OrderDetailItemLazyLoad">
    select * from orderdetail where odid = #{odid}
</select>


<!--ItemsMapper.xml文件-->
<select id="selectItemsById" parameterType="int" resultType="items">
    select * from items where iid = #{iid}
</select>
  1. 测试代码
@Test
public  void test4() throws Exception {
    SqlSession sqlSession = factory.openSession();
    OrderDetailMapper orderDetailMapper = sqlSession.getMapper(OrderDetailMapper.class);
    ItemsMapper itemsMapper = sqlSession.getMapper(ItemsMapper.class);
    OrderDetail orderDetail = orderDetailMapper.selectOrserDatailLazyLoad(2);
    sqlSession.close();
    System.out.println(orderDetail.getOrderid());
    System.out.println(orderDetail.getItems());
}

MyBatis查询缓存

​ 缓存是用“空间换时间”的设计理念,利用内存空间的资源来提高检索速度的手段之一。MyBatis包含一个非常强大的查询缓存特性,可以方便的进行配置和定制,它提供了一级缓存和二级缓存。一级缓存基于PerpetualCache的HashMap本地缓存,存储的作用域是Session,当Session被flush或close后,该Session中的所有Cache就将被清空;

二级缓存与一级缓存的机制类似,默认使用PerpetualCahce(长期缓存),hashMap存储,但它的作用域为Mapper,可以自定义存储源(Ehcache、hazelcast等)。

一级缓存

​ MyBatis默认开启一级缓存,不需要进行配置,同一个SqlSession对象中,第二次进行相同的查询时,直接获取到缓存数据,不需要去执行sql再到数据库中纪念性查询。

同一个session:
获得session对象(开始)
--->
session.commit() 或 session.close() 或 session.flush()
--->
结束
二级缓存

​ MyBatis的二级缓存是Mapper范围级别,需要在MyBatis的全局配置文件中设置二级缓存的开关,还需要在具体的mapper.xml中开启二级缓存。

  1. 添加二级缓存的相关jar包依赖
<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.0.2</version>
</dependency>

<!-- https://mvnrepository.com/artifact/net.sf.ehcache/ehcache -->
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>2.10.1</version>
</dependency>
  1. 在Mybatis全局配置文件中手动开启配置文件
<settings>
    <!--开启二级缓存-->
    <setting name="cacheEnabled" value="true"/>
</settings>
  1. 在各自的sql映射文件中单独开启二级缓存
<cache></cache>
  1. 实体类进行序列化
public class Items  implements Serializable {

5.测试

@Test
public  void test5() throws Exception {
    SqlSession sqlSession = factory.openSession();
    ItemsMapper itemsMapper = sqlSession.getMapper(ItemsMapper.class);
    Items items = itemsMapper.selectItemsById(1);
    System.out.println("第一个SqlSession的商品信息:"+items);
    sqlSession.close();

    SqlSession sqlSession1 = factory.openSession();
    ItemsMapper itemsMapper1 = sqlSession1.getMapper(ItemsMapper.class);
    Items items1 = itemsMapper1.selectItemsById(1);
    System.out.println("第二个SqlSession的商品信息:"+items1);
    sqlSession1.close();

}
二级缓存补充
  1. 禁用二级缓存

    可以在sql语句所在标签使用属性useCache = “false” 用来禁用二级缓存

<select id="selectItemsById" parameterType="int" resultType="items" useCache="false">
  1. 刷新缓存

​ 在同一个mapper作用域中, 如果有其他的DML(增删改)SQL语句时, 需要刷新缓存数据, 避免脏读, 默认情况下flushCache=“true” 会刷新缓存: 改为false则不会刷新

<update id="updateInfoByid" parameterType="int" flushCache="false">
    执行SQl后不刷新缓存
</update>
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值