Mybatis总结

之前学过Hibernate,主要的印象就是ORM(对象关系映射),直接操作对象,无需自己书写sql语句,但是这样在关联查询时,效率较低,也不好做sql优化。

现在学习了Mybatis,稍作总结。

一、什么是Mybatis,Mybatis框架原理是什么?

  Mybatis也是JDBC操作的封装,属于半ORM框架,是一个持久层的框架,将sql语句写入xml配置文件,通过提供的映射方式,自由灵活的生成满足需要的sql语句。

  Mybatis的框架原理

  第一步:通过SqlMapConfig.xml,配置了数据源、事务等Mybatis的运行环境

  第二步:根据配置文件,创建SqlSessionFactory,使用单例模式,用来创建SqlSession

  第三步:SqlSession是一个接口,面向程序员的接口,用来操作数据库的增删改查

  第四步:Executor(执行器),是一个接口(基本执行器,缓存执行器),是在SqlSession内部通过执行器操作数据库

  第五步:mapped statement(底层封装对象),对操作数据库存储封装,包括sql语句,输入参数类型,输出结果类型。

  第六步:mysql上执行操作

二、Mybatis的核心配置文件SqlMapConfig.xml

  在sqlMapConfig.xml中的主要配置,其中包括settings标签,environments标签,mappers标签等。

  setting配置全局参数,mappers配置mapper.xml映射的引入(单个引入,批量引入)

  

  db.properties的配置文件

  

三、Mybatis的核心

  1、输入映射和输出映射

    这块主要是看mapper.xml配置文件

    举例,对用户表的操作

    用户表如下:

    

    UserMapper.xml配置如下:

    

    这里只是简单的输入映射和输出映射,mapper的namespace对应mapper映射接口(有点类似包的作用),主要的有select标签,insert标签,update标签,delete标签等。

    其中,id参数是标识(与mapper接口中的方法名一致),parameterType参数是输入映射,resultType参数是输出映射。

    值得注意的是除了resultType(查询到的列名和resultType指定的pojo的属性名一致,才会映射成功),还有resultMap,Mybatis可以使用自定义的resultMap完成高级映射。下面再举例讲。

    另外,#{} 表示占位符  ?  ,${} 表示拼接符  会导致sql注入  不推荐使用。

 

  2、mapper接口代理开发的方式

    这是在配置文件写好之后,再编写对应的mapper接口,需要与mapper.xml配置文件要同名,并放在一个包下

    举例,对应UserMapper.xml的UserMapper.java

    

    需要注意的是,UserMapper.java是一个接口,方法名与UserMapper.xml中id对应,方法的参数与parameterType对应,方法的返回值类型与resultType对应。 

    测试代码如下,sqlSessionFactory使用单例。

      

  3、原生Dao开发(主要还是用Mapper接口代理开发方式) 

    这部分和之前编写Dao一样,也是Dao接口,然后是DaoImpl类。

    举例,对用户表操作

    UserDao.java如下

    

    UserDaoImpl.java如下:

    

    这里主要注意的是SqlSession的方法,常用的selectOne(返回单个对象),selectList(返回集合对象),insert,update,delete等

    

    测试代码如下:

    

  4、动态sql语句

    这部分也是在Mapper.xml中配置的,通过表达式进行判断,对sql进行灵活拼接,组装。总之,根据不同的需求进行拼装。可以引用自定义的sql片段,不用重复书写同样的sql。

    根据需求进行举例。

    进行综合查询。在给定的几个id中查询对应性别和模糊查询姓名。

    所用到的po类,UserQueryVo类是专门用来测试用的po类,UserCutom类是User类的扩展类(在这里没有扩展什么,相当于一样)

    

    

    

    这里是UserMapper.xml中配置的,自定义的sql片段,以及引用sql片段。包括sql标签,if标签,foreach标签

    

    在where标签中,使用include标签根据sql片段的id,引用sql片段。注意where标签可以自动去除拼接条件中第一个and

    

    这里拼接的语句是select * from user where user.sex=? and user.username LIKE '%xxxx%'  and ( id=? or id =? or id =?)

    测试使用JUnit4。测试代码如下:

    综合查询:在给定的id为1,7,12中查询性别为1(男)和姓名中包含wzq的用户。

    

    这里很重要,也很灵活,需要根据不同的需求进行操作。

    2018.7.9 明天继续总结

四、高级结果集映射

   这里说的高级结果集映射包括一对一,一对多,多对多,其中po类中包含单个po类或者多个po类

   首先要学会分析数据库表。首先,按着模块进行查看所需的单个表内记录的内容;然后,查看每个表的重要字段,如非空字段,外键字段;再次,在数据库级别上查看表与表之间的主外键关系;最后,看表与表之间的业务关系。

   至于,高级结果集映射的主要配置是在mapper.xml中,根据自定义的resultMap进行映射。

   一对一查询,可以使用resultMap,也可以使用resultType。这里举例查询订单,关联查询下订单的用户信息。

   订单表和用户表如下:

         

   另外,补充一下order类

    

    UserMapper.xml的配置

    首先配置select查询,select标签的resultMap属性是根据resultMap的id来查找的。

    

    使用resultMap的自定义输出映射,需要注意的是resultMap标签中的属性type,id。还有id标签(主键id的配置),result标签(),以及association标签(关联对应的po类,再进行映射配置)。

    

    UserMapper.java中添加对应的方法名

    

    然后就是测试代码

    

    一对多查询,需求是还是查询订单,但关联查询订单详细条目

    订单详细条目表如下:

    

    订单详情表对应的pojo类,如下:

    

    首先也是配置mapper.xml,然后在mapper接口中添加对应id的方法名,最后通过测试代码实现。

    这里配置自定义的reusltMap时,继承了上面关联用户查询的resultMap,在查询时把用户信息和订单详情都查询出来啦。

    1.先上select标签,再就是resultMap标签

    值得注意的是order类中有成员变量list,在自定义resultMap中 使用collection标签进行映射

    

    

    2.在mapper接口中添加对应id的方法名

    

    3.进行测试

     

    多对多查询,查询用户信息和用户所购买的商品信息

    先看一下item表和item表对应的pojo类

      

    还是三步走,配置(select,resultMap),接口(添加方法名),测试(实现)。

    1.配置如下:

    

    然后配置resultMap

    

    2.mapper接口中添加对应的方法名

    

    3.测试

    

    到这里,一对一,一对多,多对多,都举例完成。

    主要是resultType和resultMap的用法,resultMap标签里的association和collection标签用来完成一对一和一对多的映射。

五、延迟加载和查询缓存

  1.延迟加载

   什么是延迟加载?

     延迟加载是先从单表查询,当需要时再从关联表去关联查询。

     为什么要延迟加载,延迟加载有什么好处?

     延迟加载能大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。

     如何实现延迟加载?

     可以使用association、collection来实现延迟加载的功能。

   具体做法,在mapper.xml中自定义的resultMap中的association、collection进行配置。

   在mapper.xml配置之前,需要在sqlMapConfig.xml中的settings标签中,开启延迟加载和关闭积极加载。

   

   举例说明,如查询订单,关联查询用户信息。先单表查询订单表,在需要用户信息时,再查询用户表。

   首先,在mapp.xml中配置两个select查询,再自定义resultMap进行延迟加载的配置。

   

   

   然后就是在mapper.java中添加方法。

   

   最后测试

   

   结果如下,并没有一次性关联查询出结果,在需要用户信息时才会去查询用户表。

    

  2.查询缓存

    Mybatis提供查询缓存,用于减轻数据压力,提高数据库性能,减少IO操作。

    Mybatis提供一级缓存和二级缓存。

    一级缓存,是sqlSession级别的缓存,在操作数据库时,需要构造一个sqlSession对象,这个对象里面有一个数据结构(HashMap),用于存储缓存数据。不同sqlSession之间的缓存数据区域是互不影响的。

    一级缓存是默认开启的,不需要在配置文件中配置。

    二级缓存,是mapper级别的缓存,多个sqlSession去操作同一个mapper的sql语句,多个sqlSession可以共用二级缓存,二级缓存是跨sqlSession。

    二级缓存是默认开启的,但是除了在sqlMapConfig.xml中有一个总开关外,还需在对应的mapper.xml中开启二级缓存。

    在sqlMapConfig.xml的settings标签内配置 <setting name= "cacheEnabled" value="true"/>

    在对应的maaper.xml中配置对应的<cache><cache/>

    

    在一级缓存中,当sqlSession查询完毕后,关闭时,Mybatis会清空一级缓存,并会将数据写入二级缓存,当另一个sqlSession查询同样数据时,会从二级缓存中取出。

    当sqlSession操作数据库进行数据更改后,提交commit()后,会清空二级缓存对应的数据,当再次查询时,会再次从发送sql从数据库中查询,再存入一级缓存,当sqlSession.close()之后,再写入二级缓存。

    二级缓存应用场景,对访问多的查询请求且用户对查询结果实时性要求不高的情况。比如耗时较高的统计分析sql,电话账单sql等。

    同时,二级缓存也有局限性,因为二级缓存是mapper级别的,比如商品信息,用户查询的都是最新的商品信息,当商品信息成千上万的在二级缓存中时,只要更新了一个商品信息,就会清空所有的商品信息。解决方法:可以从在业务层根据需求对数据有针对性缓存。

六、逆向工程

    Mybatis需要程序员自己书写sql,但是Mybatis也提供逆向工程,针对数据库的单表,自动生成所需的mapper.xml和mapper.java。

       运行逆向工程需要三步,第一步下载逆向工程的jar包,第二步配置生成代码的配置文件,第三步书写java生成程序,执行。(当然还有别的方法,请查询官网,常用的是使用java程序)

    第一步,jar包

    

    第二步,配置生成代码的配置文件

<generatorConfiguration>
    <!-- <classPathEntry location="F:\mybatis-generator-core-1.3.2\lib\mysql-connector-5.1.8.jar" /> -->
    <!--  -->
    <context id="sysGenerator" 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="root">
        </jdbcConnection>
        <!--  -->
        <javaTypeResolver>
            <!-- 默认为false JDBC DECIMAL和NUMERIC类型解析为Integer
                为true, JDBC DECIMAL和NUMERIC类型解析为BigDecimal -->
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>
        
        <!-- 生成po类的位置 -->
        <javaModelGenerator targetPackage="cn.itcast.ssm.po"
            targetProject="./src">
            <property name="enableSubPackages" value="false" />
            <property name="trimStrings" value="true" />
        </javaModelGenerator>
        <!-- mapper映射文件 -->
        <sqlMapGenerator targetPackage="cn.itcast.ssm.mapper"
            targetProject="./src">
            <property name="enableSubPackages" value="false" />
        </sqlMapGenerator>
        <!-- mapper接口 -->
        <javaClientGenerator type="XMLMAPPER"
            targetPackage="cn.itcast.ssm.mapper" targetProject="./src">
            <property name="enableSubPackages" value="false" />
        </javaClientGenerator>
        <!--指定数据库的表  -->
        <table tableName="user"></table>
        <table tableName="orders"></table>
        <table tableName="orderdetail"></table>
        <table tableName="items"></table>
    </context>
</generatorConfiguration>

    第三步,书写java程序生成

    

import java.io.File;
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.internal.DefaultShellCallback;

public class Generator {
    public void generator() throws Exception{
        List<String> warnings = new ArrayList<String>();
        boolean overwrite = true;
        File configFile = new File("config/generator.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 {
        Generator generator = new Generator();
        generator.generator();
    }
}

   逆向工程会使用就行。

   回头再总结一下Spring,Springmvc,整合SSM等。

posted @ 2018-07-09 16:45  oweiziqiango  阅读(150)  评论(0编辑  收藏  举报