介绍
虽然 ORM 通常将 Java 对象映射到数据库表(反之亦然),但 MyBatis 采取了不同的方法,将 Java 方法映射到 SQL 语句。这使您可以完全控制 SQL 的编写及其后续执行。在映射器的帮助下,MyBatis 也允许自动将数据库对象映射到 Java 对象。
像所有其他的 Java 持久化框架一样,MyBatis 的主要目标是减少使用原始 JDBC 与数据库通信的人力时间和编码要求。它遵循 Apache License 2.0 协议,可以免费使用。
为什么使用 MyBatis?
MyBatis 的设计采用了以数据库为中心的方法,因此如果你的应用程序是由关系型设计驱动的,MyBatis 是一个非常好的选择。如果您正在开发新应用程序,或在现有数据库基础设施之上扩展现有应用程序,这也是一个不错的选择。
MyBatis 可以非常快速、整齐地执行读取操作,因此对于面向分析和报告的应用程序来说,它非常方便。因为它被设计为直接使用 SQL,所以,它让你对数据库执行的查询有低级别和完全的控制权。最重要的是,在 MyBatis 数据映射器的帮助下,Java 中的对象模型和数据库中的数据模型是可以不同的。这为 Java 编码提供了更大的灵活性。
亮点特性
让我们继续使用 'largecities' 表,来演示 MyBatis 的特性。
前提条件
要开始使用 MyBatis,首先你需要下载它的 jar 文件,你可以从项目发布页面获取。该文件需要与 PostgreSQL JDBC 驱动程序一起,处在项目的 classpath 中。
接下来,您需要创建 Java 对象类,如下所示:
package org.rockdata.javabook.mybatis;
public class LargeCities {
private int rank;
private String name;
public int getRank() {
return rank;
}
public void setRank(int rank) {
this.rank = rank;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
最后,MyBatis 需要一个配置 XML,来告诉它如何连接到数据库。在此示例中,我们将文件命名为 '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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver"value="org.postgresql.Driver" />
<property name="url" value="jdbc:postgresql://localhost:5432/postgres" />
<property name="username" value="postgres" />
<property name="password" value="" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/rockdata/javabook/mybatis/LargeCitiesMapper.xml" />
</mappers>
</configuration>
注意到此文件末尾的 标签及其内容了吗?这将在下面的部分中解释。
映射器 XML – 简单 SELECT
映射器 XML 文件,告诉 MyBatis 如何将传入的数据库对象映射到 Java 对象。下面是一个映射器 XML 文件的示例,对 largecities 表运行一条简单的 SELECT 查询。
<?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">
<mapper namespace="org.rockdata.javabook.mybatis.Mapper">
<select id="selectCities" resultType="org.rockdata.javabook.mybatis.LargeCities">
SELECT * FROM largecities
</select>
</mapper>
使用映射器 XML
MyBatis 提供了许多资源,可以很容易地加载 XML 数据和创建输入流。使用映射器 XML 文件读取数据的事件时序如下:
- 1. 从映射器 XML 创建输入流
- 2. 使用上面的 SqlSessionFactoryBuilder 和 inputStream,创建一个 sqlSessionFactory
- 3. 从这个 sessionFactory 打开一个新会话
- 4. 调用封装 SQL 查询的 Java 方法
因此,最终代码如下所示:
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
List<LargeCities> list = session.selectList("selectCities");
for (LargeCities a : list) {
System.out.println("Rank: " + a.getRank() + " Name: " + a.getName());
}
}
catch (Exception e) {
e.printStackTrace();
}
请注意,在创建 InputStream 时如何引用 mybatis-config.xml,然后使用 selectCities 的 id(在映射器 XML 中声明)来调用 Java 方法。
此代码的输出如下:
Rank: 1 Name: Tokyo
Rank: 2 Name: Seoul
Rank: 3 Name: Shanghai
Rank: 4 Name: Guangzhou
Rank: 5 Name: Karachi
Rank: 6 Name: Delhi
Rank: 7 Name: Mexico City
Rank: 8 Name: Beijing
Rank: 9 Name: Lagos
Rank: 10 Name: Sao Paulo
传递参数
为了指定提取条件,您可以将参数传递给您的查询。这在映射器 XML 中指定。例如:
<select id="selectCitiesWithInput" resultType="org.rockdata.javabook.mybatis.LargeCities">
SELECT * FROM largecities where rank < #{rank}
</select>
在此示例中,将检索排名小于 #{rank} 参数指定值的所有结果。
此方法从 main 函数中调用,如下所示:
List<LargeCities> list = session.selectList("selectCitiesWithInput", 6);
此代码的输出为:
Rank: 1 Name: Tokyo
Rank: 2 Name: Seoul
Rank: 3 Name: Shanghai
Rank: 4 Name: Guangzhou
Rank: 5 Name: Karachi
插入数据
插入数据需要在映射 XML 文档中添加另一个条目。
<insert id="insertCity">
INSERT INTO largecities (rank, name) VALUES (#{rank},#{name})
</insert>
然后,可以使用以下 Java 代码完成插入:
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
LargeCities mumbai = new LargeCities();
mumbai.setRank(11);
mumbai.setName("Mumbai");
session.insert("insertCity", mumbai);
session.commit();
List<LargeCities> list = session.selectList("selectCities");
for (LargeCities a : list) {
System.out.println("Rank: " + a.getRank() + " Name: " + a.getName());
}
}
catch (Exception e) {
e.printStackTrace();
}
请注意,在调用会话的 'insert' 方法时,Java 对象是如何自动映射到数据库对象的。
此代码将排名第 11 位的 Mumbai 插入数据库,然后提交事务。代码的输出如下:
Rank: 1 Name: Tokyo
Rank: 2 Name: Seoul
Rank: 3 Name: Shanghai
Rank: 4 Name: Guangzhou
Rank: 5 Name: Karachi
Rank: 6 Name: Delhi
Rank: 7 Name: Mexico City
Rank: 8 Name: Beijing
Rank: 9 Name: Lagos
Rank: 10 Name: Sao Paulo
Rank: 11 Name: Mumbai
更新数据
用于更新数据的映射 XML 中的条目,会如下所示:
<update id="updateCity">
UPDATE largecities SET name = #{name} WHERE rank = #{rank}
</update>
在我们的 Java 代码中,可以这样使用此映射:
LargeCities newYork = new LargeCities();
newYork.setRank(11);
newYork.setName("New York");
session.insert("updateCity", newYork);
session.commit();
List<LargeCities> list = session.selectList("selectCities");
for (LargeCities a : list) {
System.out.println("Rank: " + a.getRank() + " Name: " + a.getName());
}
同样,请注意,Java 对象会根据我们的映射 XML 自动映射到数据库对象。
该程序的输出为:
Rank: 1 Name: Tokyo
Rank: 2 Name: Seoul
Rank: 3 Name: Shanghai
Rank: 4 Name: Guangzhou
Rank: 5 Name: Karachi
Rank: 6 Name: Delhi
Rank: 7 Name: Mexico City
Rank: 8 Name: Beijing
Rank: 9 Name: Lagos
Rank: 10 Name: Sao Paulo
Rank: 11 Name: New York
删除数据
现在,让我们专注于删除我们插入并更新的第 11 个条目。映射 XML 代码如下所示:
<delete id="deleteCity">
DELETE FROM largecities WHERE rank = #{rank}
</delete>
Java 代码将按如下方式使用此映射:
LargeCities newYork = new LargeCities();
newYork.setRank(11);
newYork.setName("New York");
session.insert("deleteCity", newYork);
session.commit();
List<LargeCities> list = session.selectList("selectCities");
for (LargeCities a : list) {
System.out.println("Rank: " + a.getRank() + " Name: " + a.getName());
}
输出内容现在返回到了,我们开始时原始的表数据:
Rank: 1 Name: Tokyo
Rank: 2 Name: Seoul
Rank: 3 Name: Shanghai
Rank: 4 Name: Guangzhou
Rank: 5 Name: Karachi
Rank: 6 Name: Delhi
Rank: 7 Name: Mexico City
Rank: 8 Name: Beijing
Rank: 9 Name: Lagos
Rank: 10 Name: Sao Paulo
使用 MyBatis 的缺点
由于 MyBatis 以数据库为中心的方法,它不太适合于以对象为中心设计的应用程序。此外,虽然 MyBatis 在数据检索方面非常出色,但对于复杂的领域实体,执行写入操作可能会变得相当繁琐。
MyBatis 被设计为直接使用 SQL,因此在使用此框架时,你不能不编写 SQL。由于这种低级别控制,任何数据库的更改都需要对 Java 代码进行手动干预。
此外,由于您将自己编写 SQL,因此运行时错误的可能性始终存在。Java 编译器将无法捕获 SQL 中的错误,并且您的应用可能会抛出非描述性的 JDBC 错误。