首页 > 数据库 >MyBatis-04-数据库配置

MyBatis-04-数据库配置

时间:2024-04-16 22:57:34浏览次数:16  
标签:04 数据库 throws Override connection SQLException void MyBatis public

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

标签:04,数据库,throws,Override,connection,SQLException,void,MyBatis,public
From: https://www.cnblogs.com/chenxingyang/p/18139462

相关文章

  • MyBatis-06-Spring的SqlSession和原始区别
    DefaultSqlSession这个就不说了,SQL执行是调用执行器Executor执行SqlSessionTemplate构造函数,虽然没有立即创建SqlSession传入代理拦截器SqlSessionInterceptor,但是拦截器是一个实例内部类,可以访问到SqlSessionFactory并且SqlSessionTemplate不支持commit、rollback......
  • MyBatis-05-MyBatis使用流程简读
    代码//使用流程//1.读取配置文件InputStreaminputStream=Resources.getResourceAsStream("mybatis-config.xml");//2.创建SqlSessionFactory工厂SqlSessionFactorysqlSessionFactory=newSqlSessionFactoryBuilder().build(inputStream);//3.生产SqlSession......
  • MyBatis-07-插件原理
    MyBatis插件MyBatis的插件实际上就是Interceptor,拦截器,拦截并重写SQLInterceptor:拦截器InterceptorChain:拦截器链Invocation:封装Object.method(args),反射调用Plugin:JDK代理处理器InvocationHandler,封装一个Interceptor及其拦截的方法,及拦截对象+拦截方......
  • MyBatis-08-Spring的MyBatis Interceptor
    addInterceptor3个地方XML解析的SqlSessionFactoryBean:生成SqlSession的FactoryBeanPageHelperAutoConfiguration:分页助手的自动配置SqlSessionFactoryBean发现现在都没有将他作为一个FactoryBean使用了getObject调用了afterPropertiesSet生成SqlSessionF......
  • MyBatis-09-FactoryBean的问题
    ListableBeanFactory#getBeanNamesForType(Class<?>)这个方法的逻辑在对FactoryBean进行判断时,会使用FactoryBean的生成的对象的类型进行判断BD的属性数据AttributeAccessor.getAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE)反射创建对象并调用FactoryBean#getObjectT......
  • MyBatis-01-Demo
    数据库DDLCREATEDATABASE`mybatis_demo01`;--mybatis_demo01.`user`definitionCREATETABLE`user`(`id`intNOTNULLAUTO_INCREMENT,`username`varchar(100)DEFAULTNULL,`birthday`datetimeDEFAULTNULL,`sex`char(1)DEFAULTNULL,`address`......
  • MyBatis-02-别名
    别名TypeAliasRegistry默认注册了很多别名,构造函数注册的publicTypeAliasRegistry(){registerAlias("string",String.class);registerAlias("byte",Byte.class);registerAlias("char",Character.class);registerAlias("character"......
  • MyBatis-03-environment
    配置<environmentsdefault="default"><environmentid="default"><!--事务类型--><transactionManagertype="JDBC"/><!--数据源类型--><dataSourcetype="POOLED">&l......
  • 控制台连接数据库成功,驱动也导入了没问题,但tomcat的servlet启动会报错。报错信息:java.
    查了很多资料这个报错信息是因为驱动导入不成功,但我确定我已经导入了,因为我在控制台输出了出来。找了很久,发现了这个小问题。原因是我在Eclipse中创建是一个标准的Web工程,它是自带lib文件夹的,然后我自己又自建了一个lib文件夹用来放驱动,结果就像这样报出一个错误!解决方案:......
  • 2024/04/15!!!!!!!!!
    周末国九条、伊朗攻击以色列强度不及预期,国际黄金期货高位巨量放空、美国cpi和ppi不及预期,降息预期进一步降低等等一系列的消息,基本上都对中润资源不利但是国九条中关于分红和退市的规定,对市场的影响最大,我知道国九条对小盘股和垃圾股的不利,对白马股利好,但是没有想到影响来的如此......