MyBait听课笔记

来源:互联网 发布:php foreach循环 编辑:程序博客网 时间:2024/06/07 01:51

传统JDBC的问题:

1、数据库连接,使用时创建,不使用时立即释放,对数据库进行频繁连接开启和关闭,造成数据库资源浪费,影响数据库性能。

      解决方案:数据库连接池

2、将sql语句硬编码到java代码中,如果sql语句修改,需要重新编译java代码,不利于系统维护。

设想:将sql语句配置在xml配置文件中,即使sql变化,不需要对java代码进行重新编译。

3、向preparedStatement中设置参数,对占位符号位置和设置参数值,硬编码在java中,不利于系统维护。

设想:将sql语句及占位符和参数全部配置在xml语句中。

4、从resultSet中遍历结果集数据时,存在硬编码,将获取表的字段进行硬编码,不利于系统维护

设想:将查询的结果集自动映射为javad对象


Mybait框架原理

1、mybait是什么?

mybait是一个持久层框架,是apache的顶级项目https://github.com/mybatis/mybatis-3/releases

mabait让程序员将主要精力放在sql上,通过mybait提供的映射方式,自由灵活生成(半自动话,大部分需要程序员编写sql)满足需求的sql语句

mybait可以将向preparedStatement中的输入参数自动进行输入映射,将查询结果集灵活映射成java对象(输出映射)


2、mybait框架


      

入门程序

1、导入jar包

lib下:依赖包

mybaits-3.3.0.jar:核心包

mybaits-3.3.0.pdf:操作指南

加入mysql驱动包


2、配置log4j.properties

# Global logging configuration

#在开发环境下日志级别要设置成DEBUG

log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n


3、SqlMapConfig.xml

配置mybaits的运行环境,数据源、事务等。

<?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"><configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <mappers> <mapper resource="org/mybatis/example/BlogMapper.xml"/> </mappers></configuration>


4、根据用户id(主键)查询用户信息

1)创建po


2)映射文件命名

User.xml(原始ibaits命名方式),mapper代理开发映射文件名称叫XXXMapper.xml,比如:UserMapper.xml

在映射文件中配置sql语句


3)在SqlMapConfig中加载map文件


5、根据用户名称模糊查询用户信息


6、添加用户

1)映射文件

在User.xml中配置添加用户的Statement

2)自增主键返回

mysql自增主键,执行insert提交之前自动生成一个自增主键。

通过mysql函数获取刚插入记录的自增主键

LAST_INSERT_ID()是insert之后调用

3)非自增主键返回(使用uuid())

使用mysql的uuid()函数生成主键,需要修改表中id字段类型为string,长度设置为35位

执行思路:

先通过uuid()查询到主键,将主键输入到sql语句中

执行uuid()语句顺序相对于insert语句之前执行



总结

1、parameterType

在映射文件中通过parameterType指定输入参数的类型。

2、resultType

在映射文件中通过resultType指定输出结果的类型

3、#{}和${}

#{}表示一个占位符,#{}接收输入参数,类型可以是简单类型,pojo、hashmap。

如果接收简单类型,#{}种可以写成value或其他名称。

#{}接收pojo对象值,通过OGNL读取对象中的属性值.,通过属性.属性.属性。。。。的方式获取对象属性值。


${}表示一个拼接符号,会引用sql注入,所以不建议使用${}.

${}接收输入参数,类型可以是简单类型,pojo、hashmap。

如果接收简单类型,${}中只能写成value。

${}接收pojo对象值,通过OGNL读取对象中的属性值.,通过属性.属性.属性。。。。的方式获取对象属性值。


4、selectOne和selectList

selectOne表示查询出一条记录进行映射,如果使用selectOne可以实现使用selectList也可以实现(list中只有一个对象)

selectList表示查询出一个列表(多条记录)进行映射。如果使用selectList查询多条记录,不能使用selectOne



mybatis和hibernate的本质区别和应用场景

hibernate:是一个标准的orm框架(对象关系映射)。入门门槛较高,不需要程序员写sql,sql语句自动生成。

对sql语句进行优化、修改比较困难

应用场景:

           适用与需求变化不多的中小型项目:比如:后台管理系统,ERP、ORM、OA...


mybatis:专注sql本身,需要程序员自己编写sql语句,sql修改优化比较方便。mybatis是一个不完全的ORM框架,虽然程序员自己写sql,mybatis也可以实现映射(输入映射、输出映射)

应用场景:

        适用与需求变化较多的项目,比如:互联网项目


企业进行技术选型,以低成本、高回报作为技术选型的原则,根据项目组的技术力量进行选择。


Mybatis开发dao的方法

1、SqlSession的使用范围

    1.1 SqlSessionfactoryBuilder

         通过SqlSessionFactoryBuiler创建会话工厂SqlSessionFactory

        将SqlSessionFactoryBuilder当成一个工具类使用即可,只需要new一次SqlSessionFactoryBuilder即可

    1.2  SqlSessionFactory

         通过SqlSessionFactory创建SqlSession,使用单例模式管理sqlSessionFactory(工厂一旦创建,使用一个实例)。

         将来mybait和spring整合后,使用单例模式 管理sqlSessionFactoy

     1.3 SqlSession

        SqlSession是一个面向用户(程序员)的接口。

        SqlSession中提供了很多操作数据库的方法,如:selectOne(单个返回对象)、selectList(返回单个或多个对象)

       SqlSession是线程不安全,在SqlSession实现类中除了有接口中的方法(操作数据库的方法)还有数据域属性

       SqlSession最佳应用场合在方法体内,定义成局部变量


总结原始dao开发问题

1、dao接口实现类方法中存在大量模板方法,设想能否将这些代码提取出来,大大减轻程序员的工作量。

2、调用sqlsession方法时将statement的id硬编码了

3、调用sqlsession方法时传入的变量,由于sqlsession方法使用泛型,即使变量类型传入错误,在编译阶段也不报错,不利于程序员开发。




mapper代理方法(程序员只需要mapper接口(相当于dao接口))

思路:

程序员还需要编写mapper.xml映射文件

程序员编写mapper接口需要遵循一些开发规范(相当于dao),mybatis可以自动生成mapper接口实现类代理对象


开发规范:

1、在mapper.xml中namespace等于mapper接口地址

2、mapper.java接口中的方法名和mapper.xml中的statement的id一致

3、mpper.java接口中的方法输入参数类型和mapper.xml中的statement的parameterType中制定的类型一致

4、mpper.java接口中的方法返回值类型和mapper.xml中statement中的resultType指定的类型一致。


总结:

以上开发规范主要是对下边代码进行统一的生成:

User user=sqlSession.selectOne("test.findUserById",id)

sqlSession.inser(    ,user);。。。。


mapper.java

mapper.xml

在SqlMapConfig.xml中加载mapper.xml文件


代理对象内部调用selectOne或selectList

如果mapper方法返回单个pojo对象(非集合对象),代理对象内部通过selectOne查询数据库

如果mapper方法返回集合对象,代理对象内部通过selectList查询数据库


mapper接口方法参数只能有一个是否影响系统开发?

系统框架中,dao层的代码是被业务层公用的,即使mapper接口只有一个参数,可以使用包装类型的pojo满足业务方法的需求。

注意:持久层方法参数可以使用包装类型,service方法建议不要使用包装类型(不利于业务层的可扩展性 )


SqlMapConfig.xml

mybatis的全局配置文件SqlMapConfig.xml,配置内容如下:

properties(属性)

settings(全局配置参数)

typeAliases(类型别名)

typeHandlers(类型处理器)

objectFactory(对象工厂)

plugins(插件)

environments(环境集合属性对象)

     environment(环境子属性对象)

          transactionManager(事务管理)

          datasource(数据源)

mpper(映射器)


properties属性

需求:

将数据库连接参数单独配置在db.properties中,只需要在sqlMapConfig.xml中加载db.properties的树形值。

在sqlMapConfig.xml中就不需要对数据库连接参数硬编码。


将数据库连接参数只配置在db.properties中,原因:方便对参数进行统一管理,其他xml可以引用该db.properties。

注意:Mybatis将按照下面的顺序来加载属性:

1)在properties元素体内定义的属性首先被读取

2)然后会读取properties元素中resource或url加载的属性,它会覆盖已读取的同名属性

3)最后读取parameterType传递的属性,它会覆盖已读取的同名属性


因此,通过parameterType传递的属性具有最高优先级,resource或url加载的属性次之,最低优先级是properties元素体内定义的书信

建议:不要在properties元素体内添加任何属性值,只将属性定义在properties文件夹中

在properties文件中定义属性名要有一定的特殊性,如:xxx.xxx.xxx


setting全局参数配置

mybatis框架在运行时可以调整一些运行参数。

比如:开启二级缓存、开启延迟加载。。。。



typeAliases(别名) 重点

在mapper.xml中,定义很多的statement,statement需要parameterType指定输入参数的类型、需要resultType指定输出类型


如果在指定类型时输入类型的全路径,不方便进行开发,可以针对parameterType或resultType指定的类型定义一些别名,在mapper.xml

中通过别名定义,方便开发


自定义别名

    1)单个别名定义

    2)批量定义别名(常用)


typeHandlers(类型处理器)

mybatis中通过typehandlers完成jdbc类型和java类型的转换。

通常情况下,mybatis提供的类型处理器满足日常需要,不需要自定义


mappers(映射配置)

     1)通过resource加载单个映射文件

      2)通过mapper接口来加载

      3)批量加载mapper接口(推荐使用)





输入映射

通过parameterType指定输入参数的类型,类型可以是简单类型、hashmap、pojo包装类型


     传递pojo的包装对象

        需求

            完成用户信息的综合查询,需要传入查询条件(可能包括用户信息、其他信息、比如商品、订单的)

        定义包装类型pojo

            针对上边的需求,建议使用自定义的包装类型pojo。

            在包装类型的pojo中将复杂的查询条件包装进去。

       mapper.xml

       在UerMapper.xml中定义用户信息综合查询(查询条件复杂,通过高级查询进行复杂关联查询)

       mapper.java


输出映射

       1)resultType

            使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以成功映射

           如果查询出来的列名和pojo中的属性名全部不一致,没有创建pojo对象

            只要查询出来的列名和pojo中的属性有一个一致,就会创建pojo对象

           小结:

                查询出来的结果集只有一行且一列,可以使用简单类型进行输出映射

     2)resultMap

                 mybatis中使用resultMap完成高级输出结果映射

             resultMap使用方法

            如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间作一个映射

             1、定义resultMap

              2、使用resultMap作为statement的输出映射类型


                      将下边的sql使用User完成映射

                      select id id_ ,username username_ from user where id=#{value}

                       UserCustom类属性名和上边查询列名不一致


     3)输出pojo对象和pojo列表

           不管是输出的pojo单个对象还是一个列表(list中包括pojo),在mapper.xml
           中resultType指定类型是一样的。

           在mapper.java指定的方法返回值类型不一样:

          1、输出单个pojo对象,方法返回值是单个对象类型

          2、输出pojo对象list,方法返回值时list<pojo>


        生成的动态代理对象中是根据mapper方法的返回值类型确定调用selectOne(返回单个对象调用)还是selectList

         4)输出hashmap

              输出pojo对象可以改用hashmap输出类型,将输出的字段名称作为map的key,value为字段值


      


动态sql

            什么是动态sql

            mybatis核心:对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接,组装

           

            需求

            用户信息综合查询列表和用户信息查询列表总数这两个statement的定义使用动态sql

         

            对查询条件进行判断,如果输入参数不为空才进行查询条件拼接


           sql判断

            需求

            将上边实现的动态sql判断代码块抽取出来,组成一个sql片段。其他的statement中就可以引用sql片段


           定义sql片段

           引用sql片段

            

      foreach

     向sql传递数组或List,mybatis使用foreach解析

      

     需求

    在用户查询列表和查询总数的statement中增加多个id输入查询

     sql语句如下:

      两种方法:

       select * from user where id=1 or id=10 or id=16

        select * from user where id in(1,10,16)

      在输入参数类型中天剑List<integer> ids传入多个id








1、订单商品数据模型

 1.1数据模型分析思路

1、每张表记录的数据内容

       分模块对每张表记录的内容进行熟悉,相当于学习系统 需求(功能)的过程

2、每张表重要字段设置

      非空字段、外键字段

3、数据库级别表与表之间的关系

     外键关系

4、表与表之间的业务关系

    在分析表与表之间的业务关系是一定要建立在某个业务意义基础上去分析。




实现一对一查询:

resultType:使用resultType实现较为简单,如果pojo中没有包括查询出来的列名,需要增加列名对应的树形,即完成映射。

如果没有查询结果的特殊要求建议使用resultType


resultMap:需要单独定义resultMap,实现有点麻烦,如果对查询结果有特殊要求,使用reslutMap可以完成将关联查询映射pojo的属性中


resultMap可以实现延迟加载,resultType无法实现延迟加载


实现一对多查询:


mybaits使用collection对关联查询的多条记录映射到一个list集合属性中。

使用resultType实现:

将订单明细映射到orders中的orderdetails中,需要自己处理,使用双重循环遍历,去掉重复记录,将订单明细放在orderdetails中。


建议使用resultMap



实现多对多查询

需求:查询用户及用户购买商品信息

分析:

          查询主表是:用户表

          关联表:由于用户和商品没有直接关联,通过订单和订单明细进行关联,所以关联表:orders,orderdetail,items


映射思路:

        将用户信息映射到user中。

        在user类中添加订单列表属性List<Orders> orderslist.
        在Orders中添加订单明细列表属性List<OrderDetail> ordertails.

        在Orderdetail中添加items属性,将订单明细所对应的商品映射到items


多对多查询总结:

          需求1:

           将查询用户购买的商品信息明细清单,(用户名,用户地址,购物商品名称,购买商品时间,购买商品数量)

           针对上边的需求使用resultType将查询到的记录映射到一个扩展的pojo中,很简单实现明细清单的功能

          需求2:

           查询字段:用户账号、用户名称、购买商品数量、商品明细(鼠标移上显示明细)

           使用resultMap将用户购买的商品明细列表映射到user对象中

           总结:

           使用resultMap时针对那些对查询结果映射有特殊要求的功能,比如特殊要求映射成list中包括多个list



resultMap总结

            使用association和collection完成一对一和一对多高级映射(对结果)

          

           association:

                    作用:将关联查询信息映射到一个pojo对象中。

                   场合:为了方便查询关联信息可以使用association将关联订单信息映射为用户兑现挂的pojo属性中,比如:查询订单及关联用户信息

                               使用resultType无法将查询结果映射到pojo对象的pojo属性中,根据结果集查询遍历的需要选择使用resultType还是resultMap.

           collection:

                   作用:将关联查询信息映射到一个list集合中

                    场合:

                           为方便查询遍历关联信息可以使用collection将关联信息映射到list集合中,比如:查询用户权限范围模块及模块下的菜单,可使用collection将模块映射到模块list中,

                          将菜单列表映射到模块对象的菜单list属性中,这样做的目的是方便崔查询结果集进行遍历查询。

                           如果使用resultType无法将查询结果映射到


延迟加载

          什么是延迟加载

           resultMap可以实现高级映射(使用association、collection实现一对一及一对多映射),association、collection具备延迟加载功能。

          需求:

           如果查询订单并且关联查询用户信息,如果先查询订单信息即可满足要求,当我们需要查询用户信息时再查询用户信息。把对用户信息的按需去查询就是延迟加载。

       

            延迟加载:先从表单查询、需要时再从关联表去关联查询,大大提高数据库性能,因为查询表单要比查询多张表速度要快


          mppper.xml

        需要定义两个mapper的方法对应的statement。

       1、只查询订单信息

          select * from orders

           在查询订单的statement中的association去延迟加载(执行)下边的statement(关联查询用户信息)

        2、关联查询用户信息

               通过上边查询到的订单信息中user_id去查询用户信息

       

         上边先去执行findOrdersUserLazyLoading,当需要去查询用户的时候再去执行findUserById,通过resultMap的定义将延迟加载执行配置起来。

         

            mybatis默认没有开启延迟加载,需要在SqlMapConfig.xml中setting设置

        

      如果不适用mybatis提供的association及collection中的延迟加载功能,如何实现延迟加载?

        实现方法:

                      1、查询订单列表 

                       2、根据用户id查询用户信息

        实现思路:

                     先去查询第一个mapper方法,获取订单信息列表

                      在程序中(service),按需去调用第二个mapper方法去查询用户信息


       总之:使用延迟加载方法,先去查询简单的sql(最好是单表,也可以是关联查询,),再去按需要加载关联查询其他信息。



查询缓存

              什么是查询缓存?

               mybatis提供查询花村,用于减轻数据压力,提高数据库性能

               mybatis提供一级缓存和二级缓存

             

                   一级缓存是sqlsession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构(hashmap)用于存储数据

                    不同的sqlsession之间的缓存数据区域(hashmap)是互相不影响

                  

                    二级缓存是mapper级别的缓存,多个sqlsession去操作统一个mapper的sql语句,多个sqlsession去操作数据库得到数据会存在二级缓存区域,二级缓存是跨sqlsession的。

                   为什么要用缓存?

                    如果缓存中有数据就不用从数据库中获取,大大提高系统性能。


                原理

                   下图是根据id查询用户的一级缓存图解:

                   

                    第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信息

                   得到用户信息,将用户信息存储到一级缓存中

                 如果sqlsession去执行commit操作,清空sqlsession中的以及缓存,这样做的目的是为了让缓存中存储的是最新信息,避免脏读

                  第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中取用户信息。

                 

                     mybatis默认支持一级缓存,不需要配置文件去配置。

            

                一级缓存测试

                一级缓存应用

                正式开发,是将mybatis和spring进行整合开发,事务控制在service中。

                   一个service方法中包括很多mapper方法调用

                   service{

                                 //开始执行时,开启事务,创建SqlSession对象

                                //第一次调用mapper的方法findUserById(1)

                                 //第二次调用mapper的方法findUserById(1),从一级缓存中取数据

                               //方法结束,sqlSession关闭

                    }

                     如果是执行两次service调用查询相同的用户信息,不走一级缓存,因为session方法结束,sqlSession就关闭,一级缓存就清空



                二级缓存测试

               原理:

               


               与分布式缓存框架整合


               不使用分布缓存,缓存的数据在个服务器单独存储,不方便系统开发,所以要使用分布式缓存对缓存数据进行集中管理。

               mybatis无法实现分布式缓存,需要和其他分布式缓存框架进行整合

             

                整合方法

                mybatis提供了一个cache接口,如果要实现自己的缓存逻辑,实现cache接口开发即可。

                mybatis和encache整合,mybatis和encache整合包中提供了一个cache接口的实现类。

               

                mybatis默认实现的cache类为:PerpetualCache.java


                1)加入encahce的包https://github.com/mybatis/ehcache-cache/releases/tag/mybatis-ehcache-1.0.3

              
                    参考文章:http://blog.csdn.net/reblue520/article/details/48729327

                                     http://blog.csdn.net/rishengcsdn/article/details/39993387

                2)引入ehcache.xml配置文件

                       

             应用场景

             对于访问多的查询请求且用户对查询结果实时性要去不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度,业务场景比如:耗时较高的统计分析sql、电话账单查询sql等

              实现方式如下:通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushinterval,比如设置为30分钟、60分钟、24小时等,根据需求而定。

           局限性

             mybatis二级缓存对细粒度的数据级别的缓存实现不好,比如如下需求:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品信息,

             此时如果使用mybatis的二级缓存就无法实现当一个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息,因为mybaits的二级缓存区域以mapper为单位划分,

            当一个商品信息变化会将所有商品信息的缓存数据全部清空。解决此类问题需要在业务层根据需求对数据有针对性缓存。




           spring和mybatis整合

                整合思路

                  需要spring通过单例方式管理SqlSessionFactory.

                 spring和mybatis整合生成代理对象,使用SqlSessionFactory创建SqlSession(spring和mabaits整合自动完成)

                 持久层的mapper都需要由spring进行管理。

                 

                  整合环境

                 jar包:

                  1、mybatis3.2.7的jar包

                  2、spring3.2.0 的jar包

                  3、mybatis和spring的整合包:早期ibatis和spring整合是由spring官方提供,mybatis和spring整合有mybatis提供


                 1、SqlSessionFactory

                  在applicationContext.xml配置sqlSessionFactory和数据源

                   sqlSessionFactory在mybatis和spring的整合包下


               2、 原始dao开发(和spring整合后)

                   1)mapper.xml

                        在SqlMapConfig.xml中加载mapper.xml

                   2)dao(实现类继承SqlSessionDaoSupport)

                       dao接口实现类需要注入SqlSessionFactory,通过spring进行注入。

                      这里spring声明配置方式,配置dao的bean:

                       让UserDaoImpl实现类继承SqlSessionDaoSupport

                   3)配置dao

                      在applicationcontext.xml中配置dao


             3、Mapper代理开发

                   1)mapper.xml和mapper.java接口

                    2)配置mapper

                   此方法问题:需要针对每个mapper进行配置,麻烦。

                   3)mapper的批量扫描,从mapper包中扫描出mapper接口,自动创建代理对象并且在spring容器中注册

 


              逆向工程

               什么 是逆向工程?

               mybatis需要程序员自己编写slq语句,mybatis官方提供逆向工程,可以针对单表自动生成mybatis执行所需要的代码(mapper.java,mapper.xml,po...)

             

               企业实际开发中,常用的逆向工程方式:

               由于数据库的表生成java代码。

             

                下载逆向工程

                       使用方法:

                          还可以通过eclipse的插件生成代码

                    建议使用java程序方式,不依赖开发工具

                         

              1)生成代码配置文件

               2)执行生成程序

                3)使用生成的代码

                    需要将生成工程中所生成的代码拷贝到自己的工程中

                   测试itemsMapper中的方法


















0 0
原创粉丝点击