Spring、MyBatis、Druid、MySQL使用事务执行SQL语句分析

Druid数据库连接 | Spring Boot 集成 Druid实现数据库连接和完善的SQL执行监控 我们知道,应用系统最频繁,最主要的操作还是数据库的操作,所以数据库的性能和安全对于整个系统平台的重要性不言而喻。为了提高数据库性能,我们可以使用数据库连接池,有时候我们需要增加一些列的日志或是数据库性能监控工具来确保数据库的性能,同时还得防范数据库的SQL注入等安全问题。 所以,今天我们来介绍一款集数据库连接池、数据库监控、SQL执行日志于一身的神器:Druid。 一、Druid简介 Druid 是阿里巴巴开源平台上的一个数据库连接池项目,它结合了 C3P0、DBCP 等数据库池的优点,同时加入了S 阅读详情

1. 前言

使用MySQL数据库时,使用事务与不使用事务相比,出现问题时排查更复杂。

不使用事务时,客户端只需要请求MySQL服务一次(只考虑显式执行的SQL语句);使用事务时,客户端至少需要请求MySQL服务四次(开启事务、执行SQL语句、提交/回滚事务、恢复自动提交)。

在Java中存在一些用法会导致事务失效,有的问题比较明显可以较快定位,有的问题隐藏较深可能需要较长时间排查。

因此需要对MySQL的事务执行原理进行分析,并整理用于排查事务相关问题的快速有效的方法。

在Java应用中访问MySQL服务时,涉及Java应用、网络传输、MySQL服务这三层,在每一层都可以对执行的SQL语句与事务操作进行监控与观测,涉及的内容如下图所示:

在这里插入图片描述

以下对Java应用使用Spring、MyBatis、Druid、MySQL Connector,使用事务执行SQL语句的情况进行分析。

可参考以下相关内容:

内容链接
MySQL SQL语句与事务执行及日志分析https://blog.youkuaiyun.com/a82514921/article/details/126563449
tcpdump、Wireshark抓包分析MySQL SQL语句与事务执行https://blog.youkuaiyun.com/a82514921/article/details/126563471
Spring、MyBatis、Druid、MySQL不使用事务执行SQL语句分析https://blog.youkuaiyun.com/a82514921/article/details/126563515
Spring、MyBatis、Druid、MySQL使用事务执行SQL语句分析https://blog.youkuaiyun.com/a82514921/article/details/126563542
Spring、MyBatis、Druid、MySQL执行SQL语句与事务监控https://blog.youkuaiyun.com/a82514921/article/details/126563558
数据源使用错误导致MySQL事务失效分析https://blog.youkuaiyun.com/a82514921/article/details/126563573
TiDB乐观事务、悲观事务模型验证https://blog.youkuaiyun.com/a82514921/article/details/126563502

2. 使用事务执行SQL语句大致阶段

在使用事务执行SQL语句时,每次执行SQL语句时的大致阶段如下:

从连接池借出连接(可能需要创建新连接)
关闭自动提交
执行SQL语句1
执行SQL语句n
提交/回滚事务
开启自动提交
归还连接至连接池

如下图所示:

在这里插入图片描述

使用事务执行SQL语句时,事务管理主要通过Spring完成,SQL语句执行主要通过MyBatis完成

3. 不使用与使用事务执行SQL语句的区别

3.1. SQL语句执行阶段的区别

  • 不使用事务执行SQL语句

当不使用事务执行SQL语句时,每次执行SQL语句时,都需要先从连接池借出连接,再执行SQL语句,最后归还连接至连接池;

SQL语句会自动提交,不需要执行事务相关的阶段。

  • 使用事务执行SQL语句

当使用事务执行SQL语句时,除了以上阶段外,还需要执行事务相关的阶段,包括:关闭自动提交、提交/回滚事务、开启自动提交等。

3.2. 对系统变量autocommit使用的区别

  • 不使用事务执行SQL语句

当不使用事务执行SQL语句时,可一直使用MySQL系统变量autocommit的默认值(开启),不需要对系统变量autocommit进行修改与恢复;

  • 使用事务执行SQL语句

当使用事务执行SQL语句时,需要先关闭当前连接会话的autocommit,以开启事务,再执行SQL语句;

在归还连接至连接池之前,需要开启当前连接会话的autocommit,使该系统变量恢复为默认值开启(保证当前会话能够继续正常使用)。

3.3. 对数据库连接使用的区别

在执行SQL语句时,无论是否使用事务,在从连接池借出连接,到归还连接至连接池这两个阶段之间的时间段,对应的连接是被当前线程独占的。

  • 不使用事务执行SQL语句

当不使用事务执行SQL语句时,对于所使用的数据库连接没有特殊要求,每次执行SQL语句时从连接池获取一个可用的连接即可;

每条SQL语句执行完毕后,即可归还连接至连接池;

从连接池借出连接、归还连接至连接池的操作,通过MyBatis完成。

  • 使用事务执行SQL语句

当使用事务执行SQL语句时,需要使用同一个连接执行当前事务的所有SQL语句(一条或多条);

执行完所有的SQL语句(以及提交/回滚事务、开启自动提交)之后,才能归还连接至连接池。

从连接池借出连接、归还连接至连接池的操作,通过Spring完成。

4. 示例项目

以下使用的示例项目下载地址为:https://github.com/Adrninistrator/DB-Transaction-test,使用说明可参考“README.md”,

相关的执行日志保存在DB-Transaction-test-log目录中,log-print_stack_trace_off目录中是未打印调用堆栈的日志,log-print_stack_trace_on目录中是打印调用堆栈的日志。

5. 验证环境

  • JDK版本

1.8

  • Spring版本

5.3.20

  • Mybatis版本

org.mybatis:mybatis:3.2.8
org.mybatis:mybatis-spring:1.2.2

  • Druid版本

1.2.10

  • MySQL Connector版本

8.0.29

  • MySQL版本

MariaDB 10.0.36

  • Spring事务传播机制

默认值REQUIRED

6. 通过@Transactional注解使用事务的处理步骤

通过Spring的@Transactional注解使用事务时,与使用事务模板TransactionTemplate存在一些区别。使用@Transactional注解时,会先经过Spring AOP的相关处理,在org.springframework.transaction.interceptor.TransactionAspectSupport类的invokeWithinTransaction()方法中,会进行事务相关的以下处理:

调用TransactionAttributeSource tas的getTransactionAttribute()方法,在该方法中获取@Transactional注解所在方法上的事务属性TransactionAttribute txAttr;

调用determineTransactionManager()方法,在该方法中根据事务属性txAttr获取事务管理器TransactionManager tm。在determineTransactionManager()方法中,优先使用@Transactional注解的value或transactionManager属性指定的事务管理器的名称;若未指定时则使用默认的事务管理器,默认的事务管理器名称可通过Spring XML中“tx:annotation-driven”元素的“transaction-manager”属性指定;

在示例项目中指定的事务管理器类型为org.springframework.jdbc.datasource.DataSourceTransactionManager,未实现ReactiveTransactionManager接口,因此不会执行满足“this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager”判断条件时才会执行的代码;

调用asPlatformTransactionManager()方法,在该方法中检查以上获取的事务管理器TransactionManager tm应为null,或有实现PlatformTransactionManager接口,不满足时会抛出异常。在示例项目中使用的事务管理器DataSourceTransactionManager有实现PlatformTransactionManager接口,因此当前方法不会抛出异常,可以继续执行;

在示例项目中使用的事务管理器类型为DataSourceTransactionManager,未实现CallbackPreferringPlatformTransactionManager接口,因此会执行满足“txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)”判断条件时才会执行的代码;

调用createTransactionIfNecessary()方法,在该方法中调用prepareTransactionInfo()方法,经过以上处理后,获得TransactionInfo类型的对象txInfo,该对象中的transactionManager成员变量为当前使用的事务管理器;

调用invocation.proceedWithInvocation()方法,执行@Transactional注解所在的需要在事务中执行的自定义方法;

调用自定义方法若出现异常,会调用completeTransactionAfterThrowing()方法,在该方法中调用当前使用的事务管理器的rollback()或commit()方法,进行事务回滚或事务提交,详细说明见后续内容;

调用自定义方法未出现异常时,调用commitTransactionAfterReturning()方法,在该方法中调用txInfo.getTransactionManager().commit()方法,即调用当前使用的事务管理器DataSourceTransactionManager的commit()方法进行事务提交。

以上步骤对应的TransactionAspectSupport.invokeWithinTransaction()方法代码如下:

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
    final InvocationCallback invocation) throws Throwable {

  // If the transaction attribute is null, the method is non-transactional.
  TransactionAttributeSource tas = getTransactionAttributeSource();
  final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
  final TransactionManager tm = determineTransactionManager(txAttr);

  if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
      ...
  }

  PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
  final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

  if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
    // Standard transaction demarcation with getTransaction and commit/rollback calls.
    TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

    Object retVal;
    try {
      // This is an around advice: Invoke the next interceptor in the chain.
      // This will normally result in a target object being invoked.
      retVal = invocation.proceedWithInvocation();
    }
    catch (Throwable ex) {
      // target invocation exception
      completeTransactionAfterThrowing(txInfo, ex);
      throw ex;
    }
    finally {
      cleanupTransactionInfo(txInfo);
    }

    if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
      ...
    }

    commitTransactionAfterReturning(txInfo);
    return retVal;
  }
  ...

7. 使用事务执行SQL语句详细过程

使用事务执行SQL语句时,可以分为以下三个主要的阶段:

  • 从连接池借出连接、关闭自动提交阶段,由Spring完成;

  • 执行SQL语句阶段,由MyBatis完成;

  • 提交/回滚事务、开启自动提交、归还连接至连接池阶段,由Spring完成。

7.1. 创建连接

使用事务执行SQL语句,在创建连接时,与“Spring、MyBatis、Druid、MySQL不使用事务执行SQL语句分析”中的内容类似,略。

7.2. 执行SQL语句前Spring的处理

使用事务执行SQL语句时,执行SQL语句之前,包含以下操作,通过Spring完成,主要步骤在DataSourceTransactionManager及其父类AbstractPlatformTransactionManager中。

7.2.1. 从连接池借出连接

  • 使用@Transactional注解的处理

使用@Transactional注解时,从项目代码开始,到Spring的AbstractPlatformTransactionManager.getTransaction()方法,调用堆栈如下:

test.db.transaction.normal.commit.transaction_manager.TestNormalCommit_Ds1Mapper_Ds1TM.doTest(TestNormalCommit_Ds1Mapper_Ds1TM:15)
test.db.transaction.service.TransactionService$$EnhancerBySpringCGLIB$$26f4c143.runByTransactionalDs1TM(<generated>)
org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy:708)
org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy:763)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation:186)
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor:119)
org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport:382)
org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport:595)
org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager:373)

从以上调用堆栈可以看到,执行过程经过了Spring AOP增强的类(EnhancerBySpringCGLIB),也经过了以上描述的TransactionAspectSupport.invokeWithinTransaction()方法。

  • 使用TransactionTemplate的处理

使用TransactionTemplate时,从项目代码开始,到AbstractPlatformTransactionManager.getTransaction()方法,调用堆栈如下:

test.db.transaction.service.TransactionService.runByTransactionTemplate(TransactionService:79)
org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate:137)
org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager:373)

从以上调用堆栈可以看到,执行过程中不需要经过Spring AOP处理,在调用TransactionTemplate.execute()方法后,就调用了AbstractPlatformTransactionManager.getTransaction()方法方法。

  • 后续步骤相同的处理

使用@Transactional注解或TransactionTemplate时,后续的步骤相同,从AbstractPlatformTransactionManager.getTransaction()方法开始,到Druid从连接池借出连接,调用堆栈如下:

org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager:373)
org.springframework.transaction.support.AbstractPlatformTransactionManager.startTransaction(AbstractPlatformTransactionManager:400)
org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager:265)
com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource:100)
com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource:1399)
com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource:1407)
com.alibaba.druid.filter.FilterChainImpl.dataSource_connect(FilterChainImpl:5055)
test.db.druid_filter.DruidMonitorFilter.dataSource_getConnection(DruidMonitorFilter:59)
com.alibaba.druid.filter.FilterAdapter.dataSource_getConnection(FilterAdapter:2756)
com.alibaba.druid.filter.FilterChainImpl.dataSource_connect(FilterChainImpl:5059)
com.alibaba.druid.pool.DruidDataSource.getConnectionDirect(DruidDataSource:1429)
com.alibaba.druid.pool.DruidDataSource.getConnectionInternal(DruidDataSource:1783)
com.alibaba.druid.pool.DruidPooledConnection.<init>(DruidPooledConnection:79)

7.2.2. 关闭自动提交

使用事务执行SQL语句时,在从连接池借出连接后,需要关闭自动提交,使当前会话开启事务。

从AbstractPlatformTransactionManager.startTransaction()方法,经过Druid,到MySQL Connector通过NativeProtocol.sendQueryPacket()方法向MySQL发送SQL语句,调用堆栈如下:

org.springframework.transaction.support.AbstractPlatformTransactionManager.startTransaction(AbstractPlatformTransactionManager:400)
org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager:287)
com.alibaba.druid.pool.DruidPooledConnection.setAutoCommit(DruidPooledConnection:740)
com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl.setAutoCommit(ConnectionProxyImpl:429)
com.alibaba.druid.filter.FilterChainImpl.connection_setAutoCommit(FilterChainImpl:733)
test.db.druid_filter.DruidMonitorFilter.connection_setAutoCommit(DruidMonitorFilter:259)
com.alibaba.druid.filter.FilterAdapter.connection_setAutoCommit(FilterAdapter:986)
com.alibaba.druid.filter.FilterChainImpl.connection_setAutoCommit(FilterChainImpl:738)
com.mysql.cj.jdbc.ConnectionImpl.setAutoCommit(ConnectionImpl:2033)
com.mysql.cj.NativeSession.execSQL(NativeSession:663)
com.mysql.cj.protocol.a.NativeProtocol.sendQueryString(NativeProtocol:997)
com.mysql.cj.protocol.a.NativeProtocol.sendQueryPacket(NativeProtocol:1051)

在MySQL Connector的ConnectionImpl.setAutoCommit()方法中,可能执行“SET autocommit=1”或“SET autocommit=0”语句。在关闭自动提交时,执行的SQL语句为“SET autocommit=0”。

从MySQL Connector的NativeProtocol.sendQueryPacket()方法,到通过输出流向MySQL服务发送SQL语句,调用堆栈如下:

com.mysql.cj.protocol.a.NativeProtocol.sendQueryPacket(NativeProtocol:1051)
com.mysql.cj.protocol.a.NativeProtocol.sendCommand(NativeProtocol:683)
com.mysql.cj.protocol.a.NativeProtocol.send(NativeProtocol:619)
com.mysql.cj.protocol.a.TimeTrackingPacketSender.send(TimeTrackingPacketSender:50)
com.mysql.cj.protocol.a.SimplePacketSender.send(SimplePacketSender:51)
java.io.FilterOutputStream.write(FilterOutputStream:97)
java.io.BufferedOutputStream.write(BufferedOutputStream:117)

7.2.3. 在ThreadLocal中记录ConnectionHolder

在关闭自动提交之后,执行SQL语句之前,需要在ThreadLocal中记录org.springframework.jdbc.datasource.ConnectionHolder,在该类中保存了数据库连接对象,在后续执行SQL语句时需要使用。

在Spring的DataSourceTransactionManager.doBegin()方法中,会调用TransactionSynchronizationManager.bindResource()方法,在ThreadLocal的Map中记录信息,传入的key类型为javax.sql.DataSource(使用Druid时为com.alibaba.druid.pool.DruidDataSource),value为ConnectionHolder。

7.3. 执行SQL语句时MyBatis的处理

使用事务时,以下执行SQL语句的操作通过MyBatis完成。

7.3.1. 从调用MyBatis的Mapper接口到SimpleExecutor

使用事务执行SQL语句,从调用MyBatis的Mapper接口到SimpleExecutor,与“Spring、MyBatis、Druid、MySQL不使用事务执行SQL语句分析”中的内容类似,略。

7.3.2. 执行第一条SQL语句

在事务中执行第一条SQL语句与执行非第一条SQL语句相比,获取数据库连接的步骤存在区别。

7.3.2.1. 从ThreadLocal中获取ConnectionHolder

在事务中执行第一条SQL语句时,需要从ThreadLocal中获取ConnectionHolder,以获得数据库连接对象。

执行查询操作时,从MyBatis的SimpleExecutor.doQuery()方法开始,到Spring的TransactionSynchronizationManager.doGetResource()方法,调用堆栈如下:

org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor:59)
org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor:72)
org.apache.ibatis.executor.BaseExecutor.getConnection(BaseExecutor:279)
org.mybatis.spring.transaction.SpringManagedTransaction.getConnection(SpringManagedTransaction:67)
org.mybatis.spring.transaction.SpringManagedTransaction.openConnection(SpringManagedTransaction:81)
org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils:80)
org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils:105)
org.springframework.transaction.support.TransactionSynchronizationManager.getResource(TransactionSynchronizationManager:135)
org.springframework.transaction.support.TransactionSynchronizationManager.doGetResource(TransactionSynchronizationManager:157)

执行更新操作时,SimpleExecutor.doUpdate()方法也会调用prepareStatement()方法,后续调用堆栈相同。

在事务中执行第一条SQL语句时,执行到SpringManagedTransaction类的getConnection()方法时,成员变量Connection connection为null,需要调用openConnection()方法打开连接;

SpringManagedTransaction类的相关方法代码如下:

public Connection getConnection() throws SQLException {
  if (this.connection == null) {
    openConnection();
  }
  return this.connection;
}

private void openConnection() throws SQLException {
  this.connection = DataSourceUtils.getConnection(this.dataSource);
  this.autoCommit = this.connection.getAutoCommit();
  this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);

后续经过Spring的DataSourceUtils类,到TransactionSynchronizationManager.doGetResource()方法,从ThreadLocal中根据DataSource获取对应的ConnectionHolder。

7.3.2.2. 在SpringManagedTransaction中记录Connection

如以上所示的SpringManagedTransaction.openConnection()方法的代码,在调用DataSourceUtils.getConnection()方法获取到ConnectionHolder后,会将其记录在成员变量Connection connection中。

7.3.2.3. 执行SQL语句

使用事务执行SQL语句时,与“Spring、MyBatis、Druid、MySQL不使用事务执行SQL语句分析”中的内容类似,略。

7.3.3. 执行非第一条SQL语句

7.3.3.1. 从SpringManagedTransaction中获取Connection

在事务中执行非第一条SQL语句时,需要从SpringManagedTransaction中获取Connection,以获得数据库连接。

执行更新操作时,从MyBatis的SimpleExecutor.doUpdate()方法开始,到SpringManagedTransaction.getConnection()方法,调用堆栈如下:

org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor:47)
org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor:72)
org.apache.ibatis.executor.BaseExecutor.getConnection(BaseExecutor:279)
org.mybatis.spring.transaction.SpringManagedTransaction.getConnection(SpringManagedTransaction:69)

执行查询操作时,SimpleExecutor.doQuery()方法也会调用prepareStatement()方法,后续调用堆栈相同。

如以上所示的SpringManagedTransaction.getConnection()方法的代码,在事务中执行非第一条SQL语句时,成员变量Connection connection非null,会直接返回其值,不会调用openConnection()方法。

7.3.3.2. 执行SQL语句

略。

7.4. 执行SQL语句后Spring的处理

使用事务执行SQL语句时,执行SQL语句之后,以下操作通过Spring完成,主要步骤在AbstractPlatformTransactionManager.commit()/rollback()方法中,分别对应提交事务/回滚事务的场景。

7.4.1. 提交事务

  • 使用@Transactional注解的处理

使用@Transactional注解时,从项目代码开始,到AbstractPlatformTransactionManager.commit()方法,调用堆栈如下:

test.db.transaction.normal.commit.transaction_manager.TestNormalCommit_Ds1Mapper_Ds1TM.doTest(TestNormalCommit_Ds1Mapper_Ds1TM:15)
test.db.transaction.service.TransactionService$$EnhancerBySpringCGLIB$$26f4c143.runByTransactionalDs1TM(<generated>)
org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy:708)
org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy:763)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation:186)
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor:119)
org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport:407)
org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport:654)
org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager:711)
  • 使用TransactionTemplate的处理

使用TransactionTemplate时,从项目代码开始,到AbstractPlatformTransactionManager.commit()方法,调用堆栈如下:

test.db.transaction.service.TransactionService.runByTransactionTemplate(TransactionService:79)
org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate:152)
org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager:711)
  • 后续步骤相同的处理

使用@Transactional注解或TransactionTemplate时,后续的步骤相同,从AbstractPlatformTransactionManager.commit()方法开始,经过Druid,到MySQL Connector向MySQL发送SQL语句,调用堆栈如下:

org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager:711)
org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager:743)
org.springframework.jdbc.datasource.DataSourceTransactionManager.doCommit(DataSourceTransactionManager:333)
com.alibaba.druid.pool.DruidPooledConnection.commit(DruidPooledConnection:782)
com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl.commit(ConnectionProxyImpl:122)
com.alibaba.druid.filter.FilterChainImpl.connection_commit(FilterChainImpl:194)
test.db.druid_filter.DruidMonitorFilter.connection_commit(DruidMonitorFilter:198)
com.alibaba.druid.filter.FilterAdapter.connection_commit(FilterAdapter:782)
com.alibaba.druid.filter.FilterChainImpl.connection_commit(FilterChainImpl:199)
com.mysql.cj.jdbc.ConnectionImpl.commit(ConnectionImpl:794)
com.mysql.cj.NativeSession.execSQL(NativeSession:663)
com.mysql.cj.protocol.a.NativeProtocol.sendQueryString(NativeProtocol:997)
com.mysql.cj.protocol.a.NativeProtocol.sendQueryPacket(NativeProtocol:1051)

在MySQL Connector的ConnectionImpl.commit()方法中,会执行“commit”语句,用于提交事务。

7.4.2. 回滚事务

  • 使用@Transactional注解的处理

使用@Transactional注解时,从项目代码开始,到AbstractPlatformTransactionManager.rollback()方法,调用堆栈如下:

test.db.transaction.normal.rollback.transaction_manager.TestNormalRollback_Ds1Mapper_Ds1TM.lambda$doTest$0(TestNormalRollback_Ds1Mapper_Ds1TM:16)
test.db.transaction.service.TransactionService$$EnhancerBySpringCGLIB$$26f4c143.runByTransactionalDs1TM(<generated>)
org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy:708)
org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy:763)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation:186)
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor:119)
org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport:392)
org.springframework.transaction.interceptor.TransactionAspectSupport.completeTransactionAfterThrowing(TransactionAspectSupport:672)
org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager:809)

在TransactionAspectSupport.completeTransactionAfterThrowing()方法中,判断以下两个条件是否都满足:

a. 参数中的TransactionInfo txInfo对象的transactionAttribute非空;

b. txInfo.transactionAttribute.rollbackOn(ex)方法返回值为true。

当以上判断条件都满足时,调用txInfo.getTransactionManager().rollback()方法,通过当前使用的事务管理器的rollback()方法回滚事务;

当以上判断条件存在不满足时,调用txInfo.getTransactionManager().commit()方法,通过当前使用的事务管理器的commit()方法提交事务。

以上rollbackOn()方法用于判断出现异常时是否需要使事务回滚,当@Transactional注解的rollbackFor、rollbackForClassName、noRollbackFor、noRollbackForClassName属性与异常对象ex的类型匹配时,代表需要回滚事务;

若以上不匹配,再通过RuleBasedTransactionAttribute的父类DefaultTransactionAttribute的rollbackOn()方法,判断异常对象是否满足RuntimeException、Error类型,若满足则代表需要回滚事务;

若以上都不满足,则代表不回滚事务。

根据以上内容可知,通过@Transactional注解使用事务时,若出现异常,对于需要回滚的异常类型,会使事务回滚;对于其他异常类型,事务会提交。

TransactionAspectSupport.completeTransactionAfterThrowing()方法的代码如下:

protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
  if (txInfo != null && txInfo.getTransactionStatus() != null) {
    if (logger.isTraceEnabled()) {
      logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
          "] after exception: " + ex);
    }
    if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
      try {
        txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
      }
      catch (...) {
        ...
      }
    }
    else {
      // We don't roll back on this exception.
      // Will still roll back if TransactionStatus.isRollbackOnly() is true.
      try {
        txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
      }
  • 使用TransactionTemplate的处理

使用TransactionTemplate时,从项目代码开始,到AbstractPlatformTransactionManager.rollback()方法,调用堆栈如下:

test.db.transaction.service.TransactionService.runByTransactionTemplate(TransactionService:79)
org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate:144)
org.springframework.transaction.support.TransactionTemplate.rollbackOnException(TransactionTemplate:168)
org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager:809)

在Spring的TransactionTemplate.execute()方法中,在调用TransactionCallback<T> action参数的doInTransaction()方法,执行需要在事务中执行的自定义方法时,会进行异常处理:

当捕获到满足RuntimeException或Error类型的异常时,调用rollbackOnException()方法进行回滚处理;

当捕获到其他类型的异常时,在调用rollbackOnException()方法进行回滚处理后,还会抛出UndeclaredThrowableException异常。

TransactionTemplate.execute()方法的代码如下:

public <T> T execute(TransactionCallback<T> action) throws TransactionException {
  Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");

  if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
    return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
  }
  else {
    TransactionStatus status = this.transactionManager.getTransaction(this);
    T result;
    try {
      result = action.doInTransaction(status);
    }
    catch (RuntimeException | Error ex) {
      // Transactional code threw application exception -> rollback
      rollbackOnException(status, ex);
      throw ex;
    }
    catch (Throwable ex) {
      // Transactional code threw unexpected exception -> rollback
      rollbackOnException(status, ex);
      throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
    }
    this.transactionManager.commit(status);
    return result;
  }
}
  • 后续步骤相同的处理

使用@Transactional注解或TransactionTemplate时,后续的步骤相同,从AbstractPlatformTransactionManager.rollback()方法开始,到MySQL Connector向MySQL发送SQL语句,调用堆栈如下:

org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager:809)
org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager:835)
org.springframework.jdbc.datasource.DataSourceTransactionManager.doRollback(DataSourceTransactionManager:348)
com.alibaba.druid.pool.DruidPooledConnection.rollback(DruidPooledConnection:814)
com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl.rollback(ConnectionProxyImpl:399)
com.alibaba.druid.filter.FilterChainImpl.connection_rollback(FilterChainImpl:709)
test.db.druid_filter.DruidMonitorFilter.connection_rollback(DruidMonitorFilter:216)
com.alibaba.druid.filter.FilterAdapter.connection_rollback(FilterAdapter:974)
com.alibaba.druid.filter.FilterChainImpl.connection_rollback(FilterChainImpl:714)
com.mysql.cj.jdbc.ConnectionImpl.rollback(ConnectionImpl:1824)
com.mysql.cj.jdbc.ConnectionImpl.rollbackNoChecks(ConnectionImpl:1927)
com.mysql.cj.NativeSession.execSQL(NativeSession:663)
com.mysql.cj.protocol.a.NativeProtocol.sendQueryString(NativeProtocol:997)
com.mysql.cj.protocol.a.NativeProtocol.sendQueryPacket(NativeProtocol:1051)
com.mysql.cj.protocol.a.NativeProtocol.sendCommand(NativeProtocol:635)

在MySQL Connector的ConnectionImpl.rollbackNoChecks()方法中,会执行“rollback”语句,用于回滚事务。

7.4.3. 清理ThreadLocal中的ConnectionHolder

在提交事务或回滚事务时,都会清理ThreadLocal中的ConnectionHolder,提交事务与回滚事务分别调用AbstractPlatformTransactionManager类的commit()/rollback()方法,后续都会调用到cleanupAfterCompletion()方法。

从AbstractPlatformTransactionManager类的commit()方法到cleanupAfterCompletion()方法的调用堆栈如下:

org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager:711)
org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager:790)
org.springframework.transaction.support.AbstractPlatformTransactionManager.cleanupAfterCompletion(AbstractPlatformTransactionManager:992)

从AbstractPlatformTransactionManager类的rollback()方法到cleanupAfterCompletion()方法的调用堆栈如下:

org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager:809)
org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager:875)
org.springframework.transaction.support.AbstractPlatformTransactionManager.cleanupAfterCompletion(AbstractPlatformTransactionManager:992)

从AbstractPlatformTransactionManager.cleanupAfterCompletion()方法到TransactionSynchronizationManager.unbindResource()方法的调用堆栈如下:

org.springframework.transaction.support.AbstractPlatformTransactionManager.cleanupAfterCompletion(AbstractPlatformTransactionManager:992)
org.springframework.jdbc.datasource.DataSourceTransactionManager.doCleanupAfterCompletion(DataSourceTransactionManager:371)
org.springframework.transaction.support.TransactionSynchronizationManager.unbindResource(TransactionSynchronizationManager:197)

在调用TransactionSynchronizationManager.unbindResource()方法时,传入参数key的类型为com.alibaba.druid.pool.DruidDataSource,会将ThreadLocal的Map中以上key对应的键值对清理,对应的value类型为ConnectionHolder。

7.4.4. 开启自动提交

在归还连接至连接池之前,需要开启自动提交,用于将当前会话的系统变量autocommit恢复默认值。

从AbstractPlatformTransactionManager.cleanupAfterCompletion()方法开始,经过Druid,到MySQL Connector向MySQL发送SQL语句,调用堆栈如下:

org.springframework.transaction.support.AbstractPlatformTransactionManager.cleanupAfterCompletion(AbstractPlatformTransactionManager:992)
org.springframework.jdbc.datasource.DataSourceTransactionManager.doCleanupAfterCompletion(DataSourceTransactionManager:378)
com.alibaba.druid.pool.DruidPooledConnection.setAutoCommit(DruidPooledConnection:740)
com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl.setAutoCommit(ConnectionProxyImpl:429)
com.alibaba.druid.filter.FilterChainImpl.connection_setAutoCommit(FilterChainImpl:733)
test.db.druid_filter.DruidMonitorFilter.connection_setAutoCommit(DruidMonitorFilter:259)
com.alibaba.druid.filter.FilterAdapter.connection_setAutoCommit(FilterAdapter:986)
com.alibaba.druid.filter.FilterChainImpl.connection_setAutoCommit(FilterChainImpl:738)
com.mysql.cj.jdbc.ConnectionImpl.setAutoCommit(ConnectionImpl:2033)
com.mysql.cj.NativeSession.execSQL(NativeSession:663)
com.mysql.cj.protocol.a.NativeProtocol.sendQueryString(NativeProtocol:997)
com.mysql.cj.protocol.a.NativeProtocol.sendQueryPacket(NativeProtocol:1051)

在MySQL Connector的ConnectionImpl.setAutoCommit()方法中,在开启自动提交时,会执行“SET autocommit=1”语句。

7.4.5. 归还连接至连接池

从AbstractPlatformTransactionManager.cleanupAfterCompletion()方法开始,到Druid归还连接至连接池,调用堆栈如下:

org.springframework.transaction.support.AbstractPlatformTransactionManager.cleanupAfterCompletion(AbstractPlatformTransactionManager:992)
org.springframework.jdbc.datasource.DataSourceTransactionManager.doCleanupAfterCompletion(DataSourceTransactionManager:391)
org.springframework.jdbc.datasource.DataSourceUtils.releaseConnection(DataSourceUtils:360)
org.springframework.jdbc.datasource.DataSourceUtils.doReleaseConnection(DataSourceUtils:393)
org.springframework.jdbc.datasource.DataSourceUtils.doCloseConnection(DataSourceUtils:406)
com.alibaba.druid.pool.DruidPooledConnection.close(DruidPooledConnection:286)
com.alibaba.druid.filter.FilterChainImpl.dataSource_recycle(FilterChainImpl:5045)
test.db.druid_filter.DruidMonitorFilter.dataSource_releaseConnection(DruidMonitorFilter:119)
com.alibaba.druid.filter.FilterAdapter.dataSource_releaseConnection(FilterAdapter:2750)
com.alibaba.druid.filter.FilterChainImpl.dataSource_recycle(FilterChainImpl:5049)
com.alibaba.druid.pool.DruidPooledConnection.recycle(DruidPooledConnection:351)
com.alibaba.druid.pool.DruidDataSource.recycle(DruidDataSource:1951)
com.alibaba.druid.pool.DruidConnectionHolder.reset(DruidConnectionHolder:296)

7.5. 关闭连接

使用事务执行SQL语句,在关闭连接时,与“Spring、MyBatis、Druid、MySQL不使用事务执行SQL语句分析”中的内容类似,略。

druid mysql 事务处理_Springboot+Mybatis+Druid 实现多数据源,与事务管理 1.需求一个主库的数据已经不能满足我们生产需求,需要额外的辅助库集成到项目里来获取所需的数据。或是将读写分开为两个库,完成自有的逻辑。2.实现原理如同在Springboot中配置一个数据源一样,我们需要一个主数据源,然后再用同样的方法配置另外一个数据源作为辅,两个数据源有各自独立的DataSourceTransactionManager与SqlSessionFactroy。3.具体的实现1) po... 阅读详情

相关推荐

mysql+Spring + SpringMVC + Druid + MyBatisi源码/框架分析-druid参数

Spring + SpringMVC + Druid + MyBatis ------------- sqlSessionFactory 提前加载找不到${jdbc.username}------------- 参考:https://www.cnblogs.com/java-class/p/6229920.html a.MapperScannerConfigurer 提前初始化导致 spring 注入配置文件失效 <bean class="org.mybatis.spri...

qq_15458763的博客 366

mybatis中的自动提交事务的设置

通过源码、在mybatis中只要在创建SQLSession时设置里面的值为true就可以了。

m0_67400972的博客 2185

老年人教程:MyBatis拦截器动态修改SQL(更新与插入)语句

注:本文编写与 2019年12月17日, 内容可能存在时效性问题。 数据库使用MySQL5.7 集成于SpringBoot 2.0.X , 引用国产的开源工具类Hutool 本教程建议显示大纲视图 配合食用 一 、简介 设定使用场景 任意 insert 、update 语句,都需要记录下语句的操作用户(CREATOR), 但由于系统早期设计不规范,大量SQL语句中,部分有写入CREAT...

波特多的博客 4530

SpringBoot 连接mysql踩到的坑

首先对于用SpringBoot连接mysql我先说明一下pom文件中需要引入那些jar: &lt;dependency&gt; &lt;groupId&gt;mysql&lt;/groupId&gt; &lt;artifactId&gt;mysql-connector-java&lt;/artifactId&gt; &lt;version&gt;6.0.6...

wangliang369的博客 5393

Druid连接池与Spring AOP监控配置实战:实现业务方法级SQL追踪

在Java企业级应用开发中,数据库连接池和面向切面编程(AOP)是构建高性能、可维护系统的两大核心技术。数据库连接池负责高效管理数据库连接资源,而Spring AOP则通过拦截特定连接点,实现了日志、事务、监控等横切关注点的统一管理。将两者结合,其技术价值在于能够将JDBC层面的SQL执行监控,与业务逻辑层的方法调用进行精准关联,从而构建从业务方法到具体SQL的完整可观测链路。这一融合方案尤其适用于需要深度分析性能瓶颈、审计数据操作行为的应用场景,例如高并发电商系统或复杂的企业级应用。通过配置Druid的`

aocaiti5781的博客 690

SSM+MySQL农场信息管理系统实战:从建库到避坑的完整落地指南

在农业信息化与农产品溯源需求持续增长的背景下,农场信息管理系统需要处理地块、批次、农事记录、投入品出入库等多实体间的复杂关联关系。SSM框架通过Spring管理事务与依赖、SpringMVC分发请求、MyBatis将SQL显式收拢,配合MySQL 8的窗口函数与JSON类型,能够有效支撑这类字段频繁调整、报表SQL反复优化的业务场景。相比全自动ORM,MyBatis的XML映射让SQL可控可调,避免N+1查询与深分页性能陷阱;Druid连接池的空闲检测机制则解决了MySQL 8小时断连的经典问题。从地块录入

weixin_34239592的博客 367

mybatis结合spring执行Sql的流程

mybatis执行Sql的流程 首先讲上一篇出现过的一段代码new SqlSessionTemplate public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) { if (!this.externalSqlSession) { this.sqlSession = new SqlSessionTemplate(sqlSessionFactory); } } 进入new SqlSessio

a429095958的博客 606

Spring Boot + MyBatis + Druid整合实践项目

本文还有配套的精品资源,点击获取 简介:本示例项目"spring-boot-mybatis-druid.7z"结合了Spring Boot、MyBatis和Druid数据源,演示了在Spring Boot框架中整合这些组件来构建一个基于MySQL 5.6的应用程序。项目包含了完整配置文件、源代码、数据库脚本等,旨在帮助开发者理解和学习如何搭建、运行此类系统。关键知识点涵盖S...

weixin_32311823的博客 1025

Spring、MyBatis、Druid、MySQL不使用事务执行SQL语句分析

使用MySQL数据库时,使用事务与不使用事务相比,出现问题时排查更复杂。不使用事务时,客户端只需要请求MySQL服务一次(只考虑显式执行的SQL语句);使用事务时,客户端至少需要请求MySQL服务四次(开启事务、执行SQL语句、提交/回滚事务、恢复自动提交)。在Java中存在一些用法会导致事务失效,有的问题比较明显可以较快定位,有的问题隐藏较深可能需要较长时间排查。因此需要对MySQL的事务执行原理进行分析,并整理用于排查事务相关问题的快速有效的方法。在Java应用中访问MySQL服务时,涉及Java应用、

adrninistrat0r的博客 2025

别再硬啃理论了!用Simulink双脉冲实验,5分钟搞懂MOSFET二极管反向恢复

本文通过Simulink双脉冲实验仿真,帮助电力电子学习者快速理解MOSFET二极管反向恢复特性。文章详细介绍了实验搭建步骤、关键参数配置及波形解析,将抽象理论转化为可视波形,大幅提升学习效率。特别适合需要直观理解反向恢复过程的工程师和学生。

weixin_30918633的博客 955

LVGL配置文件lv_conf.h详解

lv_conf.h是一个用户级别的文件,它不属于内核的部分,因此,在不同的工程中,该文件有可能存在差异。lv_conf.h文件具有两大功能:(1)配置功能:内存、屏幕刷新周期、输入设备的读取周期,等等;(2)裁剪功能:使能失能某些功能,有效地优化Flash的分配。

qq_28576837的博客 5560

Spring、MyBatis、Druid、MySQL执行SQL语句与事务监控

Druid支持使用自定义Filter,可对SQL语句与事务执行按照需要进行监控。使用Druid自定义Filter监控SQL语句与事务执行的效果,可参考“数据源使用错误导致MySQL事务失效分析”。在Spring XML中,可通过以下方式,在“com.alibaba.druid.pool.DruidDataSource”对应的bean中配置Druid自定义Filter。上类FilterEventAdapter为FilterAdapter的子类。...

adrninistrat0r的博客 1886

【初阶】手把手教你轻松上手Denodo | 连接数据库并创建基本视图 (二)

在本教程的第二部分,我们将涵盖:连接到数据库,与创建基本视图。

Denodo的博客 1106

【SpringBoot框架篇】12.使用druid的monitor工具查看sql执行性能

使用druid的monitor工具查看sql执行性能

皓亮君的博客 8456

AI大模型应用性能核心指标:TTFT 与 TPOT 详解

这两个指标专门衡量大模型流式响应性能,是评估用户体验的关键指标。· 是什么:从请求到第一个输出的等待时间· 为什么重要:决定用户的第一印象和响应感知· 优化方向:模型加载、预处理、冷启动优化· 行业标准:最好<500ms,可接受<1.5s· 是什么:每个输出token的平均生成时间· 为什么重要:决定流式输出的流畅度和总完成时间· 优化方向:推理引擎、内存带宽、批处理优化· 行业标准:最好<50ms/token,可接受<100ms/token在Dify/大模型应用中的意义。

lovehu6686的博客 3968

基于互联网的智能旧衣回收箱设计与实现

本文介绍了基于嵌入式系统的智能旧衣回收箱的设计与实现,涵盖了硬件设计、软件开发、图像识别、物联网连接等方面的内容。通过利用最新的技术,如图像识别、物联网和云计算,实现了智能、便捷的旧衣物回收系统。未来,随着技术的不断进步,智能回收系统将会在环保领域发挥更大的作用。

2201_76125393的博客 908

SpringBoot使用Mybatis执行多条SQL

在SpringBoot中实现Mybatis执行多条SQL,先Google了一波,发现只需要在连接Mysql的url后面加上这个就可以了: allowMultiQueries=true 添加后的url是这样滴: jdbc:mysql://...:3306/test?useUnicode=true&amp;amp;characterEncoding=gbk&amp;amp;zeroDateTimeBehavior=c...

biubiu2it的博客 5404

(第七章)FAST开发方法

摘要: FAST是一种轻量级、业务驱动的系统分析与开发框架,适用于中小型项目,强调快速交付和组件化开发。其核心包括8个阶段:范围定义、问题分析、需求分析、逻辑设计、决策分析、物理设计、构造测试和安装发布。特点为结构化、用户参与、迭代渐进,适合需求明确且需快速交付的项目。与RUP(重量级)、敏捷(极轻量)相比,FAST更侧重业务分析和模块化开发。软考中可通过口诀“范围问题求逻辑,决策物理构发布”记忆阶段,并掌握五大开发方法(瀑布、原型、FAST、RUP、敏捷)的核心区别及适用场景。

echo的博客 915

解决SpringBoot+Druid+Mybatis Plus 执行MySQL批量插入,更新 报错的问题

项目实际开发中,使用到了MySQL批量插入的语法,在MySQL中执行成功后,移植到项目时发生了问题,语句如下: REPLACE INTO table1( id, works_fusion_id, statistics_date, chapter_number, new_chapter, works_hot, works_like_number, ...

技术博客 6684

100天精通Python(可视化篇)——第109天:Pyecharts绘制各种常用地图(参数说明+代码实战)

100天精通Python(可视化篇)——第109天:Pyecharts绘制各种常用地图(参数说明+代码实战)

努力让自己发光,对的人才能迎着光而来 8万+

十五、【测试执行篇】异步与并发:使用 Celery 实现测试任务的后台执行与结果回调

本文介绍如何使用Celery实现测试任务的异步执行与结果回调,解决同步执行测试计划导致的请求阻塞问题。主要内容包括:Celery的基本概念与工作原理(任务队列、消息中间件、Worker进程),在Django项目中集成Celery的步骤,以及将同步测试逻辑改造为异步任务的方法。

blues_C的博客 711

Spring Boot 使用p6spy 分析MyBatis-Plus 执行sql性能 出现的问题

问题 Caused by: java.lang.IllegalStateException: dbType not support : null, url jdbc:p6spy:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false at com.alibaba.druid.w...

IceStreamLab 2168

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Spring Boot 集成Mybatis Mysql Druid

这次准备使用Spring Boot来集成Mybatis,数据库则使用MySql,数据库连接池采用阿里巴巴的Druid,其实可以用其他连接池的,但是看了好几篇博客都推荐用这个就试了一下。而Mybatis目前有两种配置方式,一种是传统的XML配置,一种是基于注解的配置,在下面我将会简单的介绍一下两种配置方式。

TkmTtT的博客 4786

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

druid 执行sql_Spring Boot从零入门8_mybatis + druid + mysql + workbench + docker 入门

1 简介2 名词术语3 相关技术用法综述4 环境搭建4.1 开发工具4.2 Docker 搭建 MySQL 环境3 手动 MyBatis 映射器 Demo 实现3.1 实现步骤3.2 实现细节4 小结5 参考资料1 简介这篇文章主要学习关系型数据库主流的技术栈,我们使用 Docker 快速搭建一个 MySQL 数据库学习环境,通过 MySQL 官方提供的 Workbench 可视化工具的...

weixin_30957307的博客 300

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

Spring Boot整合MyBatis

整合MyBatis之前,先搭建一个基本的Spring Boot项目开启Spring Boot。然后引入mybatis-spring-boot-starter和数据库连接驱动(这里使用关系型数据库mysql5.7.30)。

wno704的博客 728

SpringBoot集成MySQL数据库:tech-pdai-spring-demos中的JPA与MyBatis最佳实践

tech-pdai-spring-demos项目提供了Spring Framework5/SpringBoot 2.5.x的丰富示例,其中SpringBoot集成MySQL数据库的实现尤为全面,涵盖了JPA和MyBatis两大主流持久层框架的最佳实践。本文将带你快速掌握这两种技术在实际项目中的应用方法。 ## 一、环境准备:MySQL数据库配置指南 在SpringBoot项目中集成MySQL的

gitblog_00194的博客 1113
上一篇: Spring、MyBatis、Druid、MySQL不使用事务执行SQL语句分析
下一篇: Spring、MyBatis、Druid、MySQL执行SQL语句与事务监控
adrninistrat0r
博客等级 码龄18年 395粉丝 136原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值