您的位置 首页 java

我的Java Web之路55 – ORM框架(MyBatis)初步使用

本系列文章旨在记录和总结自己在 java  Web开发之路上的知识点、经验、问题和思考,希望能帮助更多(Java)码农和想成为(Java)码农的人。 

目录

  1. 介绍
  2. 什么是ORM
  3. MyBatis 概述
  4. 提供Configuration元数据
  5. 打开MyBatis的日志开关
  6. 构造 SQL SessionFactory对象
  7. 生命周期的思维
  8. 装配SqlSessionFactory对象
  9. Maven 的 src/main/resources 目录
  10. 获取SqlSession对象
  11. 提供Mapper元数据
  12. 创建Mapper接口
  13. 执行Mapper
  14. 总结

介绍

从 开始,我们使用了 JDBC 来访问数据库,然而却带来一系列问题:

  • 有很多代码重复的地方;
  • 访问数据库的代码没有独立出来(事实上,应该从Service层独立出来形成DAO层);
  • 访问数据库的一些资源没有释放,比如连接、Statement、结果集;
  • 每次访问都要建立数据库连接,性能低下;
  • 与数据库设计耦合严重;
  • 正文代码中仍然有用于测试的添加模拟数据的代码;
  • 数据库访问的异常处理不够;
  • 等等

其中,代码重复、资源释放、异常处理这三个问题通过 中引入Spring JDBC框架中的JdbcTemplate帮助我们解决了;

每次访问数据库都需要建立和销毁连接导致的性能低下这个问题通过 引入连接池帮助我们解决了;

本篇文章通过使用ORM框架来解决与数据库设计耦合严重的问题。

什么是ORM

我们先再查看一下HouseService的代码(可以参考 ),重点关注执行SQL语句的部分,我这里列举一些放在一起:

jdbcTemplate.update("insert into house values(?, ?, ?)", "1", "金科嘉苑3-2-1201", "详细信息");
List<House> list = jdbcTemplate.query("select id,name,detail from house", new HouseMapper());
House house = jdbcTemplate.queryForObject("select id,name,detail from house where id = ?", new Object[]{houseId}, new HouseMapper());
jdbcTemplate.update("update house set id=?, name=?, detail=? where id=?", house.getId(), house.getName(), house.getDetail(), house.getId()); 

HouseMapper做的事是:

		public House mapRow(ResultSet rs, int rowNum) throws SQLException {
			return new House(rs.getString("id"), rs.getString("name"), rs.getString("detail"));
		} 

我们可以发现访问数据库的本质是:

  • 把Java 对象 (如House)中包含的数据转换 / 映射 (存储)到关系数据库的 关系 表;
  • 把关系数据库的 关系 表中的数据转换 / 映射 (读取)到Java 对象 (如House);

这个就是ORM(Object/Relation Mapping,简称ORM)的含义,即ORM框架就是帮你做这种 对象-关系之间的映射 的框架。

同时,我们也可以发现上述代码把SQL语句或SQL语句中的某些列名 硬编码 到代码中,一方面SQL语句如果比较复杂的话会导致代码很乱,可读性降低;另一方面SQL语句的修改会导致代码的修改,因此要重新编译,这就是耦合严重的问题。

还有,这里也有一些比较隐蔽的 代码重复 ,比如每次执行SQL语句都要编写: jdbcTemplate.query 或 jdbcTemplate.queryForObject 或 jdbcTemplate.update;每次将查询结果映射到对象都要编写: public House mapRow(ResultSet rs, int rowNum) throws SQLException 等等。如果能够只用Java面向对象编程的方式将数据持久化那该多好。

比如,我想往数据库的房源表中新增一个房源信息,就直接调用 saveHouse(house) 或者 addHouse(house) 或其他名字的方法即可,而这个方法自动就将house对象的数据映射到某个SQL语句中,并调用 jdbcTemplate.update 来执行该SQL语句。这样我们的代码会更加的清晰、可读、简练。当然,我们必须提供一些元数据:

  • 哪个类的哪个方法是执行哪个SQL语句的;
  • (参数或结果)对象的各属性与关系表的各列如何一一对应的;
  • 等等。

ORM框架有很多,Hibernate、JPA、MyBatis等等。

MyBatis概述

MyBatis的官网是 org /mybatis-3 :

据说MyBatis在国内用的比较多,国外主要用的是Hibernate,不知道是不是这样,不必深究。

官网对其的介绍是:MyBatis支持定制SQL、存储过程和高级映射,能够去除几乎所有JDBC代码、参数设置、查询结果提取,使用XML和注解提供配置元数据(这点类似于Spring框架)。

截止到撰写本文之时,MyBatis的最新版本是 3.5.3 。你可以手动到它指定的地方下载,实际上是托管在 GitHub 上()。但是现在我们使用Maven来管理项目的依赖,所以只要在我们的项目POM文件中添加如下依赖即可:

<!--  -->
<dependency>
 <groupId>org.mybatis</groupId>
 <artifactId>mybatis</artifactId>
 <version>3.5.3</version>
</dependency>
 

MyBatis需要两种配置元数据,一种用于配置框架的运行参数,比如控制MyBatis的行为,数据源和事务管理器(关于事务,以后再讨论)的参数,用于提供对象-关系映射的元数据在何处等等。这叫做 Configuration 元数据,我们以后就把这个叫做配置元数据也可以的。

另一种配置元数据就是对象-关系映射的元数据,这叫做 Mapper 元数据。

MyBatis的核心有两个接口:

  • SqlSessionFactory
  • SqlSession

提供Configuration元数据

首先,我们要为MyBatis提供运行参数,即Configuration元数据,我采用基于XML的方式。

那我们要把这个XML文件放到工程结构的哪个位置呢?我们知道,之前Servlet技术中的Web部署描述符web.xml和Spring IoC配置元数据dispatcher.xml是放在 WebContent/WEB-INF 目录下的,既然都是XML文件,那我们就暂时先放在此处吧,同时把这个XML文件命名为 mybatis-config.xml:

我的Java Web之路55 - ORM框架(MyBatis)初步使用

它的内容是这样的,我们先只配置最简单的参数,主要是数据源:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
 PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 "#34;>
<configuration>
 <environments default="development">
 <environment id="development">
 <transactionManager type="JDBC"/>
 <dataSource type="UNPOOLED">
 <property name="driver" value="org.h2.Driver"/>
 <property name="url" value="jdbc:h2:~/h2db/houserenter"/>
 <property name="username" value="sa"/>
 <property name="password" value=""/>
 </dataSource>
 </environment>
 </environments>
 <mappers>
 </mappers>
</configuration> 

前面的部分是XML声明和根元素声明,大家可以参考 。

根元素<configuration> 里面最重要的两个元素就是<environments> 和 <mappers>了。

<environments>是用来为各个环境(比如开发环境、测试环境、生产环境等)提供参数配置的,所以子元素就是其单数形式<environment> ,这里可以配置多个<environment>,每个<environment>可以用 id 属性来标识,<environments>使用 default 属性来指定当前使用哪一个<environment>。

而<environment> 中最重要的两个元素是<transactionManager> 和 <dataSource>,它们分别是配置事务管理器和数据源的。事务管理器我们暂时不介绍,数据源的配置有点类似于我们之前使用Druid连接池时的配置(参考 ),不再赘述。

不过,<dataSource>元素有个 type 属性,它有三个MyBatis内置的值:

  • UNPOOLED:显然是不使用连接池的方式;
  • POOLED:显然是使用连接池的方式,应该是MyBatis以连接池的技术实现了DataSource接口;
  • JNDI:使用Java命名和目录接口(Java Naming and Directory Interface)的方式,以后介绍JNDI。

我们后面可以选择不使用连接池的方式(UNPOOLED)、使用MyBatis内置连接池的方式(POOLED)配置数据源。

<mappers> 元素就是用来提供 Mapper 元数据的位置的,因为 Mapper 元数据可以是基于XML或Java注解的,因此该元素有以下四种方式:

<mappers>
 <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
 <mapper url="file:///var/mappers/AuthorMapper.xml"/>
 <mapper class="org.mybatis.builder.AuthorMapper"/>
 <package name="org.mybatis.builder"/>
</mappers>
<!-- 代码来源于MyBatis官网 --> 

前面两种是基于XML的,不过第一个是基于工程目录相对位置的,一种是基于文件系统绝对位置的;

后面两种是基于Java注解的,一个是指定某个接口,一个是指定包。

打开MyBatis的日志开关

可以往配置元数据中添加如下元素:

 <settings>
 <setting name="logImpl" value="STDOUT_LOGGING"/>
 </settings> 

这样既可在我们的控制台窗口中输出MyBatis执行SQL语句的日志,这对我们调试程序很有帮助。

构造SqlSessionFactory对象

我们先将原来dispatcher.xml中配置DataSource和JdbcTemplate的部分注释或删除:

<?xml version="1.0" encoding="UTF-8"?>
< Bean s xmlns="#34;
	xmlns:context="#34;
	xmlns:xsi="#34;
	xsi:schemaLocation=" 
		 
		
		#34;>
	
	<context:component-scan base-package="houserenter"/>

<!-- 	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
		<property name="url" value="jdbc:h2:~/h2db/houserenter" />
		<property name="username" value="sa" />
		<property name="password" value="" />

		<property name="maxActive" value="20" />
		<property name="initialSize" value="1" />
		<property name="maxWait" value="60000" />
		<property name="minIdle" value="1" />
	</bean>
	
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<constructor-arg ref="dataSource" />
	</bean> -->
</beans> 

既然有了MyBatis的配置元数据,那么MyBatis必然会提供某个组件以便在运行时来读取这些配置元数据,并在后面的运行期间使用这些参数。

这个组件就是 SqlSessionFactoryBuilder 。单从类名上看,可以猜测这个类使用了 设计模式 中的 Builder(建造者)模式 ,这个以后再介绍。简单理解就好像是造房子一样,先打地基,再浇筑建筑框架,再砌墙,再安装水电,再内部装修这样一步一步构造出一个房子出来。具体到MyBatis这个组件就是类似于先造各个environment元素对象,再造各个mapper元素对象,再造其他的配置元素对象这样一步一步构造一个SqlSessionFactory对象出来。

实际上,SqlSessionFactoryBuilder这个组件提供了很多接口给我们调用:

大家可以自行查看其源代码或者 JavaDoc 。我采用的是:

public SqlSessionFactory build(InputStream inputStream) 

现在还有一个问题就是,我们到底要构造多少个SqlSessionFactory对象?是造一个然后给所有其他组件用呢,还是每个组件都造一个,还是每个请求都造一个?这就是SqlSessionFactory对象的 生命周期 的问题,即一个SqlSessionFactory对象到底存活多长时间(本质是在内存多长时间)?

根据官网的介绍,最佳实践就是我们只需要在应用开始运行时构造一个SqlSessionFactory对象即可,该对象在应用的整个运行期间都可以一直供其他组件对象使用,在应用结束运行时销毁即可,官网也不建议重复生成多个SqlSessionFactory对象。

既然如此,这就意味着我们需要编写某种代码来确保我们每次使用的都是同一个SqlSessionFactory对象,而不会生成多个SqlSessionFactory对象,我们可以使用 设计模式 中的 单例模式 来达到这个目的。

但是,Spring IoC就可以帮助我们实现这一点,所以我们不必再重复制造轮子了。我们可以使用Spring IoC的基于Java配置生产和装配Bean的方式(可以参考 )来实现:

package houserenter.config;

import java.io.IOException;
import java.io.InputStream;

import org.apache. ibatis .io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.springframework.context. annotation .Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MybatisConfig {

	@Bean
	public SqlSessionFactory sqlSessionFactory() throws IOException {
		String resource = "mybatis-config.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		return new SqlSessionFactoryBuilder().build(inputStream);
	}
}
 

Spring IoC默认是使用单例模式来生成Bean,因此,上述代码在应用运行期间只会执行一次,即只生成一个SqlSessionFactory对象。同时,我提供了MyBatis配置元数据的位置,暂时先只写该XML文件的名字,看是否能够找到 WebContent/WEB-INF/ 目录下的 mybatis-config.xml 。

上述代码我放在了 houserenter.config包中:

事实上,我们也可以使用Spring IoC基于XML的方式来构造SqlSessionFactory对象,不过这需要使用到另外一个项目依赖,即MyBatis与Spring集成的项目,后面再介绍。

生命周期的思维

这里插一个题外章节。

事实上,世间一切都有生命周期,不管是有生命的,没有生命的,客观的,主观的,都是如此。

我们的编程世界中也是如此,我们可以经常使用这个思维来设计我们的程序,特别是在面向对象编程中。

一个对象一般都包括生成、初始化、使用中、销毁前、销毁等阶段。当然,根据领域的不同,可以划分成的生命周期阶段也不同。

而我们使用过的Spring IoC,其实就可以管理Bean的生命周期,这个以后再介绍。

装配SqlSessionFactory对象

现在,我们可以在需要访问数据库的组件中注入生成的SqlSessionFactory对象,比如在我们的租房网应用中的HouseService组件中:

	@Autowired
	private SqlSessionFactory sqlSessionFactory; 

事实上,现在我们就可以来验证一下,重新发布租房网应用,在Eclipse中重新启动Tomcat,然而天不尽如人意,出现了以下异常:

当然,此异常的根本原因是找不到配置元数据 mybatis-config.xml,显然有两种解决方案:

  • 要不移动 mybatis-config.xml
  • 要不代码中使用绝对路径

我想肯定能够移动到某个位置下,让代码仅仅使用文件名就能够找到该文件的。经过不断的试错,原来放到 src/main/java 目录底下即可。

通过官网我们得知,只要是放到 classpath 下MaBatis就可以找到基于XML的配置元数据,而我们现在是使用Maven来管理项目,其默认源码路径就是 src/main/java ,既然Java类都在此目录下,那么此目录显然是属于 classpath 的。

Maven的 src/main/resources 目录

大家可以执行 Maven build 命令(可以参考 ),然后看看打包好的war包是一个什么样的结构。在Windows系统中的Eclipse中可以快速的导航到文件系统中的工程目录下:

我的Java Web之路55 - ORM框架(MyBatis)初步使用

进一步进入 target 目录即可看到打包好的 house-renter-0.0.1-SNAPSHOT.war ,使用解压缩工具 WinRAR 打开该文件:

我的Java Web之路55 - ORM框架(MyBatis)初步使用

可以看到,Maven管理的源码目录 src/main/java 在打好的war包里面对应的是 WEB-INF/classes 目录。

事实上,我们也可以在Eclipse中该工程的属性对话框中看到这种对应关系:

我的Java Web之路55 - ORM框架(MyBatis)初步使用

为了便于管理这种除了Java源码之外的资源(Maven把这种配置文件归为资源),设置了另外一个默认的目录,这就是 src/main/resources (可以到官方文档 查看标准的Maven工程结构)

我们也可以建立这样一个目录,然后执行 Maven -> Update Project… 这个工程右键菜单命令即可(可以参考 )。现在我们的租房网应用的工程结构如下:

我的Java Web之路55 - ORM框架(MyBatis)初步使用

我们可以再次发布应用、启动Tomcat验证一下,异常消除了,可以正常启动了。

获取SqlSession对象

有了SqlSessionFactory对象,我们就可以不断的从其中获取SqlSession对象,正如它的类名所示那样,它就像是一个工厂,一个制造SqlSession对象的工厂,这就是 设计模式 中的 工厂模式

我们暂时先别管工厂模式是什么样的,要想获取SqlSession对象,只需要调用它的 openSession() 方法即可:

SqlSession session = sqlSessionFactory.openSession(); 

不过,SqlSession对象是一种资源,使用完它之后需要释放,可以使用 try-catch-finally 语法:

		SqlSession sqlSession = sqlSessionFactory.openSession();
		try {
			//这里使用sqlSession访问数据库
		} finally {
			sqlSession.close();
		} 

不过,Java为我们提供了一种更加简练的方式,就是带资源声明的 try-catch 语法,此语法好像是Java SE 8 版本才引入的:

try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
			//这里使用sqlSession访问数据库
}  

实际上,从上面的代码中我们也可以看出,SqlSession对象只适合局部使用,即它的生命周期是方法级别的,意思就是调用某个方法时才生成该对象,该方法执行完后就销毁该对象。

MyBatis官网也描述它为 不是线程安全 的,最好是每个线程都有自己的一个SqlSession对象,而不是多个线程共用一个SqlSession对象。

提供Mapper元数据

SqlSession对象可以简单理解为一个到数据库的连接,类似于JDBC的Connection对象。

要想执行SQL,最起码还需要SQL语句吧。当然,MyBatis将SQL语句、参数绑定、对象-关系映射等数据都以 Mapper 元数据的形式来提供。

Mapper 元数据可以使用XML,也可以使用Java注解,当然,XML的方式应该是功能最全面的。

下面就使用XML的方式来为我们的租房网应用提供 Mapper 元数据,当然,目前主要是针对房源表的操作。

同样,我们将在 Maven 的 src/main/resources 目录中建立 HouseMapper.xml 文件,其内容如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "#34;>
<mapper namespace="houserenter.mapper.HouseMapper">

	<update id="dropTableIfExistsHouse">
		drop table if exists house
	</update>

	<update id="cteateTable">
		create table house(id varchar(20) primary key, name varchar(100), detail varchar(500))
	</update>

	<insert id="insert" parameterType="houserenter.entity.House">
		insert into house(id, name, detail) values(#{id}, #{name}, #{detail})
	</insert>

	<select id="selectAll" resultType="houserenter.entity.House">
		select id,name,detail from house
	</select>
	
	<select id="selectById" parameterType="java.lang.String" resultType="houserenter.entity.House">
		select id,name,detail from house where id = #{id}
	</select>
	
	<update id="updateById" parameterType="houserenter.entity.House">
		update house set id=#{id}, name=#{name}, detail=#{detail} where id=#{id}
	</update>
</mapper> 

前面的部分依旧是XML声明和根元素声明,大家可以参考 。不过,现在的根元素变成了 <mapper> 。它有一个很重要的属性 namespace ,最好设置为相应的Mapper接口的全限定名称。

这里主要用到了以下三个子元素:

  • <update>
  • <insert>
  • <select>

它们要执行的SQL语句显然与其元素名相呼应。重要的是它们都有一个 id 属性,这个属性很重要,必须与相应的Mapper接口中的方法名相同。

然后是给每个SQL语句传参数的方式,采用属性 parameterType ,其值可以是任何Java类,最好写全限定的类名,即带包路径的类名。而SQL语句中使用 #{fieldName} 的形式来与Java类的属性进行自动绑定,所以必须确保Java类中有fieldName这个属性。

最后是查询SQL语句的结果集映射到Java类对象中,采用属性 resultType ,其用法与属性 parameterType 类似。不过需要注意的是,如果结果集返回的是多条记录,那么将映射到一个Java集合类上,此时属性 resultType 的值应该设置为该集合类所包含的元素的类型,而不是集合类本身的类型。

事实上,还有一个属性 resultMap 可以结果集到Java类对象的映射,暂不讨论。

现在可以看到,Mapper元数据的主要作用就是:

  • 映射SQL语句与Mapper接口的方法,通过元素 id 和接口方法名;
  • 映射参数与Java类对象,通过属性 parameterType;
  • 映射结果集与Java类对象,通过属性 resultType 或属性 resultMap (不能同时用);

最后,我们需要将此 Mapper 元数据的位置告诉 MyBatis ,即需要修改 mybatis-config.xml 中的 <mappers> 元素:

 <mappers>
 	<mapper resource="HouseMapper.xml"/>
 </mappers> 

创建Mapper接口

接下来,我们需要创建Mapper接口,这样我们的其他组件才能够使用Mapper接口来访问数据库,我们可以新建一个包,叫做 mapper,然后在该包下新建一个接口 HouseMapper :

其内容如下:

package houserenter.mapper;

import java.util.List;

import houserenter.entity.House;

public interface HouseMapper {

	int dropTableIfExistsHouse();
	
	int cteateTable();
	
	int insert(House house);
	
	List<House> selectAll();
	
	House selectById(String id);
	
	int updateById(House house);
}
 

可以看到:

  • 这个接口的全限定名称 houserenter.mapper.HouseMapper 正是Mapper元数据中声明的 namespace 。
  • 这个接口的方法也与Mapper元数据中的SQL语句是一一对应的,并且方法名与相应元素的 id 是相同的。
  • 参数的类型也与 parameterType 的值相同。
  • 一般执行写操作SQL语句的方法,返回的是 int 类型的值,表示受影响的记录有多少条;执行查询SQL语句的方法有两种,一种是只返回唯一的一条记录,此时方法的返回类型就是我们的领域类型(比如,House);一种是返回多条记录,此时方法的返回类型一般是一个集合类,但往往使用泛型(以后再讨论)指定了集合所包含元素的类型(比如,List<House>)。
  • 实际上,执行查询SQL语句的方法的返回类型可以不是领域类型,而是Java中的 Map<> 类型。

执行Mapper

现在,可以使用我们的Mapper接口来操作数据库了。

首先,我们要从 SqlSession 对象中获取 Mapper 接口的对象,比如,我们的 HouseMapper:

			HouseMapper houseMapper = sqlSession.getMapper(HouseMapper.class); 

然后,就可以直接调用 Mapper 接口的方法了,比如:

			houseMapper.dropTableIfExistsHouse();
			houseMapper.cteateTable();
			houseMapper.insert(new House("1", "金科嘉苑3-2-1201", "详细信息"));
			houseMapper.insert(new House("2", "万科橙9-1-501", "详细信息"));
 

最后,千万别忘记了 执行写操作SQL语句之后,要手动提交事务 ,否则执行写操作SQL语句将会回滚,即导致执行无效:

			sqlSession.commit(); 

因为,我们在 mybatis-config.xml 配置的事务管理器是 JDBC :

<transactionManager type="JDBC"/> 

这样,结合前面装配 SqlSessionFactory 对象,获取 SqlSession 对象,我们的 HouseService 的内容如下:

package houserenter.service;
import java.io.IOException;
import java.util.List;

import javax.annotation.PostConstruct;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import houserenter.entity.House;
import houserenter.mapper.HouseMapper;
@Service
public class HouseService {
	
	@Autowired
	private SqlSessionFactory sqlSessionFactory;
	
	@PostConstruct
	public void generateMockHouses() throws IOException {
		
		try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
			HouseMapper houseMapper = sqlSession.getMapper(HouseMapper.class);
			houseMapper.dropTableIfExistsHouse();
			houseMapper.cteateTable();
			houseMapper.insert(new House("1", "金科嘉苑3-2-1201", "详细信息"));
			houseMapper.insert(new House("2", "万科橙9-1-501", "详细信息"));
			sqlSession.commit();
		} 
		
	}
	
	public List<House> findHousesInterested(String userName) {
		// 这里查找该用户感兴趣的房源,省略,改为用模拟数据
		try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
			HouseMapper houseMapper = sqlSession.getMapper(HouseMapper.class);
			return houseMapper.selectAll();
		} 
	}
	public House findHouseById(String houseId) {
		try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
			HouseMapper houseMapper = sqlSession.getMapper(HouseMapper.class);
			return houseMapper.selectById(houseId);
		} 
	}
	public void updateHouseById(House house) {
		try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
			HouseMapper houseMapper = sqlSession.getMapper(HouseMapper.class);
			houseMapper.updateById(house);
			sqlSession.commit();
		} 
	}
} 

总结

最后,大家可以将应用重新发布并启动Tomcat进行验证,应该没什么大问题,一切正常。

可以看到,我们除了

  • 增加MyBatis的配置元数据 mybatis-config.xml
  • 使用Spring IoC基于Java的生成SqlSessionFactory这个Bean,MybatisConfig.java
  • 增加MyBatis的Mapper元数据 HouseMapper.xml
  • 创建Mapper接口 HouseMapper.java

这些新增文件以外,剩下的只需要修改我们的HouseService组件即可,这就是分层、MVC的好处。

不过,整体上看来,HouseService组件的代码比之前使用Spring JDBC时(参考 )差不多,此时虽然把SQL语句、参数绑定、结果映射从Java代码中剔除出去了,但是,获取SqlSession对象、获取Mapper接口对象等又出现了类似之前提到的代码重复。这个问题可以进一步使用另外一个项目依赖来解决,后续再介绍。

  • ORM的核心功能(本质)就是其名称所示的对象-关系映射;
  • 主要是三方面的映射:SQL语句与Mapper接口方法、SQL语句的参数与方法参数、SQL语句的执行结果集与方法返回类型;
  • MyBatis的核心组件是SqlSessionFactory、SqlSession;
  • SqlSessionFactory的生命周期是应用级别,即单例;
  • SqlSession是非线程安全的,生命周期最好是线程级别、或请求级别、或方法级别;
  • MyBatis的使用主要步骤是:提供配置元数据、Mapper元数据、Mapper接口、构造单例的SqlSessionFactory对象、方法内用带资源的try-catch语法获取SqlSession对象、获取Mapper接口对象、调用Mapper接口的方法、必要时手动提交事务;
  • 生命周期的思维很重要,大家要经常使用,不管是在编程中,还是在管理工作中,甚至是生活中;
  • 本篇文章涉及的设计模式有单例、建造者(Builder)、工厂(Factory),以后专门介绍它们;

文章来源:智云一二三科技

文章标题:我的Java Web之路55 – ORM框架(MyBatis)初步使用

文章地址:https://www.zhihuclub.com/201238.shtml

关于作者: 智云科技

热门文章

网站地图