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

推广网站可以做跳转吗北京市建设资格注册中心网站

推广网站可以做跳转吗,北京市建设资格注册中心网站,seo网站推广seo,网站开发月薪前面我们说了一级缓存#xff0c;但是实际上我们说那玩意其实不咋实用。于是既然设计了缓存体系#xff0c;就不可能弄个不实用的给人们。所以这里就引出二级全局缓存。 全局缓存就是无视sqlSession#xff0c;你可以理解为一个分布式的缓存。作为全局的访问。 一、二级缓存…前面我们说了一级缓存但是实际上我们说那玩意其实不咋实用。于是既然设计了缓存体系就不可能弄个不实用的给人们。所以这里就引出二级全局缓存。 全局缓存就是无视sqlSession你可以理解为一个分布式的缓存。作为全局的访问。 一、二级缓存 1、开启方式 二级缓存默认是不开启的所以他需要你手动去开启。开启方式需要满足下面四个条件。 1、需要在核心配置文件我的是sqlMapConfig.xml中指定在setting 中的配置。其实最新版mybatis这个条件其实可以不用因为在configuration中的cache默认就是true。 2、需要在mapper.xml中引进二级缓存Cache的标签。 3、需要在查询标签select中引入useCache属性打开。其实这个也是可以不用配置的我们这里就先配置上。 4、需要有事务的存在。第一步和第三步可以不写。 于是我们就来操作验证一下我们首先在UserMapper.xml中配置第二步和第三步。 mapper namespacecom.yx.dao.IUserDaocache/cacheselect idfindAll resultTypecom.yx.domain.User useCachetrueSELECT * FROM user/select /mapper然后在代码中开启事务的提交。 Test public void test3() throws IOException {// 读取配置文件转化为流InputStream inputStream Resources.getResourceAsStream(sqlMapConfig.xml);SqlSessionFactory factory new SqlSessionFactoryBuilder().build(inputStream);SqlSession sqlSession factory.openSession();SqlSession sqlSession2 factory.openSession();//这⾥不调⽤SqlSession的api,⽽是获得了接⼝对象调⽤接⼝中的⽅法。使用JDK动态代理产生代理对象IUserDao userDao sqlSession.getMapper(IUserDao.class);IUserDao userDao2 sqlSession2.getMapper(IUserDao.class);// 第一次执行查询ListUser userList userDao.findAll();userList.forEach(user - {System.out.println(user.toString());});// 事务提交sqlSession.commit();System.out.println(*************************************************);// 第二次执行相同的查询ListUser userList2 userDao2.findAll();userList2.forEach(user - {System.out.println(user.toString());});// 事务提交sqlSession2.commit(); }我们看下输出 Opening JDBC Connection Loading class com.mysql.jdbc.Driver. This is deprecated. The new driver class is com.mysql.cj.jdbc.Driver. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary. Created connection 203819996. Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImplc260bdc]Preparing: SELECT * FROM userParameters: Columns: id, nameRow: 1, 张飞Row: 2, 关羽Row: 3, 孙权Total: 3 User{id1, username张飞} User{id2, username关羽} User{id3, username孙权} ************************************************* As you are using functionality that deserializes object streams, it is recommended to define the JEP-290 serial filter. Please refer to https://docs.oracle.com/pls/topic/lookup?ctxjavase15idGUID-8296D8E8-2B93-4B9A-856E-0A65AF9B8C66 Cache Hit Ratio [com.yx.dao.IUserDao]: 0.5// 缓存命中 User{id1, username张飞} User{id2, username关羽} User{id3, username孙权}我们看到缓存被命中了第二次新的sqlsession中并没有执行sql也没有创建连接可见mybatis内部是维护着二级缓存的。而且我们看到命中率是0.5其实就是我们查了两次只有第二次命中了就是百分之五十。 二、源码设计 1、装饰器的使用 我们前面说过装饰器模式https://blog.csdn.net/liuwenqiang1314/article/details/135583787?spm1001.2014.3001.5501 在这个二级缓存这里可以看到一个类起主要作用就是CachingExecutor他是Executor接口的实现类。而他和其他的SimpleExecutorBatchExecutor有啥区别呢。 我们上一章知道BatchExecutor和SimpleExecutor通过继承BaseExecutor这个适配器来进行操作数据库。 而CachingExecutor是直接实现了Executor实际上他是一个装饰器他用来装饰其他的Executor。怎么证明呢。我们来想想Executor是在哪里创建呢我们前面说Configuration的时候知道Configuration不仅仅包罗万象而且创建了很多基本操作类其中就包括Exector。我们可以看到他的源码位于。 org.apache.ibatis.session.Configuration#newExecutor public Executor newExecutor(Transaction transaction, ExecutorType executorType) {executorType executorType null ? defaultExecutorType : executorType;executorType executorType null ? ExecutorType.SIMPLE : executorType;Executor executor;// 根据参数类型创建不同的executor 默认是SimpleExecutorif (ExecutorType.BATCH executorType) {executor new BatchExecutor(this, transaction);} else if (ExecutorType.REUSE executorType) {executor new ReuseExecutor(this, transaction);} else {executor new SimpleExecutor(this, transaction);}/*** 我们看到这里有个配置就是当开启这个cache的时候就去创建缓存的 CachingExecutor* 这里我们说cacheEnabled默认值就是trueprotected boolean cacheEnabled true;* 这个变量其实就是mybatis核心配置文件里面的那个setting里面配置的缓存开启* 最后封装在Configuration的cacheEnabled里面不过默认为true不用配就开了*/if (cacheEnabled) {executor new CachingExecutor(executor);}executor (Executor) interceptorChain.pluginAll(executor);return executor;}我们前面说过装饰器的时候我们说就是套娃这里可以看到他把上面创建的BatchExecutor或者是SimpleExecutor或者是ReuseExecutor。为了方便说下面我们统一叫做SimpleExecutor。所以这里就套娃了他把SimpleExecutor套入CachingExecutor做装饰器的增强。 于是我们就跟入这个增强类也就是CachingExecutor来看一下这个增强发生的地方。 public class CachingExecutor implements Executor {private final Executor delegate;private final TransactionalCacheManager tcm new TransactionalCacheManager();// 套娃就发生在这里我们看到他把SimpleExecutor交给了CachingExecutor 的delegatepublic CachingExecutor(Executor delegate) {this.delegate delegate;delegate.setExecutorWrapper(this);}我们看到他把SimpleExecutor交给了CachingExecutor 的delegate那么增强到底发生在哪里呢既然缓存是针对查询的那么我们就去看CachingExecutor的查询方法。也就是org.apache.ibatis.executor.CachingExecutor#query Override public E ListE query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)throws SQLException {// 去MappedStatement中获取缓存开启了缓存其实就是UserMapper.xml中的cache/cache这个配置开启了没有// 因为MappedStatement封装的就是mapper文件所以这个变量就是封装在MappedStatement中的Cache cache ms.getCache();// 如果存在也就是开启了if (cache ! null) {// 如果你在sql中配置了flushCachetrue那就会来刷新缓存实时查询保证一致性。但是一般不配置不然缓存其实就没用了但是有些查询可能需要这个实时性那就需要在这类sql上配置。而且update操作就会刷新缓存。避免脏数据而且清空的就是这个MappedStatement 其他的并不清空。flushCacheIfRequired(ms);// 如果你的sql标签上指定了useCachetrue,现在也是默认的了不用管了if (ms.isUseCache() resultHandler null) {ensureNoOutParams(ms, boundSql);SuppressWarnings(unchecked)// 此时有缓存直接就拿了tcm就是装饰器增强的业务list是为了尊重sql的排序sql查出来啥顺序就是啥顺序set和map可能会导致顺序和sql的不一致ListE list (ListE) tcm.getObject(cache, key);if (list null) {// 这里是你开启了cache/cache然后发现没缓存其实就是第一次那也来这里查一次库list delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);// 设置第一次查的结果去缓存tcm.putObject(cache, key, list); // issue #578 and #116}return list;}}// 如果没开启cache/cache那就去查SimpleExecutor这个装饰器被装饰的Executor中的查询方法return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }2、何时创建cache 我们说我们配置了cache标签才会使用到所以那一定是在解析这个标签的时候才触发的。但是我们又知道在核心配置文件中的那个已经没用了我们主要是在mapper中配置的那个cache才是有用的于是我们就应该去找到解析mapper封装MappedStatement 的地方去找。路子就是 SqlSessionFactory factory new SqlSessionFactoryBuilder().build(inputStream);中的build方法往下 org.apache.ibatis.builder.xml.XMLConfigBuilder#parseConfiguration 然后其中的mapperElement(root.evalNode(“mappers”));是解析mapper文件的我们点进去。其中的mapperParser.parse();一看就是解析的点进去。 configurationElement(parser.evalNode(“/mapper”));这句一看就是找到根目录开始解析。点进去。 org.apache.ibatis.builder.xml.XMLMapperBuilder#configurationElement private void configurationElement(XNode context) {try {String namespace context.getStringAttribute(namespace);if (namespace null || namespace.isEmpty()) {throw new BuilderException(Mappers namespace cannot be empty);}builderAssistant.setCurrentNamespace(namespace);cacheRefElement(context.evalNode(cache-ref));// 处理缓存的点进去cacheElement(context.evalNode(cache));parameterMapElement(context.evalNodes(/mapper/parameterMap));resultMapElements(context.evalNodes(/mapper/resultMap));sqlElement(context.evalNodes(/mapper/sql));buildStatementFromContext(context.evalNodes(select|insert|update|delete));} catch (Exception e) {throw new BuilderException(Error parsing Mapper XML. The XML location is resource . Cause: e, e);}}cacheElement(context.evalNode(“cache”));就是判断这个缓存标签的我们就知道这里是处理的点进去看看。 private void cacheElement(XNode context) {if (context ! null) {String type context.getStringAttribute(type, PERPETUAL);Class? extends Cache typeClass typeAliasRegistry.resolveAlias(type);String eviction context.getStringAttribute(eviction, LRU);Class? extends Cache evictionClass typeAliasRegistry.resolveAlias(eviction);Long flushInterval context.getLongAttribute(flushInterval);Integer size context.getIntAttribute(size);boolean readWrite !context.getBooleanAttribute(readOnly, false);boolean blocking context.getBooleanAttribute(blocking, false);Properties props context.getChildrenAsProperties();// 我们看到这里开始使用新的缓存其实就是这里创建的。builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props);}}org.apache.ibatis.builder.MapperBuilderAssistant#useNewCache public Cache useNewCache(Class? extends Cache typeClass,Class? extends Cache evictionClass,Long flushInterval,Integer size,boolean readWrite,boolean blocking,Properties props) {// 这里是个建造者模式Cache cache new CacheBuilder(currentNamespace).implementation(valueOrDefault(typeClass, PerpetualCache.class)).addDecorator(valueOrDefault(evictionClass, LruCache.class)).clearInterval(flushInterval).size(size).readWrite(readWrite).blocking(blocking).properties(props).build();configuration.addCache(cache);currentCache cache;return cache;}此时就创建出来缓存对象了。也就是我们前面说的装饰器模式的那个Cache不过后面你会套娃给他不断增强。虽然默认的也没有。我们来看下他怎么build的我们点进去build的实现。 public Cache build() {setDefaultImplementations();// 如果你自己实现了cache这里就会执行你的那个缓存方式创建你的cache比如你用redis就会创建redis方式的cache至于怎么创建后面我们再看// 底层就是反射你要是没实现那就还是他自己的PerpetualCacheCache cache newBaseCacheInstance(implementation, id);// cache的seeting有多个配置这里设置进去你自己配置的多个后面我们来看,类似这样/*cacheproperty name value/property name value//cache*/setCacheProperties(cache);// issue #352, do not apply decorators to custom caches// 你没自定义扩展这里就是默认的PerpetualCache就进这里if (PerpetualCache.class.equals(cache.getClass())) {// 针对你自己的decorators来进行增强装饰你也可以自己配置for (Class? extends Cache decorator : decorators) {cache newCacheDecoratorInstance(decorator, cache);setCacheProperties(cache);}// 没有你自己的那就直接进行装饰装饰的方法也是根据你的配置evictionFIFO就是把默认的换成FIFO/*** cache size flushInterval blocking readOnly* property name value/* property name value/* /cache*//**MetaObject metaCache SystemMetaObject.forObject(cache);if (size ! null metaCache.hasSetter(size)) {metaCache.setValue(size, size);}// 配的定时清理就是任务的装饰器下面有各自的可以多配顺序套娃即可你加了才会给你配置不加就是默认那两个LoggingCacheSynchronizedCacheif (clearInterval ! null) {cache new ScheduledCache(cache);((ScheduledCache) cache).setClearInterval(clearInterval);}if (readWrite) {cache new SerializedCache(cache);}// 这两个是都有的cache new LoggingCache(cache);cache new SynchronizedCache(cache);if (blocking) {// 你赔了这个就是走的阻塞队列装饰增强cache new BlockingCache(cache);}return cache;*/cache setStandardDecorators(cache);}// 如果不是默认的那就给你加强一个装饰器就是日志装饰器的套娃其实就是一旦你不默认打日志出来让你看看else if (!LoggingCache.class.isAssignableFrom(cache.getClass())) {cache new LoggingCache(cache);}return cache;}所以你能看到他会整合你的配置进行对应的增强创建出新的cache对象(可能是redis这种)后面再通过装饰器模式进行功能的增强。这样cache对象就创建出来了最终放到mappstatement里面。于是我们就知道CachingExecutor 在使用缓存的时候需要通过MappedStatement 来获取缓存。Cache cache ms.getCache(); 也就是org.apache.ibatis.executor.CachingExecutor#query public E ListE query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql){// 去MappedStatement中获取缓存开启了缓存其实就是UserMapper.xml中的cache/cache这个配置开启了没有// 因为MappedStatement封装的就是mapper文件所以这个变量就是封装在MappedStatement中的Cache cache ms.getCache(); 三、一级二级缓存的时机 我们现在知道一级缓存和二级缓存了那么问题来了当我开启二级缓存的时候是先触发一级缓存呢还是二级缓存呢。我们来看下创建Exector的地方。 org.apache.ibatis.session.Configuration#newExecutor public Executor newExecutor(Transaction transaction, ExecutorType executorType) {executorType executorType null ? defaultExecutorType : executorType;executorType executorType null ? ExecutorType.SIMPLE : executorType;Executor executor;if (ExecutorType.BATCH executorType) {executor new BatchExecutor(this, transaction);} else if (ExecutorType.REUSE executorType) {executor new ReuseExecutor(this, transaction);} else {executor new SimpleExecutor(this, transaction);}/*** 我们看到这里有个配置就是当开启这个cache的时候就去创建缓存的 CachingExecutor* 这里我们说cacheEnabled默认值就是trueprotected boolean cacheEnabled true;* 这个变量其实就是mybatis核心配置文件里面的那个setting里面配置的缓存开启* 最后封装在Configuration的cacheEnabled里面不过默认为true不用配就开了*/if (cacheEnabled) {executor new CachingExecutor(executor);}executor (Executor) interceptorChain.pluginAll(executor);return executor;}我们看到最后其实当你开启二级缓存的时候他会给你创建出来的是executor new CachingExecutor(executor);就是CachingExecutor。 CachingExecutor包装了(套娃了)SimpleExecutor而SimpleExecutor的查询功能是放在适配器BaseExecutor中的。所以他的处理链路是。 CachingExecutor-BaseExecutor-SimpleExecutor CachingExecutor是去查二级缓存的BaseExecutor是去查一级缓存的所以其实是先二级再一级。可以debug看一下。 1、debug验证 断点跟这个方法就看到了。今天乙流就不弄了很简单的。 org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)
http://www.pierceye.com/news/769041/

相关文章:

  • 网站图片做多大浙江建设人才网
  • 网站关键词宝塔wordpress腾讯云
  • 优化排名推广教程网站免费房地产网站模板
  • 商城网站建设都需要多少钱电子商务网站建设预算
  • 万荣做网站怎么优化一个网站关键词
  • 潍坊市建设局网站网络工程师 网站建设
  • 做网站要求什么条件计算机网络技术学什么
  • 建设网站呼叫中心有什么好处中国能源建设集团有限公司级别
  • 免费论坛建站二 网站建设的重要性
  • wordpress站点迁移怎样做带音乐的表白网站
  • 海淀网站制作网站建设基本技术
  • 做一个平面网站的成本如何搭建一个app平台
  • 建设工程学部研究生培养网站义乌网站建设和制作
  • 简单的模板网站吉安网站建设jxthw
  • js做的网站佛山本地的网站设计公司
  • 企业网站页面网站建设朝阳
  • ui设计工具有哪些百度seo排名优化系统
  • 网站建设案例简介怎么写淘宝官方网站主页
  • 国外网站 dns南京模板做网站
  • 河北企业网站建设技术江西省外省建设入库网站
  • 网站建设的概念如何将自己做的网站放到网上去
  • 网站维护明细报价表最新的网站建设架构
  • 百度大全seo推广话术
  • 做网站赚钱流程英文网站建设注意什么
  • 腾讯 云上做网站教程开源系统 网站
  • 临沂罗庄做网站服装商城网站建设价格
  • 保定企业官网搭建对网站有效的优化软件
  • 网站后台代码在哪修改股权众筹网站建设
  • 站群源码北京公司注销
  • 营销型网站策划建设台州市住房和城乡建设厅网站