xml基本配置
<!-- 配置事务通知属性 -->
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED" rollback-for="Exception,RuntimeException,SQLException"/>
<tx:method name="remove*" propagation="REQUIRED" rollback-for="Exception,RuntimeException,SQLException"/>
<tx:method name="edit*" propagation="REQUIRED" rollback-for="Exception,RuntimeException,SQLException"/>
<tx:method name="login" propagation="NOT_SUPPORTED"/>
<tx:method name="query*" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:advisor advice-ref="transactionAdvice" pointcut-ref="transactionPointcut"/>
<aop:aspect ref="dataSource">
<aop:pointcut id="transactionPointcut" expression="execution(public * com.gupaoedu..*.service..*Service.*(..))" />
</aop:aspect>
</aop:config>
package org.springframework.jdbc.datasource;
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, InitializingBean {
@Nullable
private DataSource dataSource;
@Override
protected void doCommit(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Committing JDBC transaction on Connection [" + con + "]");
}
try {
con.commit();
}
catch (SQLException ex) {
throw new TransactionSystemException("Could not commit JDBC transaction", ex);
}
}
@Override
protected void doRollback(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
}
try {
con.rollback();
}
catch (SQLException ex) {
throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
}
}
}
public class DruidDataSource extends DruidAbstractDataSource implements DruidDataSourceMBean, ManagedDataSource, Referenceable, Closeable, Cloneable, ConnectionPoolDataSource {
public DruidPooledConnection getConnection() throws SQLException {
return this.getConnection(this.maxWait);
}
public DruidPooledConnection getConnection(long maxWaitMillis) throws SQLException {
this.init();
if (this.filters.size() > 0) {
FilterChainImpl filterChain = new FilterChainImpl(this);
return filterChain.dataSource_connect(this, maxWaitMillis);
} else {
return this.getConnectionDirect(maxWaitMillis);
}
}
}
package java.sql;
public interface Connection extends Wrapper, AutoCloseable {}
package com.mysql.jdbc;
public interface Connection extends java.sql.Connection, ConnectionProperties {}
package com.mysql.jdbc;
public interface MySQLConnection extends Connection, ConnectionProperties {}
package com.mysql.jdbc;
public class ConnectionImpl extends ConnectionPropertiesImpl implements MySQLConnection {
private MysqlIO io;
/**
* 执行事务提交方法
*/
public void commit() throws SQLException {
synchronized(this.getMutex()) {
this.checkClosed();
try {
......
this.execSQL((StatementImpl)null, "commit", -1, (Buffer)null, 1003, 1007, false, this.database, (Field[])null, false);
} catch (SQLException var9) {
} finally {
this.needsPing = this.getReconnectAtTxEnd();
}
}
}
/**
* 执行事务回滚方法
*/
private void rollbackNoChecks() throws SQLException {
if (!this.getUseLocalTransactionState() || !this.versionMeetsMinimum(5, 0, 0) || this.io.inTransactionOnServer()) {
this.execSQL((StatementImpl)null, "rollback", -1, (Buffer)null, 1003, 1007, false, this.database, (Field[])null, false);
}
}
/**
* 执行SQL
*/
public ResultSetInternalMethods execSQL(StatementImpl callingStatement, String sql, int maxRows, Buffer packet, int resultSetType, int resultSetConcurrency, boolean streamResults, String catalog, Field[] cachedMetadata) throws SQLException {
return this.execSQL(callingStatement, sql, maxRows, packet, resultSetType, resultSetConcurrency, streamResults, catalog, cachedMetadata, false);
}
/**
* 关闭链接
*/
public synchronized void close() throws SQLException {
if (this.connectionLifecycleInterceptors != null) {
(new IterateBlock(this.connectionLifecycleInterceptors.iterator()) {
void forEach(Object each) throws SQLException {
((ConnectionLifecycleInterceptor)each).close();
}
}).doForAll();
}
this.realClose(true, true, false, (Throwable)null);
}
/**
* 创建链接
*/
private void coreConnect(Properties mergedProps) throws SQLException, IOException {
int newPort = 3306;
String newHost = "localhost";
String protocol = mergedProps.getProperty("PROTOCOL");
......
this.port = newPort;
this.host = newHost;
// 创建socket
this.io = new MysqlIO(newHost, newPort, mergedProps, this.getSocketFactoryClassName(), this.getProxy(), this.getSocketTimeout(), this.largeRowSizeThreshold.getValueAsInt());
this.io.doHandshake(this.user, this.password, this.database);
}
}
public class MysqlIO {
// 链接就是socket
protected Socket mysqlConnection = null;
protected String host = null;
protected int port = 3306;
......
public MysqlIO(String host, int port, Properties props, String socketFactoryClassName, MySQLConnection conn, int socketTimeout, int useBufferRowSizeThreshold) throws IOException, SQLException {
this.connection = conn;
this.port = port;
this.host = host;
this.socketFactory = this.createSocketFactory();
......
try {
// socket工厂创建socket,跟数据库建立链接
this.mysqlConnection = this.socketFactory.connect(this.host, this.port, props);
......
} catch (IOException var10) {
throw SQLError.createCommunicationsException(this.connection, 0L, 0L, var10, this.getExceptionInterceptor());
}
}
}
关系
Connection 封装了 socket
DataSource 封装了 Connection
TransactionManager 管理 Connection
声明式事务|Spring事务传播属性
propagation=“REQUIRED”
数据库事务隔离级别
isolation=“REPEATABLE_READ”
脏读、幻读、不可重复读
Spring事务隔离级别
isolation=“REPEATABLE_READ”
流程
判断是否是readonly,是:自动提交设置为true,不是:自动提交设置为false(才能回滚)