文档章节

springmvc+Mybatis整合中sqlSession的创建问题

困觉的曼巴er
 困觉的曼巴er
发布于 2016/05/06 18:17
字数 2105
阅读 52
收藏 0
点赞 2
评论 0

spring/springmvc+mybatis在整合时,可以在applicationContent.xml文件中进行spring,springmvc,事务管理,数据库连接池等以及与Mybatis整合的配置,当然也可以分开配置各自的xml文件。在mybatis-config.xml中主要进行一些别名,查询的分页方式的配置。例如:

applicationContext.xml中与mybatis的整合配置:

<!--由mybatis.xml文件构建一个sqlSessionFactory的实例-->
	<bean id="sqlSessionFactory" class="com.minmate.web.dao.mybatis.SqlSessionFactoryBean">
		<property name="configLocation" value="classpath:/config/mybatis/mybatis.xml" />
		<!--配置数据源-->
		<property name="dataSource" ref="dataSource" />
		<!--配置实体类的Mapper.xml文件-->
		<property name="mapperLocations" value="classpath:/config/mybatis/mapper/**/*Mapper.xml" />
	</bean>
mybatis.xml中的配置:
<configuration>
	<typeAliases>
		<typeAlias alias="Pair" type="com.minmate.util.Pair" />
	</typeAliases>
	<!-- 使用数据库的物理分页方式,iBatis默认分页方式采用游标数据量时候严重影响性能 -->
	<plugins>
		<plugin interceptor="com.minmate.web.dao.mybatis.support.OffsetLimitInterceptor">
			<property name="dialectClass" value="com.minmate.web.dao.mybatis.support.MySQLPageDialect" />
		</plugin>
	</plugins>
</configuration>

 

applicationContext.xml配置mybatis的映射文件,除了用

<property name="mapperLocations" value="classpath:/config/mybatis/mapper/**/*Mapper.xml" />

也可以使用MapperScannerConfigurer扫描basePackage指定的包,找到映射接口类和映射XML文件,并注入:

<!-- 扫描mybatis映射接口类 -->  
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">  
    <property name="basePackage" value="com.mybatis.mapper"/>  
    <property name="sqlSessionFactoryBeanName" value="lazySqlSessionFactory"/>  
</bean>

这个配置的前提条件是:映射接口类文件(.java)和映射XML文件(.xml)需要放在相同的包下(com.mybatis.mapper)


接下来主要理理与数据库操作有关的sqlSession是如何产生的。

在我们的项目中创建SqlSessionFactory实例时,使用的SqlSessionFactoryBean类实现了FactoryBean<SqlSessionFactory>,InitializingBean这两个接口,重写了它们的方法。其中FactoryBean接口及各个方法的作用:

package org.springframework.beans.factory;

public abstract interface FactoryBean<T>
{
  /*
  返回由 FactoryBean 创建的 Bean 实例,如果 isSingleton() 返回 true ,
  则该实例会放到Spring 容器单实例缓存池中
  **/
  public abstract T getObject()
    throws Exception;
  /*
  返回 FactoryBean 创建的 Bean 类型
  **/
  public abstract Class<?> getObjectType();
  /*
  FactoryBean 创建的 Bean 实例的作用域是 singleton 还是 prototype 
  **/
  public abstract boolean isSingleton();
}

注:

当配置文件中<bean>  class 属性配置的实现类虽然是 SqlSessionFactoryBean,但通过 getBean() 方法返回的不是SqlSessionFactoryBean类本身的对象,而是 FactoryBean.getObject() 方法所返回的对象,相当于 FactoryBean.getObject() 代理了getBean() 方法。例如下面代码是返回了一个sqlSessionFactory对象,而不是SqlSessionFactoryBean类的对象。

   @Override
    public SqlSessionFactory getObject()
    {
        return sqlSessionFactory;
    }

如果要得到FactoryBean本身,则需要在使用getBean(beanName)方法时,beanName前加上“&”,如:getBean(&beanName)

 

InitializingBean接口:   

package org.springframework.beans.factory;

public abstract interface InitializingBean
{

  /*
  在所有属性被设置完之后,容器会调用afterPropertiesSet()方法,
  应用对象可以在这里执行任何定制的初始化操作(init-method方法与它的区别——不依赖springAPI,
  从而降低与spring的耦合)
  **/
  public abstract void afterPropertiesSet()
    throws Exception;
}

在我们的项目中afterPropertiesSet()方法的重写:

 @Override
    public void afterPropertiesSet() throws IOException
    {
        if( configLocation==null ) throw new IOException("configLocation in SqlSessionFactoryBean can't be null.");

        this.sqlSessionFactory = createSqlSessionFactory();
    }

利用createSqlSessionFactory()方法创建了一个sqlSessionFactory实例,getObject()得到的就是这个sqlSessionFactory。这个产生sqlSessionFactory的方法中关键的代码:

  //封装配置文件的流
  reader = new InputStreamReader(new ByteArrayInputStream(XMLHelper.toString(document).getBytes("utf-8")));         
 // 创建sqlSessionFactory
 sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
 //将解析配置文件后的内容放入Configuration
 Configuration conf = sqlSessionFactory.getConfiguration();

可以看出是通过SqlSessionFactoryBuilder这个类的build方法来创建的,查看一下SqlSessionFactoryBuilder.java的源码,其中就只有build方法的重载,部分实现如下:

 package org.apache.ibatis.session;
 
 public SqlSessionFactory build(Reader reader, String environment, Properties props)
  {
    try
    {
      XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, props);
      Configuration config = parser.parse();
      return build(config);
    }
    catch (Exception e)
    {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    }
    finally
    {
      ErrorContext.instance().reset();
      try
      {
        reader.close();
      }
      catch (IOException e) {}
    }
  }
  
  public SqlSessionFactory build(Configuration config)
  {
    return new DefaultSqlSessionFactory(config);
  }

可以看到SqlSessionFactoryBuilder类只是解析了xml文件然后将解析后的内容赋给一个Configuration对象,而真正创建SqlSessionFactory的是DefaultSessionFactory类,它是实现SqlSessionFactory接口的类,SqlSessionFactory接口的源码:

package org.apache.ibatis.session;

import java.sql.Connection;

public abstract interface SqlSessionFactory
{
  public abstract SqlSession openSession();
  
  public abstract SqlSession openSession(boolean paramBoolean);
  
  public abstract SqlSession openSession(Connection paramConnection);
  
  public abstract SqlSession openSession(TransactionIsolationLevel paramTransactionIsolationLevel);
  
  public abstract SqlSession openSession(ExecutorType paramExecutorType);
  
  public abstract SqlSession openSession(ExecutorType paramExecutorType, boolean paramBoolean);
  
  public abstract SqlSession openSession(ExecutorType paramExecutorType, TransactionIsolationLevel paramTransactionIsolationLevel);
  
  public abstract SqlSession openSession(ExecutorType paramExecutorType, Connection paramConnection);
  
  public abstract Configuration getConfiguration();
}

可以看到SqlSessionFactory接口中包含了一系列可以得到SqlSession对象的抽象重载方法,由类DefaultSqlSessionFactory来实现这个接口,其中部分实现以及几个关键的方法为:

 package org.apache.ibatis.session.defaults;
 
 ...
  private static final Log log = LogFactory.getLog(Connection.class);
  private final Configuration configuration;
  private final TransactionFactory managedTransactionFactory;
  /**构造函数初始化*/
  public DefaultSqlSessionFactory(Configuration configuration)
  {
    this.configuration = configuration;
    this.managedTransactionFactory = new ManagedTransactionFactory();
  }
  public SqlSession openSession()
  {
    return openSessionFromDataSource(this.configuration.getDefaultExecutorType(), null, false);
  }
  
  ...

  **********************************关键的方法**************************************
  /**
  根据数据源创建session
  @params execType执行器的类型 level事物隔离级别 autoCommit是否自动提交
  */
  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit){...}
    /**根据连接对象创建session*/
   private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection){...}
   /**从环境中获取数据源*/
    private DataSource getDataSourceFromEnvironment(Environment environment){...}
    /**从环境配置中获取事务工厂*/
    private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment){...}
    /**包装连接,使连接拥有日志功能*/
    private Connection wrapConnection(Connection connection){...}

创建的SqlSession 包含了所有执行数据库SQL 语句的方法,能够直接地通过SqlSession 实例执行映射SQL 语句。其源码接口中定义了数据库操作的一系列抽象方法:

package org.apache.ibatis.session;

import java.sql.Connection;
import java.util.List;

public abstract interface SqlSession
{
  public abstract Object selectOne(String paramString);
  
  public abstract Object selectOne(String paramString, Object paramObject);
  
  public abstract List selectList(String paramString);
  
  public abstract List selectList(String paramString, Object paramObject);
  
  public abstract List selectList(String paramString, Object paramObject, RowBounds paramRowBounds);
  
  public abstract void select(String paramString, Object paramObject, ResultHandler paramResultHandler);
  
  public abstract void select(String paramString, Object paramObject, RowBounds paramRowBounds, ResultHandler paramResultHandler);
  
  public abstract int insert(String paramString);
  
  public abstract int insert(String paramString, Object paramObject);
  
  public abstract int update(String paramString);
  
  public abstract int update(String paramString, Object paramObject);
  
  public abstract int delete(String paramString);
  
  public abstract int delete(String paramString, Object paramObject);
  
  public abstract void commit();
  
  public abstract void commit(boolean paramBoolean);
  
  public abstract void rollback();
  
  public abstract void rollback(boolean paramBoolean);
  
  public abstract void close();
  
  public abstract void clearCache();
  
  public abstract Configuration getConfiguration();
  
  public abstract <T> T getMapper(Class<T> paramClass);
  
  public abstract Connection getConnection();
}

由DefaultSqlSession类来实现该接口,部分源码为:

package org.apache.ibatis.session.defaults;
...

public class DefaultSqlSession implements SqlSession
{
  private Configuration configuration;
  private Executor executor;
  private boolean autoCommit;
  private boolean dirty;
  
  public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit)
  {
    this.configuration = configuration;
    this.executor = executor;
    this.autoCommit = autoCommit;
    this.dirty = false;
  }
  ...
public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler)
  {
    try
    {
      MappedStatement ms = this.configuration.getMappedStatement(statement);
      this.executor.query(ms, wrapCollection(parameter), rowBounds, handler);
    }
    catch (Exception e)
    {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    }
    finally
    {
      ErrorContext.instance().reset();
    }
  }
  ...
  public int update(String statement, Object parameter)
  {
    try
    {
      this.dirty = true;
      MappedStatement ms = this.configuration.getMappedStatement(statement);
      return this.executor.update(ms, wrapCollection(parameter));
    }
    catch (Exception e)
    {
      throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
    }
    finally
    {
      ErrorContext.instance().reset();
    }
  }
  ...
}

可以看到真正对数据库进行操作的是executor对象,org.apache.ibatis.executor包中的Executor接口封装了数据库的操作方法,这个接口和它的实现类的关系:

执行器(Executor)类型只有三种

SIMPLE:普通的执行器;

REUSE:执行器会重用预处理语句(prepared statements);

BATCH:执行器将重用语句并执行批量更新。

具体类型的指定是在用openSession()方法创建sqlSession传入参数指定的,执行器的实现类里面封装了最原始的JDBC操作。

 

了解了sqlSession的整个产生过程,看看我们的项目中是怎么来使用的。在我们的项目中用一个MyBatisDaoSupport类来执行DAO层的操作:

public class MyBatisDaoSupport extends DaoSupport
{
    protected final Logger log = Logger.getLogger(getClass());
    
    /** factory */
    private SqlSessionFactory sqlSessionFactory;
    
    /** session template */
    private SqlSessionTemplate sqlSessionTemplate;
    
    @Resource
    private SqlSessionFactoryBean sqlSessionFactoryBean;
    
    @PostConstruct
    public void init()
    {
        /**获取sqlSessionFactory*/
        this.sqlSessionFactory = sqlSessionFactoryBean.getObject();
        /**实例化sqlSession持久化模版*/
        this.sqlSessionTemplate = new SqlSessionTemplate(sqlSessionFactory);
    }
    ...
    
    
    /** SqlSessionTemplate */
    public static class SqlSessionTemplate
    {
        /** factory */
        private SqlSessionFactory sqlSessionFactory;
        
        /** 构造函数 */
        public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory)
        {
            this.sqlSessionFactory = sqlSessionFactory;
        }
        
        /** execute */
        public Object execute(SqlSessionCallback action)
        {
            SqlSession session = null;
            
            try
            {
                /**通过openSession()方法获取session,上面已经说过*/
                session = sqlSessionFactory.openSession();
                return action.doInSession(session);
            }
            finally
            {
                if( session!=null )
                {
                    session.commit();
                    session.close();
                    session = null;
                }
            }
        }
        
        /** 插入记录 */
        public int insert(final String statement)
        {
            /**这里的SqlSessionCallback是匿名内部类,用来返回执行sql语句后的结果*/
            return (Integer)execute(new SqlSessionCallback()
            {
                @Override
                public Object doInSession(SqlSession session)
                {
                    return session.insert(statement);
                }
            });
        }
        
        ...
    }
    
    
    /** session 回调 */
    private static interface SqlSessionCallback
    {
        public Object doInSession(SqlSession session);
    }
    ...
}
 

其中在静态内部类SqlSessionTemplate中有一个execute()方法,其使用一个匿名内部类作为参数,该类实际上实现了SqlSessionCallback接口 ,其余的insert、update等方法内都调用了execute()方法将其结果返回,返回的实际上是该匿名内部类实现的接口SqlSessionCallback中doInSession()方法执行后的结果,而在doInSession()方法中就使用sqlSession对象进行sql语句的映射操作。

这段匿名内部类的写法等价于如下代码:

   /** session 回调 */
    private static interface SqlSessionCallback
    {
        public Object doInSession(SqlSession session);
    }
    private static class SqlSessionCallbackImpl implements SqlSessionCallback
    {
        private String statement; Object param; int firstResult, maxResults;
        SqlSessionCallbackImpl(String statement, Object param, int firstResult, int maxResults)
        {
            this.statement = statement;
            this.firstResult = firstResult;
            this.maxResults = maxResults;
            this.param = param;
        }
        
        @Override
        public Object doInSession(SqlSession session)
        {
            return session.selectList(statement, param, new RowBounds(firstResult, maxResults));
        };
    }

        /** 分页参数查询 */
        public List<?> selectList(final String statement, final Object param, final int firstResult, final int maxResults)
        {
            SqlSessionCallbackImpl sqlSessionCallbackImpl = new SqlSessionCallbackImpl(statement,param,firstResult,maxResults);
            return (List<?>)execute(sqlSessionCallbackImpl);
        }

 

 

 

© 著作权归作者所有

共有 人打赏支持
困觉的曼巴er
粉丝 1
博文 25
码字总数 12169
作品 0
其它
程序员
SprignMVC myBatis整合(一) 基于MapperFactoryBean

其提供了与整合相关的API: SqlSessionFactoryBean --为整合应用提供SqlSession对象资源 MapperFactoryBean --根据指定的Mapper接口生成Bean实例 MapperScannerConfigurer --根据指定包批量扫...

杨中仁
2015/05/18
0
0
springmvc+mybatis整合案例

----------------------------映射文件----重要的是插入一条记录--------------------------------------- <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.o......

李永china
2016/05/21
86
0
【MyBatis框架】Mybatis开发dao方法第一部分

下面来讨论mybatis开发Dao的方法 先来说一下基本架构流程中使用到的几个类 1.SqlSession使用范围 1.1SqlSessionFactoryBuilder 通过SqlSessionFactoryBuilder创建会话工厂SqlSessionFactory...

Mysoft
2015/09/17
220
0
MyBatis整合Spring-->SqlSession获取

目的 MyBatis在执行SQL语句时,都需要创建一个SqlSession,但是这里还需要与Spring的事务进行整合,那么SqlSession是怎么创建的呢?下面就来分析一下。 上一章节已经分析MapperProxy代理类中...

tara_qri
2015/11/01
0
0
SpringMVC+mybatis整合报异常!!!

最近在学SpringMVC和mybatis,现在想用注解的方式把这两个整合到一起做个简单的增删改查,现在一启动项目就报异常,试了好多方法都解决不了 这是配置文件

小肚子A
2014/09/21
9.4K
3
mybatis的缓存机制(一级缓存二级缓存和刷新缓存)和mybatis整合ehcache

大 中 小 mybatis的缓存机制(一级缓存二级缓存和刷新缓存)和mybatis整合ehcache 一、 查询缓存 1.1 什么是查询缓存 mybatis提供查询缓存,用于减轻数据压力,提高数据库性能。 mybaits提供...

LYQ1990
2016/05/26
153
0
Mybatis开发dao的方法

SqlSessionFactoryBuilder:通过创建会话工厂,将当成一个工具类使用即可,不需要使用单例管。 在需要创建时候,只需要一次即可。 SqlSessionFactory:通过创建,使用单例模式管理(工厂一旦...

小小蒜头
2017/11/24
0
0
MyBatis开发dao方法

一 SqlSession使用范围 SqlSessionFactoryBuilder 通过SqlSessionFactoryBuilder创建会话工厂SqlSessionFactory 将SqlSessionFactoryBuilder当作一个工具类使用即可,不需要使用单例管理Sql...

Bbigbug
2017/11/17
0
0
springmvc+mybatis

十一月 28, 2014 10:19:54 上午 org.apache.catalina.core.AprLifecycleListener init 信息: Loaded APR based Apache Tomcat Native library 1.1.31 using APR version 1.4.8. 十一月 28, ......

Love_Song
2014/11/28
591
3
IDEA中使用maven整合mybatis与spring

整合思路 需要spring通过方式管理SqlSessionFactory. spring和mybatis整合生成代理对象,使用SqlSessionFactory创建SqlSession.(Sping和mybati整合自动完成). 持久层的mapper都需要有spring进...

中柠檬
2016/11/18
42
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Android 获取各大音乐平台的真实下载地址

废话 电脑使用谷歌浏览器或者QQ浏览器的时候。。。。。。。说不清楚,还是看图吧 大概意思就是,只要网页上需要播放,只要能播放并且开始播放,这个过程就肯定会请求到相关的音乐资源,然后就...

她叫我小渝
35分钟前
0
0
shell中的函数、shell中的数组、告警系统需求分析

shell中的函数 格式: 格式: function f_name() { command } 函数必须要放在最前面 示例1(用来打印参数) 示例2(用于定义加法) 示例3(用于显示IP) shell中的数组 shell中的数组1 定义数...

Zhouliang6
今天
2
0
用 Scikit-Learn 和 Pandas 学习线性回归

      对于想深入了解线性回归的童鞋,这里给出一个完整的例子,详细学完这个例子,对用scikit-learn来运行线性回归,评估模型不会有什么问题了。 1. 获取数据,定义问题     没有...

wangxuwei
今天
1
0
MAC安装MAVEN

一:下载maven压缩包(Zip或tar可选),解压压缩包 二:打开终端输入:vim ~/.bash_profile(如果找不到该文件新建一个:touch ./bash_profile) 三:输入i 四:输入maven环境变量配置 MAVEN_HO...

WALK_MAN
今天
0
0
33.iptables备份与恢复 firewalld的9个zone以及操作 service的操作

10.19 iptables规则备份和恢复 10.20 firewalld的9个zone 10.21 firewalld关于zone的操作 10.22 firewalld关于service的操作 10.19 iptables规则备份和恢复: ~1. 保存和备份iptables规则 ~2...

王鑫linux
今天
2
0
大数据教程(2.11):keeperalived+nginx高可用集群搭建教程

上一章节博主为大家介绍了目前大型互联网项目的系统架构体系,相信大家应该注意到其中很重要的一块知识nginx技术,在本节博主将为大家分享nginx的相关技术以及配置过程。 一、nginx相关概念 ...

em_aaron
今天
1
0
Apache Directory Studio连接Weblogic内置LDAP

OBIEE默认使用Weblogic内置LDAP管理用户及组。 要整理已存在的用户及组,此前办法是导出安全数据,文本编辑器打开认证文件,使用正则表达式获取用户及组的信息。 后来想到直接用Apache Dire...

wffger
今天
2
0
HFS

FS,它是一种上传文件的软件。 专为个人用户所设计的 HTTP 档案系统 - Http File Server,如果您觉得架设 FTP Server 太麻烦,那么这个软件可以提供您更方便的档案传输系统,下载后无须安装,...

garkey
今天
1
0
Java IO类库之BufferedInputStream

一、BufferedInputStream介绍 /** * A <code>BufferedInputStream</code> adds * functionality to another input stream-namely, * the ability to buffer the input and to * sup......

老韭菜
今天
0
0
STM 32 窗口看门狗

http://bbs.elecfans.com/jishu_805708_1_1.html https://blog.csdn.net/a1985831055/article/details/77404131...

whoisliang
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部