MyBatis SqlSession事务与批量执行正确方式(默认不生效)

Mybatis之SqlSession详解 Mybatis 阅读详情
AI摘要

文章详细分析了MyBatis中SqlSessionFactory.openSession()方法在事务和批量执行方面的问题。默认情况下,SqlSession的事务和批量执行可能不生效,需额外设置。正确使用事务需设置TransactionFactory为JdbcTransactionFactory,并在Spring配置中指定。对于批量执行,MySQL需要设置rewriteBatchedStatements参数为true。文章还介绍了事务和批量执行的正确使用方式以及相关组件的工作原理。

1. 容易误用的写法

某些情况下会使用MyBatis的SqlSessionFactory.openSession()方法获取SqlSession对象,再进行数据库操作,但默认情况下SqlSession的事务与批量执行均不生效,假如希望使用SqlSession时事务或批量执行能够生效,则需要进行额外的处理

1.1. SqlSession事务默认不生效

调用org.apache.ibatis.session.SqlSessionFactory接口的以下openSession()方法时,默认情况下,指定autoCommit参数为false,实际上不会关闭自动提交,即事务不会生效:

SqlSession openSession(boolean autoCommit);
SqlSession openSession(ExecutorType execType, boolean autoCommit);

默认情况下,以下写法效果是相同的,即事务不生效:

SqlSession sqlSession = usedSqlSessionFactory.openSession(..., (autoCommit=)false);
// 两种写法效果相同
SqlSession sqlSession = usedSqlSessionFactory.openSession(..., (autoCommit=)true);

1.2. SqlSession批量执行默认不生效

调用SqlSessionFactory接口的以下openSession()方法时,默认情况下,指定execType参数为ExecutorType.BATCH,实际上sql语句不会批量执行,还是单条执行的(使用MySQL数据库)

SqlSession openSession(ExecutorType execType);
SqlSession openSession(ExecutorType execType, boolean autoCommit);
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType, Connection connection);

默认情况下,以下写法效果是相同的,即sql语句不会批量执行

SqlSession sqlSession = usedSqlSessionFactory.openSession(ExecutorType.BATCH, ...);
// 两种写法效果相同
SqlSession sqlSession = usedSqlSessionFactory.openSession(ExecutorType.SIMPLE, ...);

2. SqlSession事务正确使用方式

  • 使用方式

使用SqlSessionFactory.openSession()方法获取SqlSession时,假如需要在事务中执行数据库操作,除了指定autoCommit参数为false外,还需要进行以下处理:

在定义SqlSessionFactory接口的实现类org.mybatis.spring.SqlSessionFactoryBean时,将transactionFactory字段使用org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory的实例

假如使用XML方式定义Spring相关配置,则如下所示:

<bean id="jdbcTransactionFactory" class="org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory"/>

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="failFast" value="true"/>
    <property name="dataSource" ref="dataSource"/>
    <property name="mapperLocations">
        <list>
            <value>classpath*:xxx/*.xml</value>
        </list>
    </property>
    <property name="transactionFactory" ref="jdbcTransactionFactory"/>
</bean>

以上SqlSessionFactoryBean需要新建一个,不能使用org.mybatis.spring.mapper.MapperScannerConfigurer中使用的sqlSessionFactory

假如将MapperScannerConfigurer中使用的sqlSessionFactory的transactionFactory使用JdbcTransactionFactory的实例,会导致MyBatis中普通的Mapper数据库操作也使用事务

  • MyBatis推荐

SqlSessionFactoryBean.setTransactionFactory()方法用于设置以上transactionFactory对象

参考该方法的说明:https://mybatis.org/spring/apidocs/reference/org/mybatis/spring/SqlSessionFactoryBean.html#setTransactionFactory(org.apache.ibatis.transaction.TransactionFactory)

SqlSessionFactoryBean默认使用的TransactionFactory是SpringManagedTransactionFactory,默认的SpringManagedTransactionFactory类能很好地适用于所有的情况,强烈推荐使用默认的TransactionFactory

即MyBatis不推荐使用以上修改TransactionFactory的方式

2.1. 编程式事务建议使用方式

当需要使用编程式事务执行数据库操作时,建议使用Spring事务模板TransactionTemplate

Spring事务模板TransactionTemplate不需要人工对事务进行管理,即不需要在代码中显式执行事务开启、事务提交、事务回滚等操作,更方便稳定

可参考https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#tx-prog-template

3. SqlSession批量执行正确使用方式

使用MySQL数据库,使用SqlSessionFactory.openSession()方法获取SqlSession时,假如需要在批量执行数据库操作,除了指定execType参数为ExecutorType.BATCH外,还需要进行以下处理:

在MySQL的jdbc url中,指定rewriteBatchedStatements=true参数,使mysql-connector对SQL语句进行重写,进行批量执行,示例如下:

jdbc:mysql://1.1.1.1:3306/db_name?characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true

进行以上处理后,调用SqlSession.flushStatements()时,会批量执行当前缓存的数据库操作(调用SqlSession.flushStatements()之前的数据库写操作会被缓存)

  • 支持批量执行的情况

仅当对同一个表执行insert、replace语句,且SQL语句的结构相同时,支持批量执行

当insert、replace语句被批量执行时,insert、replace语句会被重写为以下多值形式:

insert into xxx(...) values (...),(...);
replace into xxx(...) values (...),(...);

3.1. Statement.executeBatch()与rewriteBatchedStatements

调用Statement.executeBatch()方法时,会受到rewriteBatchedStatements参数的影响

3.2. SqlSession.flushStatements()与rewriteBatchedStatements

SqlSession.flushStatements()方法中调用了Statement.executeBatch()方法,因此SqlSession.flushStatements()也会受到rewriteBatchedStatements参数的影响

3.3. MyBatis XML insert foreach与rewriteBatchedStatements

在MyBatis的XML文件的insert语句中,使用foreach方式批量执行时,MyBatis生成的SQL语句就是多值的形式,不需要重写,因此不会受到rewriteBatchedStatements参数的影响

3.4. 批量执行建议使用方式

当需要批量执行时,建议使用MyBatis的XML文件的insert语句中foreach方式,原因如上

4. 相关组件及版本

组件版本
spring5.3.22
mybatis3.5.9
mybatis-spring2.0.7
druid1.2.10
mysql-connector-java8.0.31

5. 细节分析

5.1. 相关概念

在使用MyBatis执行数据库操作及事务时,涉及到以下概念:

接口名或类名说明相关实现类或子类
org.apache.ibatis.session.SqlSessionFactory创建SqlSession的工厂类org.apache.ibatis.session.defaults.DefaultSqlSessionFactory

org.apache.ibatis.session.SqlSessionManager

org.apache.ibatis.session.SqlSession管理Sql会话,其中包含了Executororg.apache.ibatis.session.SqlSessionManager

org.apache.ibatis.session.defaults.DefaultSqlSession

org.mybatis.spring.SqlSessionTemplate

org.apache.ibatis.executor.Executor数据库操作执行类,其中包含了Transactionorg.apache.ibatis.executor.CachingExecutor

org.apache.ibatis.executor.BaseExecutor

org.apache.ibatis.executor.SimpleExecutor

org.apache.ibatis.executor.BatchExecutor

org.apache.ibatis.executor.ReuseExecutor

org.apache.ibatis.transaction.TransactionFactory创建Transaction的工厂类org.mybatis.spring.transaction.SpringManagedTransactionFactory

org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory

org.apache.ibatis.transaction.managed.ManagedTransactionFactory

org.apache.ibatis.transaction.Transaction管理事务,其中包含了Connectionorg.apache.ibatis.transaction.managed.ManagedTransaction

org.apache.ibatis.transaction.jdbc.JdbcTransaction

org.mybatis.spring.transaction.SpringManagedTransaction

java.sql.Connection数据库连接略

5.2. 基本步骤

5.2.1. 初始化

进行初始化操作时的步骤如下:

  • SqlSessionFactory获取TransactionFactory
  • TransactionFactory创建Transaction
  • SqlSessionFactory创建Executor
  • SqlSessionFactory创建SqlSession

如下所示:

SqlSessionFactory
    -> TransactionFactory
	    -> Transaction
	-> Executor
	-> SqlSession

5.2.2. 数据库操作

进行获取数据库连接、提交/回滚事务等数据库操作时,步骤如下:

  • SqlSession调用其中的Executor
  • Executor调用其中的Transaction

如下所示:

SqlSession
    -> Executor
        -> Transaction

5.3. SqlSessionFactoryBean的openSession()方法实现

SqlSessionFactoryBean类没有直接实现SqlSessionFactory接口,而是实现了org.springframework.beans.factory.FactoryBean接口,泛型类型为SqlSessionFactory,代码如下:

public class SqlSessionFactoryBean
    implements FactoryBean<SqlSessionFactory>, ...

FactoryBean接口中,getObject()方法返回工厂类管理的对象的实例,相当于做了一层代理

SqlSessionFactoryBean.getObject()方法返回的是字段SqlSessionFactory sqlSessionFactory

SqlSessionFactoryBean.afterPropertiesSet()方法中,将sqlSessionFactory字段赋值为buildSqlSessionFactory()方法返回值

SqlSessionFactoryBean.buildSqlSessionFactory()方法中,返回了sqlSessionFactoryBuilder.build()方法返回值,sqlSessionFactoryBuilder字段类型为org.apache.ibatis.session.SqlSessionFactoryBuilder

SqlSessionFactoryBuilder.build()方法中,创建了DefaultSqlSessionFactory对象并返回

即SqlSessionFactoryBean类相当于继承了DefaultSqlSessionFactory类

SqlSessionFactoryBean类未实现openSession()方法,可继承DefaultSqlSessionFactory类的对应方法

5.4. SqlSessionFactory.openSession()方法实现-TransactionFactory、Transaction、Executor、SqlSession初始化过程

调用SqlSessionFactoryBean.openSession()方法时,实际调用的是DefaultSqlSessionFactory.openSession()方法

在DefaultSqlSessionFactory.openSession()方法中,会通过TransactionFactory创建Transaction,将Transaction与Executor进行关联,再将Executor与SqlSession关联

DefaultSqlSessionFactory类有多个openSession()方法,参数中不包含Connection的openSession()方法都是调用openSessionFromDataSource()方法:

若openSession()方法有指定autoCommit参数,则调用openSessionFromDataSource()方法时autoCommit参数使用指定的值;

若openSession()方法未指定autoCommit参数,则调用openSessionFromDataSource()方法时autoCommit参数使用固定值false

DefaultSqlSessionFactory.openSessionFromDataSource()方法部分代码如下:

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

以上方法的执行步骤如下:

  • 获取环境Environment

调用org.apache.ibatis.session.Configuration.getEnvironment()方法

用于获取当前配置对应的环境信息

  • 获取事务工厂TransactionFactory

调用getTransactionFactoryFromEnvironment()方法

用于获取当前环境对应的TransactionFactory

在getTransactionFactoryFromEnvironment()方法中,若Environment.getTransactionFactory()方法返回值非null,则使用对应的TransactionFactory

对Environment中TransactionFactory进行赋值的过程见后文对SqlSessionFactoryBean.buildSqlSessionFactory()方法的分析

  • 获取事务Transaction

调用TransactionFactory.newTransaction()方法

用于创建org.apache.ibatis.transaction.Transaction

TransactionFactory存在多个实现类,newTransaction()方法有不同的实现,TransactionFactory及对应的Transaction实现类如下:

TransactionFactory实现类Transaction实现类对应包名
SpringManagedTransactionFactorySpringManagedTransactionorg.mybatis.spring.transaction
JdbcTransactionFactoryJdbcTransactionorg.apache.ibatis.transaction.jdbc
ManagedTransactionFactoryManagedTransactionorg.apache.ibatis.transaction.managed
  • 获取执行器Executor

调用Configuration.newExecutor(),使用Transaction、ExecutorType创建Executor

Configuration.newExecutor()方法部分代码如下:

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    if (ExecutorType.BATCH == executorType) {
        executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
        executor = new ReuseExecutor(this, transaction);
    } else {
        executor = new SimpleExecutor(this, transaction);
    }
    if (cacheEnabled) {
        executor = new CachingExecutor(executor);
    }

ExecutorType类型决定了创建的Executor类型:

ExecutorType类型对应的Executor类型说明
BATCHBatchExecutor支持批量执行的执行器
REUSEReuseExecutor支持重用预编译SQL语句的执行器
SIMPLESimpleExecutor简单执行器

BatchExecutor、ReuseExecutor、SimpleExecutor都是org.apache.ibatis.executor.BaseExecutor的子类

以上三种Executor的构造函数中都会调用BaseExecutor的构造函数,在其中会将参数中指定的Transaction transaction保存到类的字段中

Configuration.newExecutor()方法执行的操作如下:

使用Transaction、ExecutorType创建对应的Executor(SimpleExecutor、BatchExecutor)等

由于cacheEnabled字段默认为true,因此会使用已创建的Executor创建CachingExecutor,使用Executor delegate字段保存刚创建的Executor

  • 获取SQL会话SqlSession

使用Executor、autoCommit创建DefaultSqlSession

DefaultSqlSessionFactory.openSessionFromDataSource()方法返回的类型为DefaultSqlSession

5.5. BaseExecutor中通过Transaction获取Connection的过程

在BaseExecutor的子类BatchExecutor、ReuseExecutor、SimpleExecutor,数据库读写操作对应的doQuery()、doQueryCursor()、doUpdate()方法中,都会先直接或间接调用getConnection()方法,以获取数据库连接Connection

在BaseExecutor.getConnection()方法中,会调用Transaction transaction字段的getConnection()方法并返回:

protected Connection getConnection(Log statementLog) throws SQLException {
    Connection connection = transaction.getConnection();
    if (statementLog.isDebugEnabled()) {
        return ConnectionLogger.newInstance(connection, statementLog, queryStack);
    } else {
        return connection;
    }
}

5.6. SqlSession.commit()方法执行过程

5.6.1. SqlSession的commit过程

SqlSession.commit()方法对应DefaultSqlSession.commit()方法,该方法中会调用commit(boolean force)方法,参数值为false:

@Override
public void commit() {
    commit(false);
}

@Override
public void commit(boolean force) {
    try {
        executor.commit(isCommitOrRollbackRequired(force));
        dirty = false;

在commit(boolean force)方法中,会调用Executor executor字段的commit()方法,参数值为isCommitOrRollbackRequired()方法的返回值

isCommitOrRollbackRequired()方法代码如下:

private boolean isCommitOrRollbackRequired(boolean force) {
    return (!autoCommit && dirty) || force;
}

由于force参数为false,因此仅当autoCommit=false且dirty=true时,isCommitOrRollbackRequired()方法会返回true

即仅当关闭自动提交,且执行了写操作时,SqlSession在调用Executor的commit()方法时,传入参数为true

在DefaultSqlSession.update()方法中,会将dirty字段设置为true

insert()、delete()方法也是调用了update()方法

即dirty字段代表当前Sql会话是否有执行数据库写操作

5.6.2. Executor的commit过程

在SqlSession.commit()方法中调用Executor.commit()方法时,步骤如下:

  • CachingExecutor.commit()

在DefaultSqlSession.commit()方法中,由于DefaultSqlSession中的Executor executor字段类型为CachingExecutor,因此会调用CachingExecutor.commit()方法

在CachingExecutor.commit()方法中,会调用Executor delegate字段的commit()方法

delegate字段的类型为BaseExecutor的子类BatchExecutor、ReuseExecutor、SimpleExecutor,由于以上类中没有实现commit()方法,因此会调用父类BaseExecutor的commit()方法

  • BaseExecutor.commit()

在BaseExecutor.commit()方法中,当参数required=true时会调用Transaction transaction字段的commit()方法,参数required对应DefaultSqlSession.commit()方法中isCommitOrRollbackRequired()方法的返回值

即DefaultSqlSession中的autoCommit=false(关闭自动提交)且dirty=true(执行了写操作)时,BaseExecutor.commit()方法中会执行事务对象对应的Transaction.commit()方法

5.6.3. Transaction的commit过程

Transaction实现类的commit()方法处理见后续内容

5.6.4. SqlSession.commit()方法执行过程调用堆栈

以默认使用的Transaction实现类SpringManagedTransaction为例,SqlSession.commit()方法执行过程调用堆栈如下:

org.apache.ibatis.session.defaults.DefaultSqlSession.commit(DefaultSqlSession:214)
org.apache.ibatis.session.defaults.DefaultSqlSession.commit(DefaultSqlSession:220)
org.apache.ibatis.executor.CachingExecutor.commit(CachingExecutor:119)
org.apache.ibatis.executor.BaseExecutor.commit(BaseExecutor:244)
org.mybatis.spring.transaction.SpringManagedTransaction.commit(SpringManagedTransaction:93)

5.7. SqlSession.rollback()方法执行过程

与commit()方法执行过程类似,略

5.8. 为什么openSession(autoCommit=false)时事务默认未生效

使用SqlSessionFactory接口的实现类SqlSessionFactoryBean时,在buildSqlSessionFactory()方法中决定使用的TransactionFactory transactionFactory字段的类型,若未指定则默认使用org.mybatis.spring.transaction.SpringManagedTransactionFactory类的实例

targetConfiguration.setEnvironment(new Environment(this.environment,
    this.transactionFactory == null ? new SpringManagedTransactionFactory() : this.transactionFactory,
    this.dataSource));

在SpringManagedTransactionFactory的newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit)方法中,生成了SpringManagedTransaction类实例并返回,在生成SpringManagedTransaction类实例时,未使用autoCommit参数:

@Override
public Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit) {
  return new SpringManagedTransaction(dataSource);
}

前文已分析,Executor执行数据库读写操作前,会先调用Transaction.getConnection()方法获取数据库连接,默认情况下会执行SpringManagedTransaction.getConnection()方法

SpringManagedTransaction.getConnection()方法中会调用SpringManagedTransaction.openConnection()方法

SpringManagedTransaction.openConnection()方法用于打开数据库连接,autoCommit字段使用当前获取的connection对象的autoCommit:

this.connection = DataSourceUtils.getConnection(this.dataSource);
this.autoCommit = this.connection.getAutoCommit();

前文已分析,SqlSession.commit()方法执行时,会通过Executor,执行Transaction的commit()方法,默认情况下会执行SpringManagedTransaction.commit()方法

SpringManagedTransaction类用于进行事务提交与回滚处理的commit()、rollback()方法中,当autoCommit字段为true时,不会执行connection的commit()、rollback()方法以进行事务提交或回滚:

@Override
public void commit() throws SQLException {
  if (this.connection != null && !this.isConnectionTransactional && !this.autoCommit) {
    LOGGER.debug(() -> "Committing JDBC Connection [" + this.connection + "]");
    this.connection.commit();
  }
}

@Override
public void rollback() throws SQLException {
  if (this.connection != null && !this.isConnectionTransactional && !this.autoCommit) {
    LOGGER.debug(() -> "Rolling back JDBC Connection [" + this.connection + "]");
    this.connection.rollback();
  }
}

默认情况下使用的SpringManagedTransactionFactory对应的SpringManagedTransaction不会改变连接对象connection的autoCommit值;在MySQL中,autoCommit参数默认值为true,因此SqlSession默认情况下事务不生效

5.9. 为什么JdbcTransactionFactory能够使事务生效

  • JdbcTransactionFactory.newTransaction()方法创建事务对象过程

在TransactionFactory的实现类JdbcTransactionFactory中,newTransaction()方法(DefaultSqlSessionFactory.openSessionFromDataSource()方法中执行的)代码如下:

@Override
public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
    return new JdbcTransaction(ds, level, autoCommit);
}

以上JdbcTransactionFactory.newTransaction()方法中会创建JdbcTransaction对象,传递了autoCommit参数,对应DefaultSqlSessionFactory.openSessionFromDataSource()方法的autoCommit参数

  • JdbcTransaction.getConnection()方法获取数据库连接过程

前文已分析,BaseExecutor中会通过Transaction.getConnection()方法获取Connection

在JdbcTransaction.getConnection()方法中,会调用openConnection()方法

在JdbcTransaction.openConnection()方法中,会调用setDesiredAutoCommit()方法,参数值为类的autoCommit字段

在setDesiredAutoCommit()方法中,会将Connection的autoCommit设置为参数desiredAutoCommit指定的值,当数据库连接的自动提交关闭时,事务可以生效:

protected void setDesiredAutoCommit(boolean desiredAutoCommit) {
    try {
        if (connection.getAutoCommit() != desiredAutoCommit) {
        if (log.isDebugEnabled()) {
            log.debug("Setting autocommit to " + desiredAutoCommit + " on JDBC Connection [" + connection + "]");
        }
        connection.setAutoCommit(desiredAutoCommit);
        }
    } 

以上调用Connection.setAutoCommit()方法设置autoCommit的参数desiredAutoCommit,对应DefaultSqlSessionFactory.openSessionFromDataSource()方法的autoCommit参数

假如使用JdbcTransactionFactory,且调用DefaultSqlSessionFactory.openSessionFromDataSource()方法时autoCommit参数值为false,则获取数据库连接时会关闭自动提交,因此事务可以生效

5.10. MyBatis Mapper初始化过程

MyBatis Mapper对应的Spring Bean的初始化过程中涉及到以下类:

org.mybatis.spring.mapper.MapperFactoryBean
org.mybatis.spring.support.SqlSessionDaoSupport
org.mybatis.spring.SqlSessionTemplate
org.apache.ibatis.binding.MapperProxy

MyBatis Mapper初始化过程比较复杂,这里不展开说明

MyBatis Mapper在完成初始化之后,会变成动态代理类,对应org.apache.ibatis.binding.MapperProxy类

MapperProxy类中的SqlSession sqlSession字段类型为org.mybatis.spring.SqlSessionTemplate

SqlSessionTemplate类中的SqlSessionFactory sqlSessionFactory字段,对应org.mybatis.spring.mapper.MapperScannerConfigurer中的SqlSessionFactory sqlSessionFactory字段(可以通过sqlSessionFactoryBeanName指定)

前文已说明,在SqlSessionFactory进行处理后,会将Transaction与SqlSession关联起来,在获取数据库连接、执行提交/回滚操作时,都需要调用Transaction

5.11. 直接使用MyBatis Mapper时获取Connection过程

直接使用MyBatis Mapper执行数据库操作时,获取数据库连接Connection的调用堆栈如下:

以下使用的是默认的SpringManagedTransactionFactory对应的SpringManagedTransaction,下同

com.sun.proxy.$Proxy38.insert(Unknown Source)
org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy:86)
org.apache.ibatis.binding.MapperProxy$PlainMethodInvoker.invoke(MapperProxy:145)
org.apache.ibatis.binding.MapperMethod.execute(MapperMethod:62)
org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate:272)
com.sun.proxy.$Proxy36.insert(Unknown Source)
org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate:427)
java.lang.reflect.Method.invoke(Method:498)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl:43)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl:62)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession:181)
org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession:194)
org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor:76)
org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor:117)
org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor:49)
org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor:86)
org.apache.ibatis.executor.BaseExecutor.getConnection(BaseExecutor:337)
org.mybatis.spring.transaction.SpringManagedTransaction.getConnection(SpringManagedTransaction:66)

直接使用MyBatis Mapper执行数据库操作时,获取数据库连接Connection的过程与使用SqlSessionFactory.openSession()方法时的过程类似

5.12. 直接使用MyBatis Mapper时创建SqlSession与commit过程

直接使用MyBatis Mapper执行数据库操作时,执行commit的调用堆栈如下:

com.sun.proxy.$Proxy38.insert(Unknown Source)
org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy:86)
org.apache.ibatis.binding.MapperProxy$PlainMethodInvoker.invoke(MapperProxy:145)
org.apache.ibatis.binding.MapperMethod.execute(MapperMethod:62)
org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate:272)
com.sun.proxy.$Proxy36.insert(Unknown Source)
org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate:431)
org.apache.ibatis.session.defaults.DefaultSqlSession.commit(DefaultSqlSession:220)
org.apache.ibatis.executor.CachingExecutor.commit(CachingExecutor:119)
org.apache.ibatis.executor.BaseExecutor.commit(BaseExecutor:244)
org.mybatis.spring.transaction.SpringManagedTransaction.commit(SpringManagedTransaction:93)

在SqlSessionTemplate$SqlSessionInterceptor.invoke()方法中,完成获取SqlSession、执行数据库语句、提交事务等操作,代码如下:

SqlSession sqlSession = getSqlSession(SqlSessionTemplate.this.sqlSessionFactory,
    SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
try {
    Object result = method.invoke(sqlSession, args);
    if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
        // force commit even on non-dirty sessions because some databases require
        // a commit/rollback before calling close()
        sqlSession.commit(true);
    }
    return result;
}
  • 获取SqlSession

执行SqlSessionUtils类的getSqlSession()方法,获取SqlSession

  • 执行数据库语句

执行method.invoke()方法,执行数据库语句

  • 提交事务

当isSqlSessionTransactional()返回false,即当前事务不是由Spring管理时,执行sqlSession.commit()方法,提交事务

5.13. 为什么JdbcTransactionFactory会使所有Mapper都使用事务

以上执行的SqlSessionUtils.getSqlSession()方法代码如下:

SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);

SqlSession session = sessionHolder(executorType, holder);
if (session != null) {
    return session;
}

LOGGER.debug(() -> "Creating a new SqlSession");
session = sessionFactory.openSession(executorType);

TransactionSynchronizationManager.getResource()方法用于获取Spring管理的事务信息,由于未使用Spring管理事务,因此以上获取到的SqlSessionHolder holder、SqlSession session均为null

后续会执行sessionFactory.openSession()方法,对应DefaultSqlSessionFactory的openSession(ExecutorType execType)方法:

public SqlSession openSession(ExecutorType execType) {
    return openSessionFromDataSource(execType, null, false);
}

以上对应的DefaultSqlSessionFactory.openSession()方法中调用openSessionFromDataSource()方法时,参数3 autoCommit指定的值是false

假如SqlSessionFactoryBean中的transactionFactory字段使用JdbcTransactionFactory代替默认的SpringManagedTransactionFactory,在前文已说明在创建数据库连接时会关闭自动提交,会使事务生效

5.14. 为什么事务未提交时SqlSession关闭会回滚事务

SqlSession的数据库操作执行完毕进行关闭时,调用堆栈如下:

org.apache.ibatis.session.defaults.DefaultSqlSession.close(DefaultSqlSession:260)
org.apache.ibatis.executor.CachingExecutor.close(CachingExecutor:64)
org.apache.ibatis.executor.BaseExecutor.close(BaseExecutor:87)
org.apache.ibatis.executor.BaseExecutor.rollback(BaseExecutor:256)
org.apache.ibatis.transaction.jdbc.JdbcTransaction.rollback(JdbcTransaction:78)

DefaultSqlSession.close()部分代码如下:

executor.close(isCommitOrRollbackRequired(false));

isCommitOrRollbackRequired()方法前文已分析过,仅当关闭自动提交(autoCommit=false),且执行了写操作(dirty=true)时会返回true

BaseExecutor.close()方法中会调用rollback()方法,部分代码如下:

@Override
public void close(boolean forceRollback) {
    try {
        try {
            rollback(forceRollback);

BaseExecutor.rollback()方法代码如下:

public void rollback(boolean required) throws SQLException {
    if (!closed) {
        try {
            clearLocalCache();
            flushStatements(true);
        } finally {
            if (required) {
                transaction.rollback();
            }
        }
    }
}

在BaseExecutor.rollback()方法中,当required参数为true时,会调用Transaction transaction字段的rollback()方法。required参数对应BaseExecutor.close()方法的forceRollback参数,对应DefaultSqlSession.isCommitOrRollbackRequired()方法返回值

即DefaultSqlSession中的autoCommit=false(关闭自动提交)且dirty=true(执行了写操作)时,BaseExecutor.rollback()方法中会执行事务对象对应的Transaction.rollback()方法

(SqlSession.close()方法中会执行事务回滚操作,可以通过try-with-resource方式使用SqlSession对象,不需要在异常时显式执行rollback()方法。但由于MyBatis不建议以上使用事务的方式,因此可以忽略)

5.15. 为什么事务正常提交后SqlSession关闭不会回滚事务

在DefaultSqlSession.commit()方法中,执行Executor executor字段的commit()方法后,会将dirty字段修改为false

在以上情况下isCommitOrRollbackRequired()方法会返回false,BaseExecutor.rollback()方法执行时required参数为false,不会再执行Transaction transaction字段的rollback()方法

因此事务正常提交后SqlSession关闭不会回滚事务

5.16. 为什么openSession(ExecutorType.BATCH)时批量执行默认未生效(MySQL)

参考https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-connp-props-performance-extensions.html

mysql-connector的文档中说明,rewriteBatchedStatements参数决定executeBatch()方法执行时,是否需要将预编译的insert与replace语句重写为多值语句

该参数默认值为false,默认情况下不会将SQL语句重写为批量执行形式,即默认未开启SQL语句的批量执行

5.17. 为什么只有insert、replace支持批量执行

以上mysql-connector的文档中已说明insert与replace语句支持批量执行

在mysql-connector的com.mysql.cj.QueryInfo类,构造函数QueryInfo(String sql, Session session, String encoding)中,仅当处理insert或replace语句,且rewriteBatchedStatements参数值为true时,isRewritableWithMultiValuesClause字段值为true:

boolean rewriteBatchedStatements = session.getPropertySet().getBooleanProperty(PropertyKey.rewriteBatchedStatements).getValue();

...

// Only INSERT and REPLACE statements support multi-values clause rewriting.
boolean isInsert = strInspector.matchesIgnoreCase(INSERT_STATEMENT) != -1;
if (isInsert) {
    strInspector.incrementPosition(INSERT_STATEMENT.length()); // Advance to the end of "INSERT".
}
boolean isReplace = !isInsert && strInspector.matchesIgnoreCase(REPLACE_STATEMENT) != -1;
if (isReplace) {
    strInspector.incrementPosition(REPLACE_STATEMENT.length()); // Advance to the end of "REPLACE".
}

// Check if the statement has potential to be rewritten as a multi-values clause statement, i.e., if it is an INSERT or REPLACE statement and
// 'rewriteBatchedStatements' is enabled.
boolean rewritableAsMultiValues = (isInsert || isReplace) && rewriteBatchedStatements;

...

this.isRewritableWithMultiValuesClause = rewritableAsMultiValues;

QueryInfo.isRewritableWithMultiValuesClause()方法返回了isRewritableWithMultiValuesClause字段值:

public boolean isRewritableWithMultiValuesClause() {
    return this.isRewritableWithMultiValuesClause;
}

在com.mysql.cj.jdbc.ClientPreparedStatement类的executeBatchInternal()方法中,当QueryInfo.isRewritableWithMultiValuesClause()方法返回true时,才会执行executeBatchWithMultiValuesClause()方法,executeBatchWithMultiValuesClause()方法用于将预编译的insert与replace语句重写为多值语句:

if (getQueryInfo().isRewritableWithMultiValuesClause()) {
    return executeBatchWithMultiValuesClause(batchTimeout);
}

6. 可参考的内容

关于autoCommit参数及MySQL数据库操作使用事务时的执行过程,可参考以下内容:

“MySQL SQL语句与事务执行及日志分析”https://blog.youkuaiyun.com/a82514921/article/details/126563449

“Spring、MyBatis、Druid、MySQL使用事务执行SQL语句分析”https://blog.youkuaiyun.com/a82514921/article/details/126563542

关于对MySQL的SQL语句与事务执行过程的分析与监控方式,可参考以下内容:

“Spring、MyBatis、Druid、MySQL执行SQL语句与事务监控”https://blog.youkuaiyun.com/a82514921/article/details/126563558

“tcpdump、Wireshark抓包分析MySQL SQL语句与事务执行”https://blog.youkuaiyun.com/a82514921/article/details/126563471

mybatis的SqlSession 这个代理对象在其invoke方法中,当调用Mapper接口的方法时,会利用内部持有的SqlSession来执行相应的SQL语句,即通过SqlSession的API来完成数据库操作。当调用BaseMapper的某个方法时,实际上是调用代理对象的方法,代理对象内部通过SqlSession找到对应的MappedStatement(已解析好的SQL语句和参数映射信息),然后调用Executor执行SQL,最后将数据库结果转换为Java对象并返回。标签,定义查找用户信息的SQL查询语句,并指定它与方法的映射关系。 阅读详情

相关推荐

MyBatis原理分析之获取SqlSession

前置博客:MyBatis原理分析之获取SqlSessionFactory,本篇是续篇。 获取sqlsession主要是通过SqlSessionFactory的几个重载方法,从configuration中的environment获取datasource与transactionFactory来得到Transaction。然后得到Transaction、Executor与DefaultSqlSession。 mybatis全局配置文件中environments 结点配置如下 <environments de

小小默:进无止境 5803

MyBatis_sqlsession.flushStatements(作用总结

MyBatis_sqlsession.flushStatements(作用总结; 当有处于事物中的时候 sqlSession.flushStatements();起到一种预插入的作用(执行了这行代码之后,要插入的数据会锁定数据库的一行记录,并把数据库默认返回的主键赋值给插入的对象,这样就可以把该对象的主键赋值给其他需要的对象中去了)下面是代码跟踪过程1.刚接收参数:可以看到这个时候id是为nul

y41992910的博客 3万+

Mybatis中的SqlSession与mapper的动态代理的事务提交方式

Mybatis中的SqlSession与mapper的动态代理 我们通过SqlSessionFactory.openSession()方法创建出SqlSession对象时,自动提交事务默认是关闭的,即每次用SqlSession对象必须显示执行commit().源码如下: 欢迎使用Markdown编辑器 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markd...

Mybatis框架 4955

Spring源码之整合Mybatis底层实现

目录 1. Spring整合Mybatis底层源码 2.SqlSessionTemplate类的作用 3. Mybatis一级缓存失效问题 1. Spring整合Mybatis底层源码 Mybatis框架可以单独使用,需要用到Mybatis所提供的一些类构造出对应的Mapper对象,然后就能使用Mybatis框架提供的功能,我们先看一个Demo: @Test public void testMybatis() throws IOException { //...

奔跑的蜗牛_Kieasr 1089

MyBatis批量插入事务失效?BATCH执行器不生效的排查与解决

数据库操作中,事务一致性与批量性能往往是一对矛盾。Spring通过@Transactional声明式事务管理连接,而MyBatis的SqlSession则独立控制会话边界。当两者默认行为叠加时,批量插入常出现事务失效或ExecutorType.BATCH不生效的问题——本质在于SqlSessionTemplate在无事务时自动提交,以及BatchExecutor攒批条件未被满足。理解SqlSession与Spring事务的协作机制,掌握BATCH执行器真正生效的配置方式,并结合缓存刷新、拦截器兼容与内存控制

weixin_34159110的博客 346

【第12章】Mybatis之SqlSession

使用 MyBatis 的主要 Java 接口就是 SqlSession。你可以通过这个接口来执行命令,获取映射器实例和管理事务。在介绍 SqlSession 接口之前,我们先来了解如何获取一个 SqlSession 实例。SqlSessions 是由 SqlSessionFactory 实例创建的。SqlSessionFactory 对象包含创建 SqlSession 实例的各种方法。

zjg 1798

MyBatis SqlSession事务与批量处理:默认不生效的真相与正确姿势

在持久层框架应用中,事务管理和批量写入是高频且容易踩坑的环节。MyBatis作为主流ORM框架,其SqlSession封装了JDBC连接与Executor执行器,但许多开发者误以为调用接口就会自动开启事务或自动执行批量操作。实际上,事务边界需要显式定义,批量执行也依赖ExecutorType.BATCH的开启以及正确的flush和commit时机。理解SqlSession、Executor与JDBC Connection三层协作原理,有助于厘清事务提交、回滚和批处理刷新的真实行为。在数据同步、批量导入等场景

weixin_33800463的博客 480

智能车竞赛卡丁快跑组:自动驾驶与人车交互技术实战解析

本文深入解析了智能车竞赛卡丁快跑组的技术核心,重点探讨了自动驾驶与人车交互两大模块的实战方案。文章详细拆解了从环境感知、路径规划到语音识别、命令执行的完整流程,并分享了基于单片机平台的调试心法与赛场经验,为参赛者提供了一套从零开始、分步攻坚的系统性备赛指南。

f0g1h2的博客 1177

MyBatis SqlSession事务机制与ExecutorType批量模式实战解析

在Java应用开发中,数据库事务控制与批量操作性能优化是工程实践的核心议题。MyBatis作为主流持久层框架,其SqlSession默认采用SIMPLE执行器,事务手动提交与否、执行器类型选择直接影响数据一致性与写入效率。默认情况下,SqlSession的autoCommit为false,DML操作需显式调用commit才落库;若希望批量写入获得性能提升,则必须使用ExecutorType.BATCH模式,通过addBatch与executeBatch减少网络往返。理解DefaultSqlSession源码

weixin_30247781的博客 377

AI 辅助代码审查:开启代码质量管控的智能时代

AI辅助代码审查正在改变传统的代码质量管控方式。通过自动化分析、智能反馈和上下文感知,AI不仅提高了代码审查的效率,还提升了代码质量的一致性和可维护性。随着机器学习和深度学习技术的不断发展,未来AI将成为开发者日常工作中强大的助手,进一步推动软件开发向智能化、自动化方向发展。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 3229

用MCP扩展Cursor的5种神奇用法:从文件操作到网页抓取实战

本文深入探讨了如何利用MCP(Model Context Protocol)扩展Cursor AI编程助手,解锁五种高效实用场景。从文件系统操作、网页内容抓取,到数据库查询、Figma设计稿对接,乃至构建自定义MCP服务器,文章通过实战案例展示了如何将Cursor从代码编辑器升级为能理解并操作工作环境的智能助手,显著提升开发效率与自动化水平。

weixin_29231027的博客 315

MyBatis SqlSession 的作用,以及如何使用 SqlSession 执行 SQL 语句

对于保证 MyBatis 应用程序的正确性和性能至关重要。推荐使用 Mapper 接口的方式来执行 SQL 语句,这种方式更加简洁、类型安全,并且易于维护。是 MyBatis 中执行 SQL 语句、管理事务和获取 Mapper 接口实例的核心接口。是 MyBatis 中非常重要的一个接口,它代表了与数据库的一次会话(session)。在应用程序的生命周期内只需要创建一个实例(单例模式)。对象加上一系列操作数据库的方法。方法关闭会话,释放资源。,以确保资源被正确释放。),需要手动提交事务(

专注于技术分享 2202

手把手教你学 AI芯片 SOC软件开发专栏简介

在AI芯片(如NPU、GPU加速器)爆发式增长的今天,软件栈开发已成为AI应用落地的核心瓶颈。无论是模型推理加速、低延迟部署,还是能效优化,都依赖于对芯片底层软件的深度掌握。然而,许多开发者困于“只会调用API,不懂驱动实现”的困境,导致性能瓶颈难以突破。本专栏《手把手教你学 AI芯片 SOC软件开发》专为AI工程师、嵌入式开发者及系统架构师打造,从零基础切入,系统拆解AI芯片SOC(System on Chip)的完整软件栈,覆盖Runtime(运行时)

MHD0815的博客 171

Mybatis的批量操作

每种方法都有其适用场景和限制。例如,使用 标签生成的批量 SQL 在某些数据库中可能因为 max_allowed_packet 大小限制而失败。因此,在选择批量处理方案时,需要根据具体的业务需求和数据库特性进行综合考虑。愿你我都能在各自的领域里不断成长,勇敢追求梦想,同时也保持对世界的好奇与善意!

weixin_45809780的博客 2602

ABAP 里解构引用操作符 ->* 的使用方法详解

解除引用操作符->*可用于将“类型为REF TO …的引用变量”的值(即该引用所指向内存)取出,从而访问其实际值或内部组件。具体地,若dref是一个“引用变量”,则表达式dref->*代表对该引用进行“解除引用”,使得程序按静态类型将其视为实际类型的值对象。例如,若lr类型声明为,则lr->*表示“将 lr 引用的INT4对象看作INT4类型并访问其值”。注:若 “数据引用变量” 的静态类型是通用类型DATA,则只能在这种上下文中使用->*。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 480

anaconda navigator 卡在loading application界面一直没有反应解决办法

在打开anaconda navigator 程序的时候,遇到了2个问题。第一个问题:打开的时候弹出提示:There is an instance of Anaconda Navigator already running.第二个问题:程序一直卡在loading application界面一直没有反应。以下是我的解决办法,有效果。

猿小白的博客 4384

MyBatis SqlSession执行流程详解

Sqlsession对应着一次数据库会话。由于数据库会话不是永久的,因此Sqlsession的生命周期也不应该是永久的,相反,在你每次访问数据库时都需要创建它(当然并不是说在Sqlsession里只能执行一次sql,你可以执行多次,当一旦关闭了Sqlsession就需要重新创建它)。

深入Java世界:探索编程之美与技术深度 1018

【ArcGIS Engine二次开发】入门基础(2):ArcGIS开发方式(VBA、DLL、Add-in、Engine)对比

文章目录2.1 使用VBA进行桌面软件开发2.1.1 VBA开发方式2.1.1 VBA代码的安全性2.2 使用DLL进行桌面软件开发2.2.1 DLL开发方式2.2.2 DLL功能的应用部署2.3 使用Add-in进行桌面软件开发2.4 使用ArcGIS Engine构建独立应用程序 对于桌面GIS应用来说,ArcGIS平台不仅提供了用于开发独立运行的GIS应用软件的二次开发工包ArcGIS Engine,还提供了对ArcGIS Deskop桌面软件进行扩展的开发的话,在开发个具体的GIS 行业应用软件时

智慧空间实验室 6510

7. MyBatis中的SqlSession是什么?如何管理SqlSession的生命周期?

它提供了执行 SQL 语句的所有方法,包括插入、更新、删除和查询,还可以管理事务、获取映射器(Mapper)接口的实例等。是确保数据一致性和避免资源泄漏的关键,在手动管理和 Spring 管理模式下有不同的实现方式。的生命周期,开发者只需关注业务逻辑,Spring 会自动管理事务和资源的关闭。还负责管理一级缓存,它会自动缓存相同会话中的查询结果,减少对数据库的访问。,Spring 会在方法成功执行后自动提交事务,或在发生异常时自动回滚事务。的打开和关闭,Spring 会自动管理事务和资源。

zhzjn的博客 3068

从误检率30%到99.7%:YOLOv8/v9工业零件缺陷检测实战(附产线部署全流程与参数调优秘籍)

工业场景YOLO实战:从实验室到车间的关键调优策略 本文针对工业缺陷检测的特殊性,系统总结了YOLOv8/v9在工业应用中的实战经验。通过齿轮厂缺陷检测案例,揭示了实验室模型与工业场景的三点本质差异:小目标特性(0.2-1mm缺陷)、复杂背景干扰(油污/反光)和数据量不足问题。重点提出了工业级解决方案:1)数据采集需覆盖极端工况(不同光照/污染/角度);2)标注采用LabelStudio+预标注提升效率;3)定制工业增强策略(反光模拟/缺陷复制粘贴)。文章还提供了完整的参数调优记录和TensorRT加速部署

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1734

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Mybatis SqlSession执行流程

Mybatis执行SQL流程 在看源码之前,我们需要了解一些基本知识,如果您没有阅读Mybatis SqlSessionFactory 初始化原理,可以先阅读Mybatis SqlSessionFactory 初始化原理这篇文章,这用更有助于我们理解接下来的文章 在看源码之前,我们需要了解一些基本知识 SqlSession SqlSession是一个接口,它有两个实现类: - DefaultSqlSession:默认实现类 - SqlSessionManager:已经弃用的实现类,所以我们不需要关注他

杨海吉 1173

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Mybatis 批量操作多种实现总结

批量操作新增 1.方式一(常用) <!-- 批量新增--> <insert id="batchSave" parameterType="java.util.List"> INSERT INTO lp_user_test_batch ( id, user_id, user_name, user_age, type, create_time, update_time ) VALUES &

myStyle的博客 4402

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

手写MyBatis第104弹:SqlSession从工厂构建到执行器选择的深度剖析

本文深入解析MyBatis框架中SqlSession的创建过程,从SqlSessionFactoryBuilder构建到Executor选择策略的全链路分析。文章详细剖析了配置解析、事务初始化、执行器选择等核心环节,包括SimpleExecutor、ReuseExecutor、BatchExecutor的执行特性对比,以及CachingExecutor的缓存机制。同时探讨了插件机制在SqlSession创建中的增强作用,并提供了事务配置和连接池调优的实践建议。通过源码级分析,揭示了MyBatis在灵活性、性

源码获取 | 运行部署 | 定制二开修改,如果回复不及时请耐心等待,请见谅。 1055

MyBatis SqlSession深度解析

场景问题:在一个大型企业级应用中,开发团队使用MyBatis框架进行数据库操作。在项目初期,团队成员对MyBatis的使用还比较陌生,经常遇到数据库连接频繁关闭、数据查询效率低下等问题。这些问题不仅影响了项目的开发进度,还可能导致数据不一致和系统稳定性下降。为了解决这些问题,团队需要深入了解MyBatis的核心知识点,特别是SqlSession级别的内容。知识点介绍:MyBatis核心知识点之SqlSession级别:SqlSession概述,是MyBatis框架中一个至关重要的概念。

AIHacksCash的博客 1124

MyBatis SqlSession核心机制解析

在开发过程中,我们常常需要与数据库进行交互,执行SQL语句以获取或更新数据。然而,每次与数据库交互都需要创建和关闭连接,这样的操作既繁琐又容易出错。为了解决这个问题,MyBatis引入了SqlSession这一核心概念,它简化了数据库交互的过程,提高了开发效率。下面,我们将深入探讨MyBatis核心知识点之SqlSession:概述。场景问题:假设我们正在开发一个电商系统,系统需要频繁地与数据库进行交互,如查询商品信息、更新库存等。

我是Java程序员廖志伟,感谢朋友们的支持!不定期贡献一篇高品质、过万文字、图文并茂且附有视频解说、满载代码示例注释的良心之作,坚决杜绝粗制乱造。 1092

mybatis SqlSession事务

mybatis版本:3.4.6。 mybatis默认的SqlSessionFactory是DefaultSqlSessionFactory,它openSession()的源码是: public SqlSession openSession() { return this.openSessionFromDataSource(this.configuration.ge...

weixin_30446613的博客 2174
上一篇: MySQL中Spring管理的事务开启后不提交引起的事故
下一篇: MySQL、MariaDB、TiDB时间小数秒四舍五入与截断
adrninistrat0r
博客等级 码龄18年 395粉丝 136原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值