MyBatis框架學習-4

MyBatis框架安排

4. 第四天:

1. MyBatis的延遲加載

  1. 引入問題:在一對多中,我們有一個用戶,他有100個賬戶

    1. 問題1:在查詢用戶的時候,要不要把賬戶一起關聯出來?
    2. 問題2:在查詢賬戶時,要不要把用戶一起關聯出來?


    問題1:在查詢用戶時,應該是什麼時候使用它的賬戶,就什麼時候查。
    問題2:查詢賬戶時,用戶應該是隨着賬戶一起被查詢出來,這樣才知道賬戶對應着誰。

什麼是延遲加載:在真正使用數據時才發起查詢,不用時不查詢,又稱按需查詢(懶加載)
立即加載:不管用不用數據,只要一調用查詢方法,就立即查詢。
在對應的四種表關係中:一對多,多對一,一對一,多對多中
通常情況下:
一對多、多對多采用的是延遲加載。
一對一、多對一採用的是立即加載。
簡單記憶:右邊多的採用延遲加載,否則採用立即加載。

演示1:賬戶和用戶的關係,一對一(賬戶 | 用戶)
賬戶和用戶關係:一個賬戶只屬於一個用戶(特定時候一對一),但一個用戶可以有多個賬戶(一對多)
需求:查詢賬戶表信息,賬戶所屬的用戶信息不查詢出來(延遲加載)

  1. 準備好兩個實體類,Account,User

    package com.liuzeyu.domin;
    
    import java.io.Serializable;
    
    public class Account implements Serializable{
        private Integer id;
        private Integer uid;
        private Double money;
    
        private User user;
    
        public User getUser() {
            return user;
        }
    
        public void setUser(User user) {
            this.user = user;
        }
    
    
        @Override
        public String toString() {
            return "Account{" +
                    "id=" + id +
                    ", uid=" + uid +
                    ", money=" + money +
                    ", user=" + user +
                    '}';
        }
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public Integer getUid() {
            return uid;
        }
    
        public void setUid(Integer uid) {
            this.uid = uid;
        }
    
        public Double getMoney() {
            return money;
        }
    
        public void setMoney(Double money) {
            this.money = money;
        }
    }
    
    
    package com.liuzeyu.domin;
    
    import java.util.Date;
    import java.util.List;
    
    public class User {
        private Integer id;
        private String address;
        private String username;
        private String sex;
        private Date birthday;
    
        private List<Account> accounts;
    
        public List<Account> getAccounts() {
            return accounts;
        }
    
        public void setAccounts(List<Account> accounts) {
            this.accounts = accounts;
        }
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", address='" + address + '\'' +
                    ", username='" + username + '\'' +
                    ", sex='" + sex + '\'' +
                    ", birthday=" + birthday +
                    '}';
        }
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getSex() {
            return sex;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }
    
        public Date getBirthday() {
            return birthday;
        }
    
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
    }
    
    
    1. 兩個映射配置文件IUserDao.xml,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">
    <mapper namespace="com.liuzeyu.dao.IUserDao">
    
        <!-- 根據id查找一個 -->
        <select id="findById" resultType="user" parameterType="int">
            select * from user where id=#{uid}
        </select>
    </mapper>
    
    

    如果要配置延遲加載,association標籤則不能封裝User對象,如下

    <?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.liuzeyu.dao.IAccountDao">
        
        <resultMap id="rstAc" type="account">
            <id property="id" column="id"/>
            <result property="uid" column="uid"/>
            <result property="money" column="money"/>
            <!--javaType="user"映射後封裝的結果集 外鍵:uid
            select :屬性所指的內容就是查詢用戶的唯一標識
            column="uid",其中的uid就是select標籤要查詢的那個id ,不可以刪掉
            -->
            <association property="user" column="uid" javaType="user" select="com.liuzeyu.dao.IUserDao.findById">
            </association>
        </resultMap>
    
        <!-- 打印user表數據 -->
        <select id="findAll" resultMap="rstAc">
          SELECT * from account
        </select>
    </mapper>
    
    
    1. 準備主配置文件
    <?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>
    
        <properties resource="jdbcConfig.properties">
        </properties>
    
        <!--配置懶加載-->
        <!--<settings>-->
            <!--&lt;!&ndash;開啓mybatis支持延遲加載&ndash;&gt;-->
            <!--<setting name="lazyLoadingEnabled" value="true"/>-->
            <!--&lt;!&ndash;關閉mybatis支持立即加載,默認true:mybatis < 3.4.1&ndash;&gt;-->
            <!--<setting name="aggressiveLazyLoading" value="false"/>-->
        <!--</settings>-->
        <!--自定義爲配置文件取別名-->
        <typeAliases>
            <package name="com.liuzeyu.domin"/>
        </typeAliases>
        <!-- mysql配置文件 -->
        <environments default="mysql">
            <environment id="mysql">
                <!-- JDBC事物-->
                <transactionManager type="JDBC"></transactionManager>
                <!-- JDBC連接池 -->
                <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>
            <package name="com.liuzeyu.dao"></package>
        </mappers>
    </configuration>
    
    
    1. 測試函數
    public class Test {
        private InputStream is = null;
        private IAccountDao accountDao = null;
        private  SqlSession session = null;
        /**
         * 初始化
         * @throws IOException
         */
        @Before  //測試開始前執行
        public void init() throws IOException {
            //1.解析xml配置文件
            is = Resources.getResourceAsStream("SqlMapConfig.xml");
            //2.構建工廠
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
            //3.工廠生產SqlSession對象
            session = factory.openSession();
            //session = factory.openSession(true);  //設置事物的自動提交,可以不用//session.commit();
            //4.創建代理Dao的對象
            accountDao = session.getMapper(IAccountDao.class);
        }
        @After //測試結束後執行
        public void destory(){
            //session.commit();
            //7.釋放資源
            if( session != null){
                session.close();
            }
            if( is != null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        @org.junit.Test
        public void testSelect() throws IOException {
            //5.使用代理對象執行方法
            List<Account> accounts = accountDao.findAll();
        }
        
    }
    
    
    1. 測試結果
      1. 如果在主配置文件中不配置懶加載
        在這裏插入圖片描述
      2. 如果在主配置文件中配置懶加載
        在這裏插入圖片描述
        由以上日誌信息可知,如果不配置懶加載,就會去根據id查詢用戶表的信息,配置了懶加載,則不會去查詢用戶表。

演示2:用戶和賬戶的關係,一對多(用戶 | 賬戶)
在演示1的基礎上添加

  1. 映射配置IUserDao.xml文件添加

    <resultMap id="userMap" type="user">
        <id property="id" column="id"/>
        <result property="address" column="address"/>
        <result property="sex" column="sex"/>
        <result property="birthday" column="birthday"/>
        <result property="username" column="username"/>
        <collection property="accounts"   column="id" select="com.liuzeyu.dao.IAccountDao.findByUid"/>
    </resultMap>
    
    <!-- 根據id查找一個 -->
    <select id="findAll" resultMap="userMap">
    	select * from user
    </select>
    
  2. 映射配置IAccountDao.xml文件添加

        <!-- 打印uid查詢賬戶 -->
        <select id="findByUid" resultType="account" parameterType="int">
            SELECT * from account where uid=#{uid}
        </select>
    
  3. 測試函數

    public class UserTest {
        private InputStream is = null;
        private IUserDao userDao = null;
        private  SqlSession session = null;
        /**
         * 初始化
         * @throws IOException
         */
        @Before  //測試開始前執行
        public void init() throws IOException {
            //1.解析xml配置文件
            is = Resources.getResourceAsStream("SqlMapConfig.xml");
            //2.構建工廠
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
            //3.工廠生產SqlSession對象
            session = factory.openSession();
            //session = factory.openSession(true);  //設置事物的自動提交,可以不用//session.commit();
            //4.創建代理Dao的對象
            userDao = session.getMapper(IUserDao.class);
        }
        @After //測試結束後執行
        public void destory(){
            //session.commit();
            //7.釋放資源
            if( session != null){
                session.close();
            }
            if( is != null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        @org.junit.Test
        public void testSelect() throws IOException {
            //5.使用代理對象執行方法
            List<User> users = userDao.findAll();
        }
    }
    
  4. 測試結果

    1. 在主配置文件中不設置懶加載(默認立即加載)
      在這裏插入圖片描述
    2. 在主配置文件中設置懶加載
      在這裏插入圖片描述

2. MyBatis的緩存

  1. 什麼是緩存?
    答:存在於內存當中的臨時數據。

  2. 爲什麼使用緩存?
    答:減少與數據庫直接打交道,提高執行效率。

  3. 什麼樣的數據適用緩存,什麼樣的數據不適用?

    1. 適用緩存:
      • 不經常改變的數據
      • 並且緩存數據和數據庫不同步時最終影響不大
    2. 不適用緩存:
      • 經常改變的數據
      • 並且緩存數據和數據庫不同步時最終影響很大,如商品的庫存,銀行的匯率,股市的牌價等等
  4. MyBatis的一級緩存:一級緩存SqlSession對象範圍的緩存,當我們執行查詢之後,查詢結果會同時存入SqlSession爲我們提供的一塊區域中,該區域的結構是Map,當我們再次查詢到同樣的數據時mybatis會先從sqlSession中獲取。當調用SqlSession增刪改,commit(),close()時就會清空一級緩存。
    示例:

    1. 準備User實體類
    package com.liuzeyu.domin;
    
    import java.util.Date;
    import java.util.List;
    
    public class User {
        private Integer id;
        private String address;
        private String username;
        private String sex;
        private Date birthday;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getSex() {
            return sex;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }
    
        public Date getBirthday() {
            return birthday;
        }
    
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
    }
    
    
    1. 準備映射配置文件
    <?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.liuzeyu.dao.IUserDao">
        <!-- 根據id查找一個 -->
        <select id="findById" resultType="user" parameterType="int">
            select * from user where id=#{uid}
        </select>
    
        <!-- 根據id查找一個 -->
        <select id="updateByUser" parameterType="user">
        update user set username=#{username} where id=#{id}
        </select>
    </mapper>
    
    
    1. dao層接口
    public interface IUserDao {
    
        //根據id查找一個
        public User findById(Integer id);
    
        //根據id查找一個
        public void  updateByUser(User user);
    }
    
    1. 測試函數
    public class UserTest {
        private InputStream is = null;
        private IUserDao userDao = null;
        private  SqlSession session = null;
        SqlSessionFactory factory = null;
        /**
         * 初始化
         * @throws IOException
         */
        @Before  //測試開始前執行
        public void init() throws IOException {
            //1.解析xml配置文件
            is = Resources.getResourceAsStream("SqlMapConfig.xml");
            //2.構建工廠
            factory = new SqlSessionFactoryBuilder().build(is);
            //3.工廠生產SqlSession對象
            session = factory.openSession();
            //session = factory.openSession(true);  //設置事物的自動提交,可以不用//session.commit();
            //4.創建代理Dao的對象
            userDao = session.getMapper(IUserDao.class);
        }
        @After //測試結束後執行
        public void destory(){
            //session.commit();
            //7.釋放資源
            if( session != null){
                session.close();
            }
            if( is != null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    //    測試一級緩存session.clearCache();
        @org.junit.Test
        public void testSelect() throws IOException {
            //5.使用代理對象執行方法
            User users1 = userDao.findById(41);
            System.out.println(users1);
            session.clearCache();
            User users2 = userDao.findById(41);
            System.out.println(users2);
            System.out.println(users1 == users2);
        }
    
        //測試一級緩存:sqlSession的更新操作
        @org.junit.Test
        public void testUpdate() throws IOException {
            //5.使用代理對象執行方法
            User users1 = userDao.findById(41);
            System.out.println(users1);
            users1.setUsername("SqlSession update");
    
            userDao.updateByUser(users1);
            User users2 = userDao.findById(41);
            System.out.println(users2);
            System.out.println(users1 == users2);  //false
        }
        //測試一級緩存:sqlSession.close();
        @org.junit.Test
        public void testClose() throws IOException {
            //5.使用代理對象執行方法
            User users1 = userDao.findById(41);
            System.out.println(users1);
            session.close();
            SqlSession session = factory.openSession();
            IUserDao userDao = session.getMapper(IUserDao.class);  //true
    
            userDao.updateByUser(users1);
            User users2 = userDao.findById(41);
            System.out.println(users2);
            System.out.println(users1 == users2);   //false
        }
    }
    
    

    留下疑問:爲什麼SqlSession的更新和刪除操作,並沒有清空緩存?

  5. Mybatis的二級緩存:它是指Mybatis的SqlSessionFactory對象緩存,在同一個SqlSessionFactory創建的SqlSession對象內共享緩存。
    在這裏插入圖片描述

    二級緩存的使用步驟:

    1. 讓MyBatis框架支持二級緩存(在SqlMapConfig.xml中配置)
        <settings>
            <setting name="cacheEnabled" value="true"/>
        </settings>
    
    1. 讓接口配置文件支持二級緩存,在IUserDao.xml中配置
        <!--開啓配置文件二級緩存-->
        <cache/>
    
    1. 讓當前操作系統支持二級緩存(在接口配置文件的select 標籤中配置)
    
        <!-- useCache="true" -->
        <select id="findById" resultType="user" parameterType="int" useCache="true">
            select * from user where id=#{uid}
        </select>
    

    示例:
    在一級緩存的基礎項目上,新建測試函數

package com.liuzeyu.test;

import com.liuzeyu.dao.IUserDao;
import com.liuzeyu.domin.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;

import java.io.IOException;
import java.io.InputStream;

public class UserTest2 {
    private InputStream is = null;
    SqlSessionFactory factory = null;
    /**
     * 初始化
     * @throws IOException
     */
    @Before  //測試開始前執行
    public void init() throws IOException {
        //1.解析xml配置文件
        is = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.構建工廠
        factory = new SqlSessionFactoryBuilder().build(is);
    }
    @After //測試結束後執行
    public void destory(){
        if( is != null){
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
//    測試一級緩存session.clearCache();
    @org.junit.Test
    public void testSecondCash() throws IOException {
        SqlSession session1 = factory.openSession();
        IUserDao userDao1 = session1.getMapper(IUserDao.class);
        User user1 = userDao1.findById(41);
        System.out.println(user1);
        session1.close();

        SqlSession session2 = factory.openSession();
        IUserDao userDao2 = session2.getMapper(IUserDao.class);
        User user2 = userDao2.findById(41);
        System.out.println(user2);
        session2.close();

        System.out.println(user1 == user2);
    }

}

未配置二級緩存:
在這裏插入圖片描述
配置二級緩存:
在這裏插入圖片描述
可見兩個不同的Sqlsession對象共享二級緩存區域,session1將查詢的數據放到了二級緩存中,第二次查詢就無需重新連接數據庫查詢了。

3. MyBatis註解開發

  1. 環境搭建

    1. 準備實體類
    package com.liuzeyu.domain;
    
    import java.io.Serializable;
    import java.util.Date;
    
    public class User implements Serializable {
        private Integer id;
        private String username;
        private Date birthday;
        private String sex;
        private String address;
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", username='" + username + '\'' +
                    ", birthday=" + birthday +
                    ", sex='" + sex + '\'' +
                    ", adress='" + address + '\'' +
                    '}';
        }
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public Date getBirthday() {
            return birthday;
        }
    
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
    
        public String getSex() {
            return sex;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String adress) {
            this.address = adress;
        }
    }
    
    
    1. 主配置文件
    <?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>
        <!--加載配置文件-->
        <properties resource="jdbcConfig.properties"/>
        <!--取別名-->
        <typeAliases>
            <package name="com.liuzeyu.domain"/>
        </typeAliases>
        <!-- 配置環境 -->
        <environments default="mysql">
            <!-- 配置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>
            <!--<mapper class="com.liuzeyu.dao.IUserDao"/>-->
            <package name="com.liuzeyu.dao"/>
        </mappers>
    </configuration>
    
    1. dao層接口
    public interface IUserDao {
    
        @Select("select * from user")
        public List<User> findAll();
    }
    
    1. 測試函數
    public class AnnotationTest {
    
        public static void main(String[] args) throws Exception{
            //1.加載配置文件
            InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
            //2.創建SqlSessiionFactory
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
            //3.創建SqlSession對象
            SqlSession sqlSession = factory.openSession();
            //4.創建dao接口的代理dao
            IUserDao userDao = sqlSession.getMapper(IUserDao.class);
            //5.代理dao執行
            List<User> users = userDao.findAll();
            //6.遍歷
            for (User user : users) {
                System.out.println(user);
            }
            //7.釋放資源
            sqlSession.close();
            is.close();
    
        }
    }
    
    
    1. 查詢結果
      在這裏插入圖片描述
    2. 注意事項1:
      如果使用註解配置,只要是在resource存在,如下目錄結構的映射文件
      在這裏插入圖片描述
      無論是否在主配置文件中配置mapper映射文件的class屬性,mybatis都會認爲這是錯誤的,因爲他不認識你是否要用註解開發
      在這裏插入圖片描述
      注意事項2:
      註解開發與映射配置文件的區別,爲什麼可以使用註解開發?
      在這裏插入圖片描述
      由此配置文件有的,註解也都能提供。
  2. 單表CRUD操作

    1. 在1的基礎上操作,爲dao層接口添加如下GRUD操作
    public interface IUserDao {
    
        @Select("select * from user")
        public List<User> findAll();
    //插入一個用戶
        @Select("insert into user(username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address})")
        public List<User> insertUser(User user);
    
    //根據id查找某一用戶
        @Select("select * from user where id=#{id}")
        public User findById(Integer id);
    // 根據id刪除某一用戶
        @Delete("delete from user where id=#{id}")
        public void deleteById(Integer id);
    // 根據id更新某一用戶的用戶名
        @Update("update user set username=#{username} where id=#{id}")
        public void Update(User user);
    	// 根據name刪除某一用戶集合
        //@Select("select * from user where username like '%${username}%'")  不推薦使用
        @Select("select * from user where username like #{username}")
        public List<User> findByName(User user);
    }
    
    
    1. 測試函數
    public class AnnotationTestCRUD {
    
        private InputStream is = null;
        private SqlSession sqlSession = null;
        private SqlSessionFactory factory  = null;
        private IUserDao dao = null;
    
        @Before
        public void init() throws IOException {
            //1.加載配置文件
            is = Resources.getResourceAsStream("SqlMapConfig.xml");
            //2.創建工廠
            factory = new SqlSessionFactoryBuilder().build(is);
            //3.創建SqlSession對象
            sqlSession = factory.openSession(true);
            //4.創建代理dao對象
             dao = sqlSession.getMapper(IUserDao.class);
        }
    
        @After
        public void destory() throws IOException {
            if(sqlSession != null){
                sqlSession.close();
            }
            if(is != null){
                is.close();
    
            }
        }
    
        /**
         * 插入一個用戶
         */
        @Test
        public void testInsert(){
            User user = new User();
            user.setUsername("JAY");
            user.setAddress("莆田");
            user.setSex("男");
            user.setBirthday(new Date());
    
            dao.insertUser(user);
        }
    
        /**
         * 刪除一個用戶
         */
        @Test
        public void testDelete(){
            dao.deleteById(50);
        }
    
        /**
         * 根據id查找某一用戶
         */
        @Test
        public void testFindById(){
            User user = dao.findById(41);
            System.out.println(user);
        }
    
        /**
         * 更新某一用戶
         */
        @Test
        public void testUpdate(){
            User user = dao.findById(51);
            user.setUsername("Jack");
            dao.Update(user);
        }
    
        /**
         * 根據id查找某一用戶
         */
        @Test
        public void testFindByNames(){
            User user = new User();
    		//user.setUsername("%王%");
            user.setUsername("王");
            List<User> users  = dao.findByName(user);
            for (User u : users) {
                System.out.println(u);
            }
        }
    }
    
    
  3. 解決實體類屬性名和數據庫字段名不一致問題

    1. 在1的基礎上修改字段名,並生成對應的setXXX,getXXX方法
    
    public class User implements Serializable {
        private Integer userId;
        private String userName;
        private Date userBirthday;
        private String userSex;
        private String userAddress;
    
        @Override
        public String toString() {
            return "User{" +
                    "userId=" + userId +
                    ", userName='" + userName + '\'' +
                    ", userBirthday=" + userBirthday +
                    ", userSex='" + userSex + '\'' +
                    ", userAddress='" + userAddress + '\'' +
                    '}';
        }
    
        public Integer getUserId() {
            return userId;
        }
    
        public void setUserId(Integer userId) {
            this.userId = userId;
        }
    
        public String getUserName() {
            return userName;
        }
    
        public void setUserName(String userName) {
            this.userName = userName;
        }
    
        public Date getUserBirthday() {
            return userBirthday;
        }
    
        public void setUserBirthday(Date userBirthday) {
            this.userBirthday = userBirthday;
        }
    
        public String getUserSex() {
            return userSex;
        }
    
        public void setUserSex(String userSex) {
            this.userSex = userSex;
        }
    
        public String getUserAddress() {
            return userAddress;
        }
    
        public void setUserAddress(String userAddress) {
            this.userAddress = userAddress;
        }
    }
    
    
    1. 刪除不需要的dao方法
    public interface IUserDao {
    
        @Select("select * from user")
        public List<User> findAll();
    
        @Select("insert into user(username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address})")
        public List<User> insertUser(User user);
    
        @Select("select * from user where id=#{id}")
        public User findById(Integer id);
    
    }
    
    1. 測試findAll方法,可見並沒有被封裝進去
      在這裏插入圖片描述
    2. 解決實體類和數據庫字段對應關係
      在dao層函數上添加,與接口配置文件的resultMap標籤作用相同
        @Select("select * from user")
        @Results(id = "userMap",value = {
                @Result(id = true,property = "userId" ,column = "id"),
                @Result(property = "userName",column = "username"),
                @Result(property = "userBirthday",column = "birthday"),
                @Result(property = "userSex",column = "sex"),
                @Result(property = "userAddress",column = "address")
        })
        public List<User> findAll();
    
    1. 測試findAll
      在這裏插入圖片描述
    2. 如果需要在其它地方引用則個Map,可以使用註解ResultMap的value字段引用即可
    
        //@ResultMap(value = {"userMap"}) 簡寫如下
        @ResultMap("userMap")
        @Select("select * from user where id=#{id}")
        public User findById(Integer id);
    
    1. 測試findById
      在這裏插入圖片描述
  4. 多表查詢操作

    1. 賬戶和用戶的關係(賬戶 | 用戶,多對一) mybatis稱之爲:一對一的關係

      1. 在4的基礎上新增Account類
      public class Account implements Serializable{
          private Integer id;
          private Integer uid;
          private Double money;
      
          private User user;
      
          public User getUser() {
              return user;
          }
      
          public void setUser(User user) {
              this.user = user;
          }
      
      
          @Override
          public String toString() {
              return "Account{" +
                      "id=" + id +
                      ", uid=" + uid +
                      ", money=" + money +
                      ", user=" + user +
                      '}';
          }
      
          public Integer getId() {
              return id;
          }
      
          public void setId(Integer id) {
              this.id = id;
          }
      
          public Integer getUid() {
              return uid;
          }
      
          public void setUid(Integer uid) {
              this.uid = uid;
          }
      
          public Double getMoney() {
              return money;
          }
      
          public void setMoney(Double money) {
              this.money = money;
          }
      }
      
      
      1. 新增IAccountDao接口及方法
      import java.util.List;
      
      
      public interface IAccountDao {
      
          @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 = @One(select = "com.liuzeyu.dao.IUserDao.findById",fetchType = FetchType.LAZY))
          })
          public List<Account> findAll();
      }
      
      
      1. 測試方法
      public class AnnotationTestAccount {
      
          private InputStream is = null;
          private SqlSession sqlSession = null;
          private SqlSessionFactory factory  = null;
          private IAccountDao dao = null;
      
          @Before
          public void init() throws IOException {
              //1.加載配置文件
              is = Resources.getResourceAsStream("SqlMapConfig.xml");
              //2.創建工廠
              factory = new SqlSessionFactoryBuilder().build(is);
              //3.創建SqlSession對象
              sqlSession = factory.openSession(true);
              //4.創建代理dao對象
               dao = sqlSession.getMapper(IAccountDao.class);
          }
      
          @After
          public void destory() throws IOException {
              if(sqlSession != null){
                  sqlSession.close();
              }
              if(is != null){
                  is.close();
      
              }
          }
          /**
           * 查找所有
           */
          @Test
          public void testFindAll(){
              List<Account> accounts = dao.findAll();
              for (Account account : accounts) {
                  System.out.println(account);
              }
          }
      
      1. 測試結果
        在這裏插入圖片描述
    2. 用戶和賬戶的關係(用戶 | 賬戶 ,一對多)

      1. User實體類添加屬性Account集合
          private List<Account> accounts;
      
          public List<Account> getAccounts() {
              return accounts;
          }
      
          public void setAccounts(List<Account> accounts) {
              this.accounts = accounts;
          }
      
      
      1. 在5.1的基礎上新增dao層IAccount接口方法
      userId  屬性值
      <!-- 通過uid查詢賬戶-->
      @Select("select * from account where uid=#{userId}")
      public Account findByUid(Integer id);
      
      1. 修改IUserDao的接口方法
      public interface IUserDao {
      
          @Select("select * from user")
          @Results(id = "userMap",value = {
                  @Result(id = true,property = "userId" ,column = "id"),
                  @Result(property = "userName",column = "username"),
                  @Result(property = "userBirthday",column = "birthday"),
                  @Result(property = "userSex",column = "sex"),
                  @Result(property = "userAddress",column = "address"),
                  @Result(property = "accounts",column = "id",
                          many = @Many(select = "com.liuzeyu.dao.IAccountDao.findByUid",fetchType= FetchType.LAZY))
          })
          public List<User> findAll();
      
      }
      
      
      1. 新增測試方法
      public class AnnotationTestCRUD {
      
          private InputStream is = null;
          private SqlSession sqlSession = null;
          private SqlSessionFactory factory  = null;
          private IUserDao dao = null;
      
          @Before
          public void init() throws IOException {
              //1.加載配置文件
              is = Resources.getResourceAsStream("SqlMapConfig.xml");
              //2.創建工廠
              factory = new SqlSessionFactoryBuilder().build(is);
              //3.創建SqlSession對象
              sqlSession = factory.openSession(true);
              //4.創建代理dao對象
               dao = sqlSession.getMapper(IUserDao.class);
          }
      
          @After
          public void destory() throws IOException {
              if(sqlSession != null){
                  sqlSession.close();
              }
              if(is != null){
                  is.close();
      
              }
          }
          /**
           * 查找所有
           */
          @Test
          public void testFindAll(){
              List<User> users = dao.findAll();
              for (User user : users) {
                  System.out.println(user);
              }
          }
      }
      
      
      1. 測試結果
        在這裏插入圖片描述
  5. 緩存配置

    1. 一級緩存默認開啓,共享SqlSession
          @Test
          public void testFindById(){
              User user1 = dao.findById(41);
              //sqlSession.clearCache();  開啓後  user1 == user2爲false
              User user2 = dao.findById(41);
              System.out.println(user1 == user2);  //true
          }
      
    2. 二級緩存的配置
      1. 新增類測試二級緩存
      public class AnnotationTestSecondLevel {
      
          private InputStream is = null;
          private SqlSessionFactory factory = null;
      
          @Before
          public void init() throws IOException {
              //1.加載配置文件
              is = Resources.getResourceAsStream("SqlMapConfig.xml");
              factory = new SqlSessionFactoryBuilder().build(is);
          }
      
          @After
          public void destory() throws IOException {
              if(is != null){
                  is.close();
      
              }
          }
      
          /**
           * 測試二級緩存
           */
          @Test
          public void testSecondLevel(){
              SqlSession sqlSession1 = factory.openSession(true);
              IUserDao dao1 = sqlSession1.getMapper(IUserDao.class);
              User user1 = dao1.findById(41);
              System.out.println(user1);
              sqlSession1.close();
      
      
              SqlSession sqlSession2 = factory.openSession(true);
              IUserDao dao2 = sqlSession2.getMapper(IUserDao.class);
              User user2 = dao2.findById(41);
              System.out.println(user2);
              sqlSession2.close();
          }
      
      }
      
      
      這裏需注意的是必須是同一個工廠對象factory纔可以共享二級緩存。
      1. 還未配置二級緩存前,測試結果
        在這裏插入圖片描述
      2. 配置二級緩存
        1. 主配置文件開啓二級緩存,注意要寫到加載配置文件後
              <!--開啓二級緩存-->
              <settings>
                  <setting name="cacheEnabled" value="true"/>
              </settings>
          
        2. dao層接口
          在這裏插入圖片描述
        3. 重新運行測試函數,此時只打開一次數據庫連接
          在這裏插入圖片描述
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章