MyBatis
1.简介
MyBatis(前身是iBatis)是一个支持普通SQL查询、存储过程以及高级映射的持久层框架,它消除了几乎所有的JDBC代码和参数的手动设置以及对结果集的检索,并使用简单的XML或注解进行配置和原始映射,用以将接口和Java的POJO(PlainOld Java Object,普通Java对象)映射成数据库中的记录, MyBatis 通过将参数映射到配置的SQL 形成最终执行的SQL 语句,最后将执行SQL 的结果映射成Java 对象返回。
MyBatis框架也被称之为ORM(Object/Relational Mapping,即对象关系映射)框架。所谓的ORM就是一种为了解决面向对象与关系型数据库中数据类型不匹配的技术,它通过描述Java对象与数据库表之间的映射关系,自动将Java应用程序中的对象持久化到关系型数据库的表中。常见的ORM框架有Hibernate和MyBatis。两者区别:
- Hibernate:是一个全表映射的框架。它能自动的生成对应的SQL,并调用JDBC接口来执行,所以其开发效率会高于MyBatis。
- MyBatis:是一个半自动映射的框架。这里所谓的“半自动”是相对于Hibernate全表映射而言的,MyBatis需要手动匹配提供POJO、SQL和映射关系,而Hibernate只需提供POJO和映射关系即可。MyBatis可以配置动态SQL并优化SQL,可以通过配置决定SQL的映射规则。
MyBatis下载地址:https://github.com/mybatis/mybatis-3/releases
在项目中,需要将下载好的包导入项目。
MyBatis 的特点:采用配置文件动态管理SQL 语句,并含有输入映射、输出映射机制以及数据库连接池配置的持久层框架。
2.工作原理
简单介绍:
- 读取MyBatis配置文件mybatis-config.xml。mybatis-config.xml作为MyBatis的全局配置文件,配置了MyBatis的运行环境等信息,其中主要内容是获取数据库连接。
- 加载映射文件Mapper.xml。Mapper.xml文件即SQL映射文件,该文件中配置了操作数据库的SQL语句,需要在mybatis-config.xml中加载才能执行。mybatis-config.xml可以加载多个配置文件,每个配置文件对应数据库中的一张表。
- 构建会话工厂。通过MyBatis的环境等配置信息构建会话工厂SqlSessionFactory。
- 创建SqlSession对象。由会话工厂创建SqlSession对象,该对象中包含了执行SQL的所有方法。
- MyBatis底层定义了一个Executor接口来操作数据库,它会根据SqlSession传递的参数动态地生成需要执行的SQL语句,同时负责查询缓存的维护。
- 在Executor接口的执行方法中,包含一个MappedStatement类型的参数,该参数是对映射信息的封装,用于存储要映射的SQL语句的id、参数等。Mapper.xml文件中一个SQL对应一个MappedStatement对象,SQL的id即是MappedStatement的id。
- 输入参数映射。在执行方法时,MappedStatement对象会对用户执行SQL语句的输入参数进行定义(可以定义为Map、List类型、基本类型和POJO类型),Executor执行器会通过MappedStatement对象在执行SQL前,将输入的Java对象映射到SQL语句中。这里对输入参数的映射过程就类似于JDBC编程中对preparedStatement对象设置参数的过程。
- 输出结果映射。在数据库中执行完SQL语句后,MappedStatement对象会对SQL执行输出的结果进行定义(可以定义为Map和List类型、基本类型、POJO类型), Executor执行器会通过MappedStatement对象在执行SQL语句后,将输出结果映射至Java对象中。这种将输出结果映射到Java对象的过程就类似于JDBC编程中对结果的解析处理过程。
3.第一个程序
①创建一个Java项目,导入Mybatis.jar包,Oracle.jar包,log4j.jar包,在项目的src目录下创建log4j.properties文件,导入JUnit。
②在src目录下创建com.money.bean包,在该包下创建持久化类Book。
package com.money.bean;
public class Book {
private Integer bID;
private String bname;
private Double bprice;
private Integer bnumber;
public Integer getbID() {
return bID;
}
public void setbID(Integer bID) {
this.bID = bID;
}
public String getBname() {
return bname;
}
public void setBname(String bname) {
this.bname = bname;
}
public Double getBprice() {
return bprice;
}
public void setBprice(Double bprice) {
this.bprice = bprice;
}
public Integer getBnumber() {
return bnumber;
}
public void setBnumber(Integer bnumber) {
this.bnumber = bnumber;
}
public Book() {
super();
// TODO Auto-generated constructor stub
}
public Book(Integer bID, String bname, Double bprice, Integer bnumber) {
super();
this.bID = bID;
this.bname = bname;
this.bprice = bprice;
this.bnumber = bnumber;
}
@Override
public String toString() {
return "Book [bID=" + bID + ", bname=" + bname + ", bprice=" + bprice + ", bnumber=" + bnumber + "]";
}
}
实质上,Book就是一个POJO(普通Java对象), MyBatis就是采用POJO作为持久化类来完成对数据库操作的。
③在src目录下,创建一个com.money.mappers包,并在包中创建映射文件BookMapper. 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">
<!-- com.briup.mappers.StudentMapper是我们定义接口的全限定名字 这样就可以使用接口调用映射的SQL语句了 这个名字一定要和接口对应上 -->
<!-- 配置映射接口 -->
<mapper namespace="com.money.mappers.BookMapper">
<!-- 将实体类与数据库列匹配 -->
<resultMap type="Book" id="BookResult">
<id property="bID" column="id" />
<result property="bname" column="name" />
<result property="bprice" column="price" />
<result property="bnumber" column="sellnum" />
</resultMap>
<!-- 插入书籍 -->
<insert id="insertBook" parameterType="Book">
INSERT INTO book
values(#{bID},#{bname},#{bprice},#{bnumber})
</insert>
</mapper>
以上,第2~3行是MyBatis的约束配置,这些约束配置可以直接查到不需要手动编写;剩下的是要程序员编写的映射信息。其中,< mapper>元素是配置文件的根元素,它包含一个namespace属性,该属性为这个< mapper>指定了唯一的命名空间,通常会设置成“包名+SQL映射文件名”的形式。子元素< insert>中的信息是用于执行插入操作的配置,其id属性是< insert>元素在映射文件中的唯一标识;parameterType属性用于指定传入参数的类型,这里表示传递给执行SQL的是一个Book类型的参数;此外如果sql语句有返回值,还有resultType属性用于指定返回结果的类型。在定义的查询SQL语句中,“#{}”用于表示一个占位符,相当于“? ”,而“#{id}”表示该占位符待接收参数的名称为id,如果输入参数是简单类型(基本数据类型),那么#{}中的值可以是任意数据;select 标签对中SQL 语句的${}
符号, 表示拼接SQL 串, 将接收到的参数内容不加任何修饰地拼接在SQL 中,在"${}"中只能使用value代表其中的参数。然而,在Web 项目中,如果没有防范SQL 注入的机制, 要谨慎使用该符号拼接SQL 语句串, 因为可能会引起SQL 注入的风险。
MyBatis 的核心就是基于SQL 配直的Mapper 映射文件, 所有数据库的操作都会基于该映射文件和配置的SQL 语句。
注:xml文件中写的sql语句,最后面不要写分号,否则会报错。
创建数据库表:
create table book(
id number primary key,
name varchar2(20),
price number,
sellnum number
);
④在src目录下,创建MyBatis的核心配置文件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">
<configuration>
<typeAliases>
<typeAlias type="com.money.bean.Book" alias="Book" />
</typeAliases>
<!-- 配置数据库 -->
<environments default="development">
<environment id="development">
<!-- 配置事务管理器 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置数据库连接信息 -->
<dataSource type="POOLED">
<property name="driver"
value="oracle.jdbc.driver.OracleDriver" />
<property name="url"
value="jdbc:oracle:thin:@127.0.0.1:1521:XE" />
<property name="username" value="1" />
<property name="password" value="2" />
</dataSource>
</environment>
</environments>
<!-- 配置扫描映射文件路径 -->
<mappers>
<mapper resource="com/money/mappers/BookMapper.xml" />
</mappers>
</configuration>
以上,第2~3行是MyBatis的配置文件的约束信息,这些约束信息可以直接查到不需要手动编写;< configuration>元素中的内容就是开发人员需要编写的配置信息。按照< configuration>子元素的功能不同,将配置分为了两个步骤:第1步配置了环境,第2步配置了Mapper的位置。数字1和2的位置分别为数据库的登录名和密码。
注:在MyBatis使用手册的2.1.2小节中,已经给出了配置模板(包含约束信息),使用只需要复制过来,依照自己的项目需求修改即可。使用手册在MyBatis下载的压缩包中,是pdf文件。
⑤在com.money.mappers包中创建映射接口BookMapper.java,它对BookMapper.xml中的sql语句进行映射。
package com.money.mappers;
import com.money.bean.Book;
public interface BookMapper {
public void insertBook(Book book);
}
接口中的方法的名字要和对应XML文件此处是BookMapper. xml定义的SQL映射语句的id要相同,同时我们不需要去实现该接口,因为mybatis中提供了相应的方式在运行期间动态生成该接口的实现类对象。
⑥在src目录下,创建com.money.util包,在此包中创建com.money.util的工厂类MyBatisSqlSessionFactory:
package com.money.util;
import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MyBatisSqlSessionFactory {
private static SqlSessionFactory factory;
public static SqlSessionFactory getSqlSessionFactory() {
try {
// 1.读取配置文件
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
// 2.构建工厂对象
factory = new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
e.printStackTrace();
}
return factory;
}
/**
* 获取SQLSession对象,手动提交事务
*
* @return
*/
public static SqlSession openSession() {
return openSession(false);
}
/**
* 获取SQLSession对象,自动提交事务
*
* @param flag
* @return
*/
public static SqlSession openSession(boolean flag) {
return getSqlSessionFactory().openSession(flag);
}
}
首先通过输入流读取了配置文件,然后根据配置文件构建了SqlSessionFactory对象,接下来通过SqlSessionFactory对象又创建了SqlSession对象,接下来有两种执行sql语句的方式:
- 第一种:通过XxxxMapper接口的实现类对象来调用,此处是BookMapper接口,实现类对象通过反射创建。
- 第二种:通过SqlSession对象的insert()方法执行查询操作。insert()方法的第1个参数表示映射SQL的标识字符串,它由BookMapper.xml中< mapper>元素的namespace属性值+< insert>元素的id属性值组成;第2个参数表示插入所需要的参数。
⑦执行sql语句
第一种:在src目录下创建com.money.test包,创建BookTest.java类:
@Test
public void insert_test() {
// 1.读取全局配置文件 mybatis-config.xml
// 2.获取sqlSession对象
SqlSession sqlSession = MyBatisSqlSessionFactory.openSession();
//3.调用insert方法
sqlSession.insert("com.money.mappers.BookMapper.insertBook", new Book(1, "三国", 20.0, 200));
// 4.提交事务
sqlSession.commit();
}
第二种:可以不创建com.money.util包和其中的类,直接创建测试类:
@Test
public void insert_test() {
// 1.读取全局配置文件 mybatis-config.xml
// 2.获取sqlSession对象
SqlSession sqlSession = MyBatisSqlSessionFactory.openSession();
// 3.获取接口实现类对象
BookMapper mapper = sqlSession.getMapper(BookMapper.class);
mapper.insertBook(new Book(1, "三国", 20.0, 200));
// 4.提交事务
sqlSession.commit();
}
⑧要点
在使用“${}”进行SQL字符串拼接时,无法防止SQL注入问题。所以想要实现语句,又要防止SQL注入,可以使用SQL的concat()函数进行字符串拼接。
⑨简述MyBatis的操作:
- 读取配置文件
- 根据配置文件构建SqlSessionFactory
- 通过SqlSessionFactory创建SqlSession
- 使用SqlSession对象操作数据库(包括查询、添加、修改、删除以及提交事务等)
- 关闭SqlSession