我们今天来看一看MyBatis的“表面现象”——组件,并且讨论一下他们的作用。
MyBatis的核心组件分为4个部分:
- SqlSessionFactoryBuilder(构造器):它会根据配置或者代码来生成SqlSessionFactory,采用的是分布构建的Builder模式。
- SqlSessionFactory(工厂接口):依靠它来生成SqlSession,使用的是工厂模式。
- SqlSession(会话):一个既可以发生SQL来执行返回结果,也可以获取Mapper的接口。在现在的技术中,一般我们会让其在业务逻辑代码中“消失”,而使用的是MyBatis提供的SQL Mapper接口编程技术,它能提高代码的可读性和可维护性。
- SQL Mapper(映射器):MyBatis新设计存在的组件,它由一个Java接口和XML文件(或注解)构成,需要给出对应的SQL和映射规则。它负责发送SQL去执行,并返回结果。
下面我在来细细的说一说各个组件。
1、SqlSessionFactory(工厂接口)
使用MyBatis首先是使用配置或者代码去生产SqlSessionFactory,二MyBatis提供了构造器SqlSessionFactoryBuilder。它提供了一个类org.apache.ibatis.session.Configuration作为引导,采用的是Build模式。具体的分步则是在Configuration类里面完成的。
1)、使用XML构建SqlSessionFactory
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>
<typeAliases><!-- 别名-->
<typeAlias alias="role" type="com.learn.ssm.pojo.Role"></typeAlias>
</typeAliases>
<!-- 数据库环境 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<dataSourse type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/ssm"></property>
<property name="username" value="root"></property>
<property name="password" value="hjw19990825"></property>
</dataSourse>
</environment>
</environments>
<!-- 映射文件 -->
<mappers>
<mapper resource="com/learn/ssm/mapper/RoleMapper.xml"></mapper>
</mappers>
</configuration>
- typeAlias元素定义了一个别名role,它代表着com.learn.ssm.pojo.Role这个类。这样定义后,在MyBatis上下文中就可以使用别名去代替全限定名。
- environment元素的定义,这里描述的是数据库。
- 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.printStrackTrace();
}
首先读取mybatis-config.xml,然后通过SqlSessionFactoryBuild的Build方法去创建SqlSessionFacrtory。整个过程比较简单,但是里面的步骤还是比较繁琐的,只是MyBatis采用了Builder模式为开发者隐藏了这些细节。
2)、使用代码创建SqlSessionFactory
//数据库连接池信息
PooledDataSource dataSource=new PooledDataSource();
dataSource.setDriver("com.mysql.jdbc.Driver");
dataSource.setUsername("root");
dataSource.setPassword("hjw19990825");
dataSource.setUrl("jdbc:mysql://localhost:3306/ssm");
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);
SqlSessionFactory SqlSessionFactory=new SqlSessionFactoryBuilder().build(configuration);
return SqlSessionFactory;
2、SqlSession
在MyBatis中,SqlSession是其核心接口。在MyBatis中有两个实现类——DefaultSqlSession和SqlSessionManager。DefaultSqlSessio是单线程使用的,而SqlSessionManager是在多线程环境下使用。SqlSession的作用类似于一个JDBC中的Connection对象,代表着一个连接资源的启用。它有3个作用:
- 获取Mapper接口
- 发送SQL给数据库
- 控制数据库事务
我们先来掌握它的创建方法,有了SqlSessionFactory,创建SqlSession就很简单了,代码如下:
SqlSession sqlSession=SqlSessionFactory.openSession();
其实SqlSession只是一个门面接口,在MyBatis中,真正在干活的是Executor,我们只能在底城看到它。
SqlSession控制数据库事务的方法,代码如下:
//定义SqlSession
SqlSession sqlSession=null;
try{
//打开SqlSession会话
sqlSession=SqlSessionFactory.openSession();
//some code ...
//提交事务
sqlSession.commit();
}catch(Exeception ex){
//回滚事务
sqlSession.rollback();
}finally{
//在finally语句中确保资源被顺利关闭
if(sqlSession!=null){
sqlSession.close();
}
}
commit方法提交事务,rollback方法回滚事务
3、SQL Mapper(映射器)
映射器是MyBatis中最重要、最复杂的组件,它由一个接口和对应的XML文件(或注解)组成。
他可以配置以下内容:
- 描述映射规则
- 提供SQL语句,并可以配置SQL参数类型、返回类型、缓存刷新等信息
- 配置缓存
- 提供动态SQL
我们来说一下实现映射器的方式——XML文件形式。不过在此之前,先定义一个POJO,代码如下:
package pojo;
public class Role {
private Long id;
private String roleName;
private String note;
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;
}
}
映射器的主要作用就是将SQL查询到的结果映射为一个pojo,或者将pojo的数据插入到数据库中,并定义一些关于缓存等的重要内容。
然后我们就可以来用XML实现映射器。用XML定义映射器分为两个部分:接口和XML,代码如下:
映射器接口:
public interface RoleMapper{
public Role getRole(Long id);
}
RoleMapper.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="mapper.RoleMapper">
<select id="getRole" parameterType="long" resultType="role">
select id,role_name as rolename,note from t_role where id=#{id}
</select>
</mapper>
- mapper元素中的属性namespace所对应的是一个接口的全限定名,于是MyBatis上下文就可以通过它找到对应的接口。
- selcet元素表明这是一条查询语句,属性id表示了这条SQL,属性paramenterType=“long"说明传递给SQL的是一个long型的参数,而resultType=“role”表示返回的是一个role类型的返回值。而role是之前配置文件mybatis-config.xml配置的别名。
- 这条SQL中的#{id}表示传递进去的参数
有了映射器就可以通过SqlSession发送SQL了,我们以getRole这条SQL为例看看如何发送SQL:
Role role=(Role)sqlSession.selectOne("mapper.getRole",1L);
selectOne方法表示使用查询并且只返回一个对象,而参数一个string对象和一个Object对象。这里是一个Long参数,long参数是它的主键。String对象是有一个命名空间加上SQLid组合而成的,它完全定位了一条SQL,这样MyBatis就会找到相对应的SQL。
SqlSession还可以获取Mapper接口,通过Mapper接口发送SQL,代码如下:
RoleMapper roleMapper=sqlSession.getMapper(RoleMaapper.class);
Role role=roleMapper.getRole(1L);
最后,我们来谈一谈以上两种发送SQL的方式(一种是用SqlSession直接发送,另外一种是通过SqlSession获取Mapper接口在发送),笔者建议采用第二种,理由如下:
- 使用Mapper接口编程可以消除SqlSession带来的功能性代码,提高可读性,而SqlSession发送SQL,需要一个SQLid去匹配SQL,比较难懂。
- 使用Mapper.getRole(1L)方式,IDEA会提示错误和校验,而使用sqlSession.selectOne(…)语法,只有在运行中才能知道是否发生了错误。