面试准备

159 阅读3分钟

Mybatis源码

1,配置解析

解析mybatis-config和Mapper.xml文件,把配置文件中所有的信息都存放在Configuration类中, 返回一个DefaulSqlSesionFactory,这个类里面就是有Configuration的实例

2,会话创建

SqlSesion session = sqlSessionFactory.openSession(); 从Configuration中获取Environment,创建事务,创建执行器Executor[先创建基本类型执行器,然后如果开启了二级缓存开关,就用二级缓存包装(CachingExecutor),然后再用拦截器进行包装]【装饰器模式】,创建DefaultSqlSession,包含Configuration和Executor

3,获得Mapper代理对象

通过JDK动态代理返回一个$Proxy对象,Mapper没有实现类,它忽略了实现类,直接对接口进行了代理。 为什么Mybatis里不需要实现类呢?我们要明白实现代理类的目的是找到Mapper.xml中的StatementID,如果根据接口类型+方法的名称就可以找到StatementID,这个在MapperProxy中就可以完成,就不需要实现类了。

注释: MapperProxy可以称之为实现了InvocationHandler的触发管理类

public class MapperProxy<T> implements InvocationHandler{
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

4,执行SQL

MapperProxy调用invoke()方法,然后DefaultSqlSession调用sesssion方法(selectOne/selectList等),然后调用执行器BaseExecutor方法, 然后走一级缓存, 然后再创建StatementHandler,ParameterHandler,ResultSetHandler对象,创建connection,处理入参, 最后编译sql,执行sql,处理结果集.

如果有插件拦截,就先走插件的逻辑,然后再走二级缓存的逻辑,最后再走到BaseExecutor的逻辑。

SQL原生基本流程:

  try {
        // 注册 JDBC 驱动
        Class.forName("com.mysql.jdbc.Driver");

        // 打开连接
        conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis_demo", "root", "123456");

        // 执行查询
        stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery(String.format(sql, paramater));

        // 获取结果集
        while (rs.next()) {
            Integer bid = rs.getInt("bid");
            String name = rs.getString("name");
            Integer authorId = rs.getInt("author_id");
            blog.setAuthorId(authorId);
            blog.setBid(bid);
            blog.setName(name);
        }
        System.out.println(blog);

        rs.close();
        stmt.close();
        conn.close();
    } catch (Exception se) {
        se.printStackTrace();
    }
  }

Spring面试题

SpringMVC

SpringMVC执行流程及工作原理

Spring

Spring事务原理
 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
 </bean>
 
public interface DataSource  extends CommonDataSource, Wrapper {

  Connection getConnection() throws SQLException;

  Connection getConnection(String username, String password)
    throws SQLException;
}

//com.mysql.jdbc.Connection
public interface Connection  extends Wrapper, AutoCloseable {
    void commit() throws SQLException;
    void rollback() throws SQLException;
    void close() throws SQLException;
}
进入//com.mysql.jdbc.ConnectionImpl中
public void commit() throws SQLException {
     this.execSQL((StatementImpl)null, "commit", -1, (Buffer)null, 1003, 1007, false, this.database, (Field[])null, false);             
}

ResultSetInternalMethods execSQL(StatementImpl var1, String var2, int var3, Buffer var4, int var5, int var6, boolean var7, String var8, Field[] var9, boolean var10) throws SQLException{
     //注意这个io是MysqlIO类,
     ResultSetInternalMethods var36 = this.io.sqlQueryDirect(callingStatement, sql, encoding, (Buffer)null, maxRows, resultSetType, resultSetConcurrency, streamResults, catalog, cachedMetadata);
}

public class MysqlIO {

    protected Socket mysqlConnection ; //底层用Socket交互
    
}
//org.springframework.jdbc.datasource.DataSourceTransactionManager
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
		implements ResourceTransactionManager, InitializingBean {
	protected void doBegin(Object transaction, TransactionDefinition definition) {
            if (con.getAutoCommit()) {
                    txObject.setMustRestoreAutoCommit(true);
                        //private boolean autoCommit = true; 属性默认配置的是true。如果配置以非事务运行(比如配置NOT_SUPPORTED),会自动提交,如果配置事务,就改成false
                        con.setAutoCommit(false);//碰到事务自动提交的时候,设置为false,然后才能把数据库的事务托管给Spring来处理。
            }
        }

}

下面是ConnectionImpl中 回滚源码
public void rollback() throws SQLException {
    this.rollbackNoChecks();
}
private void rollbackNoChecks() throws SQLException {
    this.execSQL((StatementImpl)null, "rollback", -1, (Buffer)null, 1003, 1007, false, this.database, (Field[])null, false);
}
提交源码
public void commit() throws SQLException {
    this.execSQL((StatementImpl)null, "commit", -1, (Buffer)null, 1003, 1007, false, this.database, (Field[])null, false);
}
提交和回滚都是通过MysqlIO中的socket来进行和数据库操作,其实在数据库里的增删改操作都会建立一个临时表,然后进行改动操作。然后根据sping托管的事务进行commit和rollback。  commit的时候就是把临时表数据持久化到磁盘,回滚就中终止持久化操作