深入Mybatis框架

深入Mybatis框架,第1张

学习了Spring之后,我们已经了解如何将一个类作为Bean交由IoC容器管理,也就是说,现在我们可以通过更方便的方式来使用Mybatis框架,我们可以直接把SqlSessionFactory、Mapper交给Spring进行管理,并且可以通过注入的方式快速地使用它们。

因此,我们要学习一下如何将Mybatis与Spring进行整合,那么首先,我们需要在之前知识的基础上继续深化学习。

在之前,我们如果需要创建一个JDBC的连接,那么必须使用 DriverManagergetConnection() 来创建连接,连接建立后,我们才可以进行数据库 *** 作。

而学习了Mybatis之后,我们就不用再去使用 DriverManager 为我们提供连接对象,而是直接使用Mybatis为我们提供的 SqlSessionFactory 工具类来获取对应的 SqlSession 通过会话对象去 *** 作数据库。

那么,它到底是如何封装JDBC的呢?我们可以试着来猜想一下,会不会是Mybatis每次都是帮助我们调用 DriverManager 来实现的数据库连接创建?我们可以看看Mybatis的源码:

在通过 SqlSessionFactory 调用 openSession 方法之后,它调用了内部的一个私有的方法 openSessionFromDataSource ,我们接着来看,这个方法里面定义了什么内容:

也就是说,我们的数据源配置信息,存放在了 Transaction 对象中,那么现在我们只需要知道执行器到底是如何执行SQL语句的,我们就知道到底如何创建 Connection 对象了,就需要获取数据库的链接信息了,那么我们来看看,这个 DataSource 到底是个什么:

我们发现,它是在 javaxsql 定义的一个接口,它包括了两个方法,都是用于获取连接的。因此,现在我们可以断定,并不是通过之前 DriverManager 的方法去获取连接了,而是使用 DataSource 的实现类来获取的,因此,也就正式引入到我们这一节的话题了:

数据库链接的建立和关闭是极其耗费系统资源的 *** 作,通过DriverManager获取的数据库连接,

一个数据库连接对象均对应一个物理数据库连接,每次 *** 作都打开一个物理连接,使用完后立即关闭连接,频繁的打开、关闭连接会持续消耗网络资源,造成整个系统性能的低下。

因此,JDBC为我们定义了一个数据源的标准,也就是 DataSource 接口,告诉数据源数据库的连接信息,并将所有的连接全部交给数据源进行集中管理,当需要一个 Connection 对象时,可以向数据源申请,数据源会根据内部机制,合理地分配连接对象给我们。

一般比较常用的 DataSource 实现,都是采用池化技术,就是在一开始就创建好N个连接,这样之后使用就无需再次进行连接,而是直接使用现成的 Connection 对象进行数据库 *** 作。

当然,也可以使用传统的即用即连的方式获取 Connection 对象,Mybatis为我们提供了几个默认的数据源实现,我们之前一直在使用的是官方的默认配置,也就是池化数据源:

一共三个选项:

那么我们先来看看,不使用池化的数据源实现,它叫做 UnpooledDataSource ,我们来看看源码:

首先这个类中定义了很多的成员,包括数据库的连接信息、数据库驱动信息、事务相关信息等。

我们接着来看,它是如何实现 DataSource 中提供的接口的:

实际上,这两个方法都指向了内部的一个 doGetConnection 方法,那么我们接着来看:

首先它将数据库的连接信息也给添加到 Properties 对象中进行存放,并交给下一个 doGetConnection 来处理,套娃就完事了呗,接着来看下一层源码:

到这里,就返回 Connection 对象了,而此对象正是通过 DriverManager 来创建的,因此,非池化的数据源实现依然使用的是传统的连接创建方式,那我们接着来看池化的数据源实现,它是 PooledDataSource 类:

我们发现,在这里的定义就比非池化的实现复杂得多了,因为它还要考虑并发的问题,并且还要考虑如何合理地存放大量的链接对象,该如何进行合理分配,因此它的玩法非常之高级。

首先注意,它存放了一个UnpooledDataSource,此对象是在构造时就被创建,其实创建Connection还是依靠数据库驱动创建,我们后面慢慢解析,首先我们来看看它是如何实现接口方法的:

可以看到,它调用了 popConnection() 方法来获取连接对象,然后进行了一个代理,我们可以猜测,有可能整个连接池就是一个类似于栈的集合类型结构实现的。那么我们接着来看看 popConnection 方法:

经过上面一顿猛如虎的 *** 作之后,我们可以得到以下信息:

如果最后得到了连接对象(有可能是从空闲列表中得到,有可能是直接创建的新的,还有可能是经过回收策略回收得到的)。

那么连接(Connection)对象一定会被放在活跃列表中(stateactiveConnections)

那么肯定有一个疑问,现在我们已经知道获取一个链接会直接进入到活跃列表中,那么,如果一个连接被关闭,又会发生什么事情呢,我们来看看此方法返回之后,会调用 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的配置文件。

现象1:如果使用原生mybatis进行数据 *** 作,那么必须按照以下方式使用:SqlSessionsqlSession=null;try{sqlSession=sqlSessionFactoryopenSession();//namespace+idsqlSessioninsert("cnjarjardaoBlogMapperinsertBlog",blog);sqlSessioncommit(true)}catch(Exceptione){eprintStackTrace();sqlSessionrollback(true);}finally{sqlSessionclose();}也就是要像原始的javasqlConnection对象一样,必须按照:新建连接->执行SQL->提交(查询不需要)->如果 *** 作数据存在异常需要回滚->释放数据库连接。注意第一点和最后一点,每个SqlSession新建之后必须释放,不然会造成数据库连接泄露的危险。也就是意味着SqlSession是个有状态的对象,是无法进行复用的,所以只能局限于request或者方法的范围,也就是所谓的线程不安全。现象2:如果使用spring集成mybatis,官方提供了整和包mybatis-springjar,如果完成配置之后,使用方式及其简单,简单示例如下://注入spring中配置的SqlSessionTemplate对象,单例@Resource(name="sqlSessionTemplate")publicSqlSessionTemplatesqlSessionTemplate;publicvoidsaveTestTrans(){thissqlSessionTemplateselectList("testdomainselectAnySql","selectfrommy_blogwhereid='1'");}这里的SqlSessionTemplate不仅是单例的,而且不需要手工新建和关闭SqlSession问题1:那么问题来了,为什么mybatis-springjar中的SqlSessionTemplate可以被多个dao复用,而且不会造成数据连接泄露呢,并且还可以自动新建和释放数据库连接?官方解答是因为SqlSessionTemplate是线程安全的,也就是确保每个线程使用的sqlSession的唯一并不互相冲突。首先看了一下mybatis-spring的源码,发现SqlSessionTemplate是通过代理拦截和SqlSessionHolder实现的sqlsession线程安全和自动新建和释放连接的。看构造函数函数中构建代理类,该代理类实现SqlSession接口,定义了方法拦截器,如果调用代理类实例中实现SqlSession接口定义的方法,该调用则被导向SqlSessionInterceptor的invoke方法,这个方法中自动进行了SqlSession的自动请求和释放(如果不被spring托管则自己新建和释放sqlsession,如果被spring管理则使用SqlSessionHolder进行request和relase *** 作)以下网址针对SqlSessionTemplate的线程安全特性进行了详细的探究:问题2:然后又想到这样一个问题,虽然现在几乎所有项目都使用spring作为java程序的基本框架,如果我不使用spring管理mybatis,仅仅使用原始的mybatis,怎么样才能构建一个和SqlSessionTemplate相似的对象呢?首先想到必须使用java的treadLocal构建一个sqlsession的对象,如ThreadLocalsqlSession=newThreadLocal()。经过查找,发现mybatis自身就有这样一个类实现了类似的功能,类路径:orgapacheibatissessionSqlSessionManager,但是没有注释,可能存在mybatis-spring这种神器之后,mybatis放弃了对这个类的维护。该类实现了SqlSessionFactory,SqlSession并且在其中定义了一个treadLocal的sqlssion对象,同时使用了代理拦截进行了sqlsession的自动管理,具体代码可以自己查阅,对于理解mybatis原理和java的代理机制很有帮助。那么写个简单的程序验证一下SqlSessionManager是否真的可以保证线程安全和自动新建和释放sqlssion:TestSqlManagerjavaprivatestaticSqlSessionsqlSession;publicstaticSqlSessiongetSqlSessionTest(){if(sqlSession==null){//构建使用的SqlSessionFactorySqlSessionFactorysqlSessionFactory=MyBatisUtilgetSqlSessionFactory();sqlSession=SqlSessionManagernewInstance(sqlSessionFactory);}returnsqlSession;}publicstaticvoidmain(String[]args)throwsInterruptedException{Runrun=newRun();Listthreads=newArrayList();for(inti=0;i<100;i++){Threadt=newThread(run);threadsadd(t);Systemoutprintln("thread:{"+tgetName()+"},start");tstart();}for(Threadt:threads){Systemoutprintln("thread:{"+tgetName()+"},join");tjoin();}}我本机装的mysql,通过监控语句:selectSUBSTRING_INDEX(host,’:’,1)asip,count()frominformation_schemaprocesslistgroupbyip;发现执行过程中存在连接并发的情况,但是执行之后全部释放掉了。

本篇文章主要介绍了使用MyBatis框架完成数据库的增、删、改、查 *** 作。

准备工作

运行schemasql和datasql脚本文件中的 SQL 语句创建t_user表并添加部分测试数据。

schemasql:

datasql:

使用MyBatis框架 *** 作数据库步骤:

(1)定义Java实体

Userjava

(2)定义Mapper接口

UserDaojava

(3)编写XML映射文件

UserDaoxml

(4)编写MyBatis主配置文件

MyBatis使用 XML 文件格式描述配置信息,内容如下:

(5)编写测试类

Demojava

输出结果:

Mybatis *** 作数据库和 Hiberante 都差不多。此处介绍用springMVC和Mybatis

先在applicationContextxml里面配置Mybatis的信息

建好在上面实体的路径下面建好实体,XML的路径下面建好XML文件

然后在webxml下面引入applicationContextxml即可

以上就是关于深入Mybatis框架全部的内容,包括:深入Mybatis框架、mybatis 中的 sessionfactory 和 session 的特点和关系、MyBatis源码解读 - 使用MyBatis *** 作数据库等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/sjk/9852919.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-02
下一篇2023-05-02

发表评论

登录后才能评论

评论列表(0条)

    保存