XML 解析時對 environment 節點的處理
TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
DataSource dataSource = dsFactory.getDataSource();
Environment.Builder environmentBuilder = new Environment.Builder(id).transactionFactory(txFactory)
.dataSource(dataSource);
configuration.setEnvironment(environmentBuilder.build());
transactionManager
型別實際是TransactionFactory
。
Configuration 預設註冊了兩個可使用別名的
- JDBC: JdbcTransactionFactory
- MANAGED: ManagedTransactionFactory
TransactionFactory: 事務/Transaction工廠 ,透過資料庫連線池或連線獲取 Transaction 物件
public interface TransactionFactory {
default void setProperties(Properties props) {
// NOP
}
Transaction newTransaction(Connection conn);
Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);
}
Transaction:事務,管理事務/連線的提交等
public interface Transaction {
Connection getConnection() throws SQLException;
void commit() throws SQLException;
void rollback() throws SQLException;
void close() throws SQLException;
Integer getTimeout() throws SQLException;
}
JdbcTransactionFactory
對應 JdbcTransaction 的工廠,普普通通沒什麼
public class JdbcTransactionFactory implements TransactionFactory {
private boolean skipSetAutoCommitOnClose = false;
@Override
public void setProperties(Properties props) {
// 處理 Properties 中的 skipSetAutoCommitOnClose 配置的
}
@Override
public Transaction newTransaction(Connection conn) {
return new JdbcTransaction(conn);
}
@Override
public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
return new JdbcTransaction(ds, level, autoCommit, skipSetAutoCommitOnClose);
}
}
ManagedTransactionFactory:ManagedTransaction 的工廠,事務是外部控制的,對於自動提交引數、隔離級別等不會去主動設定
public class ManagedTransactionFactory implements TransactionFactory {
private boolean closeConnection = true;
@Override
public void setProperties(Properties props) {
// closeConnection 引數
}
@Override
public Transaction newTransaction(Connection conn) {
return new ManagedTransaction(conn, closeConnection);
}
@Override
public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
// 忽略自動提交引數
return new ManagedTransaction(ds, level, closeConnection);
}
}
Transaction
Transaction:事務,管理事務/連線的提交等
public interface Transaction {
Connection getConnection() throws SQLException;
void commit() throws SQLException;
void rollback() throws SQLException;
void close() throws SQLException;
Integer getTimeout() throws SQLException;
}
預設兩個實現 JdbcTransaction 和 ManagedTransaction,都有其獨立的工廠
JdbcTransaction
主要就是對 Connection 的 commit、rollback、close 進行了一定程度的封裝,支援直接傳入 Connection 和透過 DataSource 獲取 Connection
public class JdbcTransaction implements Transaction {
private static final Log log = LogFactory.getLog(JdbcTransaction.class);
// 資料庫連線、資料來源、事務隔離級別、自動提交
protected Connection connection;
protected DataSource dataSource;
protected TransactionIsolationLevel level;
protected boolean autoCommit;
protected boolean skipSetAutoCommitOnClose;
public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
this(ds, desiredLevel, desiredAutoCommit, false);
}
public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit,
boolean skipSetAutoCommitOnClose) {
dataSource = ds;
level = desiredLevel;
autoCommit = desiredAutoCommit;
this.skipSetAutoCommitOnClose = skipSetAutoCommitOnClose;
}
public JdbcTransaction(Connection connection) {
this.connection = connection;
}
@Override
public Connection getConnection() throws SQLException {
if (connection == null) {
openConnection();
}
return connection;
}
@Override
public void commit() throws SQLException {
// 若事務不是自動提交的才會提交事務
if (connection != null && !connection.getAutoCommit()) {
connection.commit();
}
}
@Override
public void rollback() throws SQLException {
if (connection != null && !connection.getAutoCommit()) {
connection.rollback();
}
}
@Override
public void close() throws SQLException {
if (connection != null) {
resetAutoCommit();
connection.close();
}
}
protected void setDesiredAutoCommit(boolean desiredAutoCommit) {
if (connection.getAutoCommit() != desiredAutoCommit) {
connection.setAutoCommit(desiredAutoCommit);
}
}
protected void resetAutoCommit() {
connection.setAutoCommit(true);
}
protected void openConnection() throws SQLException {
connection = dataSource.getConnection();
if (level != null) {
connection.setTransactionIsolation(level.getLevel());
}
setDesiredAutoCommit(autoCommit);
}
@Override
public Integer getTimeout() throws SQLException {
return null;
}
}
ManagedTransaction:相對於 JdbcTransaction 主要是忽略了 commit 和 rollback 呼叫
public class ManagedTransaction implements Transaction {
public ManagedTransaction(Connection connection, boolean closeConnection) {
this.connection = connection;
this.closeConnection = closeConnection;
}
public ManagedTransaction(DataSource ds, TransactionIsolationLevel level, boolean closeConnection) {
this.dataSource = ds;
this.level = level;
this.closeConnection = closeConnection;
}
@Override
public Connection getConnection() throws SQLException {
if (this.connection == null) {
openConnection();
}
return this.connection;
}
@Override
public void commit() throws SQLException {
// Does nothing
}
@Override
public void rollback() throws SQLException {
// Does nothing
}
@Override
public void close() throws SQLException {
if (this.closeConnection && this.connection != null) {
this.connection.close();
}
}
protected void openConnection() throws SQLException {
this.connection = this.dataSource.getConnection();
if (this.level != null) {
this.connection.setTransactionIsolation(this.level.getLevel());
}
}
@Override
public Integer getTimeout() throws SQLException {
return null;
}
}
DataSource
typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
DataSourceFactory: 生產 DataSource
public interface DataSourceFactory {
void setProperties(Properties props);
DataSource getDataSource();
}
JNDI: JndiDataSourceFactory
暫略,這種一般需要在容器內配置的檔案,而非類似 SpringBoot 配置檔案配置的
UNPOOLED: UnpooledDataSourceFactory
public class UnpooledDataSourceFactory implements DataSourceFactory {
private static final String DRIVER_PROPERTY_PREFIX = "driver.";
private static final int DRIVER_PROPERTY_PREFIX_LENGTH = DRIVER_PROPERTY_PREFIX.length();
protected DataSource dataSource;
public UnpooledDataSourceFactory() {
// DataSource 物件直接建立了
this.dataSource = new UnpooledDataSource();
}
@Override
public void setProperties(Properties properties) {
Properties driverProperties = new Properties();
MetaObject metaDataSource = SystemMetaObject.forObject(dataSource);
for (Object key : properties.keySet()) {
String propertyName = (String) key;
// 如果有資料庫配置
if (propertyName.startsWith(DRIVER_PROPERTY_PREFIX)) {
String value = properties.getProperty(propertyName);
// Properties 拆分儲存資料庫相關配置
driverProperties.setProperty(propertyName.substring(DRIVER_PROPERTY_PREFIX_LENGTH), value);
// 如果是直接配置的屬性值配置
} else if (metaDataSource.hasSetter(propertyName)) {
String value = (String) properties.get(propertyName);
// 根據 setter 的入參型別轉換值
Object convertedValue = convertValue(metaDataSource, propertyName, value);
metaDataSource.setValue(propertyName, convertedValue);
} else {
throw new DataSourceException("Unknown DataSource property: " + propertyName);
}
}
// 有資料庫相關配置, 設定給資料來源
if (driverProperties.size() > 0) {
metaDataSource.setValue("driverProperties", driverProperties);
}
}
@Override
public DataSource getDataSource() {
return dataSource;
}
private Object convertValue(MetaObject metaDataSource, String propertyName, String value) {
Object convertedValue = value;
// setter 引數型別
Class<?> targetType = metaDataSource.getSetterType(propertyName);
// 僅支援 int、long、boolean 及其包裝型別還有 String 型別
if (targetType == Integer.class || targetType == int.class) {
convertedValue = Integer.valueOf(value);
} else if (targetType == Long.class || targetType == long.class) {
convertedValue = Long.valueOf(value);
} else if (targetType == Boolean.class || targetType == boolean.class) {
convertedValue = Boolean.valueOf(value);
}
return convertedValue;
}
}
POOLED: PooledDataSourceFactory,父類是 UnpooledDataSourceFactory,UnpooledDataSourceFactory 的功能基本上是處理資料庫配置的,兩者差別就是 DataSource 型別不一樣
public class PooledDataSourceFactory extends UnpooledDataSourceFactory {
public PooledDataSourceFactory() {
this.dataSource = new PooledDataSource();
}
}
DataSource
UnpooledDataSource: 資料庫連線沒有被池管理,直接 DriverManager 獲取連線
public class UnpooledDataSource implements DataSource {
private ClassLoader driverClassLoader;
// 用於配置資料庫的引數資訊
private Properties driverProperties;
// SPI 能查詢出來的所有資料庫驅動
private static final Map<String, Driver> registeredDrivers = new ConcurrentHashMap<>();
private String driver;
private String url;
private String username;
private String password;
private Boolean autoCommit;
private Integer defaultTransactionIsolationLevel;
private Integer defaultNetworkTimeout;
// 獲取所有驅動
static {
Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
registeredDrivers.put(driver.getClass().getName(), driver);
}
}
public UnpooledDataSource() {
}
// 其他建構函式略
@Override
public Connection getConnection() throws SQLException {
return doGetConnection(username, password);
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return doGetConnection(username, password);
}
@Override
public void setLoginTimeout(int loginTimeout) {
DriverManager.setLoginTimeout(loginTimeout);
}
@Override
public int getLoginTimeout() {
return DriverManager.getLoginTimeout();
}
@Override
public void setLogWriter(PrintWriter logWriter) {
DriverManager.setLogWriter(logWriter);
}
@Override
public PrintWriter getLogWriter() {
return DriverManager.getLogWriter();
}
// driver、url、username、password、autoCommit、defaultTransactionIsolationLevel
// driverProperties、defaultNetworkTimeout、driverClassLoader 的 getter 和 setter
private Connection doGetConnection(String username, String password) throws SQLException {
// 新的 Properties, 傳入的名稱、密碼 + 其他預設配置引數組成新的
Properties props = new Properties();
if (driverProperties != null) {
props.putAll(driverProperties);
}
if (username != null) {
props.setProperty("user", username);
}
if (password != null) {
props.setProperty("password", password);
}
return doGetConnection(props);
}
private Connection doGetConnection(Properties properties) throws SQLException {
// 初始化驅動
initializeDriver();
// 直接獲取資料庫連線
Connection connection = DriverManager.getConnection(url, properties);
// 配置連線資訊
configureConnection(connection);
return connection;
}
private void initializeDriver() throws SQLException {
try {
// 沒有透過 SPI 機制自動發現的才會走到這裡
MapUtil.computeIfAbsent(registeredDrivers, driver, x -> {
Class<?> driverType;
try {
if (driverClassLoader != null) {
driverType = Class.forName(x, true, driverClassLoader);
} else {
driverType = Resources.classForName(x);
}
Driver driverInstance = (Driver) driverType.getDeclaredConstructor().newInstance();
// 為啥這裡要加上一個代理
DriverManager.registerDriver(new DriverProxy(driverInstance));
return driverInstance;
} catch (Exception e) {
throw new RuntimeException("Error setting driver on UnpooledDataSource.", e);
}
});
} catch (RuntimeException re) {
throw new SQLException("Error setting driver on UnpooledDataSource.", re.getCause());
}
}
private void configureConnection(Connection conn) throws SQLException {
if (defaultNetworkTimeout != null) {
conn.setNetworkTimeout(Executors.newSingleThreadExecutor(), defaultNetworkTimeout);
}
if (autoCommit != null && autoCommit != conn.getAutoCommit()) {
conn.setAutoCommit(autoCommit);
}
if (defaultTransactionIsolationLevel != null) {
conn.setTransactionIsolation(defaultTransactionIsolationLevel);
}
}
private static class DriverProxy implements Driver {
private final Driver driver;
DriverProxy(Driver d) {
this.driver = d;
}
// 其他略, 都是呼叫 Driver 的
@Override
public Logger getParentLogger() {
return Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
}
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
throw new SQLException(getClass().getName() + " is not a wrapper.");
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
@Override
public Logger getParentLogger() {
// requires JDK version 1.6
return Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
}
}
PooledDataSource: 使用池管理,自己僅維護池,使用 UnpooledDataSource 來獲取資料庫連線