我是靠谱客的博主 傻傻万宝路,最近开发中收集的这篇文章主要介绍Sharding JDBC源码分析-JdbcMethodInvocation类的作用       摘要      一般情况在调用Connection对象的setAutoCommit方法JdbcMethodInvocation作用分析,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

       摘要

       当当的Sharding JDBC是在JDBC规范上进行封装来实现数据库分表分库分表功能的。其整体结构非常清晰,主线就是将JDBC规范中的DataSource、Connection、Statement、PreparedStament分别封装为ShardingDataSource、ShardingConnection、ShardingStatement、ShardingPreparedStament类。然后将对象的方法进行重写,而ShardingDataSource、ShardingConnection、ShardingStatement、ShardingPreparedStament类可以看作一个代理对象,它们内部完成了根据逻辑sql语句,转化成真实sql语句,路由找到对应数据源,并根据数据源产生真实的Connection对象,然后执行真实sql语句,并将结果归并返回给应用层的功能。今天来分析一下Sharding JDBC中JdbcMethodInvocation类的作用。

      一般情况在调用Connection对象的setAutoCommit方法

默认情况下执行完的操作会被自动提交,当我们要改变时可以在执行sql前调用Connection类的setAutoCommit方法
try{  
    con = getConnection();  
    con.setAutoCommit(false);  
    /* 
     * do what you want here. 
     */  
    con.commit();  
 }catch(Throwable e){  
    if(con!=null){  
        try {  
            con.rollback();  
        } catch (SQLException e1) {  
            e1.printStackTrace();  
        }  
    }  
   throw new RuntimeException(e);  
 }finally{  
    if(con!=null){  
        try {  
            con.close();  
        } catch (SQLException e) {  
            e.printStackTrace();  
        }  
    }  
}
而ShardingJDBC的ShardingConnection类封装了JDBC中的Connection接口,ShardingConnection只是多个Connection对象的一个代理,直接调用他的重写的setAutoCommit方法无法达到实际的效果,为此ShardingJDBC中引入了JdbcMethodInvocation对ShardingConnection、ShardingStatement、ShardingPreparedStatement类中类似setAutoCommit方法的方法调用进行记录。

JdbcMethodInvocation作用分析

       通过ShardingDataSource类得到的ShardingConnection不是真的JDBC Connection对象,其内部有一个Map<String, Connection> connectionMap key为数据源名,value为真实的Connection。当调用Connection类的一些方法时,实际是调用了ShardingConnection 重写后的方法,而此时connectionMap的还是空,达不到调用真实Connection对象方法的功能,为此在ShardingConnection 重写后的方法方法中将调用的方法与方法的参数记录到JdbcMethodInvocation对象中。只有当ShardingPreparedStatement或者ShardingStatement调用对应数据操作函数时(executeQuery,execute,executeUpdate)才会调用ShardingConnection的getContetion方法产生真实的Connection对象,同时把这些对象放入connectionMap。为此在调用ShardingConnection 的setAutoCommint方法、setReadOnly方法、setTransactionIsolation方法时,要记录一下所有调用过的方法的名称与参数。当通过ShardingPreparedStatement或者ShardingStatement产生一个实际的Connection时,再通过反射的方式让真实的Connection对象调用JdbcMethodInvocation记录的方法与方法的参数。
       ShardingJDBC框架通过配置文件指定ShardingDataSource与外部应用程序交互,达到访问真实数据源的目的。其有三个成员变量
  •  private final ShardingProperties shardingProperties;
  •  private final ExecutorEngine executorEngine;
  •  private final ShardingContext shardingContext;
 shardingProperties为一些属性,executorEngine为一个多线程的执行引擎其内部采用Guava的ListeningExecutorService实现。shardingContext为上下文信息,记录了分库分表规则配置、执行引擎、sql路由引擎这些信息。以便ShardingConnection 使用。
       利用ShardingJDBC框架后通过DataSource得到的Connection实际上是包装后的ShardingConnection。ShardingDataSource对DataSource的所有方法进行了重写,其中getConnection如下:

@Override
public ShardingConnection getConnection() throws SQLException {
MetricsContext.init(shardingProperties);
return new ShardingConnection(shardingContext);
}
       得到得到的Connection实际上是包装后的ShardingConnection,而Sharding上下文对象在创建ShardingConnection时被传入。按照上面的一般情况的示例,当我们调用con.setAutoCommit方法时,实际是调用了ShardingDataSource的getConnection方法产生的ShardingConnection对象的setAutoCommit方法。
       ShardingConnection自的成员变量如下:
  •       private final ShardingContext shardingContext;
  •       private final Map<String, Connection> connectionMap = new HashMap<>();
shardingContext为Sharding上下文对象在创建ShardingConnection时被传入,而connectionMap 为保存真实Connection的Map,其key为配置文件中真实dataSource Bean的id。connectionMap 的初始值为空。在调用ShardingConnection的getConnection方法得到真实的Connection对象后,才会将其实放connectionMap 中。代码如下:
public Connection getConnection(final String dataSourceName, final SQLStatementType sqlStatementType) throws SQLException {
Connection result = getConnectionInternal(dataSourceName, sqlStatementType);
replayMethodsInvocation(result);//对记录的要执行的调用方法,在这里通过反射进行执行
return result;
}

private Connection getConnectionInternal(final String dataSourceName, final SQLStatementType sqlStatementType) throws SQLException {
if (connectionMap.containsKey(dataSourceName)) {
return connectionMap.get(dataSourceName);
}
Context metricsContext = MetricsContext.start(Joiner.on("-").join("ShardingConnection-getConnection", dataSourceName));
DataSource dataSource = shardingContext.getShardingRule().getDataSourceRule().getDataSource(dataSourceName);
if (dataSource instanceof MasterSlaveDataSource) {
dataSource = ((MasterSlaveDataSource) dataSource).getDataSource(sqlStatementType);
}
Connection result = dataSource.getConnection();
MetricsContext.stop(metricsContext);
connectionMap.put(dataSourceName, result);//将真实的Connction对象放入connectionMap中
return result;
}
按照上面的一般情况的示例,当我们调用con.setAutoCommit方法时,实际是调用ShardingConnection重写后的setAutoCommit方法。该方法在其父类AbstractConnectionAdapter中完成重写,代码如下:
@Override
public final void setAutoCommit(final boolean autoCommit) throws SQLException {
this.autoCommit = autoCommit;
//getConnections方法实际ShardingConnection对象中的coonectionMap对象的value集合,
//为空时记录调用过的方法与对应参数,当在产生真正的Connection对象时,
//再利用反射的方式让真正的Connection对象调用该方法
if (getConnections().isEmpty()) {
recordMethodInvocation(Connection.class, "setAutoCommit", new Class[] {boolean.class}, new Object[] {autoCommit});
return;
}
for (Connection each : getConnections()) {
each.setAutoCommit(autoCommit);
}
}



AbstractConnectionAdapter的setAutoCommit方法中的getConnections得到了实现是ShardingConnection对象中的coonectionMap对象的value集合。ShardingConnection对AbstractConnectionAdapter的getConnections方法的重写:
public Collection<Connection> getConnections() {
return connectionMap.values();
}
而调用setAutoCommit时coonectionMap还是空。不是达到真实Connection对象的setAutoCommit的目的,为此先对其进行记录,当在产生真实的Connection对象时,再利用反射的方法让其调用recordMethodInvocation方法记录的方法。其中recordMethodInvocation方法继续自WrapperAdapter类。记录了调用的方法与传入方法的参数,实际是将JdbcMethodInvocation对象放入WrapperAdapter的成员变量
private final Collection<JdbcMethodInvocation> jdbcMethodInvocations = new ArrayList<>();
中。WrapperAdapter中的recordMethodInvocation方法如下:
protected final void recordMethodInvocation(final Class<?> targetClass, final String methodName, final Class<?>[] argumentTypes, final Object[] arguments) {
try {
jdbcMethodInvocations.add(new JdbcMethodInvocation(targetClass.getMethod(methodName, argumentTypes), arguments));
} catch (final NoSuchMethodException ex) {
throw new ShardingJdbcException(ex);
}
}

jdbcMethodInvocations记录了所有调用的方法与参数。
@RequiredArgsConstructor
public final class JdbcMethodInvocation {
private final Method method;//调用的方法
private final Object[] arguments;//调用方法时传入的参数
/**
*  调用方法.
*
* @param target 目标对象
*/
public void invoke(final Object target) {
try {
method.invoke(target, arguments);
} catch (final IllegalAccessException | InvocationTargetException ex) {
throw new ShardingJdbcException("Invoke jdbc method exception", ex);
}
}
}
现在来看一下,当真实的Connection对象产生时,通过反射的方法调用jdbcMetiondInvoctions记录的要调用的方法与参数。真实的Connection的产生就是通过我们上面提到的ShardingConnection的getConnection方法来达到的。
 
public Connection getConnection(final String dataSourceName, final SQLStatementType sqlStatementType) throws SQLException {
Connection result = getConnectionInternal(dataSourceName, sqlStatementType);
replayMethodsInvocation(result);//对记录的要执行的调用方法,在这里通过反射进行执行
return result;
}

private Connection getConnectionInternal(final String dataSourceName, final SQLStatementType sqlStatementType) throws SQLException {
if (connectionMap.containsKey(dataSourceName)) {
return connectionMap.get(dataSourceName);
}
Context metricsContext = MetricsContext.start(Joiner.on("-").join("ShardingConnection-getConnection", dataSourceName));
DataSource dataSource = shardingContext.getShardingRule().getDataSourceRule().getDataSource(dataSourceName);
if (dataSource instanceof MasterSlaveDataSource) {
dataSource = ((MasterSlaveDataSource) dataSource).getDataSource(sqlStatementType);
}
Connection result = dataSource.getConnection();
MetricsContext.stop(metricsContext);
connectionMap.put(dataSourceName, result);//将真实的Connction对象放入connectionMap中
return result;
}

在 return result之前执行replayMethodsInvocations方法,该方法实际通过反射的方式对之前记录的方法进行了调用,这个例子中是对setAutoCommit方法进行了调用。replayMethodsInvocations继承自WrapperAdapter类,代码如下:
protected final void replayMethodsInvocation(final Object target) {
for (JdbcMethodInvocation each : jdbcMethodInvocations) {
each.invoke(target);
}
}

除了setAutoCommit方法外以下的方式也是通过这JdbcMethodInvocation实现的。
AbstractConnectionAdapter类:
  • mmitsetReadOnly
  • setTransactionIsolation
AbstractStatementAdapter类:
  • setPoolable
  • setFetchSize
  • setEscapeProcessing
  • setCursorName
  • setMaxFieldSize
  • setMaxRows
  • setQueryTimeout
因调用这些方法时真实的Connection对象、Statement对象、PreparedStatement对象还没有产生,所以要先记录下,当在真实的对象产生时,再通过反射的方式调用在JdbcMethodInvocation中记录的方法。
后面还会分享更多ShardingJDBC源码的分析,不正确的地方欢迎指正,也欢迎一同分享。

最后

以上就是傻傻万宝路为你收集整理的Sharding JDBC源码分析-JdbcMethodInvocation类的作用       摘要      一般情况在调用Connection对象的setAutoCommit方法JdbcMethodInvocation作用分析的全部内容,希望文章能够帮你解决Sharding JDBC源码分析-JdbcMethodInvocation类的作用       摘要      一般情况在调用Connection对象的setAutoCommit方法JdbcMethodInvocation作用分析所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(56)

评论列表共有 0 条评论

立即
投稿
返回
顶部