MyBatis是一个优秀的持久层框架,它对JDBC操作数据库的过程进行封装,使开发者只需要关注 SQL本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等JDBC繁杂的过程代码。
MyBatis通过 xml 文件或注解的方式将要执行的各种 statement 配置起来,并通过 Java 对象和
statement 中 sql 的动态参数进行映射生成最终执行的 sql 语句,最后由MyBatis框架执行sql并将结果映射成Java对象并返回。
一、MyBatis架构

1、Mybatis配置:
mybatis-config.xml(名称不固定),此文件作为MyBatis的全局(核心)配置文件,配置了
MyBatis的运行环境等信息。
mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在mybatisconfig.
xml中加载。
2、通过MyBatis环境等配置信息构造SqlSessionFactory,即会话工厂。
3、由会话工厂创建SqlSession即会话,操作数据库需要通过SqlSession进行。
4、MyBatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
5、MappedStatement也是MyBatis一个底层封装对象,Mybatis将SQL的配置信息加载成为一个个
MappedStatement对象(包括了传入参数映射配置、执行的SQL语句、结果映射配置),存储在内存中。mapper.xml文件中一个sql对应一个MappedStatement对象,sql的id即MappedStatement的id。
6、MappedStatement对sql执行输入参数进行定义,包括HashMap、基本类型、字符串类型、实体类类型,Executor通过MappedStatement在执行sql前将输入的Java对象映射至sql中,输入参数映射就是JDBC编程中对PreparedStatement设置参数。
7、MappedStatement对sql执行输出结果进行定义,包括HashMap、基本类型、字符串类型、实体类类型,Executor通过MappedStatement在执行sql后将输出结果映射至Java对象中,输出结果映射过程相当于JDBC编程中对结果的解析处理过程。
二、搭建MyBatis项目
首先创建一个maven项目,MyBatis是一个持久层框架,是操作数据库时使用的。所以无需创建JavaWeb项目,建立Java项目即可。
1、maven依赖配置-pom文件
java
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>mybatis-project</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mybatis-hello</artifactId>
<name>mybatis-hello</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>12</maven.compiler.release>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>5.11.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<!-- Optionally: parameterized tests support -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<scope>test</scope>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
<!-- log4j Mybatis的日志输出组件 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
</build>
</project>
2、编写MyBatis中全局配置文件
在src/main/resources目录下创建mybatis-config.xml,作用:配置了数据源、事务等MyBatis运行环境等。
注:如果src/main下面没有resources目录,那么我们手动创建一个,让其成为Resources Root。
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">
<!-- configuration 文件的根节点 -->
<configuration>
<!--
properties 用于引入外部的properties配置文件
resource:引入类路径下的文件
url:引入磁盘或网路
-->
<properties/>
<!--
environments:多个配置环境;通过default属性可以对多个环境快速切换。
environments default属性的值必须和某个environment的id值一致。
-->
<!-- 和spring整合后 environments配置将废除,了解即可 -->
<environments default="mysql">
<environment id="oracle">
<!-- 配置事务:使用jdbc的事务管理 -->
<transactionManager type="JDBC"/>
<!-- 配置数据源:连接数据库的信息
type: 表示连接是否使用连接池,POOLED表示mybatis中自带的连接池;JNDI、
POOLED、UNPOOLED
-->
<dataSource type="POOLED">
<property name="driver"
value="oracle.jdbc.driver.OracleDriver"/>
<property name="url"
value="jdbc:oracle:thin:@localhost:1521:orcl"/>
<property name="username" value="scott"/>
<property name="password" value="tiger"/>
</dataSource>
</environment>
<environment id="mysql">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ssm?characterEncoding=utf8&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 加载映射文件的位置 -->
<mappers>
<mapper resource="mapper/Emp.xml"/>
</mappers>
</configuration>
3、数据库准备
sql
CREATE TABLE `dept` (
`deptno` int PRIMARY KEY AUTO_INCREMENT,
`dname` varchar(20),
`loc` varchar(40)
);
INSERT INTO `dept` VALUES (10, 'ACCOUNTING', 'NEW YORK');
INSERT INTO `dept` VALUES (20, 'RESEARCH', 'DALLAS');
INSERT INTO `dept` VALUES (30, 'SALES', 'CHICAGO');
INSERT INTO `dept` VALUES (40, 'OPERATIONS', 'BOSTON');
CREATE TABLE `emp` (
`empno` int PRIMARY KEY AUTO_INCREMENT,
`ename` varchar(20),
`job` varchar(20),
`mgr` int,
`hiredate` date,
`sal` double,
`comm` double,
`deptno` int,
CONSTRAINT `FK_EMP_DEPTNO` FOREIGN KEY (`deptno`) REFERENCES `dept` (`deptno`)
);
INSERT INTO `emp` VALUES (7369, 'SMITH', 'CLERK', 7902, '1980-12-17', 1300,
NULL, 20);
INSERT INTO `emp` VALUES (7499, 'ALLEN', 'SALESMAN', 7698, '1981-02-20', 2100,
300, 30);
INSERT INTO `emp` VALUES (7521, 'WARD', 'SALESMAN', 7698, '1981-02-22', 1750,
500, 30);
INSERT INTO `emp` VALUES (7566, 'JONES', 'MANAGER', 7839, '1981-04-02', 3475,
NULL, 20);
INSERT INTO `emp` VALUES (7654, 'MARTIN', 'SALESMAN', 7698, '1981-09-28', 1750,
1400, 30);
INSERT INTO `emp` VALUES (7698, 'BLAKE', 'MANAGER', 7839, '1981-05-01', 3350,
NULL, 30);
INSERT INTO `emp` VALUES (7782, 'CLARK', 'MANAGER', 7839, '1981-06-09', 2950,
NULL, 10);
INSERT INTO `emp` VALUES (7788, 'SCOTT', 'ANALYST', 7566, '1987-04-19', 3500,
NULL, 20);
INSERT INTO `emp` VALUES (7839, 'KING', 'PRESIDENT', NULL, '1981-11-17', 5500,
NULL, 10);
INSERT INTO `emp` VALUES (7844, 'TURNER', 'SALESMAN', 7698, '1981-09-08', 2000,
0, 30);
INSERT INTO `emp` VALUES (7876, 'ADAMS', 'CLERK', 7788, '1987-05-23', 1600,
NULL, 20);
INSERT INTO `emp` VALUES (7900, 'JAMES', 'CLERK', 7698, '0198-12-31', 1450,
NULL, 30);
INSERT INTO `emp` VALUES (7902, 'FORD', 'ANALYST', 7566, '1981-12-03', 3500,
NULL, 20);
INSERT INTO `emp` VALUES (7934, 'MILLER', 'CLERK', 7782, '1982-01-23', 1800,
NULL, 10);
4、编写实体类
实体类作为Mybatis进行sql映射使用,实体类通常与数据库表对应,Emp.java如下:
注:实体类是用来和数据库表对应的,我们最好全部使用引用类型。
java
package org.example.entity;
import java.util.Date;
public class Emp {
private Integer empno;
private String ename;
private String job;
private Integer mgr;
private Date hiredate;
private Double sal;
private Double comm;
private Integer deptno;
public Integer getEmpno() {
return empno;
}
public void setEmpno(Integer empno) {
this.empno = empno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public Integer getMgr() {
return mgr;
}
public void setMgr(Integer mgr) {
this.mgr = mgr;
}
public Date getHiredate() {
return hiredate;
}
public void setHiredate(Date hiredate) {
this.hiredate = hiredate;
}
public Double getSal() {
return sal;
}
public void setSal(Double sal) {
this.sal = sal;
}
public Double getComm() {
return comm;
}
public void setComm(Double comm) {
this.comm = comm;
}
public Integer getDeptno() {
return deptno;
}
public void setDeptno(Integer deptno) {
this.deptno = deptno;
}
@Override
public String toString() {
return "Emp{" +
"empno=" + empno +
", ename='" + ename + '\'' +
", job='" + job + '\'' +
", mgr=" + mgr +
", hiredate=" + hiredate +
", sal=" + sal +
", comm=" + comm +
", deptno=" + deptno +
'}';
}
}
5、编写映射文件
在src/main/resources下创建mapper目录,在该目录下创建sql映射文件Emp.xml。
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: 命名空间,作用是mapper文件进行分类管理,用于隔离sql语句。
注意:如果使用mapper代理的方式进行开发,namespace有特殊的作用。
-->
<mapper namespace="emp">
<!-- 通过员工编号查询员工信息 -->
<!--
通过<select>标签编写查询语句
id: 映射文件中SQL语句的唯一标识。
mybatis会将SQL语句封装到MappedStatement对象中,所以此处的id也可以标识
MappedStatement对象的id;
注意:同一个mapper文件中id不能重复,而且id在mapper代理模式下有着重要作用;
parameterType: 输入参数的类型。
sql语句的占位符:#{};
#{empno}:其中empno表示接收输入的参数值,参数名称为empno;
但是如果参数的类型为简单类型(基本数据类型、包装类、字符串类型),参数名称可以任意
指定;
resultType: 输出参数的类型。
需要指定输出数据为Java中的数据类型(实体类的全限定名);
-->
<select id="selectById" parameterType="java.lang.Integer"
resultType="org.example.entity.Emp">
select empno, ename, job, hiredate, mgr, sal, comm, deptno from emp where
empno=#{empno}
</select>
<!--查询所有员工信息-->
<select id="selectAll" resultType="org.example.entity.Emp">
select empno, ename, job, hiredate, mgr, sal, comm, deptno from emp
</select>
<!--添加员工-->
<!--
添加操作使用insert标签;
增删改操作没有resultType,只有查询有resultType;
因为增删改操作返回值都是int类型,所以我们不需要指明;
注意:给占位符赋值,#{}中编写的内容为实体类型参数中的成员变量名称;
#{empno} Mybatis会从传递过来的参数对象里面得到emono字段的值
useGeneratedKeys表示是否开启主键返回,默认值是false
keyProperty表示用这个来接收
useGeneratedKeys="true" keyProperty="empno"
-->
<insert id="insert" parameterType="org.example.entity.Emp" >
insert into emp( ename, job, mgr, hiredate,sal, comm, deptno)
values (#{ename},#{job},#{mgr},#{hiredate},#{sal},#{comm},#{deptno})
</insert>
<!-- 更新修改员工-->
<update id="update" parameterType="org.example.entity.Emp">
update emp set ename=#{ename},job=#{job},mgr=#{mgr},hiredate=#{hiredate},sal=#{sal},comm=#{comm},deptno=#{deptno}
where empno=#{empno}
</update>
<!--删除员工-->
<delete id="delete" parameterType="java.lang.Integer">
delete from emp where empno=#{value }
</delete>
<!--根据员工名模糊查询-->
<select id="selectByEname1" parameterType="java.lang.String" resultType="org.example.entity.Emp">
select empno, ename, job, mgr, hiredate,sal, comm, deptno from emp
where ename like #{ename}
</select>
<select id="selectByEname2" parameterType="java.lang.String" resultType="org.example.entity.Emp">
select empno, ename, job, mgr, hiredate,sal, comm, deptno from emp
where ename like concat('%',#{ename},'%')
</select>
</mapper>
6、加载映射文件
在MyBatis的全局配置文件中添加映射文件位置。
XML
<!-- 加载映射文件的位置 -->
<mappers>
<mapper resource="mapper/Emp.xml"/>
</mappers>
7、log4j配置
Mybatis日志输出:log4j.properties配置文件。在resource下创建。
java
<?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">
<!-- configuration 文件的根节点 -->
<configuration>
<!--
properties 用于引入外部的properties配置文件
resource:引入类路径下的文件
url:引入磁盘或网路
-->
<properties/>
<!--
environments:多个配置环境;通过default属性可以对多个环境快速切换。
environments default属性的值必须和某个environment的id值一致。
-->
<!-- 和spring整合后 environments配置将废除,了解即可 -->
<environments default="mysql">
<environment id="oracle">
<!-- 配置事务:使用jdbc的事务管理 -->
<transactionManager type="JDBC"/>
<!-- 配置数据源:连接数据库的信息
type: 表示连接是否使用连接池,POOLED表示mybatis中自带的连接池;JNDI、
POOLED、UNPOOLED
-->
<dataSource type="POOLED">
<property name="driver"
value="oracle.jdbc.driver.OracleDriver"/>
<property name="url"
value="jdbc:oracle:thin:@localhost:1521:orcl"/>
<property name="username" value="scott"/>
<property name="password" value="tiger"/>
</dataSource>
</environment>
<environment id="mysql">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ssm?characterEncoding=utf8&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
</configuration>
8、编写测试程序
在test中创建测试类进行测试。
java
package org.example;
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.example.entity.Emp;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
public class MybatisTest {
//通过员工编号查询员工信息
@Test
public void testSelectById() throws IOException {
//1.创建读取全局配置文件的流
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
//2、获取SqlSessionFactory
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
//3、通过SqlSessionFactory得到sqlSession
SqlSession sqlSession = sessionFactory.openSession();
//4、通过sqlSession执行对应的SQL
Emp emp = sqlSession.selectOne("emp.selectById", 7369);
System.out.println("emp=" + emp);
//5.关闭资源
sqlSession.close();
}
//查询所有员工信息
@Test
public void testSelectAll() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sessionFactory.openSession();
List<Emp> emps = sqlSession.selectList("emp.selectAll");
for (Emp emp : emps) {
System.out.println(emp);
}
sqlSession.close();
}
//添加员工
@Test
public void testInsert() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sessionFactory.openSession();
Emp emp=new Emp();
emp.setEname("张三");
emp.setJob("测试工程师");
emp.setMgr(7369);
emp.setHiredate(new Date());
emp.setSal(4500.0);
emp.setComm(100.0);
emp.setDeptno(10);
int count = sqlSession.insert("emp.insert", emp);
System.out.println("count="+count);
//mybatis的事务是JDBC的事务机制,默认是手动提交
sqlSession.commit();
sqlSession.close();
}
//修改操作
@Test
public void testUpdate() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sessionFactory.openSession();
Emp emp=new Emp();
emp.setEmpno(7938);
emp.setEname("张三风");
emp.setJob("软件工程师");
emp.setMgr(7788);
emp.setHiredate(new Date());
emp.setSal(6600.0);
emp.setComm(1200.0);
emp.setDeptno(20);
int count = sqlSession.update("emp.update", emp);
System.out.println("count="+count);
//mybatis的事务是JDBC的事务机制,默认是手动提交
sqlSession.commit();
sqlSession.close();
}
//删除操作
@Test
public void testDelete() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sessionFactory.openSession();
int count = sqlSession.delete("emp.delete", 7938);
System.out.println("count="+count);
//mybatis的事务是JDBC的事务机制,默认是手动提交
sqlSession.commit();
sqlSession.close();
}
//根据员工名模糊查询
@Test
public void testSelectByEname() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sessionFactory.openSession();
String ename="s";
/*List<Emp> emps = sqlSession.selectList("emp.selectByEname1", "%" + ename + "%");
for (Emp emp : emps) {
System.out.println(emps);
}*/
List<Emp> emps = sqlSession.selectList("emp.selectByEname2", ename);
for (Emp emp : emps) {
System.out.println(emp);
}
sqlSession.close();
}
}