一、 MyBatis简介
MyBatis 是基于java的持久层框架。MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
二、 配置文件
Mybatis配置文件是xml格式文件,它包含一些能够动态影像mybatis行为的属性和设置。它的结构如下:
需要注意的是配置中的各个标签需要严格按照指定的顺序出现。
下面挑选一些比较常用的和重要的元素进行讲解。
- typeAliases
typeAliases相当于一个宏,通过定义typeAliases可以避免在Mapper文件中写类的全名
<typeAliases>
<package name="domain.blog"/>
</typeAliases>
- environments
以下是environments配置的一份示例:
<environments default="testabc">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver"value="org.apache.derby.jdbc.ClientDriver"/>
<property name="url"value="jdbc:derby://localhost:1527/TrainSystem;create=false"/>
<property name="username"value="root"/>
<property name="password"value="123"/>
</dataSource>
</environment>
<environment id="testabc">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver"value="org.apache.derby.jdbc.ClientDriver"/>
<property name="url"value="jdbc:derby://localhost:1527/TrainSystem;create=false"/>
<property name="username"value="root"/>
<property name="password"value="123"/>
</dataSource>
</environment>
</environments>
environments标签内主要包含一些数据库环境配置信息。Mybatis支持配置多个环境来满足各种用例,如不同的开发,测试,产品配置,多个数据库共用同一份映射等等。值得注意的是,如果需要连接两个数据库,那就需要创建两个SQLSessionFactory。
要启用特定的environment,在调用build方法是传入environment的id即可。
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment);
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment,properties);
也可以不输入environment的id,则后台自动调用默认环境(environment的default属性里设置)。
- 两种事务处理方式
Mybatis支持两种事务处理方式,分别是JDBC与MANAGED。用户也可以创建自己的事务处理。
dataSource属性配置了能够通过JDBC标准接口连接的容器的一些基础信息。dataSource有三种内置类型,POOLED,UNPOOLED,JNDI
比较常用的是POOLED以及UNPOOLED。
UNPOOLED代表懒连接策略,使用与一般的对速度性能要求不高的小程序。POOLED则连接的速度较快,使用与对性能要求较高的网站。
- Mapper
在Mapper标签内用户可以注册mapper配置文件。
三、 映射配置文件
Mapper配置文件是mybatis的核心部分。Mybatis专注于将SQL语句从传统的JDBC代码中扣里出来。
Mapper配置文件的核心是resultMap以及SQL语句,前者定义了数据库查询结果集到java对象的映射方式。
1增删改查语句
Select语句:
<select id="selectPerson" parameterType="int" resultType="hashmap">
SELECT * FROM PERSON WHERE ID = #{id}
</select>
其中#{id}是一个占位符,Mybatis会将其处理成预处理语句。其等效的JDBC代码如下:
// Similar JDBC code, NOT MyBatis…
String selectPerson = "SELECT * FROM PERSON WHERE ID=?";
PreparedStatement ps = conn.prepareStatement(selectPerson);
ps.setInt(1,id);
以下是插入,删除,更新的示例语句:
<insert id="insertAuthor">
insert into Author (id,username,password,email,bio)
values (#{id},#{username},#{password},#{email},#{bio})
</insert>
<update id="updateAuthor">
update Author set
username = #{username},
password = #{password},
email = #{email},
bio = #{bio}
where id = #{id}
</update>
<delete id="deleteAuthor">
delete from Author where id = #{id}
</delete>
某些数据库比如MySQL,支持动态增长的属性域。对此Mybatis也提供一支持,比如Author表的id列是自生成的,则在insert语句中设定useGenerateKeys以及keyProperty属性即可。
<insert id="insertAuthor" useGeneratedKeys="true"
keyProperty="id">
insert into Author (username,password,email,bio)
values (#{username},#{password},#{email},#{bio})
</insert>
2ResultMap基础
以下是一个简单的映射处理:
<select id="selectUsers" resultType="map">
select id, username, hashedPassword
from some_table
where id = #{id}
</select>
注意resultType属性,其值为map,map是Mybatis的内置类型,这句select语句会把结果直接映射为一个HashMap。
在大部分情况下,开发人员会吧结果集映射成一个javabean。如下:
<!-- In Config XML file -->
<typeAlias type="com.someapp.model.User" alias="User"/>
<!-- In SQL Mapping XML file -->
<select id="selectUsers" resultType="User">
select id, username, hashedPassword
from some_table
where id = #{id}
</select>
以下是User类:
package com.someapp.model;
public class User {
private int id;
private String username;
private String hashedPassword;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getHashedPassword() {
return hashedPassword;
}
public void setHashedPassword(String hashedPassword) {
this.hashedPassword = hashedPassword;
}
}
可以看到,该类的三个属性名称id,username,hashedPassword
与列名一样。
如果结果集中的列名和javabean的成员名不匹配,可以简单的通过SQL语法来进行映射,例子如下:
<select id="selectUsers" resultType="User">
select
user_id as "id",
user_name as "userName",
hashed_password as "hashedPassword"
from some_table
where id = #{id}
</select>
当然,一种更高端的方法就是使用ResultMap:
<resultMap id="userResultMap" type="User">
<id property="id" column="user_id" />
<result property="username" column="user_name"/>
<result property="password" column="hashed_password"/>
</resultMap>
要使用ResultMap的映射规则,需要在语句中进行引用:
<select id="selectUsers" resultMap="userResultMap">
select user_id, user_name, hashed_password
from some_table
where id = #{id}
</select>
四、 范围与生命周期
使用mybatis的映射功能需要使用一些列的基础类,这些类的范围与生命周期需要把握好才能保证效率与正确性。
- SqlSessionFactoryBuilder
该类是用来创建SQLSessionFactory的。使用时创建完Factory后就可以丢弃。所以该类的范围最好是在一个本地方法内,这样保证资源可以被及时的释放。
- SqlSessionFactory
该类负责创建会话(Session),生命周期应该与应用程序保持一致。可以使用一个单例来管理保存它。
- SqlSession
Session可以执行语句。该类是线程非安全的,所以不能放在一个静态变量中或者是作为一个类的以个成员出现。将Session的范围维持在一个方法内。还有很重要的一点是需要记得关闭Session,可以用finally语句来确保Session的关闭。
SqlSessionsession = sqlSessionFactory.openSession();
try {
// do work
} finally {
session.close();
}
五、 入门实例
以下实例实现了一最基本的从数据库查询数据并映射到javabean上的功能。查询方法不支持参数。
1构建测试工程
创建一个java工程,并导入需要的mybatis的jar包以及相应的数据库驱动包。本实例使用的是derby数据库,所以需要导入derby.client包。Mybatis的jar包在官方网站下载。derby.client包在derby文件系统中(官方下载)的lib目录下。
工程结构如下图所示:
2创建mybatis基础配置文件
Mybatis_cfg.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTDConfig 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<typeAlias alias="User"type="my.learner.mybitis.session.User"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver"value="org.apache.derby.jdbc.ClientDriver"/>
<property name="url"value="jdbc:derby://localhost:1527/TrainSystem;create=false"/>
<property name="username"value="root"/>
<property name="password"value="123"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="userMapper.xml"/>
</mappers>
</configuration>
其中environments元素中的default属性代表默认环境的id。
3创建javabean
创建一个用来保存从数据库中取出的数据对象的javabean。
4创建Mapper
本实例的关键部分mapper负责映射数据库数据到javabean。Mapper由一个java mapper接口以及一份xml文件构成。
Mapper接口负责被java客户代码调用,而xml文件中则详细定义了sql语句以及结果集映射方法。
UserMapper.java文件:
package my.learner.mybitis.session;
import java.util.List;
public interfaceUserMapper {
List<User>selectAllUser();
}
userMapper.xml文件:
<?xml version="1.0"encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTDMapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="my.learner.mybitis.session.UserMapper">
<select id="selectAllUser" resultMap="UserResult">
select * from APP.TBL_USER
</select>
<resultMap type="User" id="UserResult">
<result column="PK_USER_ID"property="id"/>
<result column="USERNAME"property="userName"/>
<result column="PASSWORD"property="passWord"/>
<result column="REAL_NAME"property="realName"/>
<result column="TEL_NUMBER"property="telNum"/>
<result column="USER_CREATE_TIME"property="createDate"/>
<result column="FK_USER_ROLE"property="userRole"/>
</resultMap>
</mapper>
其中select标签为sql select语句定义,它的id属性必须和mapper接口中响应的方法名一致,从而实现绑定。resultMap则指定了一个结果集映射id。
resultMap是结果映射集标签,他的type属性指定了javabean类名,而id属性则作为其表示。它的result子元素中的column属性代表数据库表中的一个列名,而property属性则是需要映射到的javabean成员变量名称。(注意:互相映射的两个数据类型必须一致)。
可以看到,mybatis实现绑定功能大量运用了判断字符串一致的方法。
select元素中可以不使用resultMap而使用resultType直接指定映射到的javabean的类名,如果这样使用的话则javanbean的成员变量名称必须和数据库中取出的数据的列名一致(不判断大小写),mybatis就会自动完成映射工作。
userMapper.xml版本2:
<?xml version="1.0"encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTDMapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="my.learner.mybitis.session.UserMapper">
<select id="selectAllUser" resultMap="User">
select * from APP.TBL_USER
</select>
</mapper>
5编写测试用例
TextEntry.java文件:
SQLSessionManager.java文件:
Mybatis session负责和数据库建立连接和查询工作。首先需要创建一个SqlSessionFactoryBuilder类,并使用配置文件创建出一个SQLSessionFactory,再由SQLSessionFactory的openSession方法来创建出一个SQLSession。
openSession方法执行时后台会读取mapper配置文件以及mybatis配置文件但并不会尝试连接数据库。当执行sql语句时后台才会去尝试连接数据库。
最后通过Session来获取需要的Mapper来执行SQL语句。
另一种使用方法是直接调用session的select方法并传入需要执行的语句的命名空间,如下:
user=session.selectList(“my.learner.mybitis.session.UserMapper.selectAllUser”);
或者使用省略方式:
user=session.selectList(“selectAllUser”);
使用省略方式需要注意多个语句的命名冲突问题。
PS:执行测试用例前请确保数据库服务器已经启动,测试数据也已经建立好。
六、 深入研究方向
1TypeHandler
处理用户自定义的类型,在何种情况下使用。
2ResultMap进阶
一些进阶子标签的使用:constructor、association、discriminator等。帮助映射复杂结果集。