MyBatis-04-数据库配置
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 来获取数据库连接