最最常用的 SqlSessionFactory 和 SqlSession,你真的了解吗?
共 9516字,需浏览 20分钟
·
2022-06-08 23:04
前言
学习框架一个比较好的路径阅读源码。本文介绍的SqlSessionFactory
和SqlSession
。可以通过了解SqlSessionFactory
接口和SqlSession
接口以及两个的实现类入手,去看源码了解实现过程。最好能把项目下载到本地,慢慢分析实现过程。
MyBatis的持久化解决方案是将用户从原始的JDBC访问中解放出来,用户只需要定义需要操作的SQL语句,无须关注底层的JDBC操作,就可以以面向对象的方式来进行持久化层操作。底层数据库连接的获取,数据访问的实现,事务控制等都无须用户关心,从而将应用层从底层的JDBC/JTA API
抽取出来。
通过配置文件管理JDBC连接,让MyBatis解决持久化的实现。在MyBatis中的常见对象有SqlSessionFactory
和SqlSession
。本文这种介绍一下两者的概念和使用。
一、 SqlSessionFactory
SqlSessionFactory
是MyBatis的关键对象,它是个单个数据库映射关系经过编译后的内存镜像。SqlSessionFactory
对象的实例可以通过SqlSessionFactoryBuilder
对象类获得,而SqlSessionFactoryBuilder
则可以从XML配置文件或一个预先定制的Configuration
的实例构建出SqlSessionFactory
的实例。
每一个MyBatis的应用程序都以一个SqlSessionFactory
对象的实例为核心。同时SqlSessionFactory
也是线程安全的,SqlSessionFactory
一旦被创建,应该在应用执行期间都存在。在应用运行期间不要重复创建多次,建议使用单例模式。SqlSessionFactory
是创建SqlSession
的工厂。
//SqlSessionFactory接口源码如下所示:
package org.apache.ibatis.session;
import java.sql.Connection;
public interface SqlSessionFactory {
SqlSession openSession();//这个方法最经常用,用来创建SqlSession对象.
SqlSession openSession(boolean autoCommit);
SqlSession openSession(Connection connection);
SqlSession openSession(TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType);
SqlSession openSession(ExecutorType execType, boolean autoCommit);
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType, Connection connection);
Configuration getConfiguration();
}
二、SqlSession
SqlSession
是MyBatis的关键对象,是执行持久化操作的独享,类似于JDBC中的Connection
。它是应用程序与持久层之间执行交互操作的一个单线程对象,也是MyBatis执行持久化操作的关键对象。SqlSession
对象完全包含以数据库为背景的所有执行SQL操作的方法,它的底层封装了JDBC连接,可以用SqlSession
实例来直接执行被映射的SQL语句。
每个线程都应该有它自己的SqlSession
实例。SqlSession
的实例不能被共享,同时SqlSession
也是线程不安全的,绝对不能讲SqlSeesion
实例的引用放在一个类的静态字段甚至是实例字段中。也绝不能将SqlSession
实例的引用放在任何类型的管理范围中,比如Servlet当中的HttpSession
对象中。使用完SqlSeesion
之后关闭Session很重要,应该确保使用finally块来关闭它。
//SqlSession接口源码如下所示:
package org.apache.ibatis.session;
import java.io.Closeable;
import java.sql.Connection;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.executor.BatchResult;
public interface SqlSession extends Closeable {
T selectOne(String statement);
T selectOne(String statement, Object parameter);
List selectList(String statement) ;
List selectList(String statement, Object parameter) ;
List selectList(String statement, Object parameter, RowBounds rowBounds) ;
Map selectMap(String statement, String mapKey) ;
Map selectMap(String statement, Object parameter, String mapKey) ;
Map selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) ;
void select(String statement, Object parameter, ResultHandler handler);
void select(String statement, ResultHandler handler);
void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);
int insert(String statement);
int insert(String statement, Object parameter);
int update(String statement);
int update(String statement, Object parameter);
int delete(String statement);
int delete(String statement, Object parameter);
void commit();
void commit(boolean force);
void rollback();
void rollback(boolean force);
List flushStatements() ;
void close();
void clearCache();
Configuration getConfiguration();
T getMapper(Class type) ;
Connection getConnection();
}
三、SqlSessionFactory和SqlSession实现过程
mybatis框架主要是围绕着SqlSessionFactory进
行的,创建过程大概如下:
(1)、定义一个Configuration
对象,其中包含数据源、事务、mapper文件资源以及影响数据库行为属性设置settings
(2)、通过配置对象,则可以创建一个SqlSessionFactoryBuilder
对象
(3)、通过 SqlSessionFactoryBuilder
获得SqlSessionFactory
的实例。
(4)、SqlSessionFactory
的实例可以获得操作数据的SqlSession
实例,通过这个实例对数据库进行操作
并且如果想按照上述方式得到SqlSessionFactory
,最好使用下面的mybatis-config
。xml类似的配置。在这里mybatis-config.xml
配置文件是没有和Spring配置文件整合过得,如果项目中mybaits的配置文件和Spring配置文件整合过了,则下面的代码运行估计会出错,因为一般spring和mybatis整合过之后,mybatis的配置文件基本没有存在的必要了。
之前在mybatis中配置的数据源和事务这两个方面,一般的做法都会spring的配置文件,则下面的代码加载mybatis-config.xml
的时候,得不到必要的信息,创建的过程中会有问题。所以在这里先给一份mybatis-config.xml
单独的配置文件。
configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="db.properties"/>
<typeAliases>
<typeAlias type="cn.itcast.javaee.mybatis.app04.Student" alias="student"/>
typeAliases>
<environments default="mysql_developer">
<environment id="mysql_developer">
<transactionManager type="jdbc"/>
<dataSource type="pooled">
<property name="driver" value="${mysql.driver}"/>
<property name="url" value="${mysql.url}"/>
<property name="username" value="${mysql.username}"/>
<property name="password" value="${mysql.password}"/>
dataSource>
environment>
<environment id="oracle_developer">
<transactionManager type="jdbc"/>
<dataSource type="pooled">
<property name="driver" value="${oracle.driver}"/>
<property name="url" value="${oracle.url}"/>
<property name="username" value="${oracle.username}"/>
<property name="password" value="${oracle.password}"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="cn/itcast/javaee/mybatis/app14/StudentMapper.xml"/>
mappers>
configuration>
下面的这行代码功能是通过配置文件mybatis-config.xml,创建SqlSessionFactory
对象,然后产生SqlSession,执行SQL语句。而mybatis的初始化发生在:
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
如果是spring和mybaits整合之后的配置文件,一般以这种方式实现,SqlSessionFactory
的创建:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource">property>
<property name="mapperLocations" value="classpath:com/cn/mapper/*.xml">property>
bean>
关于SqlSessionFactory
和SqlSession
两个对象给一个具体的使用过程:
package com.cn.testIUserService;
import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.cn.entity.User;
public class MyBatisTest {
public static void main(String[] args) {
try {
//读取mybatis-config.xml文件
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
//初始化mybatis,创建SqlSessionFactory类的实例
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//创建session实例
SqlSession session = sqlSessionFactory.openSession();
/*
* 接下来在这里做很多事情,到目前为止,目的已经达到得到了SqlSession对象.通过调用SqlSession里面的方法,
* 可以测试MyBatis和Dao层接口方法之间的正确性,当然也可以做别的很多事情,在这里就不列举了
*/
//插入数据
User user = new User();
user.setC_password("123");
user.setC_username("123");
user.setC_salt("123");
//第一个参数为方法的完全限定名:位置信息+映射文件当中的id
session.insert("com.cn.dao.UserMapping.insertUserInformation", user);
//提交事务
session.commit();
//关闭session
session.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
针对上面的代码给出详细的说明关于SqlSessionFactory
和SqlSession
创建过程涉及的内容。
结合上述SqlSessionFactory
和SqlSession
使用过程和结构图,涉及到的方法为下面步骤,结合源码中的方法为下面的步骤:
第一步首先 SqlSessionFactoryBuilder
去读取mybatis的配置文件,然后build一个DefaultSqlSessionFactory
,即得到SqlSessionFactory
//源码中涉及的包和具体方法为:
//涉及的包为:package org.apache.ibatis.session;
//第一个类为:SqlSessionFactoryBuilder,设计到此类的方法为下面部分:
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
//通过XMLConfigBuilder解析配置文件,解析的配置相关信息都会封装为一个Configuration对象
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//然后返回一个DefaultSqlSessionFactory
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
//得到DefaultSqlSessionFactory
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
//第二个类为:DefaultSqlSessionFactory,涉及的方法为:
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
第二步,获取到SqlSessionFactory
之后,就可以利用SqlSessionFactory
方法的openSession
来获取SqlSession
对象了。
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
//通过Confuguration对象去获取Mybatis相关配置信息, Environment对象包含了数据源和事务的配置
// execType为执行器类型,配置文件中定义
// SimpleExecutor -- SIMPLE 就是普通的执行器。
//ReuseExecutor -执行器会重用预处理语句(prepared statements)
//BatchExecutor --它是批量执行器
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//定义执行器,是对statement的封装
final Executor executor = configuration.newExecutor(tx, execType);
//最后返回一个SqlSession
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
得到SqlSession
对象之后就可以利用SqlSession
内部的方法进行CRUD操作了。
注意一点,Connection
对象是在SqlSession
对象创建之后进行CURD操作中创建的。深入查找之后找到在ManagedTransaction
类中找到获取Connection
对象的关键代码如下:
protected void openConnection() throws SQLException {
if (log.isDebugEnabled()) {
log.debug("Opening JDBC Connection");
}
//dataSource 来源有三种,JndiDatasource,PooledDataSource,UnpooledDataSource,配置文件中定义
this.connection = this.dataSource.getConnection();
if (this.level != null) {
this.connection.setTransactionIsolation(this.level.getLevel());
}
}
PooledDataSource
和UnPooledDataSource
的区别是PooledDataSource
使用了连接池。为什么使用连接池呢?
因为创建一个Connection
对象的过程,在底层就相当于和数据库建立的通信连接,在建立通信连接的过程,消耗了非常多的时间,而往往我们建立连接后(即创建Connection对象后),就执行一个简单的SQL语句,然后就要抛弃掉,这是一个非常大的资源浪费!
mybatis针对这一个问题提出的PooledDataSource
使用了连接池。关于数据库连接池的知识点,可以自行百度,在这里就不扩展介绍了。
来源:blog.csdn.net/u013412772/article/
details/73648537
-End-
最近有一些小伙伴,让我帮忙找一些 面试题 资料,于是我翻遍了收藏的 5T 资料后,汇总整理出来,可以说是程序员面试必备!所有资料都整理到网盘了,欢迎下载!
面试题
】即可获取