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)
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章