MyBatis (Java Persistence Framework)
Table of Contents
1. MyBatis 简介
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
和 JPA 产品相比,MyBatis 更加灵活,比如 MyBatis 很容易实现多表联合查询等功能。
1.1. 安装
要在 Maven 工程中使用 MyBatis,在 pom.xml 文件中加入下面依赖即可:
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>x.x.x</version> </dependency>
2. MyBatis 基本使用
2.1. 第一步:创建 SqlSessionFactory
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为中心的,SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。
有两种方式可以创建 SqlSessionFactory。方式一:从 XML 文件创建 SqlSessionFactory;方式二:从配置类创建 SqlSessionFactory。
这里仅介绍从 XML 中构建 SqlSessionFactory 的方法:
// 注:应用(只访问一个数据库)往往只需要一个sqlSessionFactory对象,所以常常设计为单例模式 String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
上面例子中,数据库相关配置保存在文件"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="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/your_db_name"/> <property name="username" value="root"/> <property name="password" value="your_pw"/> </dataSource> </environment> </environments> <mappers> <mapper resource="BlogMapper.xml"/> </mappers> </configuration>
2.2. 第二步:创建 SQL 语句映射
上一步中,文件"mybatis-config.xml"中下面代码片断:
<mappers> <mapper resource="BlogMapper.xml"/> </mappers>
文件"BlogMapper.xml"指定的是 SQL 语句映射,下面是该文件的一个实例:
<?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.mybatis.example.BlogMapper"> <select id="selectBlog" resultType="org.mybatis.example.Blog"> select * from Blog where id = #{id} </select> </mapper>
注:我们不仅可以在 xml 文件中指定 SQL 语句映射,还可以在 Java 类中指定 SQL 语句映射,下面是它的一个简单实例:
package org.mybatis.example; public interface BlogMapper { @Select("SELECT * FROM blog WHERE id = #{id}") Blog selectBlog(int id); }
本文不介绍这种方式。
2.3. 第三步:创建和数据库表对应的 POJO
假设数据库表 blog 有两个字段 id 和 title,我们需要构建与之对应的 Java 类。如:
package org.mybatis.example; public class Blog { private int id; private String title; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } }
2.4. 第四步:从 SqlSessionFactory 获取 SqlSession,执行 SQL 语句
从 SqlSessionFactory 获取 SqlSession,执行 SQL 语句:
SqlSession session = sqlSessionFactory.openSession(); try { // 下面这一句可以把数据库中id为101的记录查询出来,并根据结果创建一个Blog对象 Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101); // \_________________________/ \_______/ // ^ ^ // | | // namespace in BlogMapper.xml id in BlogMapper.xml } finally { session.close(); }
2.5. 实例:对用户信息进行增删改查
链接 MyBatis Tutorial – CRUD Operations and Mapping Relationships – Part 1 中有一个使用 MyBatis 对用户信息进行增删改查的例子,比较简单,可作为入门学习的资料。
3. Tips
3.1. Order By 排序问题(MyBatis 中#和$的区别)
假设数据库表 tbl1 的内容如下:
mysql> select * from tbl1; +-------+------+ | name | age | +-------+------+ | Herry | 20 | | Jack | 40 | | Alice | 35 | +-------+------+ 3 rows in set (0.00 sec)
现在我们想按列 age 排序。首先在 Mapper XML 文件中定义下面内容:
<select id="selectAll" resultType="com.xxx.yyy.User"> SELECT * FROM tbl1 ORDER BY #{columnName} <!-- 错! --> </select>
然后,Java 代码中传参 columnName 为'age'。
String columnName = "age"; List<User> users = session.selectList("org.mybatis.example.UserMapper.selectAll", columnName);
但是,你会发现,得到的结果并没有按 age 排序!
要得到排序后的结果,可以把 Mapper XML 文件中的 #{columnName}
改为 ${columnName}
,即:
<select id="selectAll" resultType="com.xxx.yyy.User"> SELECT * FROM tbl1 ORDER BY ${columnName} <!-- 正确! --> </select>
为什么会这样呢,这是因为 在 MyBatis 中, #{}
相当于 jdbc 中的 prepareStatement 中的占位符(会自动转义,不会有 SQL 注入风险,这个例子中自动加上了单引号);而 ${}
是直接输出变量的值(它有 SQL 注入风险,所以用户的输入数据千万不能直接作为这些变量值的来源)。
也就是说 SELECT * FROM tbl1 ORDER BY #{columnName}
和 SELECT * FROM tbl1 ORDER BY ${columnName}
会分别转换为:
select * from tbl1 order by 'age'; select * from tbl1 order by age;
下面在 MySQL 中分别测试一下这两个语句:
mysql> select * from tbl1 order by 'age'; -- 结果并没有按age排序,错误地使用order by +-------+------+ | name | age | +-------+------+ | Herry | 20 | | Jack | 40 | | Alice | 35 | +-------+------+ 3 rows in set (0.00 sec) mysql> select * from tbl1 order by age; -- 结果按age排序 +-------+------+ | name | age | +-------+------+ | Herry | 20 | | Alice | 35 | | Jack | 40 | +-------+------+ 3 rows in set (0.00 sec)