Mybatis—延遲加載和逆向工程(十一)

上一篇文章我們講解了《Mybatis—spring和mybatis整合(十)》下面我們繼續來講解延遲加載和逆向工程。

【延遲加載】

1、什麼是延遲加載

resultMap可以實現高級映射(使用association、collection實現一對一及一對多映射),association、collection具備延遲加載功能。

需求:
如果查詢訂單並且關聯查詢用戶信息。如果先查詢訂單信息即可滿足要求,當我們需要查詢用戶信息時再查詢用戶信息。把對用戶信息的按需去查詢就是延遲加載。

延遲加載:先從單表查詢、需要時再從關聯表去關聯查詢,大大提高 數據庫性能,因爲查詢單表要比關聯查詢多張錶速度要快。

2、使用association實現延遲加載需求

查詢訂單並且關聯查詢用戶信息

3、mapper.xml

需要定義兩個mapper的方法對應的statement。
1)只查詢訂單信息
SELECT * FROM orders
在查詢訂單的statement中使用association去延遲加載(執行)下邊的satatement(關聯查詢用戶信息)


    <!-- 查詢訂單關聯查詢用戶,用戶信息需要延遲加載 -->
    <select id="findOrdersUserLazyLoading" resultMap="OrdersUserLazyLoadingResultMap">
        SELECT * FROM orders
    </select>

2)關聯查詢用戶信息
通過上邊查詢到的訂單信息中user_id去關聯查詢用戶信息
使用UserMapper.xml中的findUserById
這裏寫圖片描述
上邊先去執行findOrdersUserLazyLoading,當需要去查詢用戶的時候再去執行findUserById,通過resultMap的定義將延遲加載執行配置起來。

4、延遲加載resultMap

使用association中的select指定延遲加載去執行的statement的id。

<!-- 延遲加載的resultMap -->
    <resultMap type="cn.itcast.mybatis.po.Orders" id="OrdersUserLazyLoadingResultMap">
            <!--對訂單信息進行映射配置  -->
            <id column="id" property="id"/>
            <result column="user_id" property="userId"/>
            <result column="number" property="number"/>
            <result column="createtime" property="createtime"/>
            <result column="note" property="note"/>
            <!-- 實現對用戶信息進行延遲加載
            select:指定延遲加載需要執行的statement的id(是根據user_id查詢用戶信息的statement)
            要使用userMapper.xml中findUserById完成根據用戶id(user_id)用戶信息的查詢,如果findUserById不在本mapper中需要前邊加namespace
            column:訂單信息中關聯用戶信息查詢的列,是user_id
            關聯查詢的sql理解爲:
            SELECT orders.*,
    (SELECT username FROM USER WHERE orders.user_id = user.id)username,
    (SELECT sex FROM USER WHERE orders.user_id = user.id)sex
     FROM orders
             -->
            <association property="user"  javaType="cn.itcast.mybatis.po.User"
             select="cn.itcast.mybatis.mapper.UserMapper.findUserById" column="user_id">
            <!-- 實現對用戶信息進行延遲加載 -->

            </association>

    </resultMap>

5、mapper.java

    //查詢訂單關聯查詢用戶,用戶信息是延遲加載
    public List<Orders> findOrdersUserLazyLoading()throws Exception;

6、測試

1)測試思路

1、執行上邊mapper方法(findOrdersUserLazyLoading),內部去調用cn.itcast.mybatis.mapper.OrdersMapperCustom中的findOrdersUserLazyLoading只查詢orders信息(單表)。

2、在程序中去遍歷上一步驟查詢出的List,當我們調用Orders中的getUser方法時,開始進行延遲加載。

3、延遲加載,去調用UserMapper.xml中findUserbyId這個方法獲取用戶信息。

2)延遲加載配置

mybatis默認沒有開啓延遲加載,需要在SqlMapConfig.xml中setting配置。

在mybatis核心配置文件中配置:
lazyLoadingEnabled、aggressiveLazyLoading
這裏寫圖片描述
在SqlMapConfig.xml中配置:

<!-- 全局配置參數,需要時再設置 -->
    <settings>
        <!-- 打開延遲加載 的開關 -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!-- 將積極加載改爲消極加載即按需要加載 -->
        <setting name="aggressiveLazyLoading" value="false"/>
        <!-- 開啓二級緩存 -->
        <setting name="cacheEnabled" value="true"/>
    </settings>

3)測試代碼

    // 查詢訂單關聯查詢用戶,用戶信息使用延遲加載
    @Test
    public void testFindOrdersUserLazyLoading() throws Exception {
        SqlSession sqlSession = sqlSessionFactory.openSession();// 創建代理對象
        OrdersMapperCustom ordersMapperCustom = sqlSession
                .getMapper(OrdersMapperCustom.class);
        // 查詢訂單信息(單表)
        List<Orders> list = ordersMapperCustom.findOrdersUserLazyLoading();

        // 遍歷上邊的訂單列表
        for (Orders orders : list) {
            // 執行getUser()去查詢用戶信息,這裏實現按需加載
            User user = orders.getUser();
            System.out.println(user);
        }

    }

7、延遲加載思考

不使用mybatis提供的association及collection中的延遲加載功能,如何實現延遲加載??

實現方法如下:
定義兩個mapper方法:
1)查詢訂單列表
2)根據用戶id查詢用戶信息
實現思路:
先去查詢第一個mapper方法,獲取訂單信息列表
在程序中(service),按需去調用第二個mapper方法去查詢用戶信息。

總之:
使用延遲加載方法,先去查詢簡單的sql(最好單表,也可以關聯查詢),再去按需要加載關聯查詢的其它信息。

【逆向工程】

1、什麼是逆向工程

mybaits需要程序員自己編寫sql語句,mybatis官方提供逆向工程 可以針對單表自動生成mybatis執行所需要的代碼(mapper.java,mapper.xml、po..)

企業實際開發中,常用的逆向工程方式:
由於數據庫的表生成java代碼。

2、下載逆向工程

這裏寫圖片描述
建議使用java程序方式,不依賴開發工具。

3、使用方法(會用)

1)運行逆向工程

這裏寫圖片描述

2)生成代碼配置文件

代碼中黑色的字體是配置數據庫的時候要更改的內容

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
  PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
  "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <context id="testTables" targetRuntime="MyBatis3">
        <commentGenerator>
            <!-- 是否去除自動生成的註釋 true:是 : false:否 -->
            <property name="suppressAllComments" value="true" />
        </commentGenerator>
        <!--數據庫連接的信息:驅動類、連接地址、用戶名、密碼 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
            connectionURL="jdbc:mysql://localhost:3306/mybatis" **userId="root"
            password="mysql">**
        </jdbcConnection>
        <!-- <jdbcConnection driverClass="oracle.jdbc.OracleDriver"
            connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:yycg" 
            userId="yycg"
            password="yycg">
        </jdbcConnection> -->

        <!-- 默認false,把JDBC DECIMAL 和 NUMERIC 類型解析爲 Integer,爲 true時把JDBC DECIMAL 和 
            NUMERIC 類型解析爲java.math.BigDecimal -->
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>

        <!-- targetProject:生成PO類的位置 -->
        <javaModelGenerator targetPackage="cn.itcast.ssm.po"
            targetProject=".\src">
            <!-- enableSubPackages:是否讓schema作爲包的後綴 -->
            <property name="enableSubPackages" value="false" />
            <!-- 從數據庫返回的值被清理前後的空格 -->
            <property name="trimStrings" value="true" />
        </javaModelGenerator>
        <!-- targetProject:mapper映射文件生成的位置 -->
        <sqlMapGenerator targetPackage="cn.itcast.ssm.mapper" 
            targetProject=".\src">
            <!-- enableSubPackages:是否讓schema作爲包的後綴 -->
            <property name="enableSubPackages" value="false" />
        </sqlMapGenerator>
        <!-- targetPackage:mapper接口生成的位置 -->
        <javaClientGenerator type="XMLMAPPER"
            targetPackage="cn.itcast.ssm.mapper" 
            targetProject=".\src">
            <!-- enableSubPackages:是否讓schema作爲包的後綴 -->
            <property name="enableSubPackages" value="false" />
        </javaClientGenerator>
        <!-- 指定數據庫表 -->
        <table tableName="items"></table>
        <table tableName="orders"></table>
        <table tableName="orderdetail"></table>
        <table tableName="user"></table>


    </context>
</generatorConfiguration>

3)執行生成程序

這裏寫圖片描述
執行後的結果:
這裏寫圖片描述

4)使用生成的代碼

需要將生成工程中所生成的代碼拷貝到自己的工程中。

測試ItemsMapper中的方法

private ApplicationContext applicationContext;

    private ItemsMapper itemsMapper;

    //在setUp這個方法得到spring容器
    @Before
    public void setUp() throws Exception {
        applicationContext = new ClassPathXmlApplicationContext("classpath:spring/applicationContext.xml");
        itemsMapper = (ItemsMapper) applicationContext.getBean("itemsMapper");
    }


//自定義條件查詢
    @Test
    public void testSelectByExample() {
        ItemsExample itemsExample = new ItemsExample();
        //通過criteria構造查詢條件
        ItemsExample.Criteria criteria = itemsExample.createCriteria();
        criteria.andNameEqualTo("筆記本3");
        //可能返回多條記錄
        List<Items> list = itemsMapper.selectByExample(itemsExample);

        System.out.println(list);

    }

    //根據主鍵查詢
    @Test
    public void testSelectByPrimaryKey() {
        Items items = itemsMapper.selectByPrimaryKey(1);
        System.out.println(items);
    }


//插入
    @Test
    public void testInsert() {
        //構造 items對象
        Items items = new Items();
        items.setName("手機");
        items.setPrice(999f);
        itemsMapper.insert(items);
    }

//更新數據
    @Test
    public void testUpdateByPrimaryKey() {

        //對所有字段進行更新,需要先查詢出來再更新
        Items items = itemsMapper.selectByPrimaryKey(1);

        items.setName("水杯");

        itemsMapper.updateByPrimaryKey(items);
        //如果傳入字段不空爲才更新,在批量更新中使用此方法,不需要先查詢再更新
        //itemsMapper.updateByPrimaryKeySelective(record);

    }

小編關於Mybatis的系列博客就先寫到這裏,歡迎讀者們的閱讀。。。。

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