当前位置: 首页 > news >正文

基于php的网站开发设计广告投放收费标准

基于php的网站开发设计,广告投放收费标准,wordpress为导航添加图标,南京浦口住房与城乡建设局网站2. Mybatis 中SQL 执行原理 这里有两种方式,一种为常用的 Spring 依赖注入 Mapper 的方式。另一种为直接使用 SqlSessionTemplate 执行 Sql 的方式。 Spring 依赖注入 Mapper 的方式 Mapper 接口注入 SpringIOC 容器 Spring 容器在扫描 BeanDefinition 阶段会扫…

2. Mybatis 中SQL 执行原理

这里有两种方式,一种为常用的 Spring 依赖注入 Mapper 的方式。另一种为直接使用 SqlSessionTemplate 执行 Sql 的方式。

Spring 依赖注入 Mapper 的方式

Mapper 接口注入 SpringIOC 容器
  1. Spring 容器在扫描 BeanDefinition 阶段会扫描 Mapper 接口类,并生成这些类的 MapperFactoryBean 的工厂 bean 定义。
  2. Spring 容器在 createBean 阶段的时候,会根据 BeanDefintion 创建 bean。在创建完 factoryBean 的时候,会调用 factoryBean 的 getObject()方法,从 DefaultSqlSession 的 knownMapper 重获取 Mapper 接口类的 mapperProxy。
  3. 使用 MapperProxy 创建出代理类。
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);if (mapperProxyFactory == null) {throw new BindingException("Type " + type + " is not known to the MapperRegistry.");} else {try {return mapperProxyFactory.newInstance(sqlSession);} catch (Exception var5) {throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);}}
}public T newInstance(SqlSession sqlSession) {MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);return this.newInstance(mapperProxy);
}protected T newInstance(MapperProxy<T> mapperProxy) {return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}
Mapper 类调用

在 Service 层或者 Controller 层通过注解引入 Bean,这个时候引入的 Mapper 就是上文创建的 MapperProxy。MapperProxy 的增强逻辑首先过滤掉了 Object 类中的 toString()、equal()等方法。

  1. 如果调用的是 Object 类中的方法,直接放过不代理

  2. 对于 Mapper 接口中的方法进行代理。代理前先检查 methodCache 是否缓存了该方法的 invoke 逻辑。

    1. default 方法的逻辑

    2. 非 default 方法的逻辑比较重要。

      1. 通过 PlainMethodInvoker 这个类代理了其他接口方法,代理逻辑在 MapperMethod 中。

      2. MapperMethod 是最为核心的逻辑。MapperMethod 在执行构建方法时,就会创建一个 SqlCommand 和一个 MethodSignature 方法签名。

        1. SqlCommand 封装了从 SqlSession 中 Config 配置中获取到的 MappedStatement。

        2. 调用 execute 方法。传参为 MappedStatement 的增删改查的类型和参数

          1. 根据增删改查的类型选择不同的执行逻辑

          2. 增删改的逻辑:

            1. 解析参数得到 param,反射根据 mybatis 中参数注解解析
            2. sqlSession.insert(this.command.getName(), param) ​或者
            3. sqlSession.update(this.command.getName(), param) ​或者
            4. sqlSession.delete(this.command.getName(), param) ​或者
            5. 处理结果返回值
          3. select 语句根据返回值类型不同调用不同执行逻辑

            1. returnVoid:返回值为空,且有专门的结果类型处理器
            2. returnsMany:​this.executeForMany(sqlSession, args);
            3. returnsMap:​this.executeForMap(sqlSession, args);
            4. returnsCursor:​this.executeForCursor(sqlSession, args);
            5. returnsOne 返回一行:sqlSession.selectOne(this.command.getName(), param);
          4. flush 刷新类型的 SQL:​result = sqlSession.flushStatements();

如果调用的是 Object 类中的方法,直接放过布袋里

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {// 对于Object类中的方法,放过不增强,直接执行即可。return Object.class.equals(method.getDeclaringClass()) ? method.invoke(this, args) :  this.cachedInvoker(method).invoke(proxy, method, args, this.sqlSession);} catch (Throwable var5) {throw ExceptionUtil.unwrapThrowable(var5);}
}

在 MapperProxy 中有一个缓存结构 methodCache:Map<Method, MapperMethodInvoker> methodCache

增强逻辑中会先判断当前方法是否被缓存在 methodCache 中,如果没有,则创建一个放到缓存中。

 MapUtil.computeIfAbsent(this.methodCache, method, (m)->{/*创建缓存*/});

创建逻辑为:

MapUtil.computeIfAbsent(this.methodCache, method, (m) -> {// default方法的逻辑DefaultMethodInvoker,java8和Java9的不一样。if (m.isDefault()) {return privateLookupInMethod == null ? new DefaultMethodInvoker(this.getMethodHandleJava8(method)) :new DefaultMethodInvoker(this.getMethodHandleJava9(method));} else {return new PlainMethodInvoker(new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration()));}
});   

default 的先不用管 DefaultMethodInvoker,直接看 else 中的 PlainMethodInvoker:

创建一个 MapperMethod,然后 PlainMethodInvoker 在 invoke 方法中调用 MapperMethod 的方法 execute()。

在构造 MapperMethod 方法中,创建了一个 SqlCommand 。SqlCommand 封装了从 SqlSession 中 Config 配置中获取到的 MappedStatement。在之后的 execute 方法中执行的就是 SqlCommand 中的 Mapped Statement。

// SqlCommand 封装了从SqlSession中Config配置中获取到的MappedStatement。
public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {this.command = new SqlCommand(config, mapperInterface, method);this.method = new MethodSignature(config, mapperInterface, method);
}private static class PlainMethodInvoker implements MapperMethodInvoker {private final MapperMethod mapperMethod;public PlainMethodInvoker(MapperMethod mapperMethod) {this.mapperMethod = mapperMethod;}public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {return this.mapperMethod.execute(sqlSession, args);}
}

接下来就是执行 SqlSession 中的增删改查方法了。可以先看一下 SqlCommand

public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {String methodName = method.getName();Class<?> declaringClass = method.getDeclaringClass();MappedStatement ms = this.resolveMappedStatement(mapperInterface, methodName, declaringClass, configuration);if (ms <span style="font-weight: bold;" class="mark"> null) {if (method.getAnnotation(Flush.class) </span> null) {throw new BindingException("Invalid bound statement (not found): " + mapperInterface.getName() + "." + methodName);}this.name = null;this.type = SqlCommandType.FLUSH;} else {this.name = ms.getId();this.type = ms.getSqlCommandType();if (this.type == SqlCommandType.UNKNOWN) {throw new BindingException("Unknown execution method for: " + this.name);}}
}

参数转化,然后 excute Sql,封装返回值:

public Object execute(SqlSession sqlSession, Object[] args) {Object result;Object param;switch (this.command.getType()) {case INSERT:// 将args参数数组转换成方法中的注解的参数param = this.method.convertArgsToSqlCommandParam(args);// 调用DefaultSqlSession的insert方法。// 处理结果返回值result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));break;case UPDATE:// 将args参数数组转换成方法中的注解的参数param = this.method.convertArgsToSqlCommandParam(args);// 调用DefaultSqlSession的update方法。// 处理结果返回值result = this.rowCountResult(sqlSession.update(this.command.getName(), param));break;case DELETE:// 将args参数数组转换成方法中的注解的参数param = this.method.convertArgsToSqlCommandParam(args);// 调用DefaultSqlSession的delete方法。// 处理结果返回值result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));break;case SELECT:// select 语句情况较多,根据返回值类型不同调用不同执行逻辑。// returnVoid:返回值为空,且有专门的结果类型处理器if (this.method.returnsVoid() && this.method.hasResultHandler()) {this.executeWithResultHandler(sqlSession, args);result = null;} else if (this.method.returnsMany()) {result = this.executeForMany(sqlSession, args);} else if (this.method.returnsMap()) {result = this.executeForMap(sqlSession, args);} else if (this.method.returnsCursor()) {result = this.executeForCursor(sqlSession, args);} else {param = this.method.convertArgsToSqlCommandParam(args);result = sqlSession.selectOne(this.command.getName(), param);if (this.method.returnsOptional() && (result == null || !this.method.getReturnType().equals(result.getClass()))) {result = Optional.ofNullable(result);}}break;case FLUSH:result = sqlSession.flushStatements();break;default:throw new BindingException("Unknown execution method for: " + this.command.getName());}if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");} else {return result;}}

SqlSessionTemplate 执行 Sql

在创建 SqlSession 的时候已经创建了 Executor。默认为 Simple

    public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {Assert.notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");Assert.notNull(executorType, "Property 'executorType' is required");this.sqlSessionFactory = sqlSessionFactory;this.executorType = executorType;this.exceptionTranslator = exceptionTranslator;this.sqlSessionProxy = (SqlSession)Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[]{SqlSession.class}, new SqlSessionInterceptor());}

在 Spring Boot 自动配置这篇文章中已经讲过

  1. Configuration 类中有一个属性 mappedStatements​。这是一个 HashMap
  2. 解析过后的 MappedStatement ​被添加到了 map 中

当我们的 SqlSession 在执行 sql 语句时,会先从 configuration 中拿到 sql。然后执行。

    private <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {List var6;try {MappedStatement ms = this.configuration.getMappedStatement(statement);var6 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, handler);} catch (Exception var10) {throw ExceptionFactory.wrapException("Error querying database.  Cause: " + var10, var10);} finally {ErrorContext.instance().reset();}return var6;}

然后看一下

    public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {BoundSql boundSql = ms.getBoundSql(parameter);CacheKey key = this.createCacheKey(ms, parameter, rowBounds, boundSql);return this.query(ms, parameter, rowBounds, resultHandler, key, boundSql);}

再往下一层,就是执行 JDBC 那一套了,获取链接,执行,得到 ResultSet,解析 ResultSet 映射成 JavaBean。

http://www.shuangfujiaoyu.com/news/22495.html

相关文章:

  • 浙江高端网站百度sem认证
  • 专业柳州网站建设广州网页定制多少钱
  • 手机端在哪里打开宁波seo整站优化
  • 网站建设 cms 下载网络优化行业的发展前景
  • 厦门seo网站关键词优推广自媒体平台app
  • 可以自己做网站做宣传吗磁力猫torrentkitty官网
  • 类型: 营销型网站建设百度网盘搜索免费资源
  • Vs做的网站调试时如何适应网页百度的代理商有哪些
  • 加油站顶棚网架价多少钱一平seo com
  • 杭州seo网站优化应用商店下载
  • 做淘宝的网站有哪些网络营销的营销策略
  • 合肥网站建设公司还有不长沙seo推广
  • 做平面什么网站的素材不侵权武汉seo优化代理
  • 建行官方网站多少钱种子搜索神器在线搜
  • 一亩地开发多少钱班级优化大师官方免费下载
  • 怎样在手机上做网站关于市场营销的100个问题
  • 做库房推广哪个网站好在哪个平台做推广比较好
  • 网站开发程序用什么好500强企业seo服务商
  • 做网站百灵鸟指数型基金是什么意思
  • 网站建设时间代运营靠谱吗
  • 单网站建设百度指数使用指南
  • 网站制作公司 北京查图百度识图
  • 广州 网站建设模板兰州网站优化
  • 专门做油画交流的网站什么软件可以免费引流
  • 网站专题页面设计海洋网络推广效果
  • 微网站怎么做的好名字吗网推获客平台
  • 做网站是否过时了网站制作免费
  • 做网站续费网站建设网络推广平台
  • 网站建设标语站长查询工具
  • 广东网站建设设计服务福州seo快速排名软件