1. 什么是框架?
MyBatis 就是一个操作数据库的框架,框架就是软件功能的半成品,框架提供了一个软件项目中通用的功能,将大多数常见的功能进行封装,无需自己重复开发。
2. 什么是对象关系映射?
MyBatis 是一个基于 “ORM” 的框架,ORM 的全称是对象关系映射(Object Relational Mapping).
对象(Object)就是Java中的对象,关系(Relational)就是数据库中的数据表,基于 “ORM” 的框架是把数据在对象和关系之间进行双向转换。
ORM 的细节可以从 3 个方面来介绍:
(1)1 个类 对应 1 个表。
(2)1 个类的对象 对应 表中的一行。
(3)1 个类的对象中的属性 对应 1 个表中的列。
ORM 映射关系如图 1-1 所示。
MyBatis 框架可以将 Java 类中的数据转化为数据表中的记录,或者将数据表中的记录封装到 Java 类中,过程如图 1-2 所示:
从图 1-2 的过程来看,程序员不再直接使用 JDBC 对象访问数据库,而是以面向对象的方式来使用实体类,对实体类进行的增加、删除、更新和查询操作都会由 ORM 框架转化成对数据库的增加、删除、更新和查询操作。
ORM 框架内部的核心技术的原理其实就是 JDBC 和 反射,这个技术是由 ORM 框架、也就是 MyBatis 来进行封装的。
3. MyBatis 的优势
MyBatis 是现阶段操作数据库的主流框架,此框架的主要作用就是更加便捷地操作数据库。它具有很多优势,具体体现在以下 7 个方面:
(1)ROW 行 与 Entity 实体类双向转换:可以将数据表中的 ROW 行与 Entity 实体类进行互相转换,比如将 ResultSet 对象返回的数据自动封装到 Entity 实体类 或 List 中,或将 Entity 实体类中的数据转换成数据表中新的一行 ROW。
(2)SQL语句 与 Java文件 分离: 可以把 SQL 语句写到 XML 文件中,目的是将 SQL语句 与 Java文件 分离,使代码分层更明确。
(3)允许对 SQL语句 进行自定义优化:因为 MyBatis框架 是使用 SQL语句 对数据库进行操作的,所以可以单独地对 SQL语句 进行优化,以提高操作效率。
(4)减化 DAO层 代码:在使用传统的 JDBC 开发方式时,需要写上必要的 DAO层 代码以对数据库进行操作,但冗余代码太多,所以 MyBatis 解决了这个问题。使用 MyBatis 做查询时可以自动将数据表中的数据记录封装到 实体类 或 Map 中,再将它们放入 List 进行放回。
(5)半自动化所带来的灵活性: MyBatis 是 “半自动化” 的 “ORM” 框架,但它应该算作 SQL映射框架(SQL Mapper Framework)。将 MyBatis 称为 “半自动化的 ORM 框架” 是因为 MyBatis 操作数据库时还是使用原始的 SQL 语句,这些 SQL语句 还需要程序员自己来进行设计,这就是半自动化。
(6)支持 XML 或 Annotation 注解的方式进行 ORM :MyBatis 可以使用 XML 或 Annotations注解的方式 将数据表中的记录 映射成 1 个 Map 或 Java POJO 实体类对象,但推荐使用 XML 方式。
(7)功能丰富:MyBatis 还可以实现自定义 SQL 段落、调用存储过程和进行高级映射等功能。
4. ORM 的原理实现
本章将用代码来模拟实现一个微型的 ORM 功能。
4.1 使用 JDBC 和反射技术实现泛型 DAO
MyBatis 实现 ROW 行与 Entity实体类双向转换的原理是基于 JDBC 和 反射技术,MyBatis 框架只是对 JDBC 技术进行了轻量级的封装,使程序员更方便地区操作数据库。
创建获得 Connection 连接对象,代码如下:
public class GetConnection {
public static Connection getConnection() throws ClassNotFoundException, SQLException {
// 使用 oracle驱动器
String driverName = "oracle.jdbc.OracleDriver";
String url = "jdbc:oracle:thin:@localhost:1521:orcl";
String username = "y2";
String password = "123";
Class.forName(driverName);//Class.forName(String) 返回与给定字符串名称的类或接口相关联的 Class对象。
Connection conn = DriverManager.getConnection(url, username, password);
return conn;
}
}
创建实体类 Userinfo,核心代码如下:
public class Userinfo {
private long id;
private String username;
private String password;
public Userinfo(long id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
//省去 get 和 set 方法
}
创建泛型 DAO 类 BaseDAO,代码如下:
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class BaseDao<T> {
// 此方法模拟了 MyBatis 的 save() 方法
// MyBatis 框架内部的核心和本示例基本一样
// 使用的技术就是 JDBC 和 反射
public void save(T t)
throws IllegalArgumentException, IllegalAccessException,
ClassNotFoundException, SQLException {
String sql = "insert into";
String colName = "";
String colParam = "";
String begin = "(";
String end = ")";
Class classRef = t.getClass(); //反射获取 t 的类对象
String tableName=classRef.getSimpleName().toLowerCase(); //getSimpleName获取具体类名称,如main
sql = sql + tableName;
List values = new ArrayList();
Field[] fieldArray = classRef.getDeclaredFields();// 返回一个 Field对象,该对象反映由该 Class对象表示的类或接口的指定声明字段。
for (int i = 0; i < fieldArray.length; i++) {
Field eachField = fieldArray[i];
eachField.setAccessible(true); //跳过连通性检验
String eachFieldName = eachField.getName();
Object eachValue = eachField.get(t);
colName = colName + "," + eachFieldName;
colParam = colParam + ",?";
values.add(eachValue);
}
colName = colName.substring(1);
colParam = colParam.substring(1);
sql = sql + begin + colName + end;
sql = sql + " values" + begin + colParam + end;
System.out.println(sql);
for (int i = 0; i < values.size(); i++) {
System.out.println(values.get(i));
}
Connection conn = GetConnection.getConnection();
PreparedStatement ps = conn.prepareStatement(sql); //JDBC 的预编译函数
for (int i = 0; i < values.size(); i++) {
ps.setObject(i + 1, values.get(i)); //批处理
}
ps.executeUpdate();
ps.close();
conn.close();
}
//Mybatis 的 get() 方法
...
//Mybatis 的 update() 方法
...
//Mybatis 的 delete() 方法
...
//由于方法实现大致类似,故在此省略
}
增加记录的代码如下:
public class Insert {
public static void main(String[] args)
throws IllegalArgumentException, IllegalAccessException,
ClassNotFoundException, SQLException {
Userinfo userinfo = new Userinfo();
userinfo.setId(1000L);
userinfo.setPassword("中国人");
userinfo.setUsername("中国");
BaseDao<Userinfo> dao = new BaseDao<Userinfo>();
dao.save(userinfo);
}
}
以上代码的作用就是使用 JDBC 结合反射技术来将数据表中的 1 行记录和实体类进行双向转换,这也是 ORM 框架的原理。以上代码用到了 JDBC(结合)反射技术,MyBatis 实现 ORM 的原理就是 JDBC 和 反射技术。
4.2 操作 XML 文件
XML,全称是 eXtensible Markup Language(可扩展标记语言),它可以自定义标记名称与内容,在灵活度上相比相比 HTML 有大幅提高,经常用在配置以及数据交互领域。