Mybatis

目录

Mybatis基础

 SqlMapConfig.xml 主配置 

dao接口

dao接口映射(XML)

使用mybatis执行数据方法层方法获取结果:

ognl表达式

resultType输出参数

resultMap输出参数

parameterType输入参数

java简单类型

pojo包装类型

对数据库的增删改

添加操作

修改操作

删除操作:

单表查询

模糊查询

特殊字符

SqlMapperconfig.xml配置文件详解

Properties标签

typeAliases标签

Mapper标签

Mybatis连接池与事务深入

Mybatis映射文件的SQL深入

标签

标签

标签

标签

标签

Mybatis的多表关联查询

一对一

一对多

多对多

用map做参数

总结

Mybatis延迟加载策略

配置延迟加载

开启延迟加载

Mybatis缓存

开启二级缓存的步骤:

Mybatis注解开发

@Insert

@Update

@Delete

@Select

@Param

一对一映射,以及延迟加载配置

一对多映射,以及延迟加载配置

对用注解实现映射的总结

用注解实现二级缓存


Mybatis基础

概述:

  1. mybatis早期版本叫做ibatis,目前代码托管在github。
  2. mybatis是对jdbc的封装,是一个持久层的框架。
  3. mybatis是通过xml或者注解进行配置,实现java对象与sql语句的对应关系。(映射)

 SqlMapConfig.xml 主配置 

在项目的位置:

xml主配置文件的内容:

  1. 数据库连接配置。
  2. 数据库连接池、事务管理。
  3. 加载接口的映射。

使用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配置环境数据库使用哪个连接-->
    <environments default="mysql">
        <!--配置具体连接到哪一个数据库-->
        <environment id="mysql">
            <!--transactionManager,配置事物控制类型为JDBC-->
            <transactionManager type="JDBC"></transactionManager>
            <!--配置数据库连接池
                        POOLED,mybatis内置的数据库连接池(推荐使用)
                        UNPOOLED,不使用连接池
                        JNDI,使用服务器tomcat容器的数据库连接池
            -->
            <dataSource type="POOLED">
                <!--mysql驱动类-->
                <property name="driver" value="com.mysql.jdbc.Driver"></property>
                <!--数据库连接字符串-->
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf8"></property>
                <!--username数据库用户名-->
                <property name="username" value="root"></property>
                <!--password数据库密码-->
                <property name="password" value="root"></property>
            </dataSource>
        </environment>

    </environments>

    <!--关联接口映射配置文件-->
    <mappers>
        <!--映射com/itheima/dao/IUserDao.xml接口实现配置文件-->
        <mapper resource="com/itheima/dao/IUserDao.xml"></mapper>
    </mappers>
</configuration>

dao接口

位置:

代码:

public interface IUserDao {
    List<User> findAll();
}

dao接口映射(XML)

配置文件名:

IUserDao.xml

  • 也可以叫做UserDaoMapper.xml

配置文件的作用:

  • myabits框架会根据这个映射文件对dao接口进行实现。所以这个配置文件相当于实现类。

映射文件位置:

1)创建在resource中,与java中的dao接口层级一样。

2)在resource创建多级目录的配置文件时,目录之前用 ,不能用 

配置文件的示例:

<?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名称空间,用于定义是哪个类的映射文件,这里需要写所映射接口的类全名-->
<mapper namespace="com.itheima.dao.IUserDao">
<select id="findAll" resultType="com.itheima.entity.User">
    select * from user
</select>
</mapper>

参数说明:

  • 标签类型写需要执行的操作。
  • namespace:对应java接口的全路径,用于指明实现具体那个接口。
  • id:用于指明实现哪个接口方法名字。
  • parameterType:用于指明方法的参数类型。
  • resultType:用于指明方法返回的类型

若类型是实体类,则写类全名。

  • 例:com.itheima.entity.User

使用mybatis执行数据方法层方法获取结果:

前提:

  1. 引入日志文件log4j.properties
  2. 引入log4j依赖

代码:

public class UserDaoTest {
    @Test
    public  void test1() throws IOException {
        //使用mybatis执行数据方法层方法获取结果
        //1.获取主配置文件的输入流(主配置配置会关联接口映射配置文件)
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //获取类路径下面的文件的输入流
        //2.创建数据库连接工厂构建类
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        //3.根据数据库连接工厂构建类创建数据库连接工厂
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
        //4.根据数据库连接工厂获取数据库连接SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //5.根据SqlSession对象获取IUserDao映射代理类对象(动态代理对象class com.sun.proxy.$Proxy4)
        IUserDao userDao = sqlSession.getMapper(IUserDao.class);
        //6.执行实现类方法(执行数据库查询操作)
        List<User> userList = userDao.findAll();
        userList.forEach(System.out::println);
        //关闭资源
        //查询可以不用提交事务
        sqlSession.commit();
        sqlSession.close();
        in.close();
    }
}

注意事项:

1)获取主配置文件的输入流有两种方法:

1)当导入的Resources是属于javax.annotation时:

  • inputStream in = Resources.class.getResourceAsStream("/sqlMapConfig.xml");

2)当导入的Resources是属于org.apache.ibatis.io时:(推荐)

  • inputStream in = Resources.getResourceAsStream("sqlMapConfig.xml");

2)手动提交和自动提交:

1)手动提交

  • 不需要任何设置,默认是手动提交。
  • 执行对数据库的操作后,需要:sqlSession.commit();

2)自动提交

  1. 执行对数据库的操作后,不需要:sqlSession.commit();
  2. 需要在设置自动提交,在创建session对象时设置参数。
  • Sqlsession sqlsession = sqlSessionFactory.openSession(true);
  • 参数是设置是否设置自动提交事务,如果不设置默认是false。

ognl表达式

格式:

  • #{对象的属性名}

作用:

  • 相当于sql语句的占位符。
  • 可以获取参数类型对象的数据,要求表达式里面的属性名与对象名必须完全一致。

作用范围:

在sql语句中。

  • 在非sql语句中,不需要写ognl表达式。

resultType输出参数

注意事项:

  • 若没有设置,默认返回影响的行数。

resultMap输出参数

出现问题:

  • 通过resultType作为输出参数,可以把查询的结果,自动封装为对象,但是有要求:数据库中的列名称,要与对象的属性一致。否则不能正确封装数据。

解决方案:

  • 使用resultMap:设置列与属性的映射关系,从而解决列与属性不一致时候不能正确封装数据的问题。

示例:

<resultMap id="userResultMap" type="com.itheima.entity.User">
    <!--建立对象的唯一标记与表的主键映射关系-->
    <id property="id" column="id_"></id>
    <!--建立对象的其他属性与表的非主键字段的映射关系-->
    <result property="username" column="username_"></result>
    <result property="birthday" column="birthday_"></result>
    <result property="sex" column="sex_"></result>
    <result property="address" column="address_"></result>
</resultMap>
<select id="findAll" resultMap="userResultMap">
    SELECT id id_,username username_,birthday birthday_,sex sex_,address address_ FROM USER
</select>

参数说明:

  • resultMap标签:建立列与属性的映射关系。
  • resultMap的id属性:需要与select中引用的resultMap名称一致。
  • type:设置要封装对象的类型。
  • id标签:数据库表主键字段的映射。
  • column:代表数据库表字段名称。
  • property:对象类型里面的属性值。

parameterType输入参数

java简单类型

  • 简单类型包括:基本类型,String类型,包装类型。

注意事项:

参数类型不区分大小写,且能写多种形式。

  • 例parameterType = "int",可以写成:
  • _int
  • integer
  • Integer
  • java.lang.Integer

注意:

  • 不可以写成:int_

pojo包装类型

概述:

  • 一个对象里面又包含了另外一个对象。

步骤:

  1. 新建一个对象:QueryVo,封装所有的查询条件。
  2. 接口方法中根据QueryVo作为输入参数查询。

示例:

<select id="findByCondition" parameterType="com.itheima.entity.QueryVo" resultType="com.itheima.entity.User">
    select * from user where username=#{user.username}
    and birthday>=#{start} and birthday &lt;= #{end}
</select>

对数据库的增删改

添加操作

参数的说明:

  • insert:执行的是插入操作。
  • id:接口中的方法名字。
  • resultType:设置返回类型,若没有设置,默认返回影响的行数。
  • parameterType:设置接口方法参数类型。

保存获取主键值:(有两种方式)

方式一:获取主键最后的自增长值封装到对象中(推荐,可以根据不同数据库类型设置,既可以oracle,也可以mysql)

示例配置:

   <insert id="save" parameterType="com.itheima.entity.User">
        <selectKey resultType="int" keyColumn="id" keyProperty="id" order="AFTER">
            SELECT LAST_INSERT_ID();
        </selectKey>
        insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
    </insert>

参数说明:

  • selectKey:获取主键最后的自增长值封装到对象中。
  • resultType:主键类型,一般都是int
  • keyColumn:主键在数据库表中的字段名
  • keyProperty:主键在对象中的属性名。
  • order:
  1. ​​​​​​​after:自增长主键插入数据之后获取主键值,适合支持具有自增长字段数据库,适合mysql。
  2. before:自增长主键插入数据之前获取主键值,适合oracle。因为oracle没有自增长列,是通过序列解决的。

方式二:获取自增长主键值。(不推荐,因为只适用于mysql,不适用于oracle)

  • 设置标签属性:useGeneratedKeys = "true"
  • 获取支持自增长字段数据库的主键值。

​​​​​​​示例配置:

 <insert id="save2" parameterType="com.itheima.entity.User" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
        insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
    </insert>

修改操作

概述:

  • update:代表修改操作。

删除操作:

概述:

delete:代表删除操作。

  • 删除一般参数只有一个基本数据类型。parameterType="int"
  • 此时在sql语句中,#{对象的属性名}里面的属性名,随便写。

单表查询

模糊查询

方式一:用ognl表达式(推荐,能防止sql注入)

格式:

  • like #{属性名}

概述:

  • #{}可以接收简单类型值或pojo属性值。
  • #{}表示一个占位符号,通过#{}可以实现PrepareStatement向占位符中设置值,自动进行java类型和jdbc类型转换。

方式二:通过拼接字符串的方式实现(不推荐,因为在sql语句中拼接字符串方式实现的模糊查询,不能防止sql注入)

格式:

  • like '[%]${value}[%]'

概述:

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

特殊字符

概述:

  1. 需要使用转义方式。
  2. 大于号不需要转义,小于号需要转义。

转义有两种方式:

  1. 一个一个转义。
  2. 将一个区域里面的所有字符批量转义。
  • ​​​​​​​格式:<!CDATA[数据]>

 示例代码:

 <select id="findByCondition" resultType="com.itheima.entity.User" parameterType="com.itheima.entity.QueryVO">
        <![CDATA[
select * from user where username like #{user.username} and birthday>=#{start} and birthday<=#{end}
        ]]>
    </select>

SqlMapperconfig.xml配置文件详解

顺序

配置标签名称

说明

1

properties

属性

2

settings

配置全局参数

3

typeAliases

类型别名

4

typeHandlers

类型处理器

5

objectFactory

对象工厂

6

plugins

插件

7

environments

环境集合属性对象

8

databaseIdProvider

多数据库支持

9

mappers

映射器

  • 在sqlMapconfig.xml中必须是从上往下的配置顺序。

Properties标签

属性:

  • resource:引用本项目类路径下的properties文件数据。(外部
  • url:引用本项目外部properties文件数据,可以访问网络上的子标签。

子标签:

property:配置内部properties数据。(内部

  • 外部和内部可以一起使用,优先使用外部。

作用:

  • 后面的environments标签的子标签dataSource用properties的数据。

示例配置:

    <properties resource="jdbc.properties" >
        <!--数据库连接字符串-->
        <property name="jdbc.url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf8"></property>
        <!--username数据库用户名-->
        <property name="jdbc.username" value="root"></property>
        <!--password数据库密码-->
        <property name="jdbc.password" value="root"></property>
    </properties>


 <environments default="mysql">
        <!--配置具体连接到哪一个数据库-->
        <environment id="mysql">
            <!--transactionManager,配置事物控制类型为JDBC-->
            <transactionManager type="JDBC"></transactionManager>
            <!--配置数据库连接池
                        POOLED,mybatis内置的数据库连接池(推荐使用)
                        UNPOOLED,不使用连接池
                        JNDI,使用服务器tomcat容器的数据库连接池
            -->
            <dataSource type="POOLED">
                <!--mysql驱动类-->
                <property name="driver" value="${jdbc.driver}"></property>
                <!--数据库连接字符串-->
                <property name="url" value="${jdbc.url}"></property>
                <!--username数据库用户名-->
                <property name="username" value="${jdbc.username}"></property>
                <!--password数据库密码-->
                <property name="password" value="${jdbc.password}"></property>
            </dataSource>
        </environment>

    </environments>

typeAliases标签

作用:

  • 用于起别名。

方式一:(不推荐

参数说明:

  • typeAlias:起别名配置,给一个一个类起别名。
  • type:设置指定类型全名。
  • alias:别名,在映射配置文件中类型只需要使用这个类名,不区分大小写。

示例:

<typeAliases>
    <typeAlias type="com.itheima.entity.User" alias="user"></typeAlias>
</typeAliases>

方式二:(推荐

参数说明:

  • package:批量给指定名下所有类起别名,会自动将名下类名作为别名,不区分大小写。

示例:

<typeAliases>
    <package name="com.itheima.entity"></package>
</typeAliases>

Mapper标签

方式一:一个一个映射文件加载。(不推荐

<mappers>
    <mapper resource="com/itheima/dao/IUserDao.xml"></mapper>
</mappers>

方式二:将这个包包下所有映射文件自动加载,批量加载。(推荐使用

<mappers>
    <package name="com.itheima.dao"></package>
</mappers>

Mybatis连接池与事务深入

Mybatis在初始化时,解析sqlMapperConfig.xml文件时,根据<dataSource>的type属性来创建相应类型的数据源DataSource:

1)type="pooled"

  • 使用mybatis内置的数据库连接池。(推荐使用
  • Mybatis会创建PooledDataSource实例。

2)type="unpooled"

  • 不使用连接池。
  • Mybatis会创建unpooledDataSource实例。

2)type="judi"

  • 使用服务器tomcat容器的数据库连接池。
  • Mybatis会从jdni服务上查找DataSource实例,然后返回使用。

注意事项:

  • PooledDataSource只是提供一种缓存连接池机制。
  • Mybatis的PooledDataSource创建连接的时候,会自动调用UnpooledDataSource中创建连接的方法。

什么时候创建连接:

  • 在真正进行数据库操作的时候,再创建连接。

Mybatis映射文件的SQL深入

<if>标签

作用:

  • 用于条件判断的结构。

属性:

  • test:条件判断,条件成立运行标签体的内容。
  • 注意:条件里面的属性名必须为输入参数的类型属性。

示例:

<select id="findByCondition" parameterType="user" resultType="user">
    select * from user where 1=1
    <!-- 判断 -->
    <if test="id != 0">
        and id=#{id}
    </if>
    <if test="username != null">
        and username=#{username}
    </if>
</select>

<where>标签

作用:

  1. 用来优化<if>标签。
  2. <if>标签在<where>标签中嵌套使用,<where>标签能判断第一个成立的<if>标签,并去掉其sql语句的 and
  3. 通过<where>标签拼接where条件,简化where写法。

示例:

<select id="findByCondition" parameterType="user" resultType="user">
    select * from user
    <where>
        <!-- 判断 -->
        <if test="id != 0">
            and id=#{id}
        </if>
        <if test="username != null">
            and username=#{username}
        </if>
    </where>
</select>

<foreach>标签

作用:

  • 遍历参数值。

参数说明:

  • foreach:用于循环遍历。
  • collection:用于遍历的集合,必须是输入类型的属性。
  • open:拼接sql的开始部分。
  • close:拼接sql的结束部分。
  • separator:循环拼接的分割符号。
  • index:当前遍历元素的索引。
  • item:要遍历的元素(集合里面的每个元素的名字)
  • #{id}:占位符的值,里面id名字与item设置的名字保持一致。

示例:

<select id="findByCondition2" parameterType="queryvo" resultType="user">
    SELECT * FROM USER WHERE 1=1
    <if test="ids != null and ids.size()>0">
        <foreach collection="ids" open="and id IN (" separator="," close=")" item="id">
            #{id}
        </foreach>
    </if>
</select>

<sql>标签

作用:

  • 定义SQL片段,抽取公用的SQL部分。

<include>标签

作用:

  • 用来引用sql片段。

总结:

  1. sql中可将重复的sql提取出来,使用时用include引用即可,最终达到sql重用的目的。
  2. <include>标签的refid属性的值就是<sql>标签定义的id的取值。
  3. 如果应用其他mapper.xml的sql片段,则在引用时需要加上namespace。
  • ​​​​​​​格式:<include refid = "空间名称.id的值"></include>

示例代码:

<sql id="selectUser">
    SELECT * FROM USER WHERE 1=1
</sql>
<select id="findByCondition2" parameterType="queryvo" resultType="user">
    <!--引用SQL片段-->
    <include refid="selectUser"></include>
    <if test="ids != null and ids.size()>0">
        <foreach collection="ids" open="and id IN (" separator="," close=")" item="id">
            #{id}
        </foreach>
    </if>
</select>

Mybatis的多表关联查询

常见的表关系:

  1. 一对一
  2. 一对多
  3. 多对多
  • ​​​​​​​双向一对多就是多对多。

一对一

参数说明:

  • association标签:用于配置一对一映射。
  • property属性:user对象在Accound对象中的属性名。
  • javaType属性:user属性的java对象类型。(没有ofType属性
  • column属性:外键。
  • id标签:数据库表主键字段映射。

示例代码:

<resultMap id="userResultMap" type="account">
        <!--建立account账户对象属性与账户表字段的映射关系-->
        <id property="accountId" column="accountId"></id>
        <result property="uid" column="uid"></result>
        <result property="money" column="money"></result>

        <association property="user" javaType="user" column="uid">
            <id property="id" column="id"></id>
            <result property="username" column="username"></result>
            <result property="birthday" column="birthday"></result>
            <result property="sex" column="sex"></result>
            <result property="address" column="address"></result>
        </association>
</resultMap>

<select id="findAll" resultMap="userResultMap">
    SELECT * FROM account a INNER JOIN USER u ON a.uid=u.id
</select>

一对多

参数说明:

  • collection:用于配置一对多映射。
  • property:在User里面的List<Account>的属性名。
  • column:主键。
  • ofType:当前account表的java类型。
  • javaType:无意义,但也有这个属性。

示例:


    <!--建立user对象的属性与查询列的映射关系-->
    <resultMap id="userResultMap" type="user">
        <!--1. 封装User对象-->
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="birthday" column="birthday"></result>
        <result property="sex" column="sex"></result>
        <result property="address" column="address"></result>
 
        <collection property="accounts" ofType="account">
            <id property="accountId" column="accountId"></id>
            <result property="uid" column="uid"></result>
            <result property="money" column="money"></result>
        </collection>
    </resultMap>
    <!--使用左外连接,因为我们查询的是用户,用户下有账户才显示账户;用户下没有账户只显示用户-->
    <select id="findAll" resultMap="userResultMap">
        SELECT * FROM USER u LEFT JOIN  account a ON a.uid=u.id
    </select>

多对多

概述:

  1. 双向一对多就是多对多。
  2. 多对多的时候,collection不用设立主键,没有意义。
  3. 多对多时,需要设立中间表,中间表分别设立两个表主键的外键,并且把外键列设置为联合主键。

中间表创建语句示例:

CREATE TABLE user_role (
  UID int(11) NOT NULL COMMENT '用户编号',
  RID int(11) NOT NULL COMMENT '角色编号',
  PRIMARY KEY  (UID,RID),
  KEY FK_Reference_10 (RID),
  CONSTRAINT FK_Reference_10 FOREIGN KEY (RID) REFERENCES role (ID),
  CONSTRAINT FK_Reference_9 FOREIGN KEY (UID) REFERENCES user (id)
) 

示例代码:

<resultMap id="userResultMap" type="user">
        <!--1.封装用户信息-->
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="birthday" column="birthday"></result>
        <result property="sex" column="sex"></result>
        <result property="address" column="address"></result>
        <!--2. 封装用户的角色集合-->
        <!--一对多配置-->
        <collection property="roles" ofType="role">
            <id property="id" column="roleId"></id>
            <result property="roleName" column="role_name"></result>
            <result property="roleDesc" column="role_desc"></result>
        </collection>
</resultMap>
    <!--注意:多表查询时候,列名称不要重复,否则影响结果封装!!!-->
    <select id="findAll" resultMap="userResultMap">
      SELECT u.*,r.ID roleId,r.ROLE_NAME,r.ROLE_DESC FROM USER u
       LEFT JOIN user_role ur ON u.id=ur.UID
       LEFT JOIN role r ON ur.RID=r.ID
    </select>

用map做参数

概述:

  • 使用map去替换QueryVo,用map做输入参数,此时标签中不用写parameter属性。

对象封装数据和使用map集合封装数据各自的优势:

  • ​​​​​​​对象更具有面向对象和提高重用性,map简单不用创建新的类型适合一次使用。

示例:

总结

  1. ​​​​​​​当进行及时加载时(一次加载所有数据),可以都不写column。
  2. 其实所有操作标签都可以不写parameterType属性,但是为了方便操作,最好写上。虽然可以不写,但是写错的话会报错,写的话一定要写对。

Mybatis延迟加载策略

什么是及时加载:

  • 一次加载所有数据。

延迟加载(懒加载):

  • 需要用到数据时才进行加载,不需要用数据时就不加载数据。

好处:

  • 先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度更快。

坏处:

  • 因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。

如何实现延迟加载:

  • association、collection具备延迟加载功能。通过设置select属性实现。

配置延迟加载

参数说明:

1)select:接口类全名.方法名

  • 用于设置当用到用户数据的时候执行哪个接口的方法名字。

​​​​​​​2)column:默认会将column指定的数据传递给select方法作为参数。

  • 一对一时,column设外键。
  • 一对多时,column设主键。
  • 在延迟加载中,多对多也要设column。

示例:

IAccountDao接口:

public interface IAccountDao {
    /**
     * 查询全部
     */
    List<Account> findAll();
}

 IUserDao接口:

public interface IUserDao {

    /**
     * 根据用户id查询
     */
    User findById(int id);
}

IUserDao.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 对应dao接口的路径-->
<mapper namespace="com.itheima.dao.IUserDao">
    <!--parameterType 方法参数类型;resultType 表示返回值类型 -->
    <select id="findById" parameterType="int" resultType="user">
        SELECT * FROM USER WHERE id=#{id}
    </select>
</mapper>

​​​​​​​IAccountDao.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 对应dao接口的路径-->
<mapper namespace="com.itheima.dao.IAccountDao">

    <!--一对一: 延迟加载查询(2) 结果集封装、以及延迟加载配置-->
    <resultMap id="accountResultMap" type="account">
        <id property="accountId" column="accountId"></id>
        <result property="uid" column="uid"></result>
        <result property="money" column="money"></result>
        <!--
            延迟加载 配置:
                select   延迟加载查询配置。
                         根据账户中用户的id,查询用户信息。
                         所以需要找到查询方法:com.itheima.dao.IUserDao.findById
        -->
        <association
                property="user" javaType="user" column="uid"
                select="com.itheima.dao.IUserDao.findById"></association>
    </resultMap>
    
    <!--一对一: 延迟加载查询(1)-->
    <select id="findAll" resultMap="accountResultMap">
        SELECT * FROM account;
    </select>

</mapper>

注意事项:

  • 需要手动开启延迟加载支持。默认不开启。

开启延迟加载

方式一:配置延迟加载的全局开关。

在SqlMapconfig.xml文件中:

 <settings>
        <!--配置延迟加载全局开关-->
        <setting name="lazyLoadingEnabled" value="true"/>
    </settings>
  • value默认为:false

方式二:设置fetchType属性

在Mapper.xml文件中:

  • 通过在association或collection标签中配置fetchType属性为lazy开启延迟加载。

​​​​​​​实例:

 <association
                property="user" javaType="user" column="uid"
                select="com.itheima.dao.IUserDao.findById" fetchType="lazy"></association>
  • fetchType="lazy"覆盖全局的配置。

Mybatis缓存

mybatis缓存分为:

  • 一级缓存
  • 二级缓存

一级缓存:

  • 一级缓存是基于sqlSession缓存,关闭sqlSession,缓存就失效。
  • 一级缓存不能跨sqlSession,由mybatis自动维护。

二级缓存:

  • 二级缓存是基于映射文件的缓存。
  • 不同的sqlSession可以访问二级缓存的内容。
  • 二级缓存是跨sqlSession的。
  • 二级缓存不能跨映射文件。

Redis和Mybatis缓存的区别:

  • ​​​​​​​Redis缓存可以集群缓存,redis的缓存有持久化。
  • Mybatis只适合单机缓存,mybatis的缓存没有持久化。

开启二级缓存的步骤:

第一步:开启二级缓存支持(可选)

  • 二级缓存的全局配置,默认开启,所以这里可以配置,也可以不配置。
 <settings>
        <!--配置二级缓存的全局开关,默认为true(可选)-->
        <setting name="cacheEnabled" value="true"></setting>
    </settings>

第二步:配置映射文件

  1. 那些映射文件中的SQL查询的结果需要放入二级缓存,需要在映射文件中配置<cache/>
  2. 执行哪些方法时不需要使用二级缓存,要在映射文件中配置useCache="false"

Mapper.xml文件中:

<select id="findById" resultType="user" useCache="true">
        SELECT * FROM USER WHERE id=#{userid}
    </select>
  • userCache属性默认值为true

第三步:实体类实现可序列化接口

  • Serializable

 

Mybatis注解开发

注意事项:

  1. 注解了的方法,不能再用xml文件去配置。
  2. 没与Spring整合前,使用注解也要配置SqlMapConfig.xml文件。并配置<mappers>标签的<package>标签,并创建对应的包。

注解说明:

@Insert实现新增
@Update实现更新
@Delete实现删除
@select实现查询
@Result实现结果集封装
@Results可以与@Result一起使用,封装多个结果集
@One实现一对一结果集封装
@Many实现一对多结果集封装
@Param当方法参数有多个的时候,建立sql语句中的占位符参数值与方法参数的映射关系

@Insert

@Update

@Delete

@Select

示例:

    @Update("update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}")
    void update(User user);

@Param

作用:

  • 当方法参数有多个的时候。
  • 例:分页sql的执行。

方式一:使用参数顺序方式

   @Select("select * from user limit #{arg0},#{arg1}")
    List<User> findByPage2(int start,int count);

方式二:使用@Param注解,定义到方法参数上,与sql语句中的占位符中的名称对应。

 @Select("select * from user limit #{start},#{count1}")
    List<User> findByPage3(@Param("start") int start, @Param("count1") int count);

用注解延迟加载封装数据

  • 必须指定id列的映射,否则为null。

一对一映射,以及延迟加载配置

IUserDao接口:

public interface IUserDao {

    /**
     * 根据用户id查询用户
     */
    @Select("select * from user where id=#{uid}")
    User findById(int uid);

}

IAccountDao接口:


public interface IAccountDao {
    @Select("select * from account")
    @Results({
            @Result(id = true,property = "accountId",column = "accountId"),
            @Result(property = "uid",column = "uid"),
            @Result(property = "money",column = "money"),
            // 一对一
            @Result(property = "user",column = "uid",javaType = User.class,
              one = @One(select = "com.itheima.dao.IUserDao.findById",fetchType = FetchType.LAZY))
    })
    List<Account> findAll();
}

参数说明:

  • @Results:建立多个查询列与对象属性的映射关系。
  • ​​​​​​​@Result:建立每一个查询列与对象属性的映射关系。
  • @id:标记主键字段,默认为false。
  • property:对象属性。
  • column:对象属性对应的查询列。
  • one:此属性表示一对一关系。

​​​​​​​@One:one属性的值的类型,就是一个注解类型,表示一对一。

  • select:延迟加载查询。对应用户接口中,根据用户id查询用户的方法。
  • fetchType:是否开启延迟加载支持。

一对多映射,以及延迟加载配置

IUserDao接口:

public interface IUserDao {

      @Select("select * from user")
    @Results({
            @Result(id = true,property = "id",column = "id"),
            @Result(property = "username",column = "username"),
            @Result(property = "birthday",column = "birthday"),
            @Result(property = "sex",column = "sex"),
            @Result(property = "address",column = "address"),
            @Result(property = "accounts",column = "id",javaType = List.class,
            many = @Many(select = "com.itheima.dao.IAccountDao.findAccountsByUserId",
                    fetchType = FetchType.LAZY))
    })
    List<User> findAll();

}

IAccountDao接口:


public interface IAccountDao {
    @Select("select * from account where uid=#{uid}")
    List<Account> findAccountsByUserId(int uid);
}

参数说明:

javaType=List.class:集合的类型

many:表示一对多关系

  • fetchType:是否开启延迟加载策略。
  • select:一对多延迟加载查询。

一对一映射,不使用select属性

Product类属性:

public class Product {
    private Long id;//id
    private String productNum;//产品编号
    private String productName;//产品名称
    private String cityName;//出发城市
    private Timestamp departureTime;//出发时间
    private double productPrice;//产品价格
    private String productDesc;//产品描述
    // 0  关闭; 1  开启
    private Integer productStatus;//产品状态
}

order类属性:

public class Order {
    private Long id;
    private String orderNum;
    private Date orderTime;
    private Integer peopleCount;
    private String orderDesc;
    private Integer payType;
    private Integer orderStatus;
    // 订单对应的产品
    private Product product;
}

IOrderDao:

public interface IOrderDao {
    /**
     * 查询全部
     */
    @Select("select o.id oid,o.ordernum,o.ordertime,o.peoplecount,o.orderdesc,o.paytype,o.orderstatus\n" +
            ",p.* from orders o inner join product p on o.productid=p.id")
    @Results({
            // 订单信息,只要指定id列与属性的映射关系,其他列会自动封装(属性与列一致)
            @Result(property = "id", column = "oid"),
            // 产品信息
            @Result(property = "product.id", column = "id"),
            @Result(property = "product.productNum", column = "productNum"),
            @Result(property = "product.productName", column = "productName"),
            @Result(property = "product.cityName", column = "cityName"),
            @Result(property = "product.departureTime", column = "departureTime"),
            @Result(property = "product.productPrice", column = "productPrice"),
            @Result(property = "product.productDesc", column = "productDesc"),
            @Result(property = "product.productStatus", column = "productStatus"),
    })
    List<Order> findAll();

}

注意事项:

  • 注意数据库字段名重复的问题,在数据库的查询中·,重复的字段应该取别名,避免重复。
  • ​​​​​​​Order类的映射关系,可写可不写,会自动封装。

对用注解实现映射的总结

注意事项:

  1. 无论时一对一还是一对多,在注解中,都使用javaType
  2. 在一对一时,xml配置形式的javaType,设为:实体类.class
  3. 在一对多时,xml配置形式的ofType,设为:List.class
  4. 在注解中,javaType可以忽略不写。

用注解实现二级缓存

在接口上使用注释@CacheNamespace,将这个接口加入二级缓存。

给接口的方法添加@Options,设置接口中当前的方法不加入二级缓存。

​​​​​​​

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值