要将spring和mybatis整合,我们可以从mybatis的核心对象看起,以前想要使用mybatis,都需要创建出mybatis的核心对象才能实现,而spring是工厂管理,因此只需要将mybatis的核心对象交给spring来管理,我们便完成了整合。
那么mybatis中的核心对象有哪些呢,康康以下代码就知道了。
InputStream stream = Resources.getResourceAsStream("mybatis-config.xml");
// 得到工厂对象的构建对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 构建工厂,根据 输入流
SqlSessionFactory factory = builder.build(stream);
SqlSession sqlSession = factory.openSession();
mapper = sqlSession.getMapper(OrdersMapper.class);
mapper.findAll();
可以看到,在以前的开发中,通常是使用SqlSessionFactoryBuilder加载mybatis配置文件来构建SqlSessionFactory,然后通过SqlSessionFactory获取到SqlSession对象,最后由SqlSession得到mapper/dao接口从而实现对数据库的操作。其中最核心的是SqlSessionFactory。
并且mybatis配置文件中需要配置数据源以及mapper配置文件的映射位置。
那么SqlSessionFactory是怎么注入到spring工厂的呢
其实SqlSessionFactory是一个接口,众所周知,接口是不能实例化的,因此也是无法注入到spring工厂的,我们以前创建的SqlSessionFactory就是通过SqlSessionFactoryBuilder创建才得到的,不是new出来的,因此如果想要用spring来管理SqlSessionFactory对象,就可以继承spring为我们提供的接口FactoryBean<SqlSessionFactory>,这也是spring中创建复杂对象的方法。复杂对象指的是不能new出来的对象,例如抽象类和接口。
因此现在我们自己开发一个SqlSessionFactory类
//自己创建sqlSessionFactory
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory> {
private String configLocations;
public void setConfigLocations(String configLocations) {
this.configLocations = configLocations;
}
@Override
//返回SqlSessionFactory对象
public SqlSessionFactory getObject() throws Exception {
InputStream is = Resources.getResourceAsStream(configLocations);
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(is);
return build;
}
@Override
//返回SqlSessionFactory类
public Class<?> getObjectType() {
return SqlSessionFactory.class;
}
@Override
//返回true代表单例
public boolean isSingleton() {
return true;
}
}
然后将SqlSessionFactory类配置到spring工厂中
<!--创建sqlSessionFactory-->
<bean id="sqlSessionFactory" class="com.chinasoft.util.SqlSessionFactoryBean">
<property name="configLocations" value="mybatis-config.xml"/>
</bean>
这样就成功的开发了一个能注入到spring工厂的SqlSessionFactoryBean了,不过本质上还是使用SqlSessionFactoryBuilder来为我们构建。
需要注意使用这个工厂的前提是mybaits的配置文件中必须配置了datasource数据源以及mapper配置文件的映射位置,因为本质上还是通过mybatis配置文件来生成SqlSessionFactory的,例如下图。
mybaits配置文件
<?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>
<!-- 和spring整合后 environments配置将废除 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&useSSL=false&characterEncoding=utf-8&serverTimezone=UTC" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
<mappers>
<!-- 注册mapper接口实现类 -->
<package name="com.demo.dao"></package>
</mappers>
</configuration>
但是在真正的开发中,我们不会在spring工厂中使用自己创建的SqlSessionFactory,因为在mybatis-spring依赖中,为我们提供了一个SqlSessionFactoryBean类。它同样实现了FactoryBean的接口,里面放的是SqlSessionFactory。
public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent>
但是也可以不依赖mybatis的配置文件,直接将数据源以及mapper配置文件的位置告诉SqlSessionFactory,其中数据源可以直接在spring中进行配置
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--<property name="configLocation" value="mybatis-config.xml" />-->
<!--完全代替mybatis的配置文件-->
<property name="dataSource" ref="dataSource"/>
<!--注入mapper配置文件通用方式-->
<property name="mapperLocations" value="classpath:com/chinasoft/dao/*.xml"/>
</bean>
经过前面对SqlSessionFactory的分析,我们就可以真正开始整合mybatis和spring了
第一步,导入依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.5</version>
</dependency>
第二步,在spring配置文件中创建数据源对象
第三步,在spring配置文件中创建SqlSessionFactory对象
但是得到SqlSessionFactory对象之后还不够,还要通过SqlSessionFactory开启SqlSession再得到dao/mapper之后才能调用方法,因此mybatis帮助我们封装了这些步骤在MapperFactoryBean中,它依赖SqlSessionFactory对象还要告诉它你要创建哪一个Dao。
需要封装的代码
SqlSession sqlSession = sqlSessionFactory.openSession();
UserDao userDao= sqlSession.getMapper(UserDao.class);
spring配置文件
<bean id="userDAO" class="org.mybatis.spring.mapper.MapperFactoryBean">
<!--注入sqlSessionFactory-->
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
<!--注入创建DAO接口类型 注入接口的全限定名 包.接口名-->
<property name="mapperInterface" value="com.demo.dao.UserDAO"/>
</bean>
但是这样写太麻烦,因此可以使用MapperScannerConfigurer类代替上面的方式,在启动工厂时一次性将所有Dao创建到工厂中,因此第四步就是创建MapperScannerConfigurer,同样依赖sqlSessionFactory以及dao/mapper中的接口
第四步,在spring配置文件中创建MapperScannerConfigurer
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--注入sqlSessionFactory-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!--扫描DAO/Mapper接口所在包-->
<property name="basePackage" value="com.demo.dao"/>
</bean>
配置完MapperScannerConfigurer后,我们便不用再通过sqlSessionFactory开启sqlSession然后再获得Dao对象了。因为Dao对象的mybaits实现类会自动注册到spring工厂中,只需要通过spring工厂来获取就可以了,使用@Autowired自动注入也可以。
最终得到一个整合完成的spring配置文件
<?xml version="1.0" encoding="UTF-8"?>
<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 https://www.springframework.org/schema/context/spring-context.xsd">
<!--包扫描所有的@component标识,并把他们注册到spring工厂中,变成bean-->
<context:component-scan base-package="com.demo" />
<!--导入resources资源目录下的的配置文件-->
<context:property-placeholder location="classpath:db.properties" />
<!--使用spring自带的线程池-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<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="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--完全代替mybatis的配置文件-->
<!--<property name="configLocation" value="mybatis-config.xml" />-->
<!--配置数据源-->
<property name="dataSource" ref="dataSource"/>
<!--注入mapper配置文件通用方式-->
<property name="mapperLocations" value="classpath:com/demo/dao/*.xml"/>
<!--注入别名相关配置 typeAliasesPackage:用来给指定包中所有类起别名 默认的别名: 类名|类名首字母小写-->
<property name="typeAliasesPackage" value="com.demo.entity"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--注入sqlSessionFactory-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!--扫描DAO/Mapper接口所在包-->
<property name="basePackage" value="com.demo.dao"/>
</bean>
</beans>
这样就成功的完成了spring与mybatis的整合了
最后,其实sqlSessionFactory也可以通过java配置类来创建让工厂管理
@Configuration
public class Config {
@Bean
public SqlSessionFactory sqlSessionFactory() throws IOException {
InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(is);
return build;
}
}