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
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的时候就是把临时表数据持久化到磁盘,回滚就中终止持久化操作