MyBatis+Spring MVC开发指南(一)

前言

MyBatis+Spring MVC这套组合,在实际互联网项目中非常流行,博主工作中也涉及过,打算由浅入深、系统的写出来!这个系列将会涵盖MyBatis开发详解、Spring MVC开发详解,以及2者的结合使用,并会分析它们的原理!(可以参考博主的另一篇文章了解Spring MVC原理:《写出我的第一个框架:迷你版Spring MVC》)

没有MyBatis之前

在早期,我们都是通过原生的JDBC来操作数据库的,而这种方式存在很多问题。

我们先来看一个例子:

原生JDBC操作方式

问题有哪些呢?

第一,在创建数据库连接这块,程序是需要时创建,用完后关闭。如果频繁的创建、关闭数据库连接,显然存在问题。当然,我们可以通过数据库连接池来处理这个问题。

第二,硬编码的地方太多了。比如,数据库连接相关的一些信息,SQL相关的一些信息。当然,我们可以通过使用配置文件,来避免这个问题。

第三,实质上,我们编写JDBC是有步骤可循的,比如,我们得先得到数据库连接对象,得有SQL,有输入参数,设置参数,去执行SQL,然后遍历结果集将数据库SQL执行的结果对象转化为JAVA对象,然后再去业务处理,最后释放资源。那么这个过程,实际上是个模板,能不能抽离出来,更好的去完成这个过程呢?

比如,Hibernate,这个纯粹的ORM(对象关系映射)框架,让程序员以面向对象的方式来完成数据库的操作,功能很强大,SQL都帮我们自动生成了,但是这也带来了一些其他问题,比如门槛较高,有时候我们想编写SQL,修改SQL,优化SQL都费劲,在互联网项目快速迭代开发中,太过笨重了!

基于这些因素,出现了iBatis,并发展为今天的MyBatis,作为Apache的顶级项目,目前已经托管到github下。


MyBatis框架的架构

上面我们说了一些JDBC的缺点,而MyBatis是避免了这些问题的。如果让我们来实现MyBatis的话,我们会怎么想呢?

第一,应该存在一个配置文件A,可以将数据库的连接信息,事务信息等放入其中;

第二,应该提供一个配置文件B,可以让程序员编写SQL,重点需要解决的是如何给SQL传递参数,以及如何将结果映射为JAVA对象;

第三,应该提供API可以执行文件B中的SQL

基于上面的分析,我们来看一下MyBatis的架构:

MyBatis的架构

这里,我们先简单了解些概念:

SqlSessionFactory用于创建SqlSession,SqlSession即操作DB的接口,其内部借助Executor执行器完成对数据库的操作。

全局配置文件,就是图中的SqlMapConfig.xml;SQL文件即是Mapper.xml文件。

对于MappedStatement而言,会完成输入映射以及输出映射。


Quick Start

这里先写个简单的DEMO带大家初步了解下。

POM依赖:

pom.xml

MyBatis的全局配置文件:

SqlMapConfig.xml

需要注意下:

第一,我们把MySQL的一些连接信息放入到db.properties中,使用<properties>标签加载属性文件,并通过${XXX}的方式引用。

第二,要知道现在的日志框架有很多,这里使用<settings>设置下日志使用LOG4J实现。

第三,我们说SQL结果集要完成到JAVA对象的映射,那么根据反射的原理,我们都能猜到必须要提供带包路径的全限定名称,那么为了简化,提供<typeAliases>标签进行别名映射处理。提供了2种方式,一个是单个的类型别名映射,一个是基于包扫描的批量映射。当然批量映射的别名就是类名。

第四,需要<mappers>标签加载SQL文件。同上面一样,也提供了基于包扫描的批量加载。

log4j.properties:

log4j.properties

在开发阶段,显然,我们希望MyBatis能够为我们打印SQL日志,方便调试,排查问题。

SQL配置:

Student.xml

需要关注下:

第一,namespace,顾名思义,命名空间,其实是想隔离SQL,不过到了MyBatis和Spring结合使用时,具有特殊的意义。这里暂且使用全限定类名。

第二,<select>等SQL Command标签需要一个ID,还需要输入参数parameterType,输出参数映射resultType等。其实这些在MyBatis的底层封装成了一个MappedStatement对象。当然定位这个对象,需要namespace.id的方式。

第三,${value} VS #{xxx}

其实2者,都可以接受JAVA简单类型,如int,也可以接受POJO,Map等复杂类型。如果是JAVA简单类型,那么$的方式必须是${value},而#{}可以随意,是因为在这种情况下,$会通过反射getValue()的方式取值。如果是POJO等复杂类型,2者其实都可以通过OGNL表达式取到,只不过#会额外的进行JAVA类型到数据库类型的转换,而$没有类型处理过程,它直接拼接。也就是说#会使用预编译成?,而$将在SQL编译阶段就采取替换操作,可能带来SQL注入的问题。所以在实际开发中,我们当然优先采用#的方式取值。

测试程序:

Test

测试程序,并没有太多可以说的,关注2点即可:

第一,selectOne VS selectList

显然,我们需要清楚的知道,SQL返回的结果集是一条记录,还是多条记录,如果使用selectOne那么必须最多返回一条记录。那么返回多条记录与返回一条记录的时候,resultType有变化么?(其实是不变的。)

第二,SqlSession

SqlSessionFactoryBuilder -> SqlSessionFactory -> SqlSession

我们重点关注的是SqlSession,它其实是一个interface,定义了很多操作数据库的接口,而且extends Closeable,很明确是需要close的。

它的实现类DefaultSqlSession中有一些数据域(比如说autoCommit,在默认情况下是不开启自动提交的),而且方法也并不是Synchronized,这说明SqlSession并不是线程安全的,因此我们应该是局部使用SqlSession,使用完毕后close掉。


Mapper代理开发

其实,除了Mapper代理开发外,还有一种原始Dao开发的方式。原始Dao开发方式的思路大致是这样的:

第一,我们提供Dao接口,有增、删、改、查的方法。

第二,我们提供Dao的实现类,在实现类中,我们利用Spring注入SqlSessionFactory,然后在各个方法中得到SqlSession,进行操作后,关闭SqlSession即可。

这种方式,重复的代码太多,已经OUT了,目前使用最多的就是Mapper代理开发。

提供Mapper.java接口:

Mapper接口

提供与之对应的Mapper.xml文件:

Mapper.xml

在全局配置文件中加载Mapper.xml:

加载mapper.xml配置

测试代码示例:

调用方式

从这里,你应该可以看出Mapper的开发应该遵循一些规范,这样MyBatis才可以自动帮助我们生成XXXMapper类的代理实现类。(说白了,这些规范,就是为了利用反射)

第一,保证XXXMapper.xml中的namespace同XXXMapper.java的全限定名称一致

第二,保证XXXMapper.xml中的Statement的ID同XXXMapper.java的方法名称一致

第三,保证XXXMapper.xml中的Statement的输入参数的类型(parameterType)、输出参数的类型(resultType)同XXXMapper.java的保持一致

从这里,你大致可以了解到Mapper代理开发,程序员主要关注的就是Mapper.java以及Mapper.xml的生成,可以说极大的简化了工作量!


关于自增主键返回

很多时候,我们面临这样的需求,A表的字段ID是主键,而且是auto_increment自动增长的;我们完成A表的插入后,希望得到主键,以便后续的操作,比如另外一个表B,和表A存在主外键关系。

MyBatis当然早就替我们想好了,只需要稍微配置下,就可以将MySQL自动生成的主键取出设置到对应的JAVA对象的属性上。

看一个例子:

自动获取主键设置

特别注意keyProperty是表示将获取到的自动增长的值设置到哪个Field域上。


关于动态SQL

我们知道,在JSP中,可以使用JSTL标签开发;而动态SQL就是类似于JSTL的一组标签,可以帮助我们灵活的生成SQL,比如实现判断,遍历数组/集合,SQL片段的复用等。值得关注的是,有些标签还挺智能,比如<where>还可以替你去掉第一个and.....

本篇博客并不会说明各个标签的使用方式,这样的例子,网上很多,大家可以参考。一句话,在开发阶段,我们只需要让MyBatis打印SQL,我们就能明白,我们的动态SQL是不是使用对了!


到这里,本篇博客就准备结束了,下一篇博客将会为大家介绍MyBatis的一些高级开发知识~

See U next time~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,290评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,107评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,872评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,415评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,453评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,784评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,927评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,691评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,137评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,472评论 2 326
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,622评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,289评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,887评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,741评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,316评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,490评论 2 348

推荐阅读更多精彩内容