一、简介
MyBatis 最重要的一个类就是 SqlSessionFactory,它的任务是通过加载全局配置文件和 Mapper 映射文件,初始化连接参数,创建会话实例类 SqlSession。
SqlSession 会话实例类是与数据库进行连接,执行 Mapper 中配置的 SQL 映射语句的核心类。
在 Spring 与 Mabatis 的整合环境中,Spring 的作用是通过单例方式管理 SqlSessionFactory,这样不仅节省连接和内存资源,而且不需要自己编写加载 Factory 的代码,从而统一了会话对象的产生源头。
Spring 也会对持久层的 Mapper 进行统一管理。不仅如此,Spring 还可以对数据库连接池、事物进行统一的管理。
二、整合步骤
2.1 配置 sqlSessionFactory
1、在 Spring 的配置文件中配置数据源和 sqlSessionFactory 的 bean,如下所示:
<!-- 数据源,使用DBCP -->
<!-- 数据源可以有3种,dbcp,c3p0,jndi -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maxActive" value="10"/>
<property name="maxIdle" value="5"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 加载Mybatis的配置文件 -->
<property name="configLocation" value="mybatis/SqlMapConfig.xml"/>
<!-- 数据源 -->
<property name="dataSource" ref="dataSource"/>
</bean>
其中 sqlSessionFactory 的 bean 实现类为 Mybatis 和 Spring 整合 jar 包中的 SqlSessionFactoryBean 类,在其中只需要注入两个参数:一个是 Mybatis 的全局配置文件 SqlMapConfig.xml;另一个是上面配置的数据源 bean。
2.2 配置 mybatis 配置文件
编写 MyBatis 配置文件 SqlMapConfig .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>
<settings>
<!-- 打开延迟加载的开关 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 将积极加载改为消极加载(按需加载) -->
<setting name="aggressiveLazyLoading" value="false"/>
<!-- 打开全局缓存开关(二级缓存)默认值就是true -->
<setting name="cacheEnabled" value="true"/>
</settings>
<!-- 别名设置 -->
<typeAliases>
<package name="cn.com.sm.po"/>
</typeAliases>
<!-- 加载映射文件 -->
<mappers>
<!-- 通过resource方法一次加载一个映射文件 -->
<mapper resource="sqlmap/UserMapper.xml"/>
<!-- 批量加载mapper -->
<package name="cn.com.sm.mapper"/>
</mappers>
</configuration>
2.3 编写 Mapper 映射文件
<?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="test">
<select id="findUserById" parameterType="int" resultType="user">
select * from user where id=#{id}
</select>
</mapper>
2.4 编写 DAO 层
编写 DAO 层,编写接口和实现类,如下
public interface UserDao{
public User findUserById(int id) throws Exception;
}
这里值得注意的是:UserDaoImpl 不仅实现了 UserDao 接口,而且继承了 SqlSessionDaoSupport 类,在 SqlSessionDaoSupport 类中包含了 sqlSessionFactory 对象作为其成员变量,而且对外提供 get 和 set 方法,方便 Spring 从外部注入 sqlSessionFactory 对象。
SqlSessionDaoSupport 类注入 sqlSessionFactory 对象后,会生成相应的 sqlSession 会话对象供子类使用。这样,在 UserDaoImpl 类中,就能够以获取新成员变量的方式直接获取 sqlSession 会话对象,进行增删改查的数据库操作了。
public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao{
public User findUserById(int id) throws Exception{
//继承SqlSessionDaoSupport类,通过this.getSqlSession()得到sqlsession
SqlSession sqlSession = this.getSqlSession();
User user = sqlSession.selectOne("test.findUserById",id);
return user;
}
}
2.5 注入 sqlSessionFactory
UserDaoImpl 类要成功获取 sqlSessionFactory 对象,还需要在 Spring 配置文件中添加 userDao 的 bean 配置,将其中定义的 sqlSessionFactory 对象当做参数注入进去,这样 UserDaoImpl 继承 SqlSessionDaoFactory 类才能起作用。
<bean id="UserDao" class="cn.com.sm.dao.UserDaoImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
三、Mapper 代理
spring 拥有自己的 Mapper 批量扫描器,用于扫描 Mapper 代理接口。此 Mapper 批量扫描器,会从 Mapper 包中扫描 Mapper 接口,自动创建代理对象并且在 Spring 容器中注入。这里遵从的规范是让 xxxMapper.java 和 mapper.xml 映射文件名称保持一致,且在一个目录中。
自动扫描出来的 Mapper 的 bean 的 id 为 Mapper 类名(首字母小写)。在 Spring 的全局配置文件中添加 Spring 的 Mapper 扫描器,用于在指定包下扫描定义的 Mapper代理接口,如下:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--指定扫描的包名,如果扫描多个包,包之间使用半角逗号分隔-->
<property name="basePackage" value="cn.com.sm.mapper" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
Mapper 扫描配置对象需要的参数是要扫描的包的路径和 sqlSessionFactory 对象,这些都可以使用注入的方式设置。
注意:一般情况下,Mapper 接口和 mapper.xml 映射文件是不在同一个包下的,怎么办呢?只需要在 sqlSessionFactory 这个 bean 里面配置一个标签即可:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 数据源 -->
<property name="dataSource" ref="dataSource"/>
<!-- 加载Mybatis的配置文件 -->
<property name="configLocation" value="mybatis/SqlMapConfig.xml"/>
<!-- 当mybatis的xml文件和mapper接口不在相同包下时,需要用mapperLocations属性指定xml文件的路径。 *是个通配符,代表所有的文件,**代表所有目录下 -->
<property name="mapperLocations" value="classpath:com/zit/cac/mapping/*.xml"/>
</bean>
四、结论
1、如果 Mapper.xml 与 Mapper 接口在同一个包下且同名,spring 扫描 Mapper.class 的同时会自动扫描同名的 Mapper.xml 并装配到 Mapper.class。
2、如果 Mapper.xml 与 Mapper.class 不在同一个包下或者不同名,就必须使用配置 mapperLocations 指定 mapper.xml 的位置,此时 spring 是通过识别 mapper.xml 中的 <mapper namespace="com.fan.mapper.UserDao"> namespace 的值来确定对应的 Mapper.class 的。