MyBatis入门+概述

MyBatis概述

参考视频:Mybatis教程IDEA版-4天-2018黑马SSM-01

三层架构
  • 表现层 展示数据
  • 业务层 处理业务需求
  • 持久层 和数据库交互
持久层技术解决方案
  1. JDBC技术:Connection、PreparedStatement、ResultSet
  2. Spring的JdbcTemplate
  3. Apache的DBUtils
  4. JDBC是规范,剩下两个都是工具类
mybatis概述
  1. mybatis是一个持久层框架,它封装了jdbc操作的很多细节,使开发者只需关注sql语句本身。它使用了ORM思想实现了结果集的封装。
  2. ORM: Object Relational Mapping 对象关系映射
    • 把数据库表和实体类及实体类的属性对应起来,让我们可以操作实体类就操作数据库表。
log4j 打印日志
  1. 在pom.xml中导入3个坐标:

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>2.0.0-alpha1</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>2.0.0-alpha1</version>
    </dependency>
    <dependency>
        <groupId>org.bgee.log4jdbc-log4j2</groupId>
        <artifactId>log4jdbc-log4j2-jdbc4.1</artifactId>
        <version>1.16</version>
    </dependency>
    
    1. 配置jdbcConfig.properties文件:
    log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator
    
    1. 配置log4j.properties文件
    ### 设置Logger输出级别和输出目的地 ### debug更详细,如果设为info那么打印出的表数据遇到字符串就不显示,此外还有logfile
    log4j.rootLogger=debug,stdout
    
    ### 把日志信息输出到控制台 ### 
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender 
    #log4j.appender.stdout.Target=System.err 
    log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout 
    
    ### 把日志信息输出到文件:jbit.log ### 
    #log4j.appender.logfile=org.apache.log4j.FileAppender 
    #log4j.appender.logfile.File=jbit.log 
    #log4j.appender.logfile.layout=org.apache.log4j.PatternLayout 
    #log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %F %p %m%n 
    
    ###显示SQL语句部分 
    #log4j.logger.com.mybatis=DEBUG
    #log4j.logger.com.mybatis.common.jdbc.SimpleDataSource=DEBUG 
    #log4j.logger.com.mybatis.common.jdbc.ScriptRunner=DEBUG 
    #log4j.logger.com.mybatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG 
    #log4j.logger.java.sql.Connection=DEBUG
    #log4j.logger.java.sql.Statement=DEBUG
    #log4j.logger.java.sql.PreparedStatement=DEBUG
    #log4j.logger.java.sql.ResultSet=DEBUG
    
    
mybatis入门
  • mybatis的环境搭建

    • 步骤
      1. 导入坐标 mybatis , mysql-connector,log4j,junit
      2. 创建实体类和dao的接口
      3. 创建mybatis的主配置文件SqlMapConfig.xml
      4. 创建映射配置文件 IUserDao.xml
    • 注意事项:
      • IUserDaoIUserMapper是一样的
      • mybatis的映射配置文件位置必须和dao接口的包结构相同
      • 映射配置文件mapper标签namespace属性的取值必须是dao接口的全限定类名。
      • 映射配置文件的操作配置(select),id属性的取值必须是dao接口的方法名。
      • 当遵循了后3点后,开发中无需写dao的实现类
  • mybatis的入门案例

    1. 读取配置文件
    2. 创建SqlSessionFactory工厂
    3. 创建SqlSession
    4. 创建Dao接口的代理对象
    5. 执行dao中的方法
    6. 释放资源
  • 基于xml

    • Config.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">
      
      <!--mybatis的主配置文件-->
      <configuration>
          <!-- 配置环境 -->
          <environments default="mysql">
              <!--配置mysql的环境-->
              <environment id="mysql">
                  <!--配置事务的类型-->
                  <transactionManager type="JDBC"></transactionManager>
                  <!--配置数据源(连接池)-->
                  <dataSource type="POOLED">
                      <!--配置连接数据库的4个基本信息-->
                      <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                      <property name="url" value="jdbc:mysql://localhost:3306/eesy_mybatis?serverTimezone=UTC&amp;useSSL=false"/>
                      <property name="username" value="root"/>
                      <property name="password" value="070622"/>
                  </dataSource>
              </environment>
          </environments>
      
          <!--指定映射配置文件的位置,映射配置文件是指每个dao独立的配置文件-->
          <mappers >
              <mapper resource="com/qmh/dao/IUserDao.xml"></mapper>
          </mappers>
      </configuration>
      
      
    • 映射配置文件 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">
      
      <mapper namespace="com.qmh.dao.IUserDao">
          <!--配置查询所有-->
          <select id="findAll" resultType="com.qmh.domain.User">
              select * from user
          </select>
      </mapper>
      
    • 入门案例测试代码:

      //1.读取配置文件
      InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
      //2.创建SqlSessionFactory工厂
      SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
      SqlSessionFactory factory = builder.build(in);
      //3.使用工厂生产SqlSession对象
      SqlSession session = factory.openSession();
      //4.使用SqlSession创建Dao接口的代理对象
      IUserDao userDao =  session.getMapper(IUserDao.class);
      //5.使用代理对象执行方法
      List<User> users = userDao.findAll();
      for(User user:users){
      System.out.println(user);
      }
      //6.释放资源
      session.close();
      in.close();
      
  • 基于注解

    • 移除IUserDao.xml,修改Dao接口类

      /**
       * 持久层接口
       */
      public interface IUserDao {
          /**
           * 查询所有
           * @return
           */
          @Select("select * from user")
          List<User> findAll();
      }
      
      
    • 修改Config配置文件的mappers

      <!--指定映射配置文件的位置,映射配置文件是指每个dao独立的配置文件
              如果使用注解进行配置,此处应该使用class属性的全限定类名-->
          <mappers >
              <mapper class="com.qmh.dao.IUserDao"></mapper>
          </mappers>
      
  • 自己实现dao实现类时

public List<User> findAll() {
        //1.使用工厂创建SqlSession对象
        SqlSession session = factory.openSession();
        //2.使用session执行查询所有 这里通过 IUserDao.xml中的namespace+id唯一定位到方法
        List<User> users = session.selectList("com.qmh.dao.IUserDao.findAll");
        session.close();
        return users;
    }
  • 自定义Mybatis的分析

    • mybatis在使用代理dao的方式实现增删改查时做的事情:

      • 创建代理对象
      • 在代理对象中调用selectList方法
    • selectList方法分析:

      2

    • 创建代理对象

      • public<T> T getMapper(Class<T> daoInterfaceClass){
            /**
            *  类加载器:和被代理对象使用相同的类加载器
            *  代理对象要实现的接口:和被代理对象实现相同的接口
            *  如何代理: 增强的方法,需要自己提供,是一个InvocationHandler的接口,需要写一个
            * 该接口的实现类,在实现类中调用selectList方法
            */ 
            Proxy.newProxyInstance(ClassLoader loader,<?>[] interfaces,InvocationHandler h)
        }
        
自定义Mybatis实现
  • 步骤:
    • 创建代理对象
    • 在代理对象中调用selectList方法
  • 入门案例中能看到的类:
    • class Resources
    • class SqlSessionFactoryBuilder
    • interface SqlSessionFactory
    • public interface SqlSession extends Closeable
  • 代码实现参考博客Mybatis学习笔记 - 01
Mybatis框架实现CRUD操作(CRUD—Create Read Update Delete )
  • 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">
    
    <mapper namespace="com.qmh.dao.IUserDao">
        <select id="findAll" resultType="com.qmh.domain.User">
            select * from user
        </select>
    
        <insert id="saveUser" parameterType="com.qmh.domain.User">
            <!-- 配置插入操作后,获取插入数据的id -->
            <selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
                select last_insert_id()
            </selectKey>
            insert into user(username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address})
        </insert>
    
        <update id="updateUser" parameterType="com.qmh.domain.User">
            update user set username=#{username},address=#{address},sex=#{sex},birthday=#{birthday} where id=#{id}
        </update>
    
        <delete id="deleteUser" parameterType="Integer">
            delete from user where id=#{uid}
        </delete>
        
        <select id="findById" parameterType="int" resultType="com.qmh.domain.User">
            select * from user where id=#{uid}
        </select>
    
        <select id="findByName" parameterType="String" resultType="com.qmh.domain.User">
            <!--   select * from user where username like #{uname} -->
            select * from user where username like '%${value}%'
        </select>
        
        <select id="findTotal" resultType="int">
            select count(id) from user
        </select>
    </mapper>
    
  • 添加操作之后获取id值,配置selectKey标签

       <insert id="saveUser" parameterType="com.qmh.domain.User">
            <!-- 配置插入操作后,获取插入数据的id -->
            <selectKey keyProperty="userId" keyColumn="id" resultType="int" order="AFTER">
                select last_insert_id()
            </selectKey>
            insert into user(username,birthday,sex,address) values (#{userName},#{userBirthday},#{userSex},#{userAddress})
        </insert>
    
  • OGNL表达式

  • Object Graphic Navigation Language 对象图导航语言

    • mybatis使用ognl表达式解析对象字段的值,#{} 或 ${}括号中的值作为pojo(plain ordinary java object,简单普通的java对象)属性名称
    • 它是通过对象的取值方法来获取数据,在写法上把get给省略了。
    • 举例:
      • 类中的写法 user.getUserName()
      • OGNL表达式写法 user.username 对象.属性
    • mybatis中的parameterType中已经提供了属性所属的类,所以此时不需要写对象名。
  • 当数据库的列名和类属性不一致时,有两种修改方式:

    • 在sql语句中使用as起别名。

    • IUserDao.xml中创建resultMap标签,将resultType修改为resultMap="userMap"

       <!-- 配置查询结果的列名和实体类的属性名的对应关系 -->
          <resultMap id="userMap" type="com.qmh.domain.User">
              <!--主键字段的对应 -->
              <id property="userId" column="id"></id>
              <!--非主键字段的对应 -->
              <result property="userName" column="username"></result>
              <result property="userAddress" column="address"></result>
              <result property="userSex" column="sex"></result>
              <result property="userBirthday" column="birthday"></result>
      
          </resultMap>
      
    • mysql数据库在windows下不区分大小写,所以userName可以写入,其他属性则不行。但在linux下是严格区分大小写的,故所有属性都无法写入。

  • mybatis主配置文件的properties标签

    • 创建jdbcConfig.properties

      jdbc.driver = com.mysql.cj.jdbc.Driver
      jdbc.url =  jdbc:mysql://localhost:3306/eesy_mybatis?serverTimezone=Hongkong
      jdbc.username = root
      jdbc.password = 070622
      
    • 修改SqlMapConfig.xml

      <configuration>
          <!-- 配置properties
              可以在标签内部配置连接数据库信息,也可以通过属性引用外部配置文件信息
              resource属性: 用于指定配置文件的位置
           -->
          <properties resource="jdbcConfig.properties">
          </properties>
          <!--配置环境-->
          <environments default="mysql">
              <environment id="mysql">
                  <!--配置事务-->
                  <transactionManager type="JDBC"></transactionManager>
                  <!--配置数据源-->
                  <dataSource type="POOLED">
                      <property name="driver" value="${jdbc.driver}"/>
                      <property name="url" value="${jdbc.url}"/>
                      <property name="username" value="${jdbc.username}"/>
                      <property name="password" value="${jdbc.password}"/>
                  </dataSource>
              </environment>
          </environments>
          <!--配置映射文件的位置-->
          <mappers>
              <mapper resource="com/qmh/dao/IUserDao.xml"></mapper>
          </mappers>
      </configuration>
      
    • 也可以使用url属性定位配置文件

        <!-- 配置properties
              可以在标签内部配置连接数据库信息,也可以通过属性引用外部配置文件信息
              resource属性: 用于指定配置文件的位置
              url属性:按照url的写法来写地址
              它的写法:
                  http://localhost:8080/mybatisserver/demo1Servlet
                  协议    主机      端口     URI
              URI uniform Resource Identifier 统一资源标识符,在应用中唯一定位一个资源
           -->
          <properties url="file:///C:\Users\qmh\IdeaProjects\MyBatis_JDBC\MyBatis\day02_eesy_01mybatisCRUD\src\main\resources\jdbcConfig.properties">
          </properties>
      
    • 配置别名typeAliases

       <typeAliases>
              <!--typeAlias 用于配置别名-->
      <!--        <typeAlias type="com.qmh.domain.User" alias="user"></typeAlias>-->
              <!--用于指定要配置别名的包,当指定之后,该包下的实体类都会注册别名,并且类名就是别名-->
              <package name="com.qmh.domain"/>
          </typeAliases>
      
    • package标签

      <!--配置映射文件的位置-->
          <mappers>
      <!--        <mapper resource="com/qmh/dao/IUserDao.xml"></mapper>-->
              <!--package标签是用于指定dao接口所在的包,当指定之后就不需要再写mapper标签-->
              <package name="com.qmh.dao"/>
          </mappers>
      
连接池
  • 存放数据库连接的容器,必须保证线程安全,同时满足队列先进先出的特点

  • mybatis中的连接池

    • mybatis连接池提供了3种方式的配置
    • 配置位置:主配置文件中的dataSource标签,type属性表示采用何种连接池方式。
    • type属性的取值:
      • POOLED 传统的javax.sql.DataSource规范中的连接池。
      • UNPOOLED采用传统的获取连接的方式
      • JNDI 采用服务器提供的JNDI技术实现,来获取DataSource对象. 目的是模仿windows的注册表
  • 查看POOLED的实现方式

    1

mybatis中的事务
  • 通过SqlSession对象的commit方法和rollback方法实现事务的提交和回滚
mybatis中的动态sql语句
  • 根据传入的参数查询。IUserDao.xml,可以做到多条件查询,如select * from user WHERE username=? and sex=?

    <select id="findUserByCondition" resultMap="userMap" parameterType="user">
            select * from user
            <where>
                <if test="userName!=null">
                    and  username=#{userName}
                </if>
                <if test="userSex!=null">
                    and sex=#{userSex}
                </if>
            </where>
        </select>
    
  • foreach标签 根据QueryVo类中的ids集合使用in进行查询。Preparing: select * from user WHERE id in ( ? , ? , ? )

    <!--根据queryVo中的id集合实现查询列表-->
    <select id="findUserInIds" resultMap="userMap" parameterType="QueryVo">
        select * from user
        <where>
            <if test="ids!=null and ids.size()>0">
                <foreach collection="ids" open ="and id in (" close=")" item="uid" separator="," >
                    #{uid}
                </foreach>
            </if>
        </where>
    </select>
    
  • include标签,抽取重复的sql语句

    <!--抽取重复的sql语句-->
    <sql id="defaultUser">
        select * from user
    </sql>
    
    <select id="findAll" resultMap="userMap">
        <include refid="defaultUser"></include>
    </select>
    
mybatis中的多表查询
  • 表之间的关系:

    • 一对多 用户和订单
    • 多对一 订单和用户 。 mybatis中认为每拿出一个订单,它只属于一个用户,所以把多对一看作一对一
    • 一对一 人和身份证号
    • 多对多 老师和学生
  • mybatis中的多表查询

    • 用户和账户
      • 一个用户可以有多个账户
      • 一个账户只能属于一个用户(多个账户也可以属于一个用户)
    • 步骤:
      1. 建立用户表和账户表,其中账户表具有外键
      2. 建立两个实体类:用户类和账户类,让这两个类能体现出一对多的关系
      3. 建立两个配置文件:用户的(IUserDao.xml)和账户的(IAccountDao.xml)
      4. 实现配置。
    • 一对一查询
    public class Account implements Serializable {
        private Integer id;
        private Integer uid;
        private Double money;
    
        //从表实体应该包含主表实体的一个对象引用
        private User user;
        ...
    }
    
    <!--定义封装account和user的resultMap-->
    <resultMap id="accountUserMap" type="Account">
        <!--配置主键-->
        <id property="id" column="aid"></id>
        <!--配置其他-->
        <result property="uid" column="uid"></result>
        <result property="money" column="money"></result>
        <!--一对一的关系映射。配置封装User的内容-->
        <association property="user" column="uid" javaType="user">
            <result property="id" column="id"></result>
            <result property="username" column="username"></result>
            <result property="address" column="address"></result>
            <result property="sex" column="sex"></result>
            <result property="birthday" column="birthday"></result>
        </association>
    </resultMap>
    <select id="findAll" resultMap="accountUserMap">
        select u.*,a.id as aid,a.uid,a.money from user u,account a where u.id=a.uid;
    </select>
    
    • 一对多查询
    public class User implements Serializable {
        private Integer id;
        private String username;
        private LocalDateTime birthday;
        private String sex;
        private String address;
    
        //一对多关系映射,主表实体应该包含从表实体的集合引用
        private List<Account> accounts;
        ...
    }
    
    <!--定义User的ResultMap-->
    <resultMap id="userAccountMap" type="user">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="address" column="address"></result>
        <result property="sex" column="sex"></result>
        <result property="birthday" column="birthday"></result>
        <!--配置user对象中accounts集合的映射-->
        <collection property="accounts" ofType="account">
            <id property="id" column="aid"></id>
            <result property="uid" column="uid"></result>
            <result property="money" column="money"></result>
        </collection>
    </resultMap>
    
    <select id="findAll" resultMap="userAccountMap">
        select * from `user` u  left outer join account a on u.id = a.uid
    </select>
    
  • 多对多查询 示例:用户和角色

    • 步骤:

      1. 建立两张表:用户表、角色表
        • 让用户表和角色表具有多对多的关系,需要使用中间表,中间表中包含各自的主键,在中间表中是外键。
      2. 建立两个实体类:用户实体类和角色实体类。 各自包含对方一个集合。
      3. 建立两个配置文件
      4. 实现配置。
    • 实现角色到用户的多对多操作

      sql语句:select r.id as rid,r.role_desc ,r.role_name ,u.* from role r left outer join user_role ur on r.id =ur.rid left outer join user u on u.id = ur.uid ;

    public class Role implements Serializable {
        private Integer roleId;
        private String roleName;
        private String roleDesc;
    
        //多对多的关系映射,一个角色可以赋予多个用户
        private List<User> users;
        ...
    }
    
    <resultMap id="roleMap" type="role">
        <id property="roleId" column="rid"></id>
        <result property="roleName" column="role_name"></result>
        <result property="roleDesc" column="role_desc"></result>
        <collection property="users" ofType="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>
    </resultMap>
    
    <select id="findAll" resultMap="roleMap">
        select r.id as rid,r.role_desc ,r.role_name ,u.* from `role` r
        left outer join user_role ur on r.id =ur.rid
        left outer join `user` u on u.id = ur.uid ;
    </select>
    
  • 实现用户到角色的多对多操作

    sql语句:select u.*,r.id as rid,r.role_desc ,r.role_name from user u left join user_role ur ON u.id = ur.uid left join role r on r.id =ur.rid ;

    public class Role implements Serializable {
        private Integer roleId;
        private String roleName;
        private String roleDesc;
    
        //多对多的关系映射,一个角色可以赋予多个用户
        private List<User> users;
        ...
    }
    
    <resultMap id="roleMap" type="role">
        <id property="roleId" column="rid"></id>
        <result property="roleName" column="role_name"></result>
        <result property="roleDesc" column="role_desc"></result>
        <collection property="users" ofType="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>
    </resultMap>
    
    <select id="findAll" resultMap="roleMap">
        select r.id as rid,r.role_desc ,r.role_name ,u.* from `role` r
        left outer join user_role ur on r.id =ur.rid
        left outer join `user` u on u.id = ur.uid ;
    </select>
    
JNDI
  • 创建maven的war工厂。

  • 导入依赖,新增:servlet-api,servlet.jsp-api

  • 配置context.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <Context>
    <!--    <Resource name="jdbc/db1" auth="Container" type="javax.sql.DataSource"-->
    <!--              username="db1" password="123456" driverClassName="com.mysql.jdbc.Driver"-->
    <!--              url="jdbc:mysql://localhost:3306/db1" maxActive="100" maxWait="50000"-->
    <!--              maxIdle="30" />-->
    <Resource
            name="jdbc/eesy_mybatis"
            type="javax.sql.DataSource"
            username="root"
            password="070622"
            auth="Container"
            driverClassName="com.mysql.cj.jdbc.Driver"
            url="jdbc:mysql://localhost:3306/eesy_mybatis?serverTimezone=UTC"
            maxActive="20"
            maxWait="1000"
            maxIdle="5" />
    </Context>
    
  • 剩下的内容由于没有部署tomcat服务器,故放弃。

mybatis的延迟加载
  • 问题:

    • 在一对多中,有一个用户有100个账户,在查询用户时,要不要把关联的账户查出来?
    • 在查询账户时,要不要把关联的用户查出来?
  • 分析

    • 在查询用户时,用户下的账户信息应该是什么时候使用,什么时候查询的 ——延迟加载/懒加载
    • 在查询账户时,账户的所属用户信息应该随账户查询时一起查询出来 —— 立即加载
    • 在四种表关系中,可以分为两组:
      • 一对多,多对多 —— 延迟加载
      • 多对一,一对一。——立即加载
  • 延迟加载举例

    • SqlMapConfig.xml中配置settings标签

       <!--配置参数-->
          <settings>
              <!--开启mybatis支持延迟加载-->
              <setting name="lazyLoadingEnabled" value="true"/>
              <!--按需加载-->
              <setting name="aggressiveLazyLoading" value="flase"/>
          </settings>
      
    • 使用collection标签、association标签中的select属性,指定调用的方法名称,同时column属性指定被用来查询的属性列名

    • 根据uid查询账户所属的用户信息

      <!--定义封装account和user的resultMap-->
      <resultMap id="accountUserMap" type="Account">
          <!--配置主键-->
          <id property="id" column="id"></id>
          <!--配置其他-->
          <result property="uid" column="uid"></result>
          <result property="money" column="money"></result>
          <!--一对一的关系映射,配置封装user的内容
              select属性指定的内容:查询用户的唯一标识
              column属性指定的内容:用户根据id查询时,所需要的参数值
          -->
          <association property="user" column="uid" javaType="user" select="com.qmh.dao.IUserDao.findById"></association>
      </resultMap>
      <select id="findAll" resultMap="accountUserMap">
         select * from account
      </select>
      
    • 根据id查询用户名下的账户信息

      <!--定义User的ResultMap-->
      <resultMap id="userAccountMap" type="user">
          <id property="id" column="id"></id>
          <result property="username" column="username"></result>
          <result property="address" column="address"></result>
          <result property="sex" column="sex"></result>
          <result property="birthday" column="birthday"></result>
          <!--配置user对象中accounts集合的映射-->
          <collection property="accounts" ofType="account" select="com.qmh.dao.IAccountDao.findAccountByUid" column="id" ></collection>
      </resultMap>
      
      <select id="findAll" resultMap="userAccountMap">
          select * from `user` u
      </select>
      
Mybatis中的缓存
  • 缓存是指存在于内存中的临时数据。

  • 减少和数据库的交互次数,提高执行效率

  • 适用于缓存:

    • 经常查询并且不经常改变的。
    • 数据的正确与否对最终结果影响不大。
  • 不适用于缓存:

    • 经常改变的数据
    • 数据的正确与否对最终结果影响很大:商品库存,银行汇率,股市牌价
  • Mybatis中的一级缓存和二级缓存

    • 一级缓存:

      • 指Mybatis中SqlSession对象的缓存,

      • 当执行查询之后,查询结果会同时存入到sqlsession提供的一块区域中,该区域的结构是一个Map,当再次查询同样的数据,mybatis会先去sqlseesion中查询。有的话,直接拿出来用

      • 当sqlsession对象消失时,mybatis的一级缓存也就消失了。

      • 当调用sqlsession的CUD操作,commit(),close()等方法,就会清空一级缓存。

        3

    • 二级缓存

      • 指Mybatis中SqlSessionFactory对象的缓存,由同一个SqlSessionFactory创建的sqlsession共享其缓存。

      • 二级缓存中存放的内容是数据,而不是对象。根据数据创建一个新的对象

      • 2

      • 使用步骤

        1. 让mybatis支持二级缓存(在SqlMapConfig.xml中配置)

          <settings>
              <setting name="cacheEnabled" value="true"/>
          </settings>
          
        2. 让当前的映射文件支持二级缓存(在IUserDao.xml中配置)

          <!--开启user支持二级缓存-->
          <cache></cache>
          
        3. 让当前操作支持二级缓存(在select标签中配置)

          <select id="findById" parameterType="int" resultType="user" useCache="true">
              select * from user where id=#{uid}
          </select>
          
Mybatis中的注解开发
  • SqlMapConfig.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="jdbcConfig.properties"></properties>
        <!--配置别名-->
        <typeAliases>
            <package name="com.qmh.domain"/>
        </typeAliases>
        <!--配置环境-->
        <environments default="mysql">
            <environment id="mysql">
                <transactionManager type="JDBC"></transactionManager>
                <dataSource type="POOLED">
                    <property name="driver" value="${jdbc.driver}"/>
                    <property name="url" value="${jdbc.url}"/>
                    <property name="username" value="${jdbc.username}"/>
                    <property name="password" value="${jdbc.password}"/>
                </dataSource>
            </environment>
        </environments>
        <!--指定dao接口所在位置-->
        <mappers>
            <package name="com.qmh.dao"/>
        </mappers>
    </configuration>
    
  • IUserDao.xml

    public interface IUserDao {
    
        @Select("select * from user")
        List<User> findAll();
    
        @Insert("insert into user(username,address,sex,birthday) values(#{username},#{address},#{sex},#{birthday})")
        void saveUser(User user);
    
        @Update("update user set username=#{username},sex=#{sex},address=#{address} where id=#{id}")
        void updateUser(User user);
    
        @Delete("delete from user where id=#{uid}")
        void deleteUser(Integer userId);
    
        @Select("select * from user where id=#{uid}")
        User findById(Integer userId);
    
        @Select("select * from user where username like #{username}")
        List<User> findUserByName(String username);
    
        @Select("select count(id) from user")
        int findTotalUser();
    }
    
  • 多对一查询(一对一)

    public interface IAccountDao {
        /**
         * 查询所有账户并带有对应的用户信息,多对一的情况下是立即加载
         * @return
         */
        @Select("select * from account")
        @Results(id="accountMap",value = {
                @Result(id = true,property = "id",column = "id"),
                @Result(property = "uid",column = "uid"),
                @Result(property = "money",column = "money"),
                @Result(property = "user", column = "uid",one =@One(select="com.qmh.dao.IUserDao.findById",fetchType= FetchType.EAGER))
        })
        List<Account> findAll();
    }
    
  • 一对多查询

    public interface IUserDao {
        /**
         * 查询所有用户,并返回用户对应的账户信息, 一对多的情况下使用懒加载
         * @return
         */
        @Select("select * from user")
        @Results(id="userMap",value = {
            @Result(id=true,column = "id",property = "userId"),
                @Result(column = "username",property = "userName"),
                @Result(column = "sex",property = "userSex"),
                @Result(column = "address",property = "userAddress"),
                @Result(column = "birthday",property = "userBirthday"),
                @Result(property = "accounts",column = "id",many = @Many(select = "com.qmh.dao.IAccountDao.findById",fetchType = FetchType.LAZY))
        })
        List<User> findAll();
    
  • 使用注解开启二级缓存

    @CacheNamespace(blocking = true)
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值