首页 > 开发 > Java > 正文

spring-mybatis与原生mybatis使用对比分析

2024-07-13 10:13:54
字体:
来源:转载
供稿:网友

原生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();  }

spring使用方法,直接注入即可

@AutowiredEmployeeMapper employeeMapper

那么spring为我们做了什么?下面研究一下mybatis-spring.jar这个jar包

首先来看一下如何使用spring整合mybatis,下面是使用spring-mybatis的四种方法:

方法一:(使用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>

这样做的缺点是每一个mapper接口都要在xml里配置一下

方法二:采用接口org.apache.ibatis.session.SqlSession的实现类 org.mybatis.spring.SqlSessionTemplate

mybatis中, sessionFactory可由SqlSessionFactoryBuilder.来创建。MyBatis-Spring 中,使用了SqlSessionFactoryBean来替代。SqlSessionFactoryBean有一个必须属性dataSource,另外其还有一个通用属性configLocation(用来指定mybatis的xml配置文件路径)。

SqlSessionFactoryBean即相当于原生mybatis中的SqlSessionFactoryBuilder

<!-- 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类实现了原生Mybatis中的SqlSession接口,实际上它就是原生mybatis中的SqlSession

方法三:采用抽象类 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类后,就可以在类中注入SessionFact
ory,进而通过getSqlSession()获取当前SqlSession

下面是 SqlSessionDaoSupport的源码 ,它是一个抽象类,并拥有sqlSession属性,在setSqlSessionFactory方法中实例化了该sqlSession:

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"); }}

方法四:(也是 最常见的使用方法 ,使用MapperScannerConfigurer,它将会查找类路径下的映射器并自动将它们创建成MapperFactoryBean)

由于直接使用MapperFactoryBean会在配置文件中配置大量mapper,因此这里使用包扫描的方式通过注解获取该bean

<!-- 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>//使用如下代码,即可完成注入@Resourceprivate 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; }

总结:spring-mybatis与原生Mybatis相比,如下概念:

1)SqlSessionFactory类在两者中都存在

2)前者用SqlSessionFactoryBean生成SqlSessionFactory,后者则使用SqlSessionFactoryBuilder;

3)前者使用SqlSessionTemplate,后者使用SqlSession,实际上前者实现了后者

4)MapperFactoryBean中实现了原生mybatis中下面的步骤,因此通过该类可以直接获取到一个mapper接口的实现对象

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

总结

以上所述是小编给大家介绍的spring-mybatis与原生mybatis使用对比分析,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对VeVb武林网网站的支持!


注:相关教程知识阅读请移步到JAVA教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表