MyBatis是一个第一类持久性框架,支持自定义SQL,存储过程和高级映射。MyBatis几乎消除了所有JDBC代码和手动设置参数以及检索结果。MyBatis可以使用简单的XML或Annotations来配置和映射基元,Map接口和Java POJO(Plain Old Java Objects)到数据库记录。
基本架构
Mybatis基本的功能架构分为以下三层:
- API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。
- 数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
- 基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。
使用JDBC的不足:
- 数据库连接创建、释放频繁造成系统资源浪费,从而影响系统性能。如果使用数据库连接池可解决此问题。
- Sql语句在代码中硬编码,造成代码不易维护,实际应用中sql变化的可能较大,sql变动需要改变java代码。
- 使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。
- 对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便。
Mybatis核心组件
Mybatis的核心组件分为4部分:
- SqlSessionFactoryBuilder(构造器):它会根据配置或者代码来生成SqlSessionFactory,采用的是分步构建的Builder模式。
- SqlSessionFactory(工厂接口):依靠它来生成SqlSession,使用的是工厂模式。
- SqlSession(会话):一个既可以发送SQL执行返回结果,也可以获取Mapper的接口。
- SQL Mapper(映射器):由一个Java接口和一个XML文件(或者注解)来构成,需要给出对应的SQL和映射规则。它负责发送SQL去执行,并返回结果。
无论是映射器Mapper还是SqlSession都可以发送SQL到数据库执行。
1、SqlSessionFactoryBuilder(构造器)
SqlSessionFactoryBuilder是每一个MyBatis的应用程序的入口,它的作用是通过XML配置文件创建Configuration对象(也可以在程序中自行创建),然后通过build方法创建SqlSessionFactory对象。没有必要每次访问Mybatis就创建一次SqlSessionFactoryBuilder,通常的做法是创建一个全局的对象就可以了。
2、SqlSessionFactory(工厂接口)
SqlSessionFactory对象由SqlSessionFactoryBuilder创建。它的主要功能是创建SqlSession对象,SqlSessionFactoryBuilder提供了一个Configuration类作为引导,采用Builder模式构建。SqlSessionFactory对象一个必要的属性是Configuration对象,它是保存Mybatis全局配置的一个配置对象,通常由SqlSessionFactoryBuilder从XML配置文件创建。
在MyBatis中,有两种方式生成SqlSessionFactory,通过读取配置的XML文件的形式和通过Java代码的形式生成。
使用XML构建SQLSessionFactory
<?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>
<typeAliases><!-- 别名 -->
<typeAlias alias="role" type="com.learn.ssm.chapter3.pojo.Role"/>
</typeAliases>
<!-- 数据库环境 -->
<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/chapter3"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 映射文件 -->
<mappers>
<mapper resource="com/learn/ssm/chapter3/mapper/RoleMapper.xml"/>
<mapper class="com.learn.ssm.chapter3.mapper.RoleMapper2"/>
</mappers>
</configuration>
对于以上代码:
- <typeAlias>元素定义了一个别名role,它代表着com.learn.ssm.chapter3.pojo.Role这个类,是为了缩短代码编写。
- <environment>元素的定义这里描述的是数据库。它里面的<transactionManager type="JDBC"/>是配置事务管理器,这里采用的是Mybatis的 JDBC 管理方式。
- <dataSource>元素用来配置数据库,其中属性type="POOLED",表示采用的是MyBatis内部提供的连接池方式,最后定义了一些JDBC的属性信息。
- <mapper>元素代表了引入的映射器。
然后通过读取此配置文件,生成SqlSessionFactory:
SqlSessionFactory sqlSessionFactory = null;
String resource = "mybatis-config.xml";
InputStream inputStream;
try {
inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
首先读取XML文件,然后通过SqlSessionFactoryBuilder的bulid方法来创建SqlSessionFactory对象。信息配置的XML中,有利于日后的维护和修改,避免了重新编译代码。
使用Java代码构建SQLSessionFactory
//数据库连接池信息
PooledDataSource dataSource = new PooledDataSource();
dataSource.setDriver("com.mysql.jdbc.Driver");
dataSource.setUsername("root");
dataSource.setPassword("123456");
dataSource.setUrl("jdbc:mysql://localhost:3306/chapter3");
dataSource.setDefaultAutoCommit(false);
//采用MyBatis的JDBC事务方式
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
//创建Configuration对象
Configuration configuration = new Configuration(environment);
//MyBatis的上下文别名
configuration.getTypeAliasRegistry().registerAlias("role", Role.class);
//加入一个映射器
configuration.addMapper(RoleMapper.class);
configuration.addMapper(RoleMapper2.class);
//使用SqlSessionFactoryBuilder构建SqlSessionFactory
sqlSessionFactory =
new SqlSessionFactoryBuilder().build(configuration);
return sqlSessionFactory;
3、SqlSession(会话)
SqlSession对象的主要功能是完成一次数据库的访问和结果的映射,它类似于数据库的session概念,由于不是线程安全的,所以SqlSession对象的作用域需限制方法内。SqlSession的默认实现类是DefaultSqlSession,它有两个必须配置的属性:Configuration和Executor.Configuration前文已经描述这里不再多说,SqlSession对数据库的操作都是通过Executor来完成的。
到目前为止,我们看到的都是mybatis的流程,我们的应用程序在什么地方插入到这个流程中并获得我们想要的结果呢?就是SqlSession这里。
SqlSession有一个重要的方法getMapper,顾名思义,这个方式是用来获取Mapper对象的。什么是Mapper对象?根据Mybatis的官方手册,应用程序除了要初始并启动Mybatis之外,还需要定义一些接口,接口里定义访问数据库的方法,存放接口的包路径下需要放置同名的XML配置文件。SqlSession的getMapper方法是联系应用程序和Mybatis纽带,应用程序访问getMapper时,Mybatis会根据传入的接口类型和对应的XML配置文件生成一个代理对象,这个代理对象就叫Mapper对象。应用程序获得Mapper对象后,就应该通过这个Mapper对象来访问Mybatis的SqlSession对象,这样就达到里插入到Mybatis流程的目的。
SqlSession sqlSession = sqlSessionFactory.openSession();
RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
Role role = roleMapper.getRole(1L);
4、Mapper映射器
映射器是由一个接口和对应的XML文件(或注解)组成的,它的主要作用就是将SQL查询到的结果映射为一个POJO,或者将POJO的数据插入数据库中。
由于它只是一个接口,接口是不能直接运行的,所以MyBatis运用了动态代理技术为接口生成一个代理对象,代理对象去处理相关逻辑。
定义一个POJO:
public class Role {
private Long id;
private String roleName;
private String note;
/**
* setter and getter
**/
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}
定义映射器接口:
public interface RoleMapper {
public int insertRole(Role role);
public int deleteRole(Long id);
public int updateRole(Role role);
public Role getRole(Long id);
public List<Role> findRoles(String roleName);
}
配置对应的XML文件:
<?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="com.learn.ssm.chapter3.mapper.RoleMapper">
<insert id="insertRole" parameterType="role">
insert into t_role(role_name, note) values(#{roleName}, #{note})
</insert>
<delete id="deleteRole" parameterType="long">
delete from t_role where id= #{id}
</delete>
<update id="updateRole" parameterType="role">
update t_role set role_name = #{roleName}, note = #{note} where id= #{id}
</update>
<select id="getRole" parameterType="long" resultType="role">
select id,
role_name as roleName, note from t_role where id = #{id}
</select>
<select id="findRoles" parameterType="string" resultType="role">
select id, role_name as roleName, note from t_role
where role_name like concat('%', #{roleName}, '%')
</select>
</mapper>
其中<mapper>元素的属性 namespace 所对应的是一个接口的全限定名,使得MyBatis上下文可以通过它找到对应的接口。
<select>元素表示是一条查询语句,其属性 id 标识了这条SQL,属性parameterType="long" resultType="role"分别表示传递给SQL的参数类型为long以及返回值类型为 role(即之前的com.learn.ssm.chapter3.pojo.Role的别名)。#{id} 表示传递的参数。
还可以通过注解来定义映射器,替代上文的XML文件,只需在接口方法上写入对应注解:
public interface RoleMapper {
@Select("select id, role_name as roleName, note from t_role where id=#{id}")
public Role getRole(Long id);
}
参考文章:
《Java EE 互联网轻量级框架整合开发》