实践MyBatis-Spring

MyBatis-Spring

1
2
3
4
5
<dependency>
	<groupId>org.mybatis</groupId>
	<artifactId>mybatis-spring</artifactId>
	<version>1.3.1</version>
</dependency>

SqlSessionFactoryBean

1
2
3
4
<bean id = "sqlSessionFactory" class = "org.mybatis.spring.SqlSessionFactoryBean">
	<property name="dataSource" ref="dataSource" />
</bean>

img

mapperLocations:支持通配符,比如:classpath*:sqlmap/*-mapper.xml"

一般情况下,mybatis的配置文件可以不需要(mybatis-config.xml),如下情况可能需要(configLocation):

  1. 需要定制<settings>,其实configurationProperties属性可以支持
  2. 需要定制<typeAliases>,其实typeHandlersPackage属性可以支持
  3. mapper xml和mapper class不在相同的classpath下,其实mapperLocation属性可以支持

mybatis配置文件中会被忽略。

SqlSessionTemplate

SqlSession的一种实现,使用了代理模式,线程安全,由于每次都获取新的SQLSession,因而不支持一级缓存

1
2
3
4
5
6
7
8
9
public class UserDaoImpl implements UserDao {
   private SqlSession sqlSession;
   public void setSqlSession(SqlSession sqlSession) {
     	this.sqlSession = sqlSession;
   }
   public User getUser(String userId) {
     	return (User) sqlSession.selectOne("org.mybatis.spring.sample.mapper.UserMapper.getUser", userId);
   }
}
1
2
3
4
5
6
7
<bean id = "sqlSession" class = "org.mybatis.spring.SqlSessionTemplate">
  <constructor-arg index="0" ref="sqlSessionFactory" />
</bean>

<bean id = "userDao" class = "org.mybatis.spring.sample.dao.UserDaoImpl">
  <property name="sqlSession" ref="sqlSession" />
</bean>

SqlSessionDaoSupport

基于SqlSessionTemplate的一种扩展

1
2
3
4
5
public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
	public User getUser (String userId) {
		return (User) getSqlSession().selectOne("org.mybatis.spring.sample.mapper.UserMapper.getUser",userId);
    }
}
1
2
3
<bean id="userMapper" class="org.mybatis.spring.sample.mapper.UserDaoImpl">
  <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

MapperFactoryBean

Spring中定义Mapper,线程安全,每次都获取新的SQLSession

1
2
3
4
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
	<property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper"/>
  	<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

MapperFactoryBean默认添加了依赖注入注解@Autowired

1
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public abstract class SqlSessionDaoSupport extends DaoSupport {

  private SqlSession sqlSession;

  private boolean externalSqlSession;

  @Autowired(required = false)
  public final void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
    if (!this.externalSqlSession) {
      this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
    }
  }

  @Autowired(required = false)
  public final void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
    this.sqlSession = sqlSessionTemplate;
    this.externalSqlSession = true;
  }
  ...
}

Mapper Scan

基于扫描自动生产Mapper

base-package:扫描Mapper的基础包,支持Ant匹配

factory-ref or template-ref

annotation:被此注解的mapper接口,比如@Mapper

marker-interface:实现此接口的mapper接口,比如MyMapper

NOTE<context:component-scan/> won’t be able to scan and register mappers. Mappers are interfaces and, in order to register them to Spring, the scanner must know how to create a MapperFactoryBean for each interface it finds.

<mybatis:scan/>

类似<context:component-scan/>

1
<mybatis:scan base-package="org.mybatis.spring.sample.mapper" />

@MapperScan

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Configuration
@MapperScan("org.mybatis.spring.sample.mapper")
public class AppConfig {

  @Bean
  public DataSource dataSource() {
    return new EmbeddedDatabaseBuilder().addScript("schema.sql").build()
  }

  @Bean
  public SqlSessionFactory sqlSessionFactory() throws Exception {
    SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
    sessionFactory.setDataSource(dataSource());
    return sessionFactory.getObject();
  }
}

MapperScannerConfigurer

推荐使用sqlSessionFactoryBeansqlSessionTemplateBean,如果没有显示注入,由于开启了按类型自动注入,则会自动注入,参见如下源代码:

org.mybatis.spring.mapper.ClassPathMapperScanner.processBeanDefinitions(Set<BeanDefinitionHolder>)

1
2
3
4
5
6
      if (!explicitFactoryUsed) {
        if (logger.isDebugEnabled()) {
          logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
        }
        definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
      }