diff --git a/docs/Mybatis/核心处理层/Mybatis-DataSource.md b/docs/Mybatis/核心处理层/Mybatis-DataSource.md new file mode 100644 index 0000000..85014bb --- /dev/null +++ b/docs/Mybatis/核心处理层/Mybatis-DataSource.md @@ -0,0 +1,356 @@ +# Mybatis DataSource +- `org.apache.ibatis.datasource.DataSourceFactory` +```java +/** + * 数据源工厂 + * @author Clinton Begin + */ +public interface DataSourceFactory { + + /** + * 设置 dataSource 属性 + * @param props + */ + void setProperties(Properties props); + + /** + * 获取 dataSource + * @return {@link DataSource} + */ + DataSource getDataSource(); + +} + +``` + +类图如下 + +![image-20191223081023730](/images/mybatis/image-20191223081023730.png) + +- `setProperties`会将下列标签放入`datasource`中 + +```java + + + + + + +``` + + + + + + + + + +- 在`org.apache.ibatis.session.Configuration`中有配置下面三个信息 +```java + typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class); + typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class); + typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class); + +``` + + + + + + + + + +## JndiDataSourceFactory + +```java +/** + * @author Clinton Begin + */ +public class JndiDataSourceFactory implements DataSourceFactory { + + public static final String INITIAL_CONTEXT = "initial_context"; + public static final String DATA_SOURCE = "data_source"; + public static final String ENV_PREFIX = "env."; + + /** + * 直接 java 数据源 + */ + private DataSource dataSource; + + /** + * 获取数据源的配置信息 + * @param allProps + * @return + */ + private static Properties getEnvProperties(Properties allProps) { + final String PREFIX = ENV_PREFIX; + Properties contextProperties = null; + for (Entry entry : allProps.entrySet()) { + String key = (String) entry.getKey(); + String value = (String) entry.getValue(); + // 只获取前缀`env` + if (key.startsWith(PREFIX)) { + if (contextProperties == null) { + contextProperties = new Properties(); + } + // 放入数据 + contextProperties.put(key.substring(PREFIX.length()), value); + } + } + return contextProperties; + } + + /** + * 设置数据源属性 + * @param properties + */ + @Override + public void setProperties(Properties properties) { + try { + InitialContext initCtx; + Properties env = getEnvProperties(properties); + if (env == null) { + initCtx = new InitialContext(); + } else { + initCtx = new InitialContext(env); + } + + if (properties.containsKey(INITIAL_CONTEXT) + && properties.containsKey(DATA_SOURCE)) { + // 如果包含`initial_context`和`data_source` + Context ctx = (Context) initCtx.lookup(properties.getProperty(INITIAL_CONTEXT)); + dataSource = (DataSource) ctx.lookup(properties.getProperty(DATA_SOURCE)); + } else if (properties.containsKey(DATA_SOURCE)) { + dataSource = (DataSource) initCtx.lookup(properties.getProperty(DATA_SOURCE)); + } + + } catch (NamingException e) { + throw new DataSourceException("There was an error configuring JndiDataSourceTransactionPool. Cause: " + e, e); + } + } + + @Override + public DataSource getDataSource() { + return dataSource; + } + +} +``` + +## PooledDataSource + +```java + protected int poolMaximumActiveConnections = 10; + protected int poolMaximumIdleConnections = 5; + protected int poolMaximumCheckoutTime = 20000; + protected int poolTimeToWait = 20000; + protected int poolMaximumLocalBadConnectionTolerance = 3; + protected String poolPingQuery = "NO PING QUERY SET"; + protected boolean poolPingEnabled; + protected int poolPingConnectionsNotUsedFor; +``` + + + +## PooledDataSourceFactory + +```java +public class PooledDataSourceFactory extends UnpooledDataSourceFactory { + + + public PooledDataSourceFactory() { + this.dataSource = new PooledDataSource(); + } + +} + + // 初始化 + public PooledDataSource() { + dataSource = new UnpooledDataSource(); + } +``` + + + +## UnpooledDataSourceFactory + +```java + @Override + public void setProperties(Properties properties) { + Properties driverProperties = new Properties(); + //metaDataSource 现在是一个dataSource + MetaObject metaDataSource = SystemMetaObject.forObject(dataSource); + for (Object key : properties.keySet()) { + String propertyName = (String) key; + if (propertyName.startsWith(DRIVER_PROPERTY_PREFIX)) { + // 如果是 driver. 前缀开头 + String value = properties.getProperty(propertyName); + driverProperties.setProperty(propertyName.substring(DRIVER_PROPERTY_PREFIX_LENGTH), value); + } else if (metaDataSource.hasSetter(propertyName)) { + String value = (String) properties.get(propertyName); + Object convertedValue = convertValue(metaDataSource, propertyName, value); + // 通过 metaDataSource 来对 dataSource 进行设置属性 + metaDataSource.setValue(propertyName, convertedValue); + } else { + throw new DataSourceException("Unknown DataSource property: " + propertyName); + } + } + if (driverProperties.size() > 0) { + metaDataSource.setValue("driverProperties", driverProperties); + } + } + +``` + + + +## UnpooledDataSource + +- `org.apache.ibatis.datasource.unpooled.UnpooledDataSource`主要定义数据库连接相关的一些属性,以及与数据库的链接对象创建 + + ```java + // 一些配置信息 + private ClassLoader driverClassLoader; + private Properties driverProperties; + private String driver; + private String url; + private String username; + private String password; + private Boolean autoCommit; + private Integer defaultTransactionIsolationLevel; + private Integer defaultNetworkTimeout; + ``` + + + +- 初始化连接对象 + + ```java + /** + * 加载链接驱动 如 mysql 链接驱动 + * @throws SQLException + */ + private synchronized void initializeDriver() throws SQLException { + if (!registeredDrivers.containsKey(driver)) { + Class driverType; + try { + if (driverClassLoader != null) { + driverType = Class.forName(driver, true, driverClassLoader); + } else { + driverType = Resources.classForName(driver); + } + // DriverManager requires the driver to be loaded via the system ClassLoader. + // http://www.kfu.com/~nsayer/Java/dyn-jdbc.html + Driver driverInstance = (Driver) driverType.getDeclaredConstructor().newInstance(); + DriverManager.registerDriver(new DriverProxy(driverInstance)); + registeredDrivers.put(driver, driverInstance); + } catch (Exception e) { + throw new SQLException("Error setting driver on UnpooledDataSource. Cause: " + e); + } + } + } + + ``` + + + +- 设置连接对象的属性 + + ```java + /** + * 设置连接对象 , 超时时间,是否自动提交事物 + * @param conn + * @throws SQLException + */ + 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); + } + } + + ``` + + + +- 获取连接对象 + + ```java + /** + * 获取链接对象 + * @param username + * @param password + * @return + * @throws SQLException + */ + private Connection doGetConnection(String username, String password) throws SQLException { + 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); + } + + ``` + + + + + + + +## 解析流程 + +- 在xml解析的过程中会执行`DataSourceFactory`相关内容 + +```java + /** + * 解析 dataSourceElement 标签 + * + * + * + * + * + * + * + * @param context + * @return + * @throws Exception + */ + private DataSourceFactory dataSourceElement(XNode context) throws Exception { + if (context != null) { + String type = context.getStringAttribute("type"); + Properties props = context.getChildrenAsProperties(); + //org.apache.ibatis.session.Configuration.Configuration() + DataSourceFactory factory = (DataSourceFactory) resolveClass(type).getDeclaredConstructor().newInstance(); + + // PooledDataSourceFactory -> UnpooledDataSourceFactory + factory.setProperties(props); + return factory; + } + throw new BuilderException("Environment declaration requires a DataSourceFactory."); + } + +``` + +从类图上或者代码中我们可以发现`PooledDataSourceFactory`是继承`UnpooledDataSourceFactory`那么方法应该也是`UnpooledDataSourceFactory`的。看看设置属性方法 + +![image-20191223083610214](/images/mybatis/image-20191223083610214.png) + +方法直接走完 + +![image-20191223083732972](/images/mybatis/image-20191223083732972.png) + diff --git a/images/mybatis/image-20191223081023730.png b/images/mybatis/image-20191223081023730.png new file mode 100644 index 0000000..f870504 Binary files /dev/null and b/images/mybatis/image-20191223081023730.png differ diff --git a/images/mybatis/image-20191223083610214.png b/images/mybatis/image-20191223083610214.png new file mode 100644 index 0000000..1ecac02 Binary files /dev/null and b/images/mybatis/image-20191223083610214.png differ diff --git a/images/mybatis/image-20191223083732972.png b/images/mybatis/image-20191223083732972.png new file mode 100644 index 0000000..966ea02 Binary files /dev/null and b/images/mybatis/image-20191223083732972.png differ