mybatis延迟加载、缓存及逆向工程

1,myibatis延迟加载

存在多表关联查询时,不需要一下子把全部表都拿出来的时候,可以采用延迟加载,先取出单表,等需要时再取出其他表,这样可以大幅提高数据库性能。

相关table可自行建立,目录结构如下:

(1)延迟加载测试方法:

// 延迟加载测试
    @Test
    public void testfindOrdersUserLazyLoad(){
        SqlSession session = MybatisUtil.getSqlSession();
        OrdersMapper mapper = session.getMapper(OrdersMapper.class);
        List<Orders> list = mapper.findOrdersUserLazyLoad();
        
        for (Orders orders : list) {
            System.out.println(orders.getUser());
        }
    }

(2)findOrdersUserLazyLoad相关的OrdersMapper.xml配置:

<!-- 延迟加载方式  查询订单信息并关联查询用户信息 -->
    <select id="findOrdersUserLazyLoad" resultMap="LazyLoadFindOrdersUser">
        SELECT * FROM orders
    </select>

<!-- 延迟加载示例映射 -->
    <resultMap type="com.mybatis.model.Orders" id="LazyLoadFindOrdersUser">
        <!-- 定义订单信息映射 -->
        <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:指定需要延迟加载的statemet的id,如果不在当前的mapper.xml文件中,
                                    则需要在前面加上对应的namespace
            coLumn:指定关联查询的列   user_id
         -->
        <association property="user" javaType="com.mybatis.model.User"
            select="com.mybatis.mapper.UserMapper.findById"
            column="user_id" >
        </association>
    </resultMap>

延迟加载配置的核心就在于association里的配置,property表示要将查询的结果注入到那个属性中,由于它是个集合,需要javaType表示集合里元素的类型,coLumn:指定关联查询的列 。

(3)设置总的配置文件的延迟加载属性

    <settings>
        <!-- 开启延迟加载 -->
        <setting name="lazyLoadingEnabled" value="true"/>
    </settings>

(4)结果展示

List<Orders> list = mapper.findOrdersUserLazyLoad();  这一步时仅会发出请求查询orders:

[DEBUG] - ==>  Preparing: SELECT * FROM orders 
[DEBUG] - ==> Parameters: 
[DEBUG] - <==      Total: 3

System.out.println(orders.getUser());   到了这一步时,由于要调用user时,所以会去查找users,之后的循环没有发出sql:
[DEBUG] - ==>  Preparing: select * from user where id = ? 
[DEBUG] - ==> Parameters: 1(Integer)
[DEBUG] - <==      Total: 1
[DEBUG] - ==>  Preparing: select * from user where id = ? 
[DEBUG] - ==> Parameters: 10(Integer)
[DEBUG] - <==      Total: 1

每根据一个user_id进行一次查询是否效率很低?

(5)aggressiveLazyLoading属性

如果在setting中加入 <setting name="aggressiveLazyLoading" value="false"/>

当设置为‘true’的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载。

这句话有点绕,实际效果如下说明:

List<Orders> list = mapper.findOrdersUserLazyLoad();  此时只执行一个sql:

[DEBUG] - ==>  Preparing: SELECT * FROM orders 
[DEBUG] - ==> Parameters: 
[DEBUG] - <==      Total: 3

for (Orders orders : list) {  到了这一步也没有发出sql

System.out.println(orders.getUser());  在方法体里,每一次循环再发出一次sql(这种方式让延迟加载按需执行)

[DEBUG] - ==>  Preparing: select * from user where id = ? 
[DEBUG] - ==> Parameters: 1(Integer)
[DEBUG] - <==      Total: 1

但是测试的时候发现aggressiveLazyLoading设为true和false发出的sql是一样的,发出sql顺序相同,没发现区别,对懒加载也没影响。可能是同时存在两个懒属性时,调用其中一个,是否会加载其他懒属性的一个区分。

2,mybaits提供一级缓存,和二级缓存。

一级缓存SqlSession级别的缓存,同一数据可以保存在同一个

二级缓存是mapper级别,多个SqlSession去操作同一个Mapper的sql语句,不用重复发送sql请求。

一级缓存比较简单,同一条sql,查了一次就不会重复查,不用配置,当其他语句更新了数据之后,通过commit更新后再查即可即可。

不过测试的过程很有意思,如下代码:

@Test
    public void testFindUser(){
        SqlSession session = MybatisUtil.getSqlSession();
        UserMapper mapper = session.getMapper(UserMapper.class);
        
//        SqlSession session2 = MybatisUtil.getSqlSession();
//        UserMapper mapper2 = session2.getMapper(UserMapper.class);
        User user = mapper.findById(1);
//        User user2 = mapper2.findById(1);
        
        /*
         * 执行了(更新,插入,删除),会自动清空sqlsession的一级缓存,
         * 目的:为了避免脏读,保持缓存中数据是最新的
         */
        User userrUser = new User();
        userrUser.setId(1);
        userrUser.setUsername("aaaaaaa");
        mapper.updateUser(userrUser);
        // 执行了更新,插入,删除操作后,需要执行 commit  提交
//        session.commit();
        
        User user1 = mapper.findById(1);
        
        System.out.println(user);
        System.out.println(user1);
        session.close();
    }

发现即使session没有commit,虽然只发出了一条sql,但是user1依然改变了username,很神奇。是不是说mybatis有一套机制避免脏读?

二级缓存同事在SqlMapConfig.xml和相关mapper.xml设置二级缓存即可。

SqlMapConfig.xml:

<settings>
        <!-- 开启二级缓存 -->
        <setting name="cacheEnabled" value="true" />
</settings>

UserMapper.xml:

<!-- 开启本mapper namespace下的二级缓存 -->
    <cache/>

或者:<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>   (ehcache是一个分布式缓存框架)

测试方法:

@Test
    public void testErJiFindUser(){
        SqlSession session = MybatisUtil.getSqlSession();
        UserMapper mapper = session.getMapper(UserMapper.class);

        SqlSession session2 = MybatisUtil.getSqlSession();
        UserMapper mapper2 = session2.getMapper(UserMapper.class);
        
        SqlSession session3 = MybatisUtil.getSqlSession();
        UserMapper mapper3 = session3.getMapper(UserMapper.class);
        
        User user = mapper.findById(1);
        System.out.println(user.getUsername());
        // 执行关闭以后,才会将数据缓存到二级缓存中
        session.close();
        
        User user2 = mapper2.findById(1);
        System.out.println(user2.getUsername());
        session2.close();
        
        /*
         * 执行了(更新,插入,删除),会自动清空sqlsession的一级缓存,
         * 目的:为了避免脏读,保持缓存中数据是最新的
         */
//        User userrUser = new User();
//        userrUser.setId(1);
//        userrUser.setUsername("aaaaaaa");
//        int i = mapper3.updateUser(userrUser);
//        System.out.println(i);
//        // 执行了更新,插入,删除操作后,需要执行 commit  提交
//        session3.commit();
//        
    }

没开启二级缓存,则会发出三条select语句。

开启二级缓存后

[DEBUG] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@223f3642]
[DEBUG] - ==>  Preparing: select * from user where id = ? 
[DEBUG] - ==> Parameters: 1(Integer)
[DEBUG] - <==      Total: 1
王五
[DEBUG] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@223f3642]
[DEBUG] - Closing JDBC Connection [

可以看出,这时只发出了一条sql。这里启用二级缓存的xml生成了一个HashMap,总的配置文件为何也要配置二级缓存?估计是为了整体管理

在statement中设置useCache=false可以禁用当前select语句的二级缓存:

<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">

为避免脏读,一个方法是commit,一个是加入flushCache="true":

<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" flushCache="true">

3,mybatis的逆向工程

mybatis的逆向工程是通过如下jar包实现的

在项目的classpath配置generatorConfig.xml 如下:

<?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/test" 
            userId="root"
            password="123456">
        </jdbcConnection>
        <!-- <jdbcConnection driverClass="oracle.jdbc.OracleDriver"
            connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:aaaaaa" 
            userId="aaaaaa"
            password="aaaaaa">
        </jdbcConnection> -->

        <!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL 和 
            NUMERIC 类型解析为java.math.BigDecimal -->
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>

        <!-- targetProject:生成PO类的位置 -->
        <javaModelGenerator targetPackage="com.mybatis.model"
            targetProject="d:\">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
            <!-- 从数据库返回的值被清理前后的空格 -->
            <property name="trimStrings" value="true" />
        </javaModelGenerator>
        <!-- targetProject:mapper映射文件生成的位置 -->
        <sqlMapGenerator targetPackage="com.mybatis.mapper" 
            targetProject="d:\">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
        </sqlMapGenerator>
        <!-- targetPackage:mapper接口生成的位置 -->
        <javaClientGenerator type="XMLMAPPER"
            targetPackage="com.mybatis.mapper" 
            targetProject="d:\">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
        </javaClientGenerator>
        <!-- 指定数据库表 -->
        <table tableName="items"></table>
        <!-- <table schema="" tableName="sys_user"></table> -->
        
        <!-- 有些表的字段需要指定java类型
         <table schema="" tableName="">
            <columnOverride column="" javaType="" />
        </table> -->
    </context>
</generatorConfiguration>
 

在测试类中输出如下:

package com.mybatis.test;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.exception.XMLParserException;
import org.mybatis.generator.internal.DefaultShellCallback;

public class GeneratorSqlmap {

    public void generator() throws Exception{

        List<String> warnings = new ArrayList<String>();
        boolean overwrite = true;
        //指定 逆向工程配置文件
        File configFile = new File("d:/generatorConfig.xml"); 
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(configFile);
        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
                callback, warnings);
        myBatisGenerator.generate(null);

    } 
    public static void main(String[] args) throws Exception {
        try {
            GeneratorSqlmap generatorSqlmap = new GeneratorSqlmap();
            generatorSqlmap.generator();
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }

}
即可在d盘生成逆向工程项目

猜你喜欢

转载自blog.csdn.net/qq_22059611/article/details/82882600
今日推荐