@Service
public class DemoServiceImpl implements DemoService {
@Autowired
private UserMapper userMapper;
@Override
@Transactional
public String sayHello(String name) {
List list= userMapper.selectUser();
return "Hello, " + name + " (from Spring Boot)"+ JSONObject.toJSONString(list);
}
}
这是一段使用查询用户列表的代码;UserMapper 是Dao层的一个接口。为什么注入了这个接口,就可以直接查询到了数据?这背后到底发生了什么?今天辉哥就来一层层的扒开她的面纱,喜欢的朋友点个赞哦;读此文需了解JDBC运行及Mybatis使用
首先我们来了解几个常用的概念,了解一下Mybatis基本运行原理
一、SqlSessionFactory简单的理解,SqlSessionFactory是一个工厂类,专门生成SqlSession;下面是Mybatis简单使用Demo
图1
@Test
public void test() throws IOException {
String resources = "mybatis-config.xml";
InputStream in = Resources.getResourceAsStream(resources);
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession = sessionFactory.openSession(true);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List users = mapper.selectUser();
for (User user : users) {
System.out.println(user);
}
}
从这一段代码中,可以看出;SqlSessionFactory由SqlSessionFactoryBuilder从配置文件中构建;
来深入一下SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in);多余的代码先去掉,直接进入到核心的代码如下:
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
从这里可以看出他只是读取了配置文件;parser.parse()主要是构建Configuration ,Configuration简单的理解就是解析Mybatis配置文件,转成一个对象类,由XmlConfigBuilder生成;SqlSessionFactory最终由build(parser.parse())方法 生成默认的SqlSessionFactory;源码如下:
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
二、SqlSession
图1中:执行语句 SqlSession sqlSession = sessionFactory.openSession(true); 生成了Session
openSession(true)方法最终调用了openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit)方法;来看一下这个源码
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();
}
}
ExecutorType execType执行器默认使用Simple版本;TransactionIsolationLevel level事务隔离级别为默认;boolean autoCommit自动提交为true
图1中执行 UserMapper mapper = sqlSession.getMapper(UserMapper.class),生成代理类。
最终调用的核心源码是
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
MapperProxy是一个InvocationHandler类,里面有代理的逻辑
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (method.isDefault()) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
执行MapperMethod类中的execute方法,来执行相应的sql
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
case INSERT: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
case DELETE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
... ...
}
Sqlsession中封装了数据源;Sql的预编译语句,等参数,可以通地SqlSession直接执行语句;
内部也封装了一级缓存,当重复sql在同 一个sqlsession中执行时,可以直接从缓存中获取;这类源码就不一一展示了,有兴趣的伙伴可以自行进入看看。
通过以上神 *** 作,整个 *** 作数据的流程就可以走通啦!
三、SqlSessionTemplateSqlsessionTemplate本质是对SqlSession的一次封装;复用当前线程中存在的SqlSession;并生成代理对象;上源码一目了然
public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
PersistenceExceptionTranslator exceptionTranslator) {
notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
notNull(executorType, "Property 'executorType' is required");
this.sqlSessionFactory = sqlSessionFactory;
this.executorType = executorType;
this.exceptionTranslator = exceptionTranslator;
this.sqlSessionProxy = (SqlSession) newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[] { SqlSession.class },
new SqlSessionInterceptor());
}
sqlSessionProxy是一个代理类,他代理了什么呢?来看一下SqlSessionInterceptor();
private class SqlSessionInterceptor implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SqlSession sqlSession = getSqlSession(
SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType,
SqlSessionTemplate.this.exceptionTranslator);
Object result = method.invoke(sqlSession, args);
if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
// force commit even on non-dirty sessions because some databases require
// a commit/rollback before calling close()
sqlSession.commit(true);
}
return result;
}
public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);
notNull(executorType, NO_EXECUTOR_TYPE_SPECIFIED);
SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
SqlSession session = sessionHolder(executorType, holder);
if (session != null) {
return session;
}
LOGGER.debug(() -> "Creating a new SqlSession");
session = sessionFactory.openSession(executorType);
registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);
return session;
}
}
从getSqlSession方法中可以看到,从当前线程的ThreadLocal中获取了SqlSessionHolder 对象; (不了解TransactionSynchronizationManager.getResource(sessionFactory);方法的,可以了解一下事务同步器获取ThreadLocal中的对象。)
并从SqlSessionHolder中获取SqlSession对象。因此本质上是从当前线程中复用SqlSession;
当然,如果当前线程中的SqlSession为空,则会执行session=sessionFactory.openSession(executorType);从新获取一个SqlSession;
至此三大重要概念都讲解完毕!下一期讲解Spring整合!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)