Сравнение весеннего мибатиса и местного мибатиса

MyBatis

Как использовать родной mybatis:

String resource = "mybatis-config.xml"; 
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 
SqlSession session = sqlSessionFactory.openSession();    
try {      
           Employee employee = new Employee(null, "doubi", "1", "ddd@sys.com"); 
           EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);     
           mapper.addEmp(employee);               
           session.commit();    
} finally {
      session.close();    
}  
Как использовать пружину, просто введите ее напрямую
@Autowired
EmployeeMapper employeeMapper

Так что же делает нам весна? Изучим пакет jar mybatis-spring.jar

Во-первых, давайте посмотрим, как использовать Spring для интеграции mybatis.Вот четыре способа использования spring-mybatis:

Способ 1: (с использованием MapperFactoryBean)

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>        
    <property name="configLocation" value="classpath:mybatis-config.xml"></property>        
    <!-- 自动扫描mapping.xml文件 -->        
    <property name="mapperLocations" value="classpath:mapper/*.xml"></property>    
</bean>
<!--上面生成sqlSessionFactory的几个方法基本相同-->

<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>

Недостатком этого является то, что каждый интерфейс картографа должен быть настроен в xml


Способ 2. Используйте класс реализации интерфейса org.apache.ibatis.session.SqlSession.org.mybatis.spring.SqlSessionTemplate

В mybatis sessionFactory можно создать с помощью SqlSessionFactoryBuilder. MyBatis-Весна , вместо этого используйте SqlSessionFactoryBean. SqlSessionFactoryBean имеет обязательный атрибут dataSource, а также общий атрибут configLocation (используется для указания пути файла конфигурации xml mybatis).

SqlSessionFactoryBean эквивалентен SqlSessionFactoryBuilder в собственном mybatis.

<!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->    
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">        
    <property name="dataSource" ref="dataSource" />        
    <property name="configLocation"  value="classpath:sqlMapConfig.xml"/>        
    <!-- 自动扫描mapping.xml文件,**表示迭代查找,也可在sqlMapConfig.xml中单独指定xml文件-->        
    <property name="mapperLocations" value="classpath:com/hua/saf/**/*.xml" />    
</bean>        

<!-- mybatis spring sqlSessionTemplate,使用时直接让spring注入即可 -->    
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">        
    <constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg>    
</bean>
//使用方法:
@Repositorypublic class UserDao{    @Resource    private SqlSessionTemplate sqlSessionTemplate;        public User getUser(int id) {        return sqlSessionTemplate.selectOne(this.getClass().getName() + ".getUser", 1);    }   }

Почему так можно написать, давайте посмотрим на SqlSessionTemplate

public class SqlSessionTemplate implements SqlSession {  private final SqlSessionFactory sqlSessionFactory;  private final ExecutorType executorType;  private final SqlSession sqlSessionProxy;  private final PersistenceExceptionTranslator exceptionTranslator;  /**   * Constructs a Spring managed SqlSession with the {@code SqlSessionFactory}   * provided as an argument.   *   * @param sqlSessionFactory   */  public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {    this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType());  }

........省略......
   public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,      PersistenceExceptionTranslator exceptionTranslator) {    notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");    notNull(executorType, "Property 'executorType' is required");    this.sqlSessionFactory = sqlSessionFactory;    this.executorType = executorType;    this.exceptionTranslator = exceptionTranslator;    this.sqlSessionProxy = (SqlSession) newProxyInstance(        SqlSessionFactory.class.getClassLoader(),        new Class[] { SqlSession.class },        new SqlSessionInterceptor());  }

}

Как показано в приведенном выше коде, класс SqlSessionTemplate реализует интерфейс SqlSession в собственном Mybatis, фактически это SqlSession в собственном Mybatis.

Способ 3: Используйте абстрактные классыorg.mybatis.spring.support.SqlSessionDaoSupportПредоставить SqlSession

    <!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation"  value="classpath:sqlMapConfig.xml"/>
        <!-- 自动扫描mapping.xml文件,**表示迭代查找,也可在sqlMapConfig.xml中单独指定xml文件-->
        <property name="mapperLocations" value="classpath:com/hua/saf/**/*.xml" />
    </bean>
public  class BaseDao extends SqlSessionDaoSupport{  //使用sqlSessionFactory  @Autowired   private  SqlSessionFactory sqlSessionFactory;      @Autowired   public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory)    {        super.setSqlSessionFactory(sqlSessionFactory);    }    /**   * 执行insert操作   * @param statement   * @return   */  public int insert(String statement) {    return getSqlSession().insert(statement);  }  /**   * 执行insert操作   * @param statement   * @param parameter   * @return   */  public int insert(String statement, Object parameter) {    return getSqlSession().insert(statement, parameter);  }    public int update(String statement) {    return getSqlSession().update(statement);  }  public int update(String statement, Object parameter) {    return getSqlSession().update(statement, parameter);  }    public int delete(String statement) {    return getSqlSession().delete(statement);  }    public int delete(String statement, Object parameter) {    return getSqlSession().delete(statement, parameter);  }    /**   * 获取一个list集合   * @param statement   * @return   */  public List<?> selectList(String statement) {    return getSqlSession().selectList(statement);  }    /**   * 根据参数 获取一个list集合   * @param statement   * @param parameter   * @return   */  public List<?> selectList(String statement, Object parameter) {    return getSqlSession().selectList(statement, parameter);  }    public Map<?, ?> selectMap(String statement, String mapKey) {    return getSqlSession().selectMap(statement, mapKey);  }  public Map<?, ?> selectMap(String statement, Object parameter, String mapKey) {    return getSqlSession().selectMap(statement, parameter, mapKey);  }    /**   * 获取Object对象   * @param statement   * @return   */  public Object selectOne(String statement) {    return getSqlSession().selectOne(statement);  }    /**   * 获取connection, 以便执行较为复杂的用法   * @return   */  public Connection getConnection() {    return getSqlSession().getConnection();  }  }

Как показано в приведенном выше коде, после того, как класс Dao наследует класс SqlSessionDaoSupport, он может внедрить SessionFactory в класс, а затем получить текущий SqlSession с помощью getSqlSession().

НижеИсходный код SqlSessionDaoSupport, который является абстрактным классом и имеет свойство sqlSession, экземпляр которого создается в методе setSqlSessionFactory:

public abstract class SqlSessionDaoSupport extends DaoSupport {  private SqlSession sqlSession;  private boolean externalSqlSession;  public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {    if (!this.externalSqlSession) {      this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);    }  }  public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {    this.sqlSession = sqlSessionTemplate;    this.externalSqlSession = true;  }  public SqlSession getSqlSession() {    return this.sqlSession;  }  protected void checkDaoConfig() {    notNull(this.sqlSession, "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required");  }}

Способ 4: (такжеСамый распространенный способ использования, используя MapperScannerConfigurer, он будет искать сопоставления в пути к классам и автоматически создавать их как MapperFactoryBean)

Поскольку использование MapperFactoryBean напрямую приведет к настройке большого количества мапперов в конфигурационном файле, здесь используется метод сканирования пакетов для получения бина через аннотации

<!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!-- 自动扫描mapping.xml文件,**表示迭代查找 -->
        <property name="mapperLocations" value="classpath:com/hua/saf/**/*.xml" />
    </bean>

    <!-- DAO接口所在包名,Spring会自动查找其下的类 ,包下的类需要使用@MapperScan注解,否则容器注入会失败 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.hua.saf.*" />
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
    </bean>




//使用如下代码,即可完成注入
@Resource
private UserDao userDao;

Давайте взглянем на класс MapperScannerConfigurer:

public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {  private String basePackage;  private boolean addToConfig = true;  private SqlSessionFactory sqlSessionFactory;  private SqlSessionTemplate sqlSessionTemplate;  private String sqlSessionFactoryBeanName;  private String sqlSessionTemplateBeanName;  private Class<? extends Annotation> annotationClass;  private Class<?> markerInterface;  private ApplicationContext applicationContext;  private String beanName;  private boolean processPropertyPlaceHolders;  private BeanNameGenerator nameGenerator;




public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {    if (this.processPropertyPlaceHolders) {      processPropertyPlaceHolders();    }    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);    scanner.setAddToConfig(this.addToConfig);    scanner.setAnnotationClass(this.annotationClass);    scanner.setMarkerInterface(this.markerInterface);    scanner.setSqlSessionFactory(this.sqlSessionFactory);    scanner.setSqlSessionTemplate(this.sqlSessionTemplate);    scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);    scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);    scanner.setResourceLoader(this.applicationContext);    scanner.setBeanNameGenerator(this.nameGenerator);    scanner.registerFilters();    scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));  }
ClassPathMapperScanner :

public Set<BeanDefinitionHolder> doScan(String... basePackages) {    Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);    if (beanDefinitions.isEmpty()) {      logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");    } else {      for (BeanDefinitionHolder holder : beanDefinitions) {        GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition();        if (logger.isDebugEnabled()) {          logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName()               + "' and '" + definition.getBeanClassName() + "' mapperInterface");        }        // the mapper interface is the original class of the bean        // but, the actual class of the bean is MapperFactoryBean        definition.getPropertyValues().add("mapperInterface", definition.getBeanClassName());        definition.setBeanClass(MapperFactoryBean.class);        definition.getPropertyValues().add("addToConfig", this.addToConfig);        boolean explicitFactoryUsed = false;        if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {          definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));          explicitFactoryUsed = true;        } else if (this.sqlSessionFactory != null) {          definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);          explicitFactoryUsed = true;        }        if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {          if (explicitFactoryUsed) {            logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");          }          definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName));          explicitFactoryUsed = true;        } else if (this.sqlSessionTemplate != null) {          if (explicitFactoryUsed) {            logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");          }          definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);          explicitFactoryUsed = true;        }        if (!explicitFactoryUsed) {          if (logger.isDebugEnabled()) {            logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");          }          definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);        }      }    }    return beanDefinitions;  }

Резюме: По сравнению с родным Mybatis, spring-mybatis имеет следующие концепции:

1) класс SqlSessionFactory существует в обоих

2) первый использует SqlSessionFactoryBean для создания SqlSessionFactory, а второй использует SqlSessionFactoryBuilder;

3) Первый использует SqlSessionTemplate, второй использует SqlSession, фактически первый реализует последний

4) Следующие шаги в нативном mybatis реализованы в MapperFactoryBean, поэтому объект реализации интерфейса картографа можно напрямую получить через этот класс.

 EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);    

Вышеупомянутое является личным резюме, если есть какие-либо ошибки, пожалуйста, поправьте меня.