当我们想在 spring 项目中使用 mybatis 的时候就需要 mybatis-spring 了,它可以让 spring 完美的整合 mybatis 代码。使用这个类库中的类,spring 将会加载必要的 mybatis 工厂类和 session 类。 这个类库也提供一个简单的方式来注入 mybatis 数据映射器和 SqlSession 到业务层的 bean 中。 而且它也会处理事务, 翻译 MyBatis 的异常到 Spring 的 DataAccessException 异常(数据访问异常)中
我们先走一个简单例子,再在基础上扩展
使用 mybatis-spring 模块,需要添加 mybatis-spring-x.x.x.jar
包
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>1.3.2version>
dependency>
同时加上 mybatis-x.x.x.jar 包和相关数据库连接包,spring 的依赖添加上 spring-context 和 spring-jdbc,如果是 web 项目,再加上 web 相关的 jar 包即可
我们在使用 mybatis 的时候,最关键的是去使用 SqlSession 去执行映射的 SQL 语句。而 SqlSession 是通过 SqlSesionFactory 来获取的。而 SqlSessionFactory 的实例则是由SqlSessionFactoryBuilder 从 XML 配置文件或一个预先定制的 Configuration 的实例构建出来的
现在,我们是要在 spring 上整合 mybatis,需要把 SqlSessionFactory 的创建和 注入交给 spring容器,在 mybatis-spring 中 SqlSessionFactory 的创建交给了 SqlSessionFactoryBean
我们在项目中创建一个 spring 的配置文件,添加相关配置,加上 SqlSessionFactoryBean 的配置
application-mybatis.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.brave"/>
<context:property-placeholder location="classpath*:conf/*.properties">context:property-placeholder>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:conf/mybatis/mybatis-config.xml">property>
<property name="mapperLocations" value="classpath*:com/brave/dao/mapper/*Mapper.xml" />
bean>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" 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}" />
bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
bean>
beans>
要注意 SqlSessionFactoryBean 实现了 Spring 的 FactoryBean 接口。
这就说明了由 Spring 最终创建的 bean 不是 SqlSessionFactoryBean 本身。 而是工厂类的 getObject()返回的方法的结果。这种情况下,Spring 将会在应用启动时为你 创建 SqlSessionFactory 对象,然后将它以 SqlSessionFactory 为名来存储。在 Java 中, 相同的代码是:
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
SqlSessionFactory sessionFactory = factoryBean.getObject();
但是一般我们不直接使用 SqlSessionFactoryBean 或 SqlSessionFactory。因为 session 工厂将会被注入到映射器中 或其它扩展了 SqlSessionDaoSupport 的 DAO(Data Access Object,数据访问对象)中
SqlSessionFactory有三个属性
mapperLocations 可以配置多个位置
<property name="mapperLocations">
<list>
<value>classpath*:conf/mybatis/**/*Mapper.xmlvalue>
<value>classpath*:conf/com/brave/**/*Mapper.xmlvalue>
list>
property>
在 mybatis 中,我们使用 SqlSessionFactory 来创建 SqlSession。获取了一个 session 之后,使用它来执行映射的 SQL 语句、提交或回滚连接,最后当不再需要它的时候关闭 session。
使用 mybatis-spring 之后,就不需要直接使用 SqlSessionFactory 了,因为你的 bean 可以通过一个线程安全的 SqlSession 来注入,基于 spring 的事务配置来自动提交、回滚、关闭 session。
SqlSessionTemplate 是 mybatis-spring 的核心。它负责管理 mybatis 的 SqlSession, 调用 mybatis 的 SQL 方法、翻译异常。它是线程安全的,可以被多个 DAO 所共享使用。
当调用 SQL 方法时,包含从映射器 getMapper()方法返回的方法,SqlSessionTemplate 将会保证使用的 SqlSession 是和当前 Spring 的事务相关的。它管理这 session 的生命周期,包含必要的关闭,提交或回滚操作。
SqlSessionTemplate 对象可以使用 SqlSessionFactory 作为构造方法的参数来创建
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
<constructor-arg index="1" value="BATCH" />
bean>
SqlSessionTemplate 实现了 SqlSession 接口,不用再代码中对 mybatis 的 SqlSession 进行替换,直接在 Dao bean中直接注入这个 SqlSession 属性就可以了
@Repository
public class UpmsUserDaoImpl implements UpmsUserDao {
@Autowired
private SqlSession sqlSession;
@Override
public UpmsUser selectOne(Long userId) {
return sqlSession.selectOne("com.brave.dao.UpmsUserDao.selectOne", userId);
}
@Override
public List<UpmsUser> selectUser(UpmsUser upmsUser) {
return sqlSession.selectList("com.brave.dao.UpmsUserDao.selectUser", upmsUser);
}
@Override
public int insertUser(UpmsUser upmsUser) {
return sqlSession.insert("com.brave.dao.UpmsUserDao.insertUser", upmsUser);
}
}
这里附上我的映射文件 upmsUserMapper.xml
<mapper namespace="com.brave.dao.UpmsUserDao">
<resultMap type="com.brave.model.UpmsUser" id="upmsUser">
<id column="user_id" property="userId"/>
<result column="loginname" property="loginname"/>
<result column="password" property="password"/>
<result column="realname" property="realname"/>
<result column="phone" property="phone"/>
<result column="email" property="email"/>
<result column="is_locked" property="locked"/>
<result column="gmt_create" property="gmtCreate"/>
<result column="gmt_modified" property="gmtModified"/>
resultMap>
<select id="selectOne" resultMap="upmsUser">
select * from upms_user where user_id = #{userId}
select>
<select id="selectUser" resultMap="upmsUser">
select * from upms_user
<where>
<if test="loginname != null and loginname != '' ">
loginname like #{loginname}
if>
<if test="realname != null and realname != '' ">
and realname like #{realname}
if>
where>
select>
<insert id="insertUser">
insert into upms_user (user_id,loginname,password,realname,is_locked)
value(#{userId},#{loginname},#{password},#{realname},#{locked})
insert>
mapper>
使用 Junit 生成测试类
@RunWith(SpringJUnit4ClassRunner.class) //使用junit4进行测试
@ContextConfiguration ("/conf/spring/applicationContext*.xml")
public class UpmsUserDaoImplTest {
@Autowired
private UpmsUserDao upmsUserDao;
@Test
public void testSelectOne() {
System.out.println(upmsUserDao.selectOne(10001L).toString());
}
@Test
public void testSelectUser() {
UpmsUser user = new UpmsUser();
user.setLoginname("zou");
user.setUserId(2L);
List<UpmsUser> upmsUsers = upmsUserDao.selectUser(user);
for (UpmsUser upmsUser : upmsUsers) {
System.out.println(upmsUser.toString());
}
}
@Test
@Transactional //声明需要事务
public void testInsertUser() {
UpmsUser upmsUser = new UpmsUser();
upmsUser.setUserId(10002L);
upmsUser.setLoginname("zou");
upmsUser.setPassword("123456");
upmsUser.setLocked(false);
int n = upmsUserDao.insertUser(upmsUser);
System.out.println("插入" + n + "行");
}
}
SqlSessionDaoSupport 是一个抽象的支持类,用来提供 SqlSession。getSqlSession()方法可以得到一个 SqlSessionTemplate
public class UpmsUserDaoImpl2 extends SqlSessionDaoSupport implements UpmsUserDao {
@Override
public UpmsUser selectOne(Long userId) {
return getSqlSession().selectOne("com.brave.dao.UpmsUserDao.selectOne", userId);
}
}
SqlSessionDaoSupport 需要设置一个 sqlSessionFactory 或 sqlSessionTemplate 属性
假如是 UpmsUserDaoImpl2 继承了 SqlSessionDaoSupport:
<bean id="upmsUserDaoImpl" class="com.brave.dao.UpmsUserDaoImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
bean>
可以创建一个公用的 SuperDao 去继承 SqlSessionDaoSupport,为 SuperDao 设置 sqlSessionFactory 属性,然后让其他 dao 去继承 SuperDao,这样就不用每个 dao 都去设置这个属性了
public class SuperDao extends SqlSessionDaoSupport {
@Autowired
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
super.setSqlSessionFactory(sqlSessionFactory);
}
}
不过通常我们更常用 MapperFactoryBean(只需要接口,不用实现类),因为它不需要额外的代码。但是如果需要在 DAO 中做其它非 MyBatis 的工作或需要具体的类,那么这个类就很有用了。
mybatis-spring 允许 mybatis 参与到 spring 的事务管理中。利用了存在于 Spring 中的 DataSourceTransactionManager,而不是创建一个新的特定的事务管理器
一旦 Spring 的 PlatformTransactionManager 配置好了,可以在 spring 中以通常的做法来配置事务。@Transactional 注解和 AOP 样式的配置都是支持的。在事务处理期间,一个单独的 SqlSession 对象将会被创建和使用。当事务完成时,这个 session 会以合适的方式提交或回滚。
一旦事务创建之后,mybatis-spring 将会透明的管理事务。在你的 DAO 类中就不需要额外的代码了
要 开 启 Spring 的 事 务 处 理 , 在 Spring 的 XML 配 置 文 件 中 简 单 创 建 一 个 DataSourceTransactionManager 对象:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
bean>
在 mybatis 中,我们可以创建一个来绑定映射的语句的接口映射器(实际上也就是我们的 dao 接口),在映射文件的命名空间与我们的映射器完全限定名一致,映射语句id名就是映射器的方法名,这样我们可以不用实现这个映射器,通过 sqlSession 获取映射器,直接使用 sql 方法
UpmsUserDao upmsUserDao = sqlSession.getMapper(UpmsUserDao.class);
UpmsUse upmsUse = upmsUserDao.selectOne(10002L);
为了代替手工使用 SqlSessionDaoSupport 或 SqlSessionTemplate 编写数据访问对象 (DAO)的代码,mybatis-spring 也提供了一个动态代理的实现:MapperFactoryBean。这个类可以让你直接注入 数据映射器接口 到你的 service 层 bean 中。当使用映射器时,直接调用就可以了,不需要实现 DAO接口,因为 mybatis-spring 将会为你创建代理。
使用注入的映射器代码,在 mybatis、spring 或 mybatis-spring 上面不会有直接的依赖。 MapperFactoryBean 创建的代理控制开放和关闭 session,会翻译任意的异常到 spring 的 DataAccessException 异常中。此外,如果需要或参与到一个已经存在活动事务中,代理将会开启一个新的 spring 事务。
想要直接使用 数据映射器接口,先添加 MapperFactoryBean 到 spring 中:
<bean id="upmsUserMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.brave.mapper.UpmsUserMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
bean>
MapperFactoryBean 创建的代理类实现了 UpmsUserMapper 接口,并且注入到应用程序中。 因为代理创建在运行时环境中,那么指定的映射器必须是一个接口,而不是一个具体的实现类。
如果 XML 映射器文件在类路径的位置和映射器类相同时,它会被 MapperFactoryBean 自动解析,否则你需要在 SqlSessionFactoryBean 的 mapperLocations 或是在 mybatis 的配置文件中指明映射文件的位置
这里附上映射文件,这里的命名空间一定要是映射器的完全限定名
<mapper namespace="com.brave.mapper.UpmsUserMapper">
<select id="selectUser" resultType="com.brave.model.UpmsUser">
select * from upms_user
select>
mapper>
接口映射器 UpmsUserMapper.java
public interface UpmsUserMapper {
List<UpmsUser> selectUser();
}
然后我们在应用程序逻辑中可以直接使用
@Service
public class UpmsUserServiceImpl implements UpmsUserService {
@Autowired
private UpmsUserMapper upmsUserMapper;
@Override
public List listUser() {
return upmsUserMapper.selectUser();
}
}
我们没有必要在 spring 的 XML 配置文件中注册所有的映射器。只用使用一个 MapperScannerConfigurer 即可,它会查找类路径下的映射器并自动将它们创建成 MapperFactoryBean
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.brave.mapper" />
bean>
这样就不用每个 mapper 都配置一个 MapperFactoryBean 了
basePackage 属性是让你为映射器接口文件设置基本的包路径。 可以使用 分号 或 逗号 作为分隔符设置多于一个的包路径。每个映射器将会在指定的包路径中递归地被搜索到
另外还有两种扫描映射器的方法
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://mybatis.org/schema/mybatis-spring
http://mybatis.org/schema/mybatis-spring.xsd">
<mybatis:scan base-package="com.brave.mapper" />
beans>
如果使用基于java的配置,可以使用@MapperScan 注解来扫描映射器 Mapper 接口。 @MapperScan 和
相同,并且也提供了对应的自定义选项
在 spring-boot 项目中可能会使用到
@SpringBootApplication
@MapperScan("com.brave.mapper")
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}