`

原理分析之一:从JDBC到Mybatis

阅读更多

 

1.引言

本文主要讲解JDBC怎么演变到Mybatis的渐变过程,重点讲解了为什么要将JDBC封装成Mybaits这样一个持久层框架。再而论述Mybatis作为一个数据持久层框架本身有待改进之处。

 

 

2.JDBC实现查询分析

我们先看看我们最熟悉也是最基础的通过JDBC查询数据库数据,一般需要以下七个步骤:

(1)  加载JDBC驱动

(2)  建立并获取数据库连接

(3)  创建 JDBC Statements 对象

(4)  设置SQL语句的传入参数

(5)  执行SQL语句并获得查询结果

(6)  对查询结果进行转换处理并将处理结果返回

(7)  释放相关资源(关闭Connection,关闭Statement,关闭ResultSet

 

以下是具体的实现代码:

 

public static List<Map<String,Object>> queryForList(){
		Connection connection = null;
		ResultSet rs = null;
		PreparedStatement stmt = null;
		List<Map<String,Object>> resultList = new ArrayList<Map<String,Object>>();
		
		try {
			//加载JDBC驱动
			Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
			String url = "jdbc:oracle:thin:@localhost:1521:ORACLEDB";
			
			String user = "trainer"; 
			String password = "trainer"; 
			
			//获取数据库连接
			connection = DriverManager.getConnection(url,user,password); 
			
			String sql = "select * from userinfo where user_id = ? ";
			//创建Statement对象(每一个Statement为一次数据库执行请求)
stmt = connection.prepareStatement(sql);
			
			//设置传入参数
			stmt.setString(1, "zhangsan");
			
			//执行SQL语句
			rs = stmt.executeQuery();
			
			//处理查询结果(将查询结果转换成List<Map>格式)
			ResultSetMetaData rsmd = rs.getMetaData();
			int num = rsmd.getColumnCount();
		    
			while(rs.next()){
				Map map = new HashMap();
				for(int i = 0;i < num;i++){
					String columnName = rsmd.getColumnName(i+1);
					map.put(columnName,rs.getString(columnName));
				}
				resultList.add(map);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
                   //关闭结果集
				if (rs != null) {
					rs.close();
					rs = null;
				}
                   //关闭执行
				if (stmt != null) {
					stmt.close();
					stmt = null;
				}
				if (connection != null) {
					connection.close();
					connection = null;
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		
		return resultList;
	}
  

 

3.JDBC演变到Mybatis过程

   上面我们看到了实现JDBC有七个步骤,哪些步骤是可以进一步封装的,减少我们开发的代码量。

 

 

第一步优化:连接获取和释放

 

问题描述:

数据库连接频繁的开启和关闭本身就造成了资源的浪费,影响系统的性能。

解决问题:

数据库连接的获取和关闭我们可以使用数据库连接池来解决资源浪费的问题。通过连接池就可以反复利用已经建立的连接去访问数据库了。减少连接的开启和关闭的时间。

 

问题描述:

但是现在连接池多种多样,可能存在变化,有可能采用DBCP的连接池,也有可能采用容器本身的JNDI数据库连接池。

 

解决问题:

我们可以通过DataSource进行隔离解耦,我们统一从DataSource里面获取数据库连接,DataSource具体由DBCP实现还是由容器的JNDI实现都可以,所以我们将DataSource的具体实现通过让用户配置来应对变化。

 

 

第二步优化:SQL统一存取

 

问题描述:

我们使用JDBC进行操作数据库时,SQL语句基本都散落在各个JAVA类中,这样有三个不足之处:

第一,可读性很差,不利于维护以及做性能调优。

第二,改动Java代码需要重新编译、打包部署。

第三,不利于取出SQL在数据库客户端执行(取出后还得删掉中间的Java代码,编写好的SQL语句写好后还得通过+号在Java进行拼凑)。

 

解决问题:

我们可以考虑不把SQL语句写到Java代码中,那么把SQL语句放到哪里呢?首先需要有一个统一存放的地方,我们可以将这些SQL语句统一集中放到配置文件或者数据库里面(以key-value的格式存放)。然后通过SQL语句的key值去获取对应的SQL语句。

既然我们将SQL语句都统一放在配置文件或者数据库中,那么这里就涉及一个SQL语句的加载问题。

 

 

第三步优化:传入参数映射和动态SQL

 

 

问题描述:

很多情况下,我们都可以通过在SQL语句中设置占位符来达到使用传入参数的目的,这种方式本身就有一定局限性,它是按照一定顺序传入参数的,要与占位符一一匹配。但是,如果我们传入的参数是不确定的(比如列表查询,根据用户填写的查询条件不同,传入查询的参数也是不同的,有时是一个参数、有时可能是三个参数),那么我们就得在后台代码中自己根据请求的传入参数去拼凑相应的SQL语句,这样的话还是避免不了在Java代码里面写SQL语句的命运。既然我们已经把SQL语句统一存放在配置文件或者数据库中了,怎么做到能够根据前台传入参数的不同,动态生成对应的SQL语句呢?

 

解决问题:

第一,我们先解决这个动态问题,按照我们正常的程序员思维是,通过ifelse这类的判断来进行是最直观的,这个时候我们想到了JSTL中的<if test=””></if>这样的标签,那么,能不能将这类的标签引入到SQL语句中呢?假设可以,那么我们这里就需要一个专门的SQL解析器来解析这样的SQL语句,但是,if判断的变量来自于哪里呢?传入的值本身是可变的,那么我们得为这个值定义一个不变的变量名称,而且这个变量名称必须和对应的值要有对应关系,可以通过这个变量名称找到对应的值,这个时候我们想到了key-valueMap。解析的时候根据变量名的具体值来判断。

假如前面可以判断没有问题,那么假如判断的结果是true,那么就需要输出的标签里面的SQL片段,但是怎么解决在标签里面使用变量名称的问题呢?这里我们需要使用一种有别于SQL的语法来嵌入变量(比如使用#变量名#)。这样,SQL语句经过解析后就可以动态的生成符合上下文的SQL语句。

还有,怎么区分开占位符变量和非占位变量?有时候我们单单使用占位符是满足不了的,占位符只能为查询条件占位,SQL语句其他地方使用不了。这里我们可以使用#变量名#表示占位符变量,使用$变量名$表示非占位符变量。

 

 

第四步优化:结果映射和结果缓存

 

问题描述:

执行SQL语句、获取执行结果、对执行结果进行转换处理、释放相关资源是一整套下来的。假如是执行查询语句,那么执行SQL语句后,返回的是一个ResultSet结果集,这个时候我们就需要将ResultSet对象的数据取出来,不然等到释放资源时就取不到这些结果信息了。我们从前面的优化来看,以及将获取连接、设置传入参数、执行SQL语句、释放资源这些都封装起来了,只剩下结果处理这块还没有进行封装,如果能封装起来,每个数据库操作都不用自己写那么一大堆Java代码,直接调用一个封装的方法就可以搞定了。

 

解决问题:

我们分析一下,一般对执行结果的有哪些处理,有可能将结果不做任何处理就直接返回,也有可能将结果转换成一个JavaBean对象返回、一个Map返回、一个List返回等等,结果处理可能是多种多样的。从这里看,我们必须告诉SQL处理器两点:第一,需要返回什么类型的对象;第二,需要返回的对象的数据结构怎么跟执行的结果映射,这样才能将具体的值copy到对应的数据结构上。

    接下来,我们可以进而考虑对SQL执行结果的缓存来提升性能。缓存数据都是key-value的格式,那么这个key怎么来呢?怎么保证唯一呢?即使同一条SQL语句几次访问的过程中由于传入参数的不同,得到的执行SQL语句也是不同的。那么缓存起来的时候是多对。但是SQL语句和传入参数两部分合起来可以作为数据缓存的key值。

 

 

第五步优化:解决重复SQL语句问题

问题描述:

由于我们将所有SQL语句都放到配置文件中,这个时候会遇到一个SQL重复的问题,几个功能的SQL语句其实都差不多,有些可能是SELECT后面那段不同、有些可能是WHERE语句不同。有时候表结构改了,那么我们就需要改多个地方,不利于维护。

 

解决问题:

     当我们的代码程序出现重复代码时怎么办?将重复的代码抽离出来成为独立的一个类,然后在各个需要使用的地方进行引用。对于SQL重复的问题,我们也可以采用这种方式,通过将SQL片段模块化,将重复的SQL片段独立成一个SQL块,然后在各个SQL语句引用重复的SQL块,这样需要修改时只需要修改一处即可。

 

 

4. 优化总结:

我们总结一下上面对JDBC的优化和封装:

(1) 使用数据库连接池对连接进行管理

(2) SQL语句统一存放到配置文件

(3) SQL语句变量和传入参数的映射以及动态SQL

(4) 动态SQL语句的处理

(5) 对数据库操作结果的映射和结果缓存

(6) SQL语句的重复

 

5.    Mybaits有待改进之处

问题描述:

Mybaits所有的数据库操作都是基于SQL语句,导致什么样的数据库操作都要写SQL语句。一个应用系统要写的SQL语句实在太多了。

 

改进方法:

我们对数据库进行的操作大部分都是对表数据的增删改查,很多都是对单表的数据进行操作,由这点我们可以想到一个问题:单表操作可不可以不写SQL语句,通过JavaBean的默认映射器生成对应的SQL语句,比如:一个类UserInfo对应于USER_INFO表, userId属性对应于USER_ID字段。这样我们就可以通过反射可以获取到对应的表结构了,拼凑成对应的SQL语句显然不是问题。

60
0
分享到:
评论
19 楼 leeahuamsg 2018-06-04  
特别好,条理很清晰
18 楼 exampleenglish 2015-12-27  
改进之处,我觉得没有必要,本来mybatis就是轻量级别的ORmapping框架应用,好不容易将其从Hibernate这个重量级框架解脱,如果再全部面向对象,直接用Hibernate就行了,何必再衍生出来mybatis。计算机软件中的技术所面临的各种的问题,都不能用一种100%完美的方案解决,灵活使用即可!
17 楼 mrwalter 2015-04-08  
挺不错的,支持一下,如果能在每个问题下面放上相应的关键代码就更好了
16 楼 最爱海贼王 2014-10-22  
很棒的文章,赞一个!
15 楼 zhangjun111xingfu 2014-09-04  
大牛,是让人读的欲罢不能啊,可真么不全啊!
14 楼 迪0129 2014-04-03  
博主提的单表自动生成sql语句的提法,貌似over design啦,sql是一个大家接受的标准,如果都用面向对象的思维去统一sql,感觉很牵强
13 楼 xfjt297857539 2014-03-21  
不错,学习了很多。
12 楼 sihai0068 2014-03-07  
才看两个问题,就感觉写得很好,顶了再看。。。
11 楼 lanfeng330 2014-01-23  
Nottyjay 写道
learnworld 写道
chenjc_it 写道
weibc 写道
对于单表操作,现在通过myabtis提供的自动生成方式可以解决这些问题

如果可以省掉生成代码这个步骤会不会更好,这样也可以减少一些配置信息,而且一旦后期数据库表一变化,你还得去修改配置文件的SQL。

chenjc_it 写道
weibc 写道
对于单表操作,现在通过myabtis提供的自动生成方式可以解决这些问题

如果可以省掉生成代码这个步骤会不会更好,这样也可以减少一些配置信息,而且一旦后期数据库表一变化,你还得去修改配置文件的SQL。

其实楼主想把hibernate的优点也放进来,但ibatis最大的优点就是简单和灵活,所有的sql都是透明的,如果自动生成,反而有点偏离初衷。


的确。虽然提升了易用性。但是违背了mybatis的设计初衷。而且为了获取字段、表名进行频繁的映射是否会增加性能开销?

其实一直在在尝试做这样的功能,在单表单记录的更新操作上(增,改,删)hibernate是有优势的,但在查询操作上mybatis的灵活性更有优势。批量更新操作也只有mybatis更适合,至于说反射javabean等类来自动组装sql的性能影响可以忽略,本身只用在单表单记录的更新操作上。设计初衷这种东西在应用层面来讲不叫个事。反倒是,但你面对一个有20,30个字段的表,要进行更新操作,不得不写sql语句时,就知道设计初衷是虚的。应用讲究的是效率。
10 楼 bluend1004 2013-08-29  
还请楼主继续写下去!非常好~~~
9 楼 liu8563525 2013-08-26  
不错,顶一个
8 楼 rickyzhuang 2013-08-07  
   
7 楼 Nottyjay 2012-11-22  
learnworld 写道
chenjc_it 写道
weibc 写道
对于单表操作,现在通过myabtis提供的自动生成方式可以解决这些问题

如果可以省掉生成代码这个步骤会不会更好,这样也可以减少一些配置信息,而且一旦后期数据库表一变化,你还得去修改配置文件的SQL。

chenjc_it 写道
weibc 写道
对于单表操作,现在通过myabtis提供的自动生成方式可以解决这些问题

如果可以省掉生成代码这个步骤会不会更好,这样也可以减少一些配置信息,而且一旦后期数据库表一变化,你还得去修改配置文件的SQL。

其实楼主想把hibernate的优点也放进来,但ibatis最大的优点就是简单和灵活,所有的sql都是透明的,如果自动生成,反而有点偏离初衷。


的确。虽然提升了易用性。但是违背了mybatis的设计初衷。而且为了获取字段、表名进行频繁的映射是否会增加性能开销?
6 楼 learnworld 2012-11-14  
chenjc_it 写道
weibc 写道
对于单表操作,现在通过myabtis提供的自动生成方式可以解决这些问题

如果可以省掉生成代码这个步骤会不会更好,这样也可以减少一些配置信息,而且一旦后期数据库表一变化,你还得去修改配置文件的SQL。

chenjc_it 写道
weibc 写道
对于单表操作,现在通过myabtis提供的自动生成方式可以解决这些问题

如果可以省掉生成代码这个步骤会不会更好,这样也可以减少一些配置信息,而且一旦后期数据库表一变化,你还得去修改配置文件的SQL。

其实楼主想把hibernate的优点也放进来,但ibatis最大的优点就是简单和灵活,所有的sql都是透明的,如果自动生成,反而有点偏离初衷。
5 楼 chenjc_it 2012-09-14  
weibc 写道
对于单表操作,现在通过myabtis提供的自动生成方式可以解决这些问题

如果可以省掉生成代码这个步骤会不会更好,这样也可以减少一些配置信息,而且一旦后期数据库表一变化,你还得去修改配置文件的SQL。
4 楼 weibc 2012-09-14  
对于单表操作,现在通过myabtis提供的自动生成方式可以解决这些问题
3 楼 cometzb_xujun 2012-05-11  
楼主写的好;不过说的mybatis的改进之处,如果通过反射动态生成sql语句,是不是就有点像hibernate了呢?
2 楼 chenjc_it 2012-03-20  
兄弟,有时间才能写啊,已经补完了。
1 楼 yzxinye123 2012-03-20  
怎么不写完啊。

相关推荐

    sharding-jdbc-mybatis.zip

    Sharding-JDBC作为一款Java客户端直连数据库的ORM框架,其工作原理是在JDBC层面上进行拦截,通过配置规则对SQL进行改写,实现数据的分片。它支持常见的数据库如MySQL、Oracle、PostgreSQL等,并且兼容JPA、MyBatis...

    drools_jdbc_mybatis_mysql.rar

    总之,通过 Drools、JDBC 和 MyBatis 的组合,我们可以构建一个具备智能推理能力的专家系统,利用 MySQL 数据库中的信息进行复杂的逻辑分析,为人工智能应用提供强大支持。在实际项目中,这种技术栈能够帮助开发者...

    源码:【Spring+MyBatis+MySQL实战入门】一、MyBatis操作入门

    本文将重点讲解MyBatis操作入门的相关知识,通过源码解析,帮助你深入理解MyBatis的工作原理及使用方法。 1. MyBatis概述 MyBatis是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。MyBatis避免了...

    Spring整合Mybatis与SpringBoot整合Mybatis原理分析

    **Spring整合Mybatis原理分析** 在Java Web开发中,Spring框架以其强大的依赖注入和面向切面编程能力,成为了事实上的核心框架。Mybatis则是一个轻量级的持久层框架,它简化了数据库操作,提供了直观的SQL映射。将...

    尚硅谷 4月份MyBatis视频教程(国内首套:源码级讲授的MyBatis视频)最新更新

    MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集,通过XML或注解的方式将接口实现类映射到数据库语句,可以让你更加专注于SQL语句本身,而无需花费精力去处理加载驱动、创建连接等繁琐的工作。...

    毕设项目:基于SpringBoot+MyBatis+mysql的飞机订票系统.zip

    这是一个基于SpringBoot、MyBatis和MySQL技术栈的毕业设计项目——飞机订票系统。这个系统旨在模拟实际的在线机票预订流程,为用户提供方便快捷的机票查询、预订、支付等服务。下面将详细介绍该系统的核心技术和实现...

    myBatis系列之七:事务管理

    MyBatis的事务管理涉及到Transaction接口和其实现类,如JdbcTransaction,它们协同工作以处理事务的生命周期。 通过以上讲解,我们可以看到MyBatis的事务管理机制不仅提供了灵活性,也确保了数据的完整性和一致性。...

    Mybatis源码分析.pdf

    MyBatis是一款优秀的持久层框架,它的源码分析对于深入理解其工作原理和优化数据库操作至关重要。MyBatis的核心设计理念是简化SQL操作,通过XML或注解的方式将SQL与Java代码分离,同时提供强大的动态SQL功能。 首先...

    mybatis源码分析

    MyBatis是一个流行的Java持久层框架,它简化了数据库操作,通过XML或注解的方式将SQL与Java代码绑定,提供了一种动态SQL的解决方案。在深入理解MyBatis的源码之前,我们需要先了解其核心概念和功能。 1. SQL映射...

    mybatis-3.5.9 源码(mybatis-3-mybatis-3.5.9.tar.gz)

    通过提供一个配置文件,MyBatis 可以将你从编写繁琐的 JDBC 代码中解放出来,让你能够专注于业务逻辑的实现。 在 MyBatis 3.5.9 版本中,我们可以看到一些关键的改进和优化,这些都与源码紧密相关。首先,让我们...

    mybatis-3.4.1源码

    通过研究其源码,开发者可以深入理解MyBatis的工作原理,提高编程技能,并优化自己的应用。 在MyBatis 3.4.1源码中,我们可以关注以下几个核心知识点: 1. **SqlSessionFactoryBuilder**: 这是创建...

    mybatis mybatis-spring source jar

    我们可以从以下几个关键点来深入理解 MyBatis: 1. **SqlSession**: 这是 MyBatis 的核心接口,提供了执行 SQL 语句、提交和回滚事务等方法。源码中可以查看到它的实现类 DefaultSqlSession,了解其工作原理。 2. ...

    深入理解mybatis原理

    通过深入分析MyBatis的源码,可以观察到其架构的优雅设计以及运行时各部分的协作方式。 总而言之,MyBatis通过简单直观的API与强大的动态SQL能力,成为了Java开发者在处理数据库交互时的首选ORM框架之一。了解和...

    mybatis源码分析视频

    分析MyBatis源码有助于开发者更深入地理解框架的工作原理,提升问题解决能力,优化性能,以及在遇到异常时能够快速定位问题所在。 3. **MyBatis核心组件** - **SqlSessionFactoryBuilder**:用于创建...

    Paul-MyBatis:简单版的 MyBatis 框架

    【标题】"Paul-MyBatis:简单版的 MyBatis 框架" 提供了一个简化版的 MyBatis 实现,旨在帮助开发者更好地理解和学习 MyBatis 的核心概念和工作原理。MyBatis 是一个流行的 Java 数据库持久层框架,它允许程序员通过 ...

    mybatis视频教学-

    5. **Mapper**:MyBatis 的主要工作流程之一是通过 Mapper XML 文件或注解定义 SQL 语句。学习如何编写 Mapper XML 文件,配置 namespace、id、resultType、parameterType 等属性,以及编写动态 SQL。 6. **Mapper ...

    深入浅出MyBatis技术原理与实战.pdf

    6. **结果映射**:MyBatis可以自动将查询结果映射到Java对象,包括一对一、一对多、多对多的复杂关系映射。 7. **缓存机制**:MyBatis内置了本地缓存和二级缓存,能够提高数据读取效率,减少对数据库的访问。 8. *...

    mybatis逆向工具

    MyBatis是一个轻量级的持久层框架,它避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。MyBatis可以将SQL语句与Java代码分离,使开发更易于维护和测试。通过XML配置文件或注解,可以灵活地将SQL语句绑定到...

    free mybatis plugins

    MyBatis 是一款深受开发者喜爱的持久层框架,它简化了Java开发中的数据库操作,使得开发者可以更加专注于SQL语句的编写,而无需过多关注底层的JDBC代码。"Free MyBatis Plugins" 提供了对MyBatis的增强功能,帮助...

Global site tag (gtag.js) - Google Analytics