2024年10月ibatismybatis(Mybatis是什么以及Mybatis和JDBC的关系)

 更新时间:2024-10-12

  ⑴ibatismybatis(Mybatis是什么以及Mybatis和JDBC的关系

  ⑵Mybatis是什么以及Mybatis和JDBC的关系

  ⑶Mybatis是什么mybatis是一个持久层ORM框架。它内部封装了jdbc,使得开发更简洁,更高效。MyBatis可以通过xml或注解完成ORM映射关系配置。Mybatis和JDBC的关系JDBC是Java提供的一个操作数据库的API;MyBatis是一个持久层ORM框架,底层是对JDBC的封装。MyBatis对JDBC操作数据库做了一系列的优化:(mybatis使用已有的连接池管理,避免浪费资源,提高程序可靠性。(mybatis提供插件自动生成DAO层代码,提高编码效率和准确性。(mybatis提供了一级和二级缓存,提高了程序性能。(mybatis使用动态SQL语句,提高了SQL维护。(此优势是基于XML配置(mybatis对数据库操作结果进行自动映射MyBatis的优点和缺点优点:简单:易于学习,易于使用,通过文档和源代du码,可以比较完全zhi的掌握它的设计思路和实现。实用:提供了数据映射功能,提供了对底层数据访问的封装(例如ado.,提供了DAO框架,可以使我们更容易的开发和配置我们的DAL层。灵活:通过sql基本上可以实现我们不使用数据访问框架可以实现的所有功能,或许更多。功能完整:提供了连接管理,缓存支持,线程支持,(分布式事物管理,通过配置作关系对象映射等数据访问层需要解决的问题。提供了DAO支持,并在DAO框架中封装了ADO.,NHibernate和DataMapper。增强系统的可维护性:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。缺点:sql工作量很大,尤其是字段多、关联表多时,更是如此。sql依赖于数据库,导致数据库移植性差。由于xml里标签id必须唯一,导致DAO中方法不支持方法重载。字段映射标签和对象关系映射标签仅仅是对映射关系的描述,具体实现仍然依赖于sql。(比如配置了一对多Collection标签,如果sql里没有join子表或查询子表的话,查询后返回的对象是不具备对象关系的,即Collection的对象为null。DAO层过于简单,对象组装的工作量较大。不支持级联更新、级联删除。编写动态sql时,不方便调试,尤其逻辑复杂时。提供的写动态sql的xml标签功能简单(连struts都比不上,编写动态sql仍然受限,且可读性低。使用不当,容易导致N+的sql性能问题。

  ⑷mybatis各阶段的详解

  ⑸比如我们在引入了jdbc的配置文件使用了properties标签,引入jdbc有什么好处?,可以在配置文件中统一管理内容而不是在很多个文件改来改去,而且在核心配置文件中把数据库连接相关的写死,显然是硬编码的所以我们用配置文件代替nice!!!

  ⑹你可能注意到了上面的写法用前缀jdbc.可以很好地将他们与其他的变量区分开,(可以从名字很容易看出是jdbc相关的数据,不至于和同名变量搞混因为username这种可能不止会出现在数据库的连接

  ⑺上面的代码中引入配置文件的部分为可以从上面看到写法:

  ⑻下面这段就是用来设置类的别名:

  ⑼那么问题来了,为什么要有类的别名这种操作??

  ⑽因为在映射文件中每次都要写全类名显然有点麻烦比如下面这样:

  ⑾一个项目是会有很多个映射文件的为了方便,所以类别名就出现了。可以在核心配置文件写接口类和对应的别名

  ⑿这样就可以在映射文件的命名空间里可以直接写User(对大小没有要求也可以是user;其实可以比这更加简单,也是我们在实际开发中常用的写法就是将整个包写成别名的形式,如果不写alias属性默认为类名(不区分大小写,这样就容易多了,我们只需一行代码,便可以在所有的映射文件命名空间中直接写对应的类名

  ⒀首先需要思考的这里是映射文件的引入,我们正常的一个项目的数据库是有很多个表组成的那么每一张表对应一个mapper接口,每个接口对应一个映射文件,那么就需要导入大量的映射文件,还容易漏掉--》

  ⒁上面这种以包的形式的导入非常方便,不用每次新建一个接口就要导入它的映射文件,但是上面这种写法需要注意一些问题:

  ⒂如果你在映射文件中编写查询语句的sql,但是粗心的你忘记了设置返回类型会在控制台抛异常且会看到这样的说明:It’slikelythatneitheraResultTypenoraResultMapwasspecified.

  ⒃下面只是指定返回类型的一种方式:resultType,还有resultMap它们的区别:

  ⒄查询的标签必须指定resultType或resultMap

  ⒅.kobedu.mybatis获取参数的两种方式:${}和#{}

  ⒆上面是使用了#{}写法相当于原生jdbc的占位符,这个前面已经提到过了所以不多赘述,需要注意的是#{}里面的变量名可以是任意的username规范显然很好,但是aaaa也没错因为只是用来占位的;还有就是在使用${}时注意’’单引号问题,因为${}是字符拼接的方式,所以需要注意!!

  ⒇传输参数时有多个参数时

  ⒈在测试代码里通过传入两个参数分别为username和password但是在上面代码的(映射文件里的部分代码执行失败,(sql语句未能解析报错:Cause:.apache.ibatis.binding.BindingException:Parameter’username’notfound.Availableparametersare

  ⒉可以从错误提示的信息不难发现我们的参数在映射文件里未能真正地接受到,可以用的方式获取,mybatis将参数放到map容器可以通过建arg,agr..的方式获取参数(也可以是param,param..将上面的代码改动:

  ⒊需要注意的是:使用${}时需要手动添加’’才能正常访问,因为他的处理方式是字符串的拼接

  ⒋做了改动之后结果很感人!!User{id=,userName=’旺财’,age=,password=’cwlz’}

  ⒌可以直接通过键访问相对应的值(通过自己的方式访问到数据,上面的形式是mybatis默认提供的map和mybatis默认的提取指的方式arg,arg...当需要传多个参数时将他们放到一个map容器,然后将map传给对应的方法(模拟mybatis的做法,就可以在sql语句中直接通过键访问到值代码如下:

  ⒍映射文件中的部分代码:

  ⒎通过键直接获取值,注意:使用${}时不要忘了单引号!!!!

  ⒏当参数以实体对象的形式传参时如何解决?只需要通过#{}以属性名的方式访问!

  ⒐所以代码的编写一定要规范,才能减少这种错误!!!

  ⒑一定要和注解中的参数名一一对应!!!

  ⒒如果查询的结果只有一个,也可以通过Map集合接收,字段名为键字段的值为值:{password=,id=,userName=图区,age=}

  ⒓java.lang.Ingeger--》int,Integer

  ⒔int--》_int,_Integer

  ⒕String--》string

  ⒖所以在批量删除的案例:需要注意的是不能使用#{}因为它是会自动添加’’所以在批量删除的语句中我们要使用${}

  ⒗若字段和属性名不一致,则可以通过resultMap设置自定义映射

  ⒘在mybatis的核心配置文件用下面的代码将数据库中命名的规范(user_name)转换为java中的命名规范(userName)

  ⒙就是手动设置属性与字段的映射关系:如果设置了手动的设置属性和字段的映射关系,注意主键使用id标签,普通字段使用result标签,就算属性和字段名一一对应,只要用了这种方式就必须要写全!!!

  ⒚if根据标签中test的属性所对应的表达式决定标签中的内容是否拼接到sql语句中

  ⒛上面的where后面的=是细节,因为当where后面的条件都为空时就成了select*fromt_userwhere显然这种sql语句是有问题的,还有一种情况就是当userName为null时语句就成了select*fromt_userwhereandage=#{age}这也是错的,所以在where后加一个恒成立的条件不仅不会影响查询结果,而且没有会在特定情况时sql语句是会报错的所以很有必要

  where当where标签中有内容时,会自动生成where关键字,并且将内容前多余的and或者or去掉当where中没有内容时,此时where标签没有任何效果就是不会生成关键字注意:在写条件时不能在后面加andor这个在下一条语句无效时mybatis不会帮你去掉!

  一个案例--》就是当我们需要批量删除一些东西时(参数以数组的形式传入

  sql片段:在我们的查询语句不能在实际开发中也一直写*;因为我们要按需查找,不必将不需要的也查询出来,我们可以将我们平常查询次数较多的字段放在sql片段内,可以在需要查询时直接进行引用!

  缓存,这个术语我们听过很多次,在web阶段时访问网页时有缓存机制!现在sql的查询时也有缓存机制,有一级缓存,一级缓存是默认开启的,一级缓存的范围时sqlSession,将我们查询到的数据先进行缓存,若下次有相同的查询时不用重新访问数据库,可以直接从缓存中取出!!!!

  手动清空缓存sqlSession.clearCache();

  在mapper配置文件中添加cache标签可以设置一些属性:

  逆向工程就是不难理解,我们之前都是由实体类到数据库,而逆向类就是通过数据库表生成实体类,

  Spring整合Mybatis一文讲透,手把手带你实操

  在介绍Spring整合Mybatis原理之前,我们得先来稍微介绍Mybatis的工作原理。

  在Mybatis中,我们可以使用一个接口去定义要执行sql,简化代码如下:定义一个接口,Select表示要执行查询sql语句。

  以下为执行sql代码:

  Mybatis的目的是:使得程序员能够以调用方法的方式执行某个指定的sql,将执行sql的底层逻辑进行了封装。这里重点思考以下mapper这个对象,当调用SqlSession的getMapper方法时,会对传入的接口生成一个代理对象,而程序要真正用到的就是这个代理对象,在调用代理对象的方法时,Mybatis会取出该方法所对应的sql语句,然后利用JDBC去执行sql语句,最终得到结果。

  UserService中的userMapper属性就会被自动注入为Mybatis中的代理对象。如果你基于一个已经完成整合的项目去调试即可发现,userMapper的类型为:.apache.ibatis.binding.MapperProxyaaad。证明确实是Mybatis中的代理对象。好,那么现在我们要解决的问题的就是:如何能够把Mybatis的代理对象作为一个bean放入Spring容器中?要解决这个,我们需要对Spring的bean生成过程有一个了解。

  Spring启动过程中,大致会经过如下步骤去生成bean

  假设有一个A类,假设有如下代码:一个A类

  一个B类,不存在ponent注解

  输出结果为:.luban.util.AacdbdfA类对应的bean对象类型仍然为A类。但是这个结论是不确定的,我们可以利用BeanFactory后置处理器来修改BeanDefinition,我们添加一个BeanFactory后置处理器:

  这样就会导致,原本的A类对应的BeanDefiniton被修改了,被修改成了B类,那么后续正常生成的bean对象的类型就是B类。此时,调用如下代码会报错:

  但是调用如下代码不会报错,尽管B类上没有ponent注解:

  并且,下面代码返回的结果是:.luban.util.Bbcea

  之所以讲这个问题,是想说明个问题:在Spring中,bean对象跟class没有直接关系,跟BeanDefinition才有直接关系。那么回到我们要解决的问题:如何能够把Mybatis的代理对象作为一个bean放入Spring容器中?在Spring中,如果你想生成一个bean,那么得先生成一个BeanDefinition,就像你想new一个对象实例,得先有一个class。

  继续回到我们的问题,我们现在想自己生成一个bean,那么得先生成一个BeanDefinition,只要有了BeanDefinition,通过在BeanDefinition中设置bean对象的类型,然后把BeanDefinition添加给Spring,Spring就会根据BeanDefinition动帮我们成个类型对应的bean对象。所以,现在我们要解决两个问题:

  注意:上文中我们使用的BeanFactory后置处理器,他只能修改BeanDefinition,并不能新增一个BeanDefinition。我们应该使用Import技术来添加一个BeanDefinition。后面再详细介绍如果使用Import技术来添加一个BeanDefinition,可以先看一下伪代码实现思路。

  假设:我们有一个UserMapper接口,他的代理对象的类型为UserMapperProxy。那么我们的思路就是这样的,伪代码如下:

  但是,这里有一个严重的问题,就是上文中的UserMapperProxy是我们假设的,他表示一个代理类的类型,然而Mybatis中的代理对象是利用的JDK的动态代理技术实现的,也就是代理对象的代理类是动态生成的,我们根本方法确定代理对象的代理类到底是什么。所以回到我们的问题:Mybatis的代理对象的类型是什么?本来可以有两个答案:.代理对象对应的代理类.代理对象对应的接口那么答案就相当于没有了,因为是代理类是动态生成的,那么我们来看答案:代理对象对应的接口如果我们采用答案,那么我们的思路就是:

  但是,实际上给BeanDefinition对应的类型设置为一个接口是行不通的,因为Spring没有办法根据这个BeanDefinition去new出对应类型的实例,接口是没法直接new出实例的。那么现在问题来了,我要解决的问题:Mybatis的代理对象的类型是什么?两个答案都被我们否定了,所以这个问题是无解的,所以我们不能再沿着这个思路去思考了,只能回到最开始的问题:如何能够把Mybatis的代理对象作为一个bean放入Spring容器中?

  总结上文的推理:我们想通过设置BeanDefinition的class类型,然后由Spring自动的帮助我们去生成对应的bean,但是这条路是行不通的。终极解决方案那么我们还有没有其他办法,可以去生成bean呢?并且生成bean的逻辑不能由Spring来帮我们做了,得由我们自己来做。FactoryBean有,那就是Spring中的FactoryBean。我们可以利用FactoryBean去自定义我们要生成的bean对象,比如

  我们定义了一个LubanFactoryBean,它实现了FactoryBean,getObject方法就是用来自定义生成bean对象逻辑的。执行如下代码:

  将打印:lubanFactoryBean:.luban.util.LubanFactoryBeandcee&lubanFactoryBean:.luban.util.LubanFactoryBeanblubanFactoryBean-class:class.sun.proxy.Proxy从结果我们可以看到,从Spring容器中拿名字为“lubanFactoryBean“的bean对象,就是我们所自定义的jdk动态代理所生成的代理对象。

  所以,我们可以通过FactoryBean来向Spring容器中添加一个自定义的bean对象。上文中所定义的LubanFactoryBean对应的就是UserMapper,表示我们定义了一个LubanFactoryBean,相当于把UserMapper对应的代理对象作为一个bean放入到了容器中。但是作为程序员,我们不可能每定义了一个Mapper,还得去定义一个LubanFactoryBean,这是很麻烦的事情,我们改造一下LubanFactoryBean,让他变得更通用,比如:

  改造LubanFactoryBean之后,LubanFactoryBean变得灵活了,可以在构造LubanFactoryBean时,通过构造传入不同的Mapper接口。实际上LubanFactoryBean也是一个Bean,我们也可以通过生成一个BeanDefinition来生成一个LubanFactoryBean,并给构造方法的参数设置不同的值,比如伪代码如下:

  特别说一下注意二,表示表示当前BeanDefinition在生成bean对象时,会通过调用LubanFactoryBean的构造方法来生成,并传入UserMapper的Class对象。那么在生成LubanFactoryBean时就会生成一个UserMapper接口对应的代理对象作为bean了。到此为止,其实就完成了我们要解决的问题:把Mybatis中的代理对象作为一个bean放入Spring容器中。

  只是我们这是用简单的JDK代理对象模拟的Mybatis中的代理对象,如果有时间,我们完全可以调Mybatis中提供的方法区生成一个代理对象。这里就不花时间去介绍了。Import到这里,我们还有一个事情没有做,就是怎么真正的定义一个BeanDefinition,并把它添加到Spring中,上文说到我们要利用Import技术,比如可以这么实现:定义如下类:

  并且在AppConfig上添加Import注解:

  这样在启动Spring时就会新增一个BeanDefinition,该BeanDefinition会生成一个LubanFactoryBean对象,并且在生成LubanFactoryBean对象时会传入UserMapper.class对象,通过LubanFactoryBean内部的逻辑,相当于会自动生产一个UserMapper接口的代理对象作为一个bean。

  总结一下,通过我们的分析,我们要整合Spring和Mybatis,需要我们做的事情如下:

  作者:程序员周瑜链接:

  mybatis基本配置详解

  MySQL驱动版本根据自己安装的MySQL选择

  我把AppTest改成了MybatisTest,不该也无妨;其中Student类暂时只设置四个字段:

  mapper接口暂时为空

  在resources目录下新建File命名为db.peoperties,配置如下内容:

  提示:以上配置适用于MySQL.X版本,.X版本按照如下配置:

  transactionManager:事务管理器;type事务管理类型:JDBC(JdbcTransactionFactory);MANAGED(ManagedTransactionFactory)自定义事务管理器:实现TransactionFactory接口.type指定为全类名

  dataSource:数据源;type:数据源类型;UNPOOLED(UnpooledDataSourceFactory);POOLED(PooledDataSourceFactory);JNDI(JndiDataSourceFactory)自定义数据源:实现DataSourceFactory接口,type是全类名

  《mapper》:注册一个sql映射文件、注册映射文件resource:引用类路径下的sql映射文件mybatis/StudentMapperpper.xmlurl:引用网路路径或者磁盘路径下的sql映射文件注册接口class:引用(注册接口,①有sql映射文件,映射文件名必须和接口同名,并且放在与接口同一目录下;②没有sql映射文件,所有的sql都是利用注解写在接口上;推荐:比较重要的,复杂的Dao接口我们来写sql映射文件不重要,简单的Dao接口为了开发快速可以使用注解;批量注册需要在资源路径下(resources)建立和dao一样的文件目录来存放想xml映射文件,如:.example.StudentMapperpper.xml

  StudentMapper

  在resources的mybatis目录下新建文件夹mapper,新建xml文件StudentMapper.xml

  namespace:名称空间;指定为接口的全类名id:唯一标识resultType:返回值类型#{id}:从传递过来的参数中取出id值resources目录(MajorMapper.xml暂时不用创建如下:

  mybatis工作原理是什么

  MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs(PlainOrdinaryJavaObjects,普通的Java对象映射成数据库中的记录。

  每个MyBatis应用程序主要都是使用SqlSessionFactory实例的,一个SqlSessionFactory实例可以通过SqlSessionFactoryBuilder获得。SqlSessionFactoryBuilder可以从一个xml配置文件或者一个预定义的配置类的实例获得。

  用xml文件构建SqlSessionFactory实例是非常简单的事情。推荐在这个配置中使用类路径资源(classpathresource),但你可以使用任何Reader实例,包括用文件路径或开头的url创建的实例。MyBatis有一个实用类----Resources,它有很多方法,可以方便地从类路径及其它位置加载资源。

  把Mybatis的功能架构分为三层:

  API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。

  数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。

  基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。

  从命名上可以看出,这个是一个Builder模式的,用于创建SqlSessionFactory的类。SqlSessionFactoryBuilder根据配置来构造SqlSessionFactory。其中配置方式有两种:mybatis-config.xml就是我们的配置文件:JavaConfig相比较XML文件的方式而言,会有一些限制。比如修改了配置文件需要重新编译,注解方式没有XML配置项多等。所以,业界大多数情况下是选择XML文件的方式。但到底选择哪种方式,这个要取决与自己团队的需要。比如,项目的SQL语句不复杂,也不需要一些高级的SQL特性,那么JavaConfig则会更加简洁一点;反之,则可以选择XML文件的方式。创建配置文件解析器XMLConfigBuilder解析mybatis-config.xml里的配置为Configuration对象,Mybatis的全局配置对象。XMLConfigBuilder#parseConfiguration解析mapper下的xmlXMLMapperBuilder#bindMapperForNamespace,根据xml里的namespace反射出mapper接口的class,如果有mapper接口,则把该mapper接口的class添加到Configuration的mapperRegistry里。如果该接口已经注册,则抛出已经绑定的异常。为该接口注册MapperProxyFactory,但这里只是注册其创建MapperProxy的工厂,并不是创建MapperProxy。如果Mapper对应的xml资源未加载,触发xml的绑定操作,将xml中的sql语句与Mapper建立关系。addMapper方法,只是为**Mapper创建对应对应的MapperProxyFactory。根据Mapper接口与SqlSession创建MapperProxy对象。根据接口类获取MapperProxyFactory。调用MapperProxyFactory的newInstance创建MapperProxy对象。SqlSessionFactory顾名思义,是用于生产SqlSession的工厂。通过如下的方式来获取SqlSession实例:SqlSession包含了执行SQL的所有的方法。以下是示例:当然,下面的方式可以做到类型安全:MapperProxy是MapperProxyFactory使用SqlSession创建出来的。所以MapperProxy中包含SqlSession。可以看到MapperProxy调用invoke方法,进而调用MapperMethod的execute(),这些MapperMethod就是和你要执行的命令相关,比如执行select语句,则会通过SqlSession的select()方法,最终调用到Executor的query方法。Executor会再协调另外三个核心组件。MapperProxy:MapperMethod:插件的构建:谈原理首先要知道StatementHandler,ParameterHandler,ResultHandler都是代理,他们是Configuration创建,在创建过程中会调用interceptorChain.pluginAll()方法,为四大组件组装插件(再底层是通过Plugin.wrap(target,XX,newPlugin(interceptor))来来创建的。插件链是何时构建的:在执行SqlSession的query或者update方法时,SqlSession会通过Configuration创建Executor代理,在创建过程中就调用interceptor的pluginAll方法组装插件。然后executor在调用doQuery()方法的时候,也会调用Configuration的newStatementHandler方法创建StatemenHandler(和上面描述的一样,这个handler就是个代理,也是通过interceptorChain的pluginAll方法构建插件插件如何执行:以statementhandler的prepare方法的插件为例,正如前面所说,statementhandler是一个proxy,执行他的prepare方法,将调用invokeHandler的invoke方法,而invokeHandler就是Plugin.wrap(target,xxx,newPlugin(interceptor))中的第三个参数,所以很自然invokeHanlder的invoke的方法最终就会调用interceptor对象的intercept方法。Mybatis的插件配置在configuration内部,初始化时,会读取这些插件,保存于Configuration对象的InterceptorChain中。.apache.ibatis.plugin.InterceptorChain.java源码。上面的for循环代表了只要是插件,都会以责任链的方式逐一执行,所谓插件,其实就类似于拦截器。插件的编写插件必须实现.apache.ibatis.plugin.Interceptor接口。-intercept()方法:执行拦截内容的地方,拦截目标对象的目标方法的执行-plugin()方法:决定是否触发intercept()方法。作用:包装目标对象,包装就是为目标对象创建一个代理对象-setProperties()方法:给自定义的拦截器传递xml配置的属性参数。将插件注册时的property属性设置进来下面自定义一个拦截器:为什么要写Annotation注解?注解都是什么含义?Mybatis规定插件必须编写Annotation注解,是必须,而不是可选。Intercepts注解:装载一个Signature列表,一个Signature其实就是一个需要拦截的方法封装。那么,一个拦截器要拦截多个方法,自然就是一个Signature列表。type=Executor.class,method=“query“,args={MappedStatement.class,Object.class,RowBounds.class,ResultHandler.class}解释:要拦截Executor接口内的query()方法,参数类型为args列表。Plugin.wrap(target,this)是干什么的?使用JDK的动态代理,给target对象创建一个delegate代理对象,以此来实现方法拦截和增强功能,它会回调intercept()方法。Mybatis可以拦截哪些接口对象?Mybatis只能拦截ParameterHandler、ResultSetHandler、StatementHandler、Executor共个接口对象内的方法。重新审视interceptorChain.pluginAll()方法:该方法在创建上述个接口对象时调用,其含义为给这些接口对象注册拦截器功能,注意是注册,而不是执行拦截。拦截器执行时机:plugin()方法注册拦截器后,那么,在执行上述个接口对象内的具体方法时,就会自动触发拦截器的执行,也就是插件的执行。Invocation可以通过invocation来获取拦截的目标方法,以及执行目标方法。分页插件原理由于Mybatis采用的是逻辑分页,而非物理分页,那么,市场上就出现了可以实现物理分页的Mybatis的分页插件。要实现物理分页,就需要对Stringsql进行拦截并增强,Mybatis通过BoundSql对象存储Stringsql,而BoundSql则由StatementHandler对象获取。因此,就需要编写一个针对StatementHandler的query方法拦截器,然后获取到sql,对sql进行重写增强。

  什么是mybatis

  mybatis是什么

  MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis是一款优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。MyBatis可以使用简单的XML或注解来配置和映射原生信息,将接口和Java的POJOs(PlainOrdinaryJavaObject,普通的Java对象)映射成数据库中的记录。

  深入Mybatis框架

  学习了Spring之后,我们已经了解如何将一个类作为Bean交由IoC容器管理,也就是说,现在我们可以通过更方便的方式来使用Mybatis框架,我们可以直接把SqlSessionFactory、Mapper交给Spring进行管理,并且可以通过注入的方式快速地使用它们。因此,我们要学习一下如何将Mybatis与Spring进行整合,那么首先,我们需要在之前知识的基础上继续深化学习。在之前,我们如果需要创建一个JDBC的连接,那么必须使用DriverManager.getConnection()来创建连接,连接建立后,我们才可以进行数据库操作。而学习了Mybatis之后,我们就不用再去使用DriverManager为我们提供连接对象,而是直接使用Mybatis为我们提供的SqlSessionFactory工具类来获取对应的SqlSession通过会话对象去操作数据库。那么,它到底是如何封装JDBC的呢?我们可以试着来猜想一下,会不会是Mybatis每次都是帮助我们调用DriverManager来实现的数据库连接创建?我们可以看看Mybatis的源码:在通过SqlSessionFactory调用openSession方法之后,它调用了内部的一个私有的方法openSessionFromDataSource,我们接着来看,这个方法里面定义了什么内容:也就是说,我们的数据源配置信息,存放在了Transaction对象中,那么现在我们只需要知道执行器到底是如何执行SQL语句的,我们就知道到底如何创建Connection对象了,就需要获取数据库的链接信息了,那么我们来看看,这个DataSource到底是个什么:我们发现,它是在javax.sql定义的一个接口,它包括了两个方法,都是用于获取连接的。因此,现在我们可以断定,并不是通过之前DriverManager的方法去获取连接了,而是使用DataSource的实现类来获取的,因此,也就正式引入到我们这一节的话题了:数据库链接的建立和关闭是极其耗费系统资源的操作,通过DriverManager获取的数据库连接,一个数据库连接对象均对应一个物理数据库连接,每次操作都打开一个物理连接,使用完后立即关闭连接,频繁的打开、关闭连接会持续消耗网络资源,造成整个系统性能的低下。因此,JDBC为我们定义了一个数据源的标准,也就是DataSource接口,告诉数据源数据库的连接信息,并将所有的连接全部交给数据源进行集中管理,当需要一个Connection对象时,可以向数据源申请,数据源会根据内部机制,合理地分配连接对象给我们。一般比较常用的DataSource实现,都是采用池化技术,就是在一开始就创建好N个连接,这样之后使用就无需再次进行连接,而是直接使用现成的Connection对象进行数据库操作。当然,也可以使用传统的即用即连的方式获取Connection对象,Mybatis为我们提供了几个默认的数据源实现,我们之前一直在使用的是官方的默认配置,也就是池化数据源:一共三个选项:那么我们先来看看,不使用池化的数据源实现,它叫做UnpooledDataSource,我们来看看源码:首先这个类中定义了很多的成员,包括数据库的连接信息、数据库驱动信息、事务相关信息等。我们接着来看,它是如何实现DataSource中提供的接口的:实际上,这两个方法都指向了内部的一个doGetConnection方法,那么我们接着来看:首先它将数据库的连接信息也给添加到Properties对象中进行存放,并交给下一个doGetConnection来处理,套娃就完事了呗,接着来看下一层源码:到这里,就返回Connection对象了,而此对象正是通过DriverManager来创建的,因此,非池化的数据源实现依然使用的是传统的连接创建方式,那我们接着来看池化的数据源实现,它是PooledDataSource类:我们发现,在这里的定义就比非池化的实现复杂得多了,因为它还要考虑并发的问题,并且还要考虑如何合理地存放大量的链接对象,该如何进行合理分配,因此它的玩法非常之高级。首先注意,它存放了一个UnpooledDataSource,此对象是在构造时就被创建,其实创建Connection还是依靠数据库驱动创建,我们后面慢慢解析,首先我们来看看它是如何实现接口方法的:可以看到,它调用了popConnection()方法来获取连接对象,然后进行了一个代理,我们可以猜测,有可能整个连接池就是一个类似于栈的集合类型结构实现的。那么我们接着来看看popConnection方法:经过上面一顿猛如虎的操作之后,我们可以得到以下信息:如果最后得到了连接对象(有可能是从空闲列表中得到,有可能是直接创建的新的,还有可能是经过回收策略回收得到的。那么连接(Connection)对象一定会被放在活跃列表中(state.activeConnections)那么肯定有一个疑问,现在我们已经知道获取一个链接会直接进入到活跃列表中,那么,如果一个连接被关闭,又会发生什么事情呢,我们来看看此方法返回之后,会调用getProxyConnection来获取一个代理对象,实际上就是PooledConnection类:它直接代理了构造方法中传入的Connection对象,也是使用JDK的动态代理实现的,那么我们来看一下,它是如何进行代理的:那么我们最后再来看看pushConnection方法:这样,我们就已经完全了解了Mybatis的池化数据源的执行流程了。只不过,无论Connection管理方式如何变换,无论数据源再高级,我们要知道,它都最终都会使用DriverManager来创建连接对象,而最终使用的也是DriverManager提供的Connection对象。通过了解数据源,我们已经清楚,Mybatis实际上是在使用自己编写的数据源(数据源有很多,之后我们再聊其他的默认使用的是池化的数据源,它预先存储了很多的连接对象。那么我们来看一下,如何将Mybatis与Spring更好的结合呢,比如我们现在希望将SqlSessionFactory交给IoC容器进行管理,而不是我们自己创建工具类来管理(我们之前一直都在使用工具类管理和创建会话首先导入依赖:在mybatis-spring依赖中,为我们提供了SqlSessionTemplate类,它其实就是官方封装的一个工具类,我们可以将其注册为Bean,这样我们随时都可以向IoC容器索要,而不用自己再去编写一个工具类了,我们可以直接在配置类中创建:最后成功得到Student实体类,证明SqlSessionTemplate成功注册为Bean可以使用了。虽然这样已经很方便了,但是还不够方便,我们依然需要手动去获取Mapper对象,那么能否直接得到对应的Mapper对象呢,我们希望让Spring直接帮助我们管理所有的Mapper,当需要时,可以直接从容器中获取,我们可以直接在配置类上方添加注解:这样,Spring会自动扫描所有的Mapper,并将其实现注册为Bean,那么我们现在就可以直接通过容器获取了:请一定注意,必须存在SqlSessionTemplate或是SqlSessionFactoryBean的Bean,否则会无法初始化(毕竟要数据库的链接信息我们接着来看,如果我们希望直接去除Mybatis的配置文件,那么改怎么去实现呢?我们可以使用SqlSessionFactoryBean类:首先我们需要创建一个数据源的实现类,因为这是数据库最基本的信息,然后再给到SqlSessionFactoryBean实例,这样,我们相当于直接在一开始通过IoC容器配置了SqlSessionFactory,只需要传入一个DataSource的实现即可。删除配置文件,重新再来运行,同样可以正常使用Mapper。从这里开始,通过IoC容器,Mybatis已经不再需要使用配置文件了,之后基于Spring的开发将不会再出现Mybatis的配置文件。

  Mybatis支持的数据类型

  Mybatis所支持的jdbcType类型,是固定的,枚举如下:BIT、FLOAT、CHAR、TIMESTAMP、OTHER、UNDEFINED、TINYINT、REAL、VARCHAR、BINARY、BLOB、NVARCHAR、SMALLINT、DOUBLE、LONGVARCHAR、VARBINARY、CLOB、NCHAR、INTEGER、NUMERIC、DATE、LONGVARBINARY、BOOLEAN、NCLOB、BIGINT、DECIMAL、TIME、NULL、CURSOR在书写jabcType类型的时候,是有严格的大小写的区分的,否则会抛出异常。

您可能感兴趣的文章:

相关文章