标题盛不下了,把报错写到这
Bean named 'sqlSessionFactory' is expected to be of type 'org.mybatis.spring.SqlSessionFactoryBean' but was actually of type 'org.apache.ibatis.session.defaults.DefaultSqlSessionFactory'
代码背景
只是在做spring整合mybatis 的练习的时候出现的一个报错,技术版本
- spiring: 5.3.1
- mybatis: 3.5.3
- mybatis-spring(sping整合mybtis的jar): 2.0.6
- aspectjweaver: 1.9.4
- junit: 4.13.1
- c3p0: 0.9.5.5
核心代码如下:
applicationContext.xml
<!-- 加载配置文件 -->
<context:property-placeholder location="jdbcConfig.properties"/>
<!-- 配置数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 配置 Mybatis 的 Session 工厂 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 数据库连接池 -->
<property name="dataSource" ref="dataSource"/>
<!-- 文件映射器 -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!-- 自动扫描 mapper.xml 文件 -->
<property name="mapperLocations" value="classpath:com/krlin/mybatis/dao/*.xml"/>
</bean>
按照spring 的理解,这样就是在 spring 的 IOC 容器中 存了两个JAVA对象,一个是存放数据库配置数据的 dataSource
,一个是 mybatis 的 核心对象 sqlSessionFactory
按照常理,放在IOC 容器中的对象可以获取并使用,于是测试类中:
@Test
public void dataSourceTest() {
/** 使用 ApplicationContext 接口, 获取 spring 容器 */
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
/** 根据 bean 的 id 获取对象 */
ComboPooledDataSource dataSource = ac.getBean("dataSource", ComboPooledDataSource.class);
System.out.println(dataSource.getJdbcUrl());
System.out.println(dataSource.getUser());
System.out.println(dataSource.getPassword());
}
@Test
public void SqlSessionFactoryTest() {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
SqlSessionFactoryBean sqlSessionFactory = ac.getBean("sqlSessionFactory", SqlSessionFactoryBean.class);
System.out.println(sqlSessionFactory);
代码分析
第一个 dataSource
的测试没有问题,第二个就报错了 Bean named 'sqlSessionFactory' is expected to be of type 'org.mybatis.spring.SqlSessionFactoryBean' but was actually of type 'org.apache.ibatis.session.defaults.DefaultSqlSessionFactory'
翻译一下也很简单, sqlSessionFactory
应该是 org.mybatis.spring.SqlSessionFactoryBean
类型的,但是实际上却是 org.apache.ibatis.session.defaults.DefaultSqlSessionFactory
类型的。
心想不对啊,我在配置文件中提供的类就是 SqlSessionFactoryBean
没错啊,怎么会出现一个其他的类,进入 SqlSessionfactoryBean
发现
他实现了 FactoryBean<T>
接口,原来是当实现了这个接口的 Bean 放到 IOC容器的时候,那么容器中实际存放的其实就是 这个泛型T
的类型,这也就不难理解,我们需要的 SqlSessionFactory
是 SqlSessionFactoryBean
来提供的,因为 SqlSessionFactoryBean
实现的接口的泛型就是 sqlSessionFactory
, 所以看似我们 放置了 SqlSessionFactoryBean
, 但实际上在 IOC 中是一个 SqlSessionFactory
罢了。
查看SqlSessionFactory
发现他是一个接口
他有两个实现类,而第一个实现类,就是放入到 IOC 里边的类型,所以我们在测试的时候,就会出现类型不匹配了。
解决办法也很简单,我们在测试类中,用 DefaultSqlSessionFactory
来接收就行了
@Test
public void SqlSessionFactoryTest() {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
DefaultSqlSessionFactory sqlSessionFactory = ac.getBean("sqlSessionFactory", DefaultSqlSessionFactory.class);
SysUserMapper mapper = sqlSessionFactory.openSession(true).getMapper(SysUserMapper.class);
List<SysUserEntity> userList = mapper.getUserList();
userList.forEach(System.out::println);
}
打印数据也没有问题(虽然我们平时也不这么用,但是逻辑上是可以同的)
代码本身没问题,就是自己的理解没有到位,没有看透 SqlSessionFactoryBean
背后的本质。