SSM中的Mybatis篇(1):
Mybatis是针对数据库进行操作的一个框架,基于jdbc产生的一个便捷的操作数据库的框架,底层是对jdbc进行封装,简化操作数据库的操作量。
Mybatis针对数据库进行操作的两种方式分别是
-
通过对主配置文件的解析,解析出配置文件中的数据,连接数据库。然后解析配置文件中的sql语句,通过sql语句对数据可进行增删改查,完成对数据库的操作
-
通过注解的形式解析出sql语句,再对数据库进行操作
这两种方式原理都是相同的,通过对主配置文件的解析来连接数据库,然后通过xml文件或者注解得到sql语句
这里我们先分析通过解析xml文件操作数据库的方式,首先在主配置文件SqlMapConfig.xml中配置连接数据库的数据库,username,password等…
然后再配置持久层Dao层接口的xml文件(这里数据库的实体类自行编写)注意:Mybatis在resource资源中的xml配置文件,必须和dao接口的包结构一致
编写到这里,我们就不用编写dao层的实现类了,因为Mybatis通过代理类的方式内部生成代理类,大致的步骤就完成了
接下来就可以先读取主配置文件,
写到这里就完成了我们对数据库查找所有的功能,到这里我们对于SqlSession和SqlSessionFactory的用途还不是很了解,下面看一下SqlSession和SqlSessionFactory的代码
SqlSession:
public interface SqlSession extends Closeable {
//以上时查询方法的接口
<T> T selectOne(String var1);
<T> T selectOne(String var1, Object var2);
<E> List<E> selectList(String var1);
<E> List<E> selectList(String var1, Object var2);
<E> List<E> selectList(String var1, Object var2, RowBounds var3);
<K, V> Map<K, V> selectMap(String var1, String var2);
<K, V> Map<K, V> selectMap(String var1, Object var2, String var3);
<K, V> Map<K, V> selectMap(String var1, Object var2, String var3, RowBounds var4);
void select(String var1, Object var2, ResultHandler var3);
void select(String var1, ResultHandler var2);
void select(String var1, Object var2, RowBounds var3, ResultHandler var4);
//增
int insert(String var1);
int insert(String var1, Object var2);
int update(String var1);
int update(String var1, Object var2);
//删
int delete(String var1);
int delete(String var1, Object var2);
//事务提交
void commit();
void commit(boolean var1);
//事务回滚
void rollback();
void rollback(boolean var1);
List<BatchResult> flushStatements();
void close();
void clearCache();
Configuration getConfiguration();
<T> T getMapper(Class<T> var1);
Connection getConnection();
}
这样看来SqlSession就是数据库crud的接口,
SqlSessionFactory:
//这个类的主要作用就是通过SqlSessionFactory的openSession方法得到一个SqlSession
public interface SqlSessionFactory {
SqlSession openSession();
SqlSession openSession(boolean var1);
SqlSession openSession(Connection var1);
SqlSession openSession(TransactionIsolationLevel var1);
SqlSession openSession(ExecutorType var1);
SqlSession openSession(ExecutorType var1, boolean var2);
SqlSession openSession(ExecutorType var1, TransactionIsolationLevel var2);
SqlSession openSession(ExecutorType var1, Connection var2);
Configuration getConfiguration();
}
这个接口的主要作用就是通过openSession方法得到一个SqlSession
我们可以清楚的通过idea查看SqlSession和SqlSessionFactory的结构图,通过结构图的查找我们可以清楚的看到
SqlSession的实现类是DefaultSqlSession和SqlSessionManager
SqlSessionFactory实现类是–DefaultSqlSessionFactory和SqlSessionManager
下面我们分析一下这两个实现类的部分用到的源码
org.apache.ibatis.session.defaults.DefaultSqlSessionFactory.java部分源码:
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private final Configuration configuration;
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
//...
DefaultSqlSession的有参构造的第一步就是注入了一个类Configuration,这个类就是解析主配置文件后,存放连接数据库的username,password等等,创建一个DefaultSqlSession并返回
org.apache.ibatis.session.defaults.DefaultSqlSession.java部分源码:
private Configuration configuration;
private Executor executor;
@Override
public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
executor.query(ms, wrapCollection(parameter), rowBounds, handler);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
@Override
public int update(String statement, Object parameter) {
try {
dirty = true;
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.update(ms, wrapCollection(parameter));
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
都是从配置对象Configuration中取出属性来,委托给执行器Executor去处理。
SqlSessionManager同时实现了SqlSession和SqlSessionFactory接口。
org.apache.ibatis.session.SqlSessionManager.java部分源码。
public class SqlSessionManager implements SqlSessionFactory, SqlSession {
private final SqlSessionFactory sqlSessionFactory;
// proxy
private final SqlSession sqlSessionProxy;
// 保持线程局部变量SqlSession的地方
private ThreadLocal<SqlSession> localSqlSession = new ThreadLocal<SqlSession>();
private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
// 这个proxy是重点
this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[]{SqlSession.class},
new SqlSessionInterceptor());
}
public static SqlSessionManager newInstance(Reader reader) {
return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, null, null));
}
public static SqlSessionManager newInstance(Reader reader, String environment) {
return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, environment, null));
}
//...
// 设置线程局部变量sqlSession的方法
public void startManagedSession() {
this.localSqlSession.set(openSession());
}
public void startManagedSession(boolean autoCommit) {
this.localSqlSession.set(openSession(autoCommit));
}
//...
@Override
public <T> T selectOne(String statement, Object parameter) {
return sqlSessionProxy.<T> selectOne(statement, parameter);
}
@Override
public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
return sqlSessionProxy.<K, V> selectMap(statement, mapKey);
}
//...
变量sqlSessionFactory:相当于DefaultSqlSessionFactory的实例(不是proxy)。
变量sqlSessionProxy:是JDK动态代理出来的proxy(是proxy)。
动态代理的目的,是为了通过拦截器InvocationHandler,增强目标target的方法调用。
target:DefaultSqlSession的实例。
所有的调用sqlSessionProxy代理对象的C、R、U、D及事务方法,都将经过SqlSessionInterceptor拦截器,并最终由目标对象target实际完成数据库操作。
sqlSessionProxy代理对象一次性执行了一系列的方法业务,最后统一异常回滚,统一关闭sqlSession,没时间了下次再更改