myBaits总结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/S_T_F666/article/details/82142349

1.总结原始dao开发问题

  1. dao接口实现类中存在大量的模板代码,将模板代码提取出来减少代码量
  2. 调用statement时将参数硬编码了
  3. 调用sqlsession方法时传入变量,由于sqlsession方法使用泛型,即使变量类型传入错误,在编译阶段也不报错。不利于开发。

2.使用mapper代理开发

注意:

namespace命名空间,作用就是对sql进行分类管理,理解sql隔离。使用mapper代理开发,namespace有特殊重要意义,namespace等于mapper接口地址,如UserMapper.java

步骤:

  1. 创建与接口同名的mapper.xml文件,作为接口的实现,注意namespace的值应为接口的全路径

  2. 在SqlMapConfig.xml文件中引用mapper.xml文件

  3. 在接口中建立对应的方法,方法名,参数,返回类型要对应。

  4. 调用接口实现相应功能

    UserMapper userMapper=session.getMapper(UserMapper.class);
    userMapper.findById(1);

3.加载属性配置文件db.properties

方法:

  1. 在SqlMapConfig.xml中引入db.properties文件。使用标签。然后结合el表达式。
  2. 还可使用标签配置相关属性
  3. 最后还会读取paramterType传递的属性,它会覆盖以读取的同名属性
  4. 通过parameterType传递的属性具有较高的优先权,resource或url加载的属性次之。最低优先级是properties元素体内定义的属性。

4.setting默认支持别名

<typeAliases>
    <pakeage name=""><!-- 批量定义别名,自动扫描包。别名是类名大写-->
</typeAliases>

5.typeHandlers类型处理器

mybaits中通过typeHandlers完成jdbc类型和java类型转换。

6.加载mapper

单个加载mapper.xml使用

使用了java接口类,并将同名的mapper.xml放置同一个报下

原始的加载方法

批量加载mapper.xml文档

批量扫描包下的所有mapper.xml文件

7.包装类思想

在开发中,不一定就是单纯的对一个实体类进行增删改查,例如完成用户信息的综合查询,又是需要传入和传出的条件比较的复杂,可能包含用户信息,关联表的其他信息等。根据这种需求,在mybaits中我们可以定义包装类的pojo,在包装类型的pojo中将复杂的查询条件写进去。

//在这个包装类,不仅包含了User的实体类,还可以包含其他的实体类,如将用户和订单联合起来组成的复杂联合查询
//这时UserQueryVo可以将这些查询条件分装起来
//在里面定义订单实体类,并生成set,get方法
//查询条件和查询结果封装到一个类中,从contral,service,dao再依次返回
public class UserQueryVo{

    private User user;
    public User getUser(){
        return user;
    }
    public void setUser(User user){
        this.user=user;
    }
    ...
    ...

}

8.resultTyperesultMap

使用resultType进行输出映射,只有查询出的列名与pojo的属性名一致时才能成功

如果查询出的列名与属性名不一致可以通过resultMap定义一个对应关系

resultMap使用在一对多,多对多的级联关系上。

resultType:新定义一个POJO继承某一个POJO,具有SQL语句查询的全部字段,作为一个查询结果的容器。这时因为一对多或者多对多的关系,显示的重复数据较多。使用双重for循环嵌套

resultMap:在处理一对多或者多对多关系时,将信息存储在list中,有自动去重的功能。

9.动态SQL

实现动态SQL表达式是基于JSTL表达式实现的,它与包装类配合使得查询语句更加的灵活,减少了sql语句代码。常用的动态sql元素主要有

if:

<where>
    <if test="userCustom!=null">
                <if test="userCustom.username!=null and userCustom.username!=''">
                    user.username like '%${userCustom.username}%'
                </if>
                <if test="userCustom.sex!=null and userCustom.sex!=''">
                    and user.sex like '%${userCustom.sex}%'
                </if>
                </if>
</where>
where标签相当于sql中的where,将其标签化,使得sql语句更加的灵活。与if语句结合组成动态sql

foreach

//foreach可以迭代集合。有几个重要的参数
//collection是想要遍历集合的名称
//item是给集合起的别名
//open是结合sql语句,迭代位置起始的拼接语句,与之对应的close是结束时的拼接语句。与sql语句紧密相关
//separator是迭代时查询之间的连接
<foreach collection="list" item="list" open="and("  separator="or" close=")" >
        user.id = #{list}
</foreach>

sql片段:将一块具有特定功能的语句抽取出来,如同一个函数,在需要的时候调用。大大的提高了代码的复用性。也使得代码界面更加的合理。

10.数据库表一对一,一对多,多对多关系分析

在分析表格之前一定要明白需求,根据需求确定关系。不能简单地说关系是一对一还是一对多,必须有一定的限定条件

11.一对一关系映射

想要实现一对一关系的映射必须实现表与表之间的关联,要有实在的主键和外键关系。结果的获得可通过resultType或resultMap方式获得。

  1. 通过resultType方法:定义一个类继承一个主表的pojo,另外还需要添加上查询条件上多出来的属性名。使得获取的数据全部装载到类中

  2. 通过resultMap方法:设置resultMap方法的id值,然后引用。resultMap中需要填写type(返回数据的POJO) id(别名) aassociation(将两个POJO联系起来,需要在POJO中写get,set对象方法)然后将字段名与属性名对应即可。

  3. 中的property中指定的是POJO中对象名的变量名,javaType是对象类型

    <!-- 使用resultMap实现一对一关系查询 -->
    <select id="findOrdersUserByResult" resultMap="getOrderResult">
        SELECT
        orders.*,
        user.username,
        user.sex,
        user.address
        FROM
        orders,
        user
        WHERE
        orders.user_id = user.id
    </select>
    <resultMap type="Orders" id="getOrderResult">
            <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"/>
        <association property="user" javaType="User">
            <id column="user_id" property="id"/>
            <result column="username" property="username"/>
            <result column="sex" property="sex"/>
            <result column="address" property="address"/>
            <result column="birthday" property="birthday"/>
        </association>
    </resultMap>

12.一对多关系映射

需求:显示订单全部信息,用户的用户名,用户地址,订单明细的id共三张表。牵涉的一对一,一对多级联查询。

SELECT
    orders.*, USER .username,
    USER .sex,
    USER .address,
    orderdetail.id orderderdetail_id
FROM
    orders,
    USER,
    orderdetail
WHERE
    orders.user_id = USER .id
AND orderdetail.orders_id = orders.user_id

定义resultMap:

牵涉一对一是使用,牵涉一对多时使用。首先在中间表里面设置对象属性,和list<对象>属性,并生成get和set方法。用于保存从数据库中查询到的信息。中有extends属性,可以用来继承一对一的resultMap,写上id即可。在 property的值为pojo中定义的变量名,还有ofType指定的是单个list中的对象名称。

13.多对多关系映射

​ 在mybaits中不同于hibernate的配置文件,之间配置两个set集合,或者把多对多拆解成两个一对多,对表进行管理。mybaits中映射多对多,无需配置文件。只需弄清楚表与表之间的级联关系(一对多,一对一,多对多)在POJO中声明对象或者List对象集合,并且生成get和set方法。在写sql语句时要清楚主键和外键,并将它们对应起来。

​ 在写resultMap时可能会牵涉到一对多,一对一嵌套的情况。将查询出的字段(别名)与POJO属性名对应即可。查询出的多条记录可能被封装到同一个对象中。

14.延迟加载

​ 当表与表之间建立有级联关系时,这时先查询单张表,然后根据需求去查另外一张表。这时可以使用延迟加载技术。由于数据库在查询多张表时速度较慢,所以采用延迟加载技术可以提高查询的效率。

​ 案例:查询订单并且关联到查询用户信息。

在SqlMapConfig.xml文件中配置

<settings>
    <!--打开延迟加载开关-->
        <setting name="lazyLoadingEnabled" value="true"></setting>
    <!--取消立即加载,改为延迟加载-->
        <setting name="aggressiveLazyLoading" value="false"></setting>
</settings>

代码

<!-- 使用延迟加载,查询订单并且关联到查询用户信息 -->
    <select id="findOrdersUserLazyLoading" resultMap="getOrderMap">
        select * from orders
    </select>
    <resultMap type="Orders" id="getOrderMap">
        <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"/>
    <association property="user" javaType="User" select="com.whz.mybatis.mapper.UserMapper.findById" column="user_id">
        <id column="user_id" property="id"/>
    </association>      
    </resultMap>
<select id="findById" parameterType="int" resultType="User">
        select *
        from user where id=#{id}
    </select>
OrdersMapper ordersMapper=session.getMapper(OrdersMapper.class);
        List<Orders> list=ordersMapper.findOrdersUserLazyLoading();
        System.out.println(list);
        for(Orders orders:list){
            System.out.println(orders.getUser().getUsername());
        }

分析:根据xml数据库会首先执行查询全部订单的操作,因为有延迟加载,后面的select语句不会执行。在测试时,由于需要用户表中的用户名数据,这时数据库会去执行查询用户表的操作。而且在迭代过程中如果用户名相同,还是不会去执行差村内用户表的操作。只有涉及级联操作时才会使用到级联,它提高了同时查询多张表时的效率。

15.一级缓存

mybaits的一级缓存是默认开启的,在平常操作中经常用到。它是SqlSession级别的,就是指当执行一个查询操作后,只要不执行commit(增加,删除,修改)这些操作。缓存不会被清除,在该SqlSession被销毁前,执行同一语句不会再向数据库发送信息。直接在缓存中得到结果。

16.二级缓存

mybaits的二级缓存默认是关闭的,开启的方式是在SqlMapConfig.xml中设置开启

<setting>
    <setting name="cacheEnabled" value="ture"></setting>
</setting>

然后在相应的Mapper.xml的标签下使用标签。这两步就开启了二级缓存,在使用二级缓存时一定要在响应的POJO类中实现序列化接口。在一次service中二级缓存是生效的,与一级缓存相似的地方在于,当有session执行了对应对象的commit(增,删,改)操作后。二级缓存就会被清空。二级缓存中存在击中率的问题,即是在缓存中查找了几次成功。

17.二级缓存的一些其他问题

  1. useCache用来禁止二级缓存,在一个方法中设置这个参数为false

    <select useCache="false">
    这种情况适用于每次查询操作后都需要最新的数据,禁止二级缓存,直接在数据库中查找数据,防止脏读情况的发生
  2. flushCache执行多方法之后刷新缓存

    <select flushCache="true">
  3. 由于mybaits的缓存的存储方式为整块的存储,当执行刷新操作时会将全部缓存清空。

  4. 分布式缓存:当使用多台服务器同时工作时,我们产生的缓存数据可能要供多台机器使用。例如,QQ是否已经登录等。mybaits通过整合ehcahe实现分布式缓存。

  5. 集成ehcahe实现分布式缓存方法:

    1. 导JAR包 :ehcache-core.jar mybaits-ehcache.jar

    2. 在需要实现ehcache二级缓存的mapper,xml的namespace下设置

    3. 在classpath下编写ehcahe.xml

      <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
      
        <diskStore path="F:\develop\ehcache"/>
      
        <defaultCache
                maxElementsInMemory="10000"
                eternal="false"
                timeToIdleSeconds="120"
                timeToLiveSeconds="120"
                maxElementsOnDisk="10000000"
                diskExpiryThreadIntervalSeconds="120"
                memoryStoreEvictionPolicy="LRU">
            <persistence strategy="localTempSwap"/>
        </defaultCache>
      </ehcache>
  6. mybaits二级缓存存在的问题

    1. 对于访问多的请求且用户对于查询结果实时性要求不高此时采用mybaits二级缓存技术降低数据库的访问量,提升了访问速度。实现方法,通过设置刷新时间间隔,由mybaits每隔一段时间自动清空缓存,根据数据变化频率设置刷新间隔flushInterval,如30分钟,60分钟
    2. mybaits二级缓存对于细粒度的数据级别的缓存实现不好,比如:对商品信息进行缓存,由于商品信息查询量大,但是要求每次查询最新的商品信息,此时使用mybaits的二级缓存就无法实现针对于一件商品信息的修改。它会将二级缓存全部清空,因为它以mapper为一个单位。

18.namespace命名规范

namespace命名是:所在包名+mapper.xml文件名(去掉xml后缀)

19.将spring与mapper接口进行整合

在applicationContext.xml文件中位置

<!-- 配置mapper接口扫描 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.whz.mybatis.mapper"></property>
    </bean>
即可完成mapper.java接口的扫描。因为mapper.xml与其绑定,所以在扫描接口的同时也会自动扫描mapper.xml。

20.ApplicationContext容器

ApplicationContext是spring中较高级的容器,与BeanFactory类似,它可以加载配置文件中所有的bean,将所有的bean集合起来,当有请求时分配bean。还可以实现从属性文本中将文件信息和事件传递给指定的监听器。ApplicationContext包含了BeanFactory所有功能,BeanFactory在轻量级应用中使用。

最常见的ApplicationContext接口实现:

  1. FileSystemXmlApplicationContext
  2. ClassPathXmlApplicationContext
  3. WebXmlApplicationContext

21.逆向工程

  1. 创建一个逆向工程,一般是新建一个工程用以保存全部逆向工程产生的文件。
  2. 需要的jar包:mybaits.jar,mybatis-generator-core.jar,mysql-connector-java-bin.jar,ojdbc.jar。还需要generatorConfig-base.xml,generatorConfig-business.xml,generatorConfig.xml三个配置文件。其中需要修改的是generatorConfig.xml将里面的包名称改为需要复制的包名称(重点:一定要提前修改好,不然后面会报错),
  3. 最后执行GeneratorSqlmap.java文件即可生成mapper和po文件,直接复制即可使用。
  4. 因为逆向工程默认实现的是接口,所以在使用时直接用sqlSession获取接口类即可
  5. 除了基本的增删改查之外,还有类是hibernate的criteria(条件),甚至更加的灵活。
  6. 条件的查询在Example.java,它根据字段的属性生成了对应的条件语句。
  7. 逆向工程生成的crud方法都是对于单表操作的。

猜你喜欢

转载自blog.csdn.net/S_T_F666/article/details/82142349