MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 有以下特点:
- 简单易学,小且简单:没有第三方依赖,最简单安装只要两个jar包+配置几个sql映射文件,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
- 灵活:MyBatis 不会对应用程序或者数据库的现有设计强加任何影响。 sql 写在 xml 里,便于统一管理和优化。通过 sql 语句可以满足操作数据库的所有需求。
- 解除 sql 与程序代码的耦合:通过提供 DAO 层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql 和代码的分离,提高了可维护性。
- 提供映射标签,支持对象与数据库的orm字段关系映射
- 提供对象关系映射标签,支持对象关系组建维护
- 提供xml标签,支持编写动态sql。
快速入门实例
引用依赖
单独使用 MyBatis,只需引入mybatis-x.x.x.jar
和相关的数据库连接包就行
使用 maven 的 dependency 配置为
1 | <dependency> |
我的例子的应用目录结构为下图
Mybatis配置和 xml映射文件配置
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory
的实例为中心的。
SqlSessionFactory
的实例可以通过 SqlSessionFactoryBuilder
获得。
而 SqlSessionFactoryBuilder
则可以从 XML 配置文件或一个预先定制的 Configuration 的实例构建出 SqlSessionFactory
的实例。
mybatis XML 配置
MyBatis 的XML配置文件(configuration XML)中包含了对 MyBatis 系统的核心设置,包含获取数据库连接实例的数据源(DataSource)和决定事务作用域和控制方式的事务管理器(TransactionManager)
这里先给出一个用 xml 配置的简单示例 mybatis-config.xml
,详细的配置文件内容后面详说:
1 |
|
数据源属性文件 database.properties
1
2
3
4jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/shiyu?autoReconnect=true&useUnicode=true&characterEncoding=utf-8
jdbc.username=zou
jdbc.password=******
通过配置文件我们可以从中构建 SqlSessionFactory 的实例1
2inputStream = Resources.getResourceAsStream("conf/mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
xml映射文件配置
我们从上面的配置可以看到有映射器的配置
<mapper resource="com/brave/dao/mapper/UpmsUserMapper.xml" />
这里先给出该映射文件示例1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!--- 命名空间 namespace -->
<mapper namespace="com.brave.dao.UpmsUserDao">
<!-- 结果集映射 -->
<resultMap type="com.brave.model.UpmsUser" id="upmsUser">
<id column="user_id" property="userId"/>
<result column="loginname" property="loginname"/>
<result column="password" property="password"/>
<result column="realname" property="realname"/>
<result column="phone" property="phone"/>
<result column="email" property="email"/>
<result column="is_locked" property="locked"/>
<result column="gmt_create" property="gmtCreate"/>
<result column="gmt_modified" property="gmtModified"/>
</resultMap>
<!-- 查询sql -->
<select id="selectOne" resultMap="upmsUser">
select * from upms_user where user_id = #{userId}
</select>
<select id="selectUser" resultMap="upmsUser">
select * from upms_user
</select>
<insert id="insertUser">
insert into upms_user (user_id,loginname,password,realname,is_locked)
value(#{userId},#{loginname},#{password},#{realname},#{locked})
</insert>
</mapper>
上面我们通过 MyBatis 配置 xml 构建了 SqlSessionFactory,有了 SqlSessionFactory,顾名思义,我们就可以从中获得 SqlSession 的实例了。SqlSession 完全包含了面向数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句:1
2
3
4
5
6
7SqlSession sqlSession = sqlSessionFactory.openSession();
try {
//这里我们通过 命名空间+sql语句的Id来执行映射的sql语句
UpmsUser upmsUser = sqlSession.selectOne("com.brave.dao.UpmsUserDao.selectOne", 10001L);
}finally {
sqlSession.close();
}
构建 SqlSessionFactory,获取 SqlSession
从上面的 MyBatis 配置和 xml 映射文件配置 我们可以了解到这样一个流程:
通过流读取 MyBatis 配置文件信息,使用 SqlSessionFactoryBuilder 构建 SqlSessionFactory,再从SqlSessionFactory 中获取 SqlSession 实例,通过 SqlSession 实例来直接执行已映射的 SQL 语句
在这里我们需要理解这三个对象的不同作用域和生命周期,错误的使用会导致非常严重的并发问题。
生命周期 | 作用域(Scope) | |
---|---|---|
SqlSessionFactoryBuilder | 可以被实例化、使用和丢弃,一旦创建了SqlSessionFactory,就不再需要它了 | 方法(也就是局部方法变量) |
SqlSessionFactory | 一旦被创建就应该在应用的运行期间一直存在,没有任何理由对它进行清除或重建 | 应用(最简单的就是使用单例模式或者静态单例模式) |
SqlSession | 每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的 | 请求 / 方法 |
因为 SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,我们可以使用单例,创建一个 SqlSessionFactoryUtil1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27public class SqlSessionFactoryUtil {
private static SqlSessionFactory sqlSessionFactory;
/**
* 每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为中心的。
* SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。
* 而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先定制的 Configuration 的实例构建出 SqlSessionFactory 的实例。
*
* SqlSessionFactoryBuilder 最佳作用域是方法作用域(也就是局部方法变量)
* SqlSessionFactory 最佳作用域是应用作用域
* SqlSession 最佳的作用域是请求或方法作用域
*/
public static SqlSessionFactory getSqlSessionFactory() {
if (sqlSessionFactory != null) {
return sqlSessionFactory;
}
InputStream inputStream;
try {
inputStream = Resources.getResourceAsStream("conf/mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
return sqlSessionFactory;
}
}
我们可以创建一个 baseDao 获取 SqlSession1
2
3
4
5
6
7
8
9public class BaseDaoImpl implements BaseDao {
public SqlSession getSqlSession() {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
return sqlSessionFactory.openSession();
}
}
通过 命名空间+sql 语句的 Id 来执行映射的 sql 语句1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39public class UpmsUserDaoImpl extends BaseDaoImpl implements UpmsUserDao {
public UpmsUser selectOne(Long userId) {
SqlSession sqlSession = getSqlSession();
UpmsUser upmsUser = null;
try {
upmsUser = sqlSession.selectOne("com.brave.dao.UpmsUserDao.selectOne", userId);
} finally {
sqlSession.close();
}
return upmsUser;
}
public List<UpmsUser> selectUser() {
SqlSession sqlSession = getSqlSession();
List<UpmsUser> upmsUsers = null;
try {
upmsUsers = sqlSession.selectList("com.brave.dao.UpmsUserDao.selectUser");
} finally {
sqlSession.close();
}
return upmsUsers;
}
public int insertUser(UpmsUser upmsUser) {
SqlSession sqlSession = getSqlSession();
int n = 0;
try {
n = sqlSession.insert("com.brave.dao.UpmsUserDao.insertUser", upmsUser);
sqlSession.commit();
} finally {
sqlSession.close();
}
return n;
}
}
我们用 Junit 创建测试类测试一下结果1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28public class UpmsUserDaoImplTest {
UpmsUserDao userDao = new UpmsUserDaoImpl();
public void testSelectOne() {
System.out.println(userDao.selectOne(10001L).toString());
}
public void testSelectUser() {
List<UpmsUser> upmsUsers = userDao.selectUser();
for (UpmsUser upmsUser : upmsUsers) {
System.out.println(upmsUser.toString());
}
}
public void testInsertUser() {
UpmsUser upmsUser = new UpmsUser();
upmsUser.setUserId(10002L);
upmsUser.setLoginname("zou");
upmsUser.setPassword("123456");
upmsUser.setLocked(false);
int n = userDao.insertUser(upmsUser);
System.out.println("插入" + n + "行");
}
}
到了这里我们其实可以发现,我们在映射文件中写的 命名空间 和 完全限定名 是一样的,如com.brave.dao.UpmsUserDao
,这个命名可以直接映射到在命名空间中同名的 Mapper 类,并将已映射的 sql 语句中的名字、参数和返回类型匹配成方法
这样我们就可以像上面那样很容易地调用这个对应 Mapper 接口的方法,只需要接口,不需要写实现类。我们的接口方法名称和 映射文件中的sql语句Id一致的话可以直接调用。
UpmsUserDao.java
1 | public interface UpmsUserDao extends BaseDao { |
测试1
2
3
4
5
6
7
8
9
10
11
public void testInterface() {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
SqlSession session = sqlSessionFactory.openSession();
//可以直接映射到在命名空间中同名的 Mapper 类 (只要映射接口类就可以了,不需要实现)
UpmsUserDao upmsUserDao = session.getMapper(UpmsUserDao.class);
List<UpmsUser> upmsUsers = upmsUserDao.selectUser();
for (UpmsUser upmsUser : upmsUsers) {
System.out.println(upmsUser.toString());
}
}
它们的映射的语句还可以不需要用 XML 来做,取而代之的是可以使用 Java 注解1
2"select * from upms_user where user_id = #{userId}") (
UpmsUser getUser(Long userId);
SqlSession 的使用和API
使用 MyBatis 的主要 Java 接口就是 SqlSession。可以通过这个接口来执行命令,获取映射器和管理事务。SqlSessions 是由 SqlSessionFactory 实例创建的。SqlSessionFactory 对象包含创建 SqlSession 实例的所有方法。而 SqlSessionFactory 本身是由 SqlSessionFactoryBuilder 创建的,它可以从 XML、注解或手动配置 Java 代码来创建 SqlSessionFactory。
MyBatis XML配置
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置(settings)和属性(properties)信息。文档的顶层结构如下:
- configuration 配置
- properties 属性
- settings 设置
- typeAliases 类型别名
- typeHandlers 类型处理器
- objectFactory 对象工厂
- plugins 插件
- environments 环境
- environment 环境变量
- transactionManager 事务管理器
- dataSource 数据源
- databaseIdProvider 数据库厂商标识
- mappers 映射器
官方的文档很详细,这里不写了,直接参考过去
http://www.mybatis.org/mybatis-3/zh/configuration.html
1 |
|
Mapper映射文件配置
MyBatis 的真正强大在于它的映射语句,也是它的魔力所在。由于它的异常强大,映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。MyBatis 就是针对 SQL 构建的,并且比普通的方法做的更好。
SQL 映射文件有很少的几个顶级元素(按照它们应该被定义的顺序):
cache
– 给定命名空间的缓存配置。cache-ref
– 其他命名空间缓存配置的引用。resultMap
– 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。parameterMap
– 已废弃!老式风格的参数映射。内联参数是首选,这个元素可能在将来被移除,这里不会记录。sql
– 可被其他语句引用的可重用语句块。insert
– 映射插入语句update
– 映射更新语句delete
– 映射删除语句select
– 映射查询语句
每个元素的细节见官方文档
http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html