一、环境搭建
对 Mybatis 整合 Spring 首先需要准备好 Mybatis 和 Spring 的包,在各自的官网都有下载,Mybatis 下载,Spring 下载。
因为 Mybatis 可以通过 dao 的形式开发和 Mapper 的形式开发,所以搭建下图所示的项目及结构,对两种开发方式进行介绍和测试。
在 src 下,包 com.po 包含的是 POJO 类;包 com.dao 中包含的是 dao 方式开发相关代码;包 com.mapper 中包含的是 mapper 方式开发相关代码;
在 test 下,包 com.dao 中包含的是对 dao 方式开发的代码进行测试的测试类;包 com.mapper 中包含的是对 mapper 方式开发的代码进行测试的测试类;
在 config 下,mapper 中的 UserMapper.xml 是 dao 方式开发的 statement;mybatis 下的SqlMapConfig.xml 是 Mybatis 相关的配置文件;spring 下的applicationContext.xml 是 Spring 相关的配置文件;db.properties 文件是数据库配置文件;
lib 是包含 Mybatis 和 Spring jar包的集合;
log4j.properties 是日志配置文件(不做介绍);
二、整合内容
1. 需要 Spring 通过单例方式管理 SqlSessionFactory;
2. 持久层的 mapper 都需要由 Spring 进行管理;
3. Spring 和 Mybatis 整合生成代理对象(applicationContext),使用SqlSessionFactory 创建 SqlSession。(Spring 和 Mybatis 整合自动完成);
三、进行整合
1. applicationContext.xml
在 Mybatis 与 Spring 整合之前,数据源由 Mybatis 自己管理,但是整合后需要 Spring 进行管理,所以在 applicationContext.xml 中需要对数据源进行配置,看下详细配置:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
<!-- 加载配置文件 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 数据源,使用dbcp -->
<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="100" />
<property name="maxIdle" value="10" />
</bean>
<!-- sqlSessinFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 加载 Mybatis 的配置文件 -->
<property name="configLocation" value="mybatis/SqlMapConfig.xml" />
<!-- 加载数据源 -->
<property name="dataSource" ref="dataSource" />
</bean>
<!-- dao接口 开发 -->
<bean id="userDao" class="com.dao.UserDaoImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
<!-- mapper 开发 -->
<!-- 单个mapper配置 MapperFactoryBean:根据mapper接口生成代理对象 -->
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<!-- mapperInterface指定mapper接口 -->
<property name="mapperInterface" value="com.mapper.UserMapper"/>
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
<!-- mapper批量扫描
从mapper包中扫描出mapper接口,自动创建代理对象并且在spring容器中注册
遵循规范:将mapper.java和mapper.xml映射文件名称保持一致,且在一个目录中
自动扫描出来的mapper的bean的id为首字母小写的mapper类名
-->
<!-- <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
指定扫描的包名 ,如果扫描多个包,每个包中间使用半角逗号分隔
<property name="basePackage" value="com.mapper"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean> -->
</beans>
和 Mybatis 一样,数据库信息是通过 properties 文件进行加载,目的是为了更好的维护和管理。
2. 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"/>
当设置为‘true’的时候,懒加载的对象可能被任何懒属性全部加载。
否则,每个属性都按需加载。
<setting name="aggressiveLazyLoading" value="false"/>
</settings> -->
<!-- 定义别名 -->
<typeAliases>
<!-- 针对单个别名定义 -->
<!-- <typeAlias type="com.po.User" alias="user"/> -->
<!-- 针对批量别名定义,别名就是类名(首字母大小写都可以) -->
<package name="com.po"/>
</typeAliases>
<!-- 类型处理器 ,通常情况下,mybatis提供的类型处理器满足日常需要,不需要自定义-->
<!-- <typeHandlers>
<typeHandler handler="" javaType="" jdbcType=""/>
</typeHandlers> -->
<!-- 加载映射文件 -->
<mappers>
<!-- 通过resource加载 -->
<mapper resource="mapper/UserMapper.xml" />
<!-- 通过mapper接口加载,但需要将接口名和映射文件名保存一致,且在同一目录 -->
<!-- <mapper class=""/> -->
<!-- 批量加载 -->
<!-- <package name="com.mapper"/> -->
</mappers>
</configuration>
3. db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=123456
四、Dao 开发
到这一步,整合的配置文件已经基本上完成了,现在开始 Dao 开发的代码编写
1. 编写 Mapper.xml 文件
下面我将以查询用户信息为例。在我们这个项目中,我们需要编写 UserMapper.xml 文件,因为我们的目的是整合,所以写一个 statement 足矣,接下来我们一起来看看代码:
<?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">
<!-- namespace:命名空间,作用是对sql进行分类化管理,
注意:在mapper代理方法开发, namespace有特殊作用 -->
<mapper namespace="test">
<select id="findUserById" parameterType="int"
resultType="com.po.User">
SELECT * FROM USER WHERE ID = #{id}
</select>
</mapper>
2. 编写 Dao.java 接口及其实现类
紧接着,我们需要编写 Mapper.xml 的 Dao 接口及其实现类,在我们项目中 Mapper.xml 的 Dao 接口是 UserDao.java,其实现是 UserDaoImpl.java,代码如下:
package com.dao;
import com.po.User;
/**
* 描述:原生dao接口,管理用户
* @author 欧阳
* @since 2018年10月9日
*/
public interface UserDao {
//根据id查询用户信息
public User findUserById(int id) throws Exception;
}
在 Dao 的实现类中,需要继承 SqlSessionDaoSupport 类,原因一是 Spring 的配置文件 applicationContext.xml 中对 sqlSessionFactory 进行注入,进而继承了 SqlSessionDaoSupport 后就可以获得 sqlSession;原因二是因为该类中有获得 SqlSession 的方法。
package com.dao;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import com.po.User;
/**
* 描述:原生dao开发实现类
* @author 欧阳
* @since 2018年10月9日
*/
public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
@Override
public User findUserById(int id) throws Exception {
SqlSession sqlSession = this.getSqlSession();
User user = sqlSession.selectOne("test.findUserById", id);
return user;
}
}
3. sqlSessionFactory 注入
在 applicationContext.xml 对刚才写的 Dao 进行 sqlSessionFactory 注入,这块的代码在上面的 applicationContext.xml 中已经有了,但是需要在这重点说明一下,不然有些人可能会忘记这块。
<!-- 原始dao接口 开发 -->
<bean id="userDao" class="com.dao.UserDaoImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
4. Mapper.xml 加载
同上,在 SqlMapConfig.xml 中已经配置。
<!-- 通过resource加载,还可通过包扫描,批量加载 <package name=""/> -->
<mapper resource="mapper/UserMapper.xml" />
5. Dao 开发测试
这块直接上代码,及运行结果
package com.dao;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.po.User;
public class UserDaoImplTest {
private ApplicationContext applicationContext;
//此方法是在执行testFindUserById之前执行
@Before
public void setUp() throws Exception {
//获得 applicationContext 对象
this.applicationContext =
new ClassPathXmlApplicationContext("classpath:spring/applicationContext.xml");
}
@Test
public void testFindUserById() {
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
try {
//调用userDao的方法
User user = userDao.findUserById(2);
System.out.println(user);
} catch (Exception e) {
e.printStackTrace();
}
}
}
控制台输出结果如下:
log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
User [id=2, username=李四, sex=null, birthday=null, address=null]
五、Mapper 开发
1. 编写Mapper.xml
在前面三步的基础上,编写 Mapper.xml 文件,在我们的项目中 Mapper.xml 是 /SpringAndMybatis/src/com/mapper/UserMapper.xml,一定要注意,namespace 为你 Mapper 接口的路径(com.mapper.UserMapper)。
<?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">
<!-- namespace:命名空间,作用是对sql进行分类化管理,
注意:在mapper代理方法开发, namespace有特殊作用 -->
<mapper namespace="com.mapper.UserMapper">
<select id="findUserById" parameterType="int"
resultType="com.po.User">
SELECT * FROM USER WHERE ID = #{id}
</select>
</mapper>
2. 编写 Mapper 接口
这个接口编写规范需要遵循 Mybatis 的 Mapper 开发规范。并且建议将 Mapper.xml 和 Mapper 接口放在同一目录下,这样可以避免一些问题。
package com.mapper;
import com.po.User;
/**
* 描述:mapper代理接口,管理用户
* @author 欧阳
* @since 2018年10月9日
*/
public interface UserMapper {
/*
* 程序员编写mapper接口需要遵循一些开发规范,
* mybatis可以自动生成mapper接口实现类代理对象。
* 开发规范:
* 1、在mapper.xml中namespace等于mapper接口地址
* 2、mapper.java接口中的方法名和mapper.xml中statement的id一致
* 3、mapper.java接口中的方法输入参数类型和mapper.xml
* 中statement的parameterType指定的类型一致。
* 4、mapper.java接口中的方法返回值类型和mapper.xml
* 中statement的resultType指定的类型一致。
*/
//根据id查询用户信息
public User findUserById(int id) throws Exception;
}
3. sqlSessionFactory 注入
这部分代码在上面的 applicationContext.xml 中已经配置编写了,代码如下:
<!-- mapper 开发 -->
<!-- 单个mapper配置 MapperFactoryBean:根据mapper接口生成代理对象 -->
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<!-- mapperInterface指定mapper接口 -->
<property name="mapperInterface" value="com.mapper.UserMapper"/>
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
需要注意这是单个 Mapper 接口进行注入,那么对于我们程序员来说,一个项目中不止一个,两个的,而是很多很多,这样单个配置实在是太麻烦。因此,在 Spring 中也想到了这个问题,可以对指定包进行扫描自动注入,代码如下:
<!-- mapper批量扫描
从mapper包中扫描出mapper接口,自动创建代理对象并且在spring容器中注册
遵循规范:将mapper.java和mapper.xml映射文件名称保持一致,且在一个目录中
自动扫描出来的mapper的bean的id为首字母小写的mapper类名
-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 指定扫描的包名 ,如果扫描多个包,每个包中间使用半角逗号分隔 -->
<property name="basePackage" value="com.mapper"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
在指定包扫描时,需要注意如果扫描多个包,每个包中间使用半角逗号分隔;然后是对 sqlSessionFactoryBeanName
注入 sqlSessionFactory
。这种方式建议使用。
提醒一下,在指定某个包扫描时,如果都将 Mapper.xml 和其对应的 Mapper 接口放在同一个目录下,将节省很多工作量。
注意:在指定某个包扫描时,MapperScannerConfigurer
类不兼容 JDK 1.8,需要1.8以下版本的 JDK 。
4. Mapper.xml 加载
如果在第一步和第二步编写的 Mapper.xml 和其对应的 Mapper 接口放在同一个目录下,这里就不需要配置了。
不然就得加载对应的 Mapper.xml。加载方式和 Dao 开发一样,也支持对包批量加载。代码如下:
<!-- 加载映射文件 -->
<mappers>
<mapper resource="Mapper.xml 的路径" />
</mappers>
5. Mapper 开发测试
这块直接上代码,及运行结果
package com.mapper;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.po.User;
public class UserMapperTest {
private ApplicationContext applicationContext;
//此方法是在执行testFindUserById之前执行
@Before
public void setUp() throws Exception {
this.applicationContext =
new ClassPathXmlApplicationContext("classpath:spring/applicationContext.xml");
}
@Test
public void testFindUserById() {
UserMapper userMapper = (UserMapper) applicationContext.getBean("userMapper");
try {
User user = userMapper.findUserById(3);
System.out.println(user);
} catch (Exception e) {
e.printStackTrace();
}
}
}
控制台输出结果:
log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
User [id=3, username=欧阳, sex=null, birthday=null, address=山东]