Day01.mybatis框架


课程计划:

  • MyBatis快速<mark>入门</mark>
  • MyBatis对数据库中数据的<mark>增删改查</mark>操作
  • #{}<mark>占位符的应用</mark>
  • <mark>动态SQL</mark>的应用
  • <mark>MyBatis的Mapper接口开发</mark>

1.1 什么是 MyBatis

MyBatis 本是<mark>apache</mark>的一个开源项目iBatis,

2010年这个项目由apache software foundation 迁移到了google code,
并且改名为MyBatis 。
<mark>2013年11月迁移到Github</mark>。

MyBatis是一个优秀的<mark>持久层框架</mark>,
它<mark>对jdbc</mark>的操作数据库的过程进行<mark>封装</mark>,
使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。

  • Mybatis<mark>通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt)配置</mark>起来,

  • 并<mark>通过java对象和statement中的sql进行映射生成最终执行的sql语句</mark>,

  • 最后由mybatis框架执行sql并将结果映射成java对象并返回。

总之,Mybatis对JDBC访问数据库的过程进行了封***r> 简化了JDBC代码,
解决JDBC将结果集封装为Java对象的麻烦。

下图是MyBatis架构图:

<mstyle mathcolor="&#35;f01"> </mstyle> \color{#f01}{** 重要 **}

  • mybatis-config.xml是Mybatis的核心配置文件,
    <mark>通过其中的配置可以生成SqlSessionFactory,也就是SqlSession工厂</mark>
  • 基于SqlSessionFactory可以生成SqlSession对象
  • SqlSession是一个可以发送SQL去执行,并返回结果的对象,
    类似于JDBC中的Connection对象,
    也是Mybatis中至关重要的一个对象。
  • <mark>Executor是SqlSession底层的对象,用于执行SQL语句</mark>
  • MapperStatement对象也是SqlSession底层的对象,
    1. 用于接收输入映射
      (SQL语句中的参数),
    2. 以及做输出映射
      (即将SQL查询的结果映射成相应的结果)


1.2 为什么要使用 MyBatis

思考:
在开始之前,思考下如何通过JDBC查询Emp表中的所有记录,
并封装到一个List集合中返回。
(演示:准备数据、导包、导入JDBC程序)

1、使用传统方式JDBC访问数据库:

(1)使用JDBC访问数据库有大量重复代码(比如注册驱动、获取连接、获取传输器、释放资源等);
(2)JDBC自身没有连接池,会频繁的创建连接和关闭连接,效率低;
(3)SQL是写死在程序中,一旦修改SQL,需要对类重新编译;
(4)对查询SQL执行后返回的ResultSet对象,需要手动处理,有时会特别麻烦;

2、使用mybatis框架访问数据库:

  • Mybatis对JDBC对了<mark>封装</mark>,可以<mark>简化JDBC代码</mark>;
  • Mybatis<mark>自身支持连接池</mark>(也可以配置其他的连接池),因此可以提高程序的效率;
  • Mybatis是将<mark>SQL配置在mapper文件</mark>中,修改SQL只是修改配置文件,<mark>类不需要重新编译</mark>。
  • <mark>对查询SQL执行后返回的ResultSet对象,Mybatis会帮我们处理,转换成Java对象</mark>。

总之,JDBC中所有的问题(代码繁琐、有太多重复代码、需要操作太多对象、释放资源、对结果的处理太麻烦等),在Mybatis框架中几乎都得到了解决!!



2 MyBatis快速入门

2.1 准备数据,创建库和表

1、创建yonghedb库、emp表,并插入若干条记录

-- 1、创建数据库 yonghedb 数据库
create database if not exists yonghedb charset utf8;
use yonghedb; -- 选择yonghedb数据库
-- 2、删除emp表(如果存在)
drop table if exists emp;
-- 3、在 yonghedb 库中创建 emp 表
create table emp(
	id int primary key auto_increment,
	name varchar(50),
	job varchar(50),
	salary double
);
-- 4、往 emp 表中, 插入若干条记录
insert into emp values(null, '王海涛', '程序员', 3300);
insert into emp values(null, '齐雷', '程序员', 2800);
insert into emp values(null, '刘沛霞', '程序员鼓励师', 2700);
insert into emp values(null, '陈子枢', '部门总监', 4200);
insert into emp values(null, '刘昱江', '程序员', 3000);
insert into emp values(null, '董长春', '程序员', 3500);
insert into emp values(null, '苍老师', '程序员', 3700);
insert into emp values(null, '韩少云', 'CEO', 5000);

2.2 创建工程,导入所需jar包、创建测试类

1、创建Maven的java工程

2、导入junit、mysql、mybaits等开发包

在pom.xml文件中引入相关依赖包即可

<dependencies>
	<!-- junit单元测试 -->
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<version>4.9</version>
	</dependency>
	<!-- mysql驱动 -->
	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
		<version>5.1.32</version>
	</dependency>
	<!-- mybatis -->
	<dependency>
		<groupId>org.mybatis</groupId>
		<artifactId>mybatis</artifactId>
		<version>3.2.8</version>
	</dependency>
	<!-- 整合log4j -->
	<!-- 通过使用Log4j,我们可以控制日志信息输送的目的地 -->
	<dependency>
		<groupId>org.slf4j</groupId>
		<artifactId>slf4j-log4j12</artifactId>
		<version>1.6.4</version>
	</dependency>
</dependencies>

3、创建com.tedu.mybatis.TestMybatis测试类,并提供findAll方法(查询emp表中所有的员工信息),开发步骤如下:

2、mybatis-config.xml文件配置如下:

mybatis-config文件头信息如下

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
    
<!-- MyBatis的全局配置文件 -->
<configuration >
	
</configuration>

详细配置如下

在这里插入代码片

2.4 添加并编写Emp实体类

注意:
<mark>在当前实例中,Emp类中的属性和数据库表的字段名称必须一致,
否则将会无法将结果集封装到Java对象中。</mark>

在src/main/java目录下创建com.tedu.pojo.Emp类并实现Emp类:
提供私有属性以及对应的getter方法、setter方法,并重写toString方法

在这里插入代码片

2.5 添加EmpMapper.xml文件

1、在src/main/resources目录下,创建EmpMapper.xml文件 (实体类的映射文件)

2、EmpMapper.xml文件配置如下:

EmpMapper文件头信息如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!-- namespace一般指定为当前文件的所在包路径+文件名(将来是接口名) 在程序中通过[ namespace + id ]定位到执行哪一条SQL语句 -->
<mapper namespace="">
	
	
</mapper>

详细配置如下:

在这里插入代码片

2.6 实现测试类,并测试

1、实现findAll方法,代码如下:

mybatis-configure.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">

<!-- MyBatis的全局配置文件 -->
<!-- 程序中读取的是这个文件, XxxMapper,xml文件在第二步中读取 即,XxxMapper.xml是通过这个文件来间接读取的! -->
<configuration >
	<!-- 提示来源: "http://mybatis.org/dtd/mybatis-3-config.dtd" 中文件提供 -->
	
	<!-- 0. 加载常量配置信息 -->
	<properties resource="c3p0.properties"/>  
	
	<!-- 1. 配置开发环境 -->
	<!-- 定义数据库信息,默认使用 develop 数据库构建环境 -->  
	<environments default="develop">
		<environment id="develop">
			<!-- 配置事务管理器(JDBC / MANAGED) type: JDBC: jdbc进行事务管理(√) MANAGED: 自己管理 -->
			<transactionManager type="JDBC"/>
			<!-- 配置数据源(连接池) DataSource type: UNPOOLED ==》 不使用连接池 POOLED ==》 使用连接池 (√) JNDI ==》 (过时) -->
			<dataSource type="POOLED" >
				<property name="username" value="${c3p0.user}"/>
				<property name="password" value="${c3p0.password}"/>
				<property name="driver" value="${c3p0.driverClass}"/>
				<property name="url" value="${c3p0.jdbcUrl}"/>
			</dataSource>	
		</environment>
	</environments>
	
	
	<!-- 2. 导入XxxMapper.xml文件 -->
	<!-- 定义映射器 -->
	<mappers>
		 <!-- 使用这个方案,可以 单独 指定 Mapper的位置 -->  
		<mapper resource="EmpMapper.xml"/>
	</mappers>
</configuration>
EmpMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!-- namespace一般指定为当前文件的所在包路径+文件名(将来是接口名) 在程序中通过[ namespace + id ]定位到执行哪一条SQL语句 -->
 
 <!-- namespace、id 是定位标识!!重要! -->
<mapper namespace="EmpMapper">
	<!-- 提示的来源:头文件中"http://mybatis.org/dtd/mybatis-3-mapper.dtd" 提供 -->
	<!-- 如果没有提示,通过配置xml***获取。 -->
	
	<!-- 练习1. 查询所有员工信息 -->
	<select id="findAll" resultType="cn.edut.pojo.Empolyee">
		select * from emp ;
	</select>
	
</mapper>
TestMybatis
package cn.edut.day33;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import cn.edut.pojo.Empolyee;

/** * MyBatis快速入门程序 */
public class TestMybatis {

	/** * 练习1:查询所有员工信息 List<Employee> * @throws IOException */
	@Test
	public void testFindAll() throws IOException {
		//1. 读取 Mybatis 的核心配置文件(mybatis-config.xml)
		InputStream in = Resources.getResourceAsStream("mybatis-config.xml") ;
		
		//2. 通过配置获取一个SqlSessionFactory对象
		SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(in) ; 
		
		//3. 通过工厂获取一个SqlSession对象
		
		SqlSession session = ssf.openSession(); 
		
		//4. 执行SQL语句(XxxMapper.xml), 返回处理后的结果
		List<Empolyee> list = session.selectList("EmpMapper.findAll");
		
		//5. 输出结果
		for (Empolyee e : list) {
			System.out.println(e);
		}
		
		
	}
}

2、执行findAll方法,输出结果为:


3 MyBatis入门细节

3.1 mybatis-config.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
    
<!-- MyBatis的全局配置文件 -->
<configuration >
	<!-- 配置环境,可配置多个环境(比如:develop开发、test测试) -->
	<environments default="develop">
		<environment id="develop">
			
			<!-- 配置事务管理方式:JDBC/MANAGED JDBC:将事务交给JDBC管理(推荐) MANAGED:自己管理事务 -->
			<transactionManager type="JDBC"></transactionManager>
			
			<!-- 配置数据源,即连接池 JNDI/POOLED/UNPOOLED JNDI:已过时 POOLED:使用连接池(推荐) UNPOOLED:不使用连接池 -->
			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.jdbc.Driver"/>
				<property name="url" value="jdbc:mysql://localhost:3306/yonghedb?characterEncoding=utf-8"/>
				<property name="username" value="root"/>
				<property name="password" value="root"/>
			</dataSource>
		</environment>
	</environments>
	
	<!-- 引入Mapper配置文件,可以配置多个 -->
	<mappers>
		<mapper resource="EmpMapper.xml"/>
	</mappers>

</configuration>

configuration是根标签,当前文件中所有的配置都在该标签内,注意其中配置的关键点:

默认的环境 ID(比如:default="develop")。

每个 environment 元素定义的环境 ID(比如:id="develop")。

事务管理器的配置(比如:type="JDBC")。

数据源的配置(比如:type="POOLED")。

  • <mark>environments标签</mark>:
    该标签内部可以配置多个environment,即多种环境,
    每种环境可以做不同配置或连接不同数据库。
    例如,
    开发、测试、生产环境可能需要不同的配置,
    连接的数据库可能也不相同,
    因此我们可以配置三个environment,分别对应上面三种不同的环境。
    但是要记住,environment可以配置多个,
    <mark>但是最终要使用的只能是其中一个</mark>!

  • <mark>environment标签</mark>:
    内部可以配置多种配置信息,
    下面介绍 <mstyle mathcolor="&#35;f01"> </mstyle> \color{#f01}{**事务管理配置**} <mstyle mathcolor="&#35;f01"> </mstyle> \color{#f01}{**数据源配置**}

  • <mark>transactionManage标签</mark>:
    <mstyle mathcolor="&#35;f01"> </mstyle> \color{#f01}{**事务管理配置**}
    mybatis中有两种事务管理方式,
    也就是 type="[JDBC|MANAGED]

    • JDBC
      这个配置就是直接使用了 JDBC 的提交和回滚设置,
      它依赖于从数据源得到的连接来管理事务范围。
      <mark>推荐使用</mark>。
    • MANAGED
      这个配置几乎没做什么。
      它从来不提交或回滚一个连接。
      需要自己手动添加并管理。
      不推荐使用。
  • <mark>dataSource标签</mark>:
    数据源,也就是连接池配置。
    这里type指定数据源类型,有三种内建的类型:
    JNDIPOOLEDUNPOOLED

    • JNDI
      已过时,不推荐使用!
    • POOLED
      使用连接池,mybatis会创建连接池,并从连接池中获取连接访问数据库,在操作完成后,将会把连接返回连接池。
    • UNPOOLED
      不使用连接池,该方式适用于只有小规模数量并发用户的简单应用程序上。
  • <mark>mappers标签</mark>:
    用于导入mapper文件的位置,
    其中可以配置多个mapper,
    即可以导入多个mapper文件。

3.2 EmpMapper.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!-- namespace一般指定为当前文件的所在包路径+文件名 将来在程序中通过[ namespace + id ]定位到执行哪一条SQL语句 -->
<mapper namespace="EmpMapper">
	<!-- 通过select、insert、update、delete标签声明要执行的SQL -->
	<select id="findAll" resultType="com.tedu.pojo.Emp">
		select * from emp
	</select>
	<!-- resultType:返回值类型,简单类型(例如:Integer,String,Emp等) 如果返回集合(List<Emp>),只需配置集合中的元素类型即可! resultMap:复杂对象结构(例如多表关联查询等),后面用到再讲解 -->
</mapper>
  • 第1行是xml的文档声明,用于声明xml的版本和编码
  • 第2、3、4行,引入了xml约束文档,当前xml文档将会按照mybatis-3-mapper.dtd文件所要求的规则进行书写。
  • Mapper标签:根标签,其中namespace(名称空间,也叫命名空间),要求不能重复。其实就是一个名称,一般我们指定为"包名+文件名"。
  • select标签:用于指定将来要执行的各种SQL语句。标签上可以声明属性,下面介绍常用的属性:id、resultType、resultMap
  • id属性:要求值不能重复。将来在执行SQL时,可以通过namespace + id找到指定SQL并执行。
  • resultType属性:从这条SQL语句中返回所期望类型的类的完全限定名称(包名+类名)。注意如果是集合情形,那应该是集合可以包含的类型,而不能是集合本身。

简而言之,resultType控制查询SQL执行后返回值的类型或集合中的泛型,例如查询emp表中的单条记录,返回值是一个Emp对象,因此,resultType=“com.tedu.pojo.Emp”;
如果查询emp表中的多条记录,返回值是一个List,此时resultType的值应该集合中的泛型,因此resultType=“com.tedu.pojo.Emp”;
resultMap属性:复杂对象结构(例如多表关联查询等)。 使用 resultType 或 resultMap,但不能同时使用。