首页 > 其他分享 >MyBatis-05-MyBatis使用流程简读

MyBatis-05-MyBatis使用流程简读

时间:2024-04-16 22:57:01浏览次数:16  
标签:autoCommit Configuration 05 SqlSession new MyBatis 简读 configuration final

代码

// 使用流程
// 1. 读取配置文件
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
// 2. 创建 SqlSessionFactory 工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 3. 生产 SqlSession 对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 4. 获取 代理对象
UserDao userDao = sqlSession.getMapper(UserDao.class);
// 5. 执行方法
List<User> users = userDao.findAll();
System.out.println(Arrays.toString(users.toArray()));
// 6. 释放资源
sqlSession.close();
inputStream.close();

new SqlSessionFactoryBuilder().build

new SqlSessionFactoryBuilder: 没有做额外动作,只是新建了一个实例,说明它不是线程安全的,每次使用要新建一个
build: 解析 XML,并将生成的相关配置保存到 Configuration 实例中,并且使用这个 Configuration 作为构造函数参数构建 DefaultSqlSessionFactory 实例

DefaultSqlSessionFactory

SqlSessionFactory: SqlSession 的实例工厂

  1. 获取 MyBatis 配置对象 Configuration
  2. 可配置
  • 自动提交
  • 连接对象
  • 事务隔离级别
  • 执行器类型

两个实现类: DefaultSqlSessionFactory、SqlSessionManager

public interface SqlSessionFactory {
    SqlSession openSession();
    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();
}

DefaultSqlSessionFactory

  1. 不传是否自动提交,默认不自动提交
  2. 不传事务隔离级别,默认使用数据库的事务隔离级别
  3. 不传执行器类型,默认使用 Configuration 的配置(默认是 SIMPLE)
  4. 保存了 Configuration 实例
    下面仅列出得到 SqlSession 的方法

openSessionFromConnection: 通过数据库连接创建对象的 SqlSession 对象
Connection -> new Transaction -> new Executor -> new DefaultSqlSession,Transaction & Executor & DefaultSqlSession 一一对应

// 从 Connection 获取 SqlSession 实例
private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
  try {
    boolean autoCommit;
    try {
      autoCommit = connection.getAutoCommit();
    } catch (SQLException e) {
      // Failover to true, as most poor drivers
      // or databases won't support transactions
      autoCommit = true;
    }
    // Environment 保存了对应 XML 标签的内容,即数据库连接相关配置
    final Environment environment = configuration.getEnvironment();
    // 主要是做了如果没有配置就使用 ManagedTransactionFactory, 因为是直接使用数据库连接获取的, Managed 本身又是数据库相关由外部控制的,因此可直接 new 它而不需要其他配置
    final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
    // 事务管理: 封装 Connection 的提交回滚等操作
    final Transaction tx = transactionFactory.newTransaction(connection);
    // 执行器,根据执行器类型创建不同的执行器实例,执行器实例持有对应的事务对象
    final Executor executor = configuration.newExecutor(tx, execType);
	// 三个参数: 配置对象、执行器对象、是否自动提交
    return new DefaultSqlSession(configuration, executor, autoCommit);
  } catch (Exception e) {
    throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
  } finally {
    ErrorContext.instance().reset();
  }
}

openSessionFromDataSource

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level,
    boolean autoCommit) {
  Transaction tx = null;
  try {
    final Environment environment = configuration.getEnvironment();
	// 一样的,如果没有配置则默认的事务的提交回滚等会失效,不由它管理
    final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
	// 新建事务对象,此时不会马上从数据源获取连接
    tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
    final Executor executor = configuration.newExecutor(tx, execType);
    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

  1. getMapper 获得 Dao/Mapper 直接操作
  2. 其它的一般都是 MyBatis 自己调用的接口,Dao/Mapper 的操作实际底层也是委托到他们去调用,说白了 Dao/Mapper 是持有对应 SqlSession 实例的
public interface SqlSession extends Closeable {
  <T> T selectOne(String statement);
  // 其他 selectOne 略
  <E> List<E> selectList(String statement);
  <T> Cursor<T> selectCursor(String statement);
  void select(String statement, Object parameter, ResultHandler handler);
  // 其他略
  // insert、update、delete
  void commit();
  void rollback();
  Configuration getConfiguration();
  // 获取 Dao/Mapper
  <T> T getMapper(Class<T> type);
  // 获取数据库连接对象
  Connection getConnection();
}

构造函数

// 持有配置对象,执行器对象
private final Configuration configuration;
private final Executor executor;

private final boolean autoCommit;
private boolean dirty;
private List<Cursor<?>> cursorList;

public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
  this.configuration = configuration;
  this.executor = executor;
  this.dirty = false;
  this.autoCommit = autoCommit;
}

public DefaultSqlSession(Configuration configuration, Executor executor) {
  this(configuration, executor, false);
}

selectOne/selectList
其他也差不多,基本上都是委托给 executor 执行的

private <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
  try {
    // statement: 类名 + 方法名, 就是 XML 中一个方法的 id
    // parameter: =MapperMethod.ParamMap,方法参数
    // rowBounds: 分页参数
    // handler: 返回值处理
    MappedStatement ms = configuration.getMappedStatement(statement);
    dirty |= ms.isDirtySelect();
    return executor.query(ms, wrapCollection(parameter), rowBounds, handler);
  } catch (Exception e) {
    throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
  } finally {
    ErrorContext.instance().reset();
  }
}

getMapper
Configuration 有 mapperRegistry 实例,所有 Mapper 都需要注册到 mapperRegistry 才能使用
Mapper 绑定 SqlSession,每次 getMapper 都是一个新的 Mapper 实例,不是单例

public <T> T getMapper(Class<T> type) {
  return configuration.getMapper(type, this);
}

public <T> T Configuration.getMapper(Class<T> type, SqlSession sqlSession) {
  return mapperRegistry.getMapper(type, sqlSession);
}

public <T> T MapperRegistry.getMapper(Class<T> type, SqlSession sqlSession) {
  final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
  if (mapperProxyFactory == null) {
    throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
  }
  try {
    return mapperProxyFactory.newInstance(sqlSession);
  } catch (Exception e) {
    throw new BindingException("Error getting mapper instance. Cause: " + e, e);
  }
}

Mapper 实例都是代理,持有 SqlSession,于是可以直接通过 SqlSession 执行 SQL

public T MapperProxyFactory.newInstance(SqlSession sqlSession) {
  final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
  return newInstance(mapperProxy);
}

标签:autoCommit,Configuration,05,SqlSession,new,MyBatis,简读,configuration,final
From: https://www.cnblogs.com/chenxingyang/p/18139463

相关文章

  • MyBatis-07-插件原理
    MyBatis插件MyBatis的插件实际上就是Interceptor,拦截器,拦截并重写SQLInterceptor:拦截器InterceptorChain:拦截器链Invocation:封装Object.method(args),反射调用Plugin:JDK代理处理器InvocationHandler,封装一个Interceptor及其拦截的方法,及拦截对象+拦截方......
  • MyBatis-08-Spring的MyBatis Interceptor
    addInterceptor3个地方XML解析的SqlSessionFactoryBean:生成SqlSession的FactoryBeanPageHelperAutoConfiguration:分页助手的自动配置SqlSessionFactoryBean发现现在都没有将他作为一个FactoryBean使用了getObject调用了afterPropertiesSet生成SqlSessionF......
  • MyBatis-09-FactoryBean的问题
    ListableBeanFactory#getBeanNamesForType(Class<?>)这个方法的逻辑在对FactoryBean进行判断时,会使用FactoryBean的生成的对象的类型进行判断BD的属性数据AttributeAccessor.getAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE)反射创建对象并调用FactoryBean#getObjectT......
  • MyBatis-01-Demo
    数据库DDLCREATEDATABASE`mybatis_demo01`;--mybatis_demo01.`user`definitionCREATETABLE`user`(`id`intNOTNULLAUTO_INCREMENT,`username`varchar(100)DEFAULTNULL,`birthday`datetimeDEFAULTNULL,`sex`char(1)DEFAULTNULL,`address`......
  • MyBatis-02-别名
    别名TypeAliasRegistry默认注册了很多别名,构造函数注册的publicTypeAliasRegistry(){registerAlias("string",String.class);registerAlias("byte",Byte.class);registerAlias("char",Character.class);registerAlias("character"......
  • MyBatis-03-environment
    配置<environmentsdefault="default"><environmentid="default"><!--事务类型--><transactionManagertype="JDBC"/><!--数据源类型--><dataSourcetype="POOLED">&l......
  • mybatisplus
    mybatisplus如何实现获取信息通过扫描实体类并通过反射获取实体类信息作为数据库表信息约定:类名、变量名驼峰转下划线作为表名id字段默认为主键常用注解@TableName,@TableId,@TableField@TableField使用场景:成员变量为boolean并且名称为is开头,转化时会去掉is......
  • 05 Vue3组件间的通信
    Vue3组件通信和Vue2的区别:移出事件总线,使用mitt代替。vuex换成了pinia把.sync优化到了v-model里面了把$listeners所有的东西,合并到$attrs中了$children被砍掉了常见搭配形式props-【父传子子传父】若父传子:属性值是非函数若子传父:属性值是函数一般都......
  • 洛谷题单指南-数学基础问题-P1403 [AHOI2005] 约数研究
    原题链接:https://www.luogu.com.cn/problem/P1403题意解读:计算1~n每个数的约数个数之和。解题思路:1、数学方法1~n的约数范围也在1~n,要计算每个数的约数个数之和可以从约数出发,比如约数是x,那么在1~n中一共有n/x个数包含x这个约数x从1一直枚举到n,就可以得出每个约数是多少个......
  • 80、SpringBoot3 SpringSecurity Mybatisplus最新版 整合 实现登入权限控制
    1、导入pom依赖<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apac......