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

大连专业做网站二级单位网站建设

大连专业做网站,二级单位网站建设,网站开发网址,找工程承包app作为后台服务开发#xff0c;在日常工作中我们天天都在跟数据库打交道#xff0c;一直在进行各种CRUD操作#xff0c;都会使用到数据库连接池。按照发展历程#xff0c;业界知名的数据库连接池有以下几种#xff1a;c3p0、DBCP、Tomcat JDBC Connection Pool、Druid 等在日常工作中我们天天都在跟数据库打交道一直在进行各种CRUD操作都会使用到数据库连接池。按照发展历程业界知名的数据库连接池有以下几种c3p0、DBCP、Tomcat JDBC Connection Pool、Druid 等不过最近最火的是 HiKariCP。 HiKariCP 号称是业界跑得最快的数据库连接池自从 SpringBoot 2.0 将其作为默认数据库连接池后其发展势头锐不可当。那它为什么那么快呢今天咱们就重点聊聊其中的原因。 数据库连接池  在讲解HiKariCP之前我们先简单介绍下什么是数据库连接池Database Connection Pooling以及为什么要有数据库连接池。 从根本上而言数据库连接池和我们常用的线程池一样都属于池化资源它在程序初始化时创建一定数量的数据库连接对象并将其保存在一块内存区中。它允许应用程序重复使用一个现有的数据库连接当需要执行 SQL 时我们是直接从连接池中获取一个连接而不是重新建立一个数据库连接当 SQL 执行完也并不是将数据库连接真的关掉而是将其归还到数据库连接池中。我们可以通过配置连接池的参数来控制连接池中的初始连接数、最小连接、最大连接、最大空闲时间等参数来保证访问数据库的数量在一定可控制的范围类防止系统崩溃同时保证用户良好的体验。数据库连接池示意图如下所示 因此使用数据库连接池的核心作用就是避免数据库连接频繁创建和销毁节省系统开销。因为数据库连接是有限且代价昂贵创建和释放数据库连接都非常耗时频繁地进行这样的操作将占用大量的性能开销进而导致网站的响应速度下降甚至引起服务器崩溃。 HikariCP 数据库连接池简介 HikariCP 号称是史上性能最好的数据库连接池SpringBoot 2.0将它设置为默认的数据源连接池。Hikari相比起其它连接池的性能高了非常多那么这是怎么做到的呢通过查看HikariCP官网介绍对于HikariCP所做优化总结如下 1. 字节码精简 优化代码编译后的字节码量极少使得CPU缓存可以加载更多的程序代码 HikariCP在优化并精简字节码上也下了功夫使用第三方的Java字节码修改类库Javassist来生成委托实现动态代理.动态代理的实现在ProxyFactory类速度更快相比于JDK Proxy生成的字节码更少精简了很多不必要的字节码。 2. 优化代理和拦截器减少代码例如HikariCP的Statement proxy只有100行代码只有BoneCP的十分之一 3. 自定义数组类型FastStatementList代替ArrayList避免ArrayList每次get()都要进行range check避免调用remove()时的从头到尾的扫描由于连接的特点是后获取连接的先释放 4. 自定义集合类型ConcurrentBag提高并发读写的效率 5. 其他针对BoneCP缺陷的优化比如对于耗时超过一个CPU时间片的方法调用的研究。 当然作为一个数据库连接池不能说快就会被消费者所推崇它还具有非常好的健壮性及稳定性。HikariCP从15年推出以来已经经受了广大应用市场的考验并且成功地被SpringBoot2.0作为默认数据库连接池进行推广在可靠性上面是值得信任的。其次借助于其代码量少占用cpu和内存量小的优点使得它的执行率非常高。最后Spring配置HikariCP和druid基本没什么区别迁移过来非常方便这些都是为什么HikariCP目前如此受欢迎的原因。 HikariCP 核心源码解析  1、FastList 是如何优化性能问题的 首先我们来看一下执行数据库操作规范化的操作步骤 通过数据源获取一个数据库连接创建 Statement执行 SQL通过 ResultSet 获取 SQL 执行结果释放 ResultSet释放 Statement释放数据库连接 当前所有数据库连接池都是严格地根据这个顺序来进行数据库操作的为了防止最后的释放操作各类数据库连接池都会把创建的 Statement 保存在数组 ArrayList 里来保证当关闭连接的时候可以依次将数组中的所有 Statement 关闭。HiKariCP 在处理这一步骤中认为 ArrayList 的某些方法操作存在优化空间因此对List接口的精简实现针对List接口中核心的几个方法进行优化其他部分与ArrayList基本一致 。 首先是get()方法ArrayList每次调用get()方法时都会进行rangeCheck检查索引是否越界FastList的实现中去除了这一检查是因为数据库连接池满足索引的合法性能保证不会越界此时rangeCheck就属于无效的计算开销所以不用每次都进行越界检查。省去频繁的无效操作可以明显地减少性能消耗。 FastList get()操作 public T get(int index) {// ArrayList 在此多了范围检测 rangeCheck(index);return elementData[index]; } 其次是remove方法当通过 conn.createStatement() 创建一个 Statement 时需要调用 ArrayList 的 add() 方法加入到 ArrayList 中这个是没有问题的但是当通过 stmt.close() 关闭 Statement 的时候需要调用 ArrayList 的 remove() 方法来将其从 ArrayList 中删除而ArrayList的remove(Object)方法是从头开始遍历数组而FastList是从数组的尾部开始遍历因此更为高效。 假设一个 Connection 依次创建 6 个 Statement分别是 S1、S2、S3、S4、S5、S6而关闭 Statement 的顺序一般都是逆序的从S6 到 S1而 ArrayList 的 remove(Object o) 方法是顺序遍历查找逆序删除而顺序查找这样的查找效率就太慢了。因此FastList对其进行优化改成了逆序查找。如下代码为FastList 实现的数据移除操作相比于ArrayList的 remove()代码 FastList 去除了检查范围 和 从头到尾遍历检查元素的步骤其性能更快。 public boolean remove(Object element) {// 删除操作使用逆序查找for (int index size - 1; index 0; index--) {if (element elementData[index]) {final int numMoved size - index - 1;// 如果角标不是最后一个复制一个新的数组结构if (numMoved 0) {System.arraycopy(elementData, index 1, elementData, index, numMoved);}//如果角标是最后面的 直接初始化为nullelementData[--size] null;return true;}}return false; } 通过上述源码分析FastList 的优化点还是很简单的。相比ArrayList仅仅是去掉了rage检查扩容优化等细节处删除时数组从后往前遍历查找元素等微小的调整从而追求性能极致。当然FastList 对于 ArrayList 的优化我们不能说ArrayList不好。所谓定位不同、追求不同ArrayList作为通用容器更追求安全、稳定操作前rangeCheck检查对非法请求直接抛出异常更符合 fail-fast(快速失败)机制而FastList追求的是性能极致。 下面我们再来聊聊 HiKariCP 中的另外一个数据结构 ConcurrentBag看看它又是如何提升性能的。 2、ConcurrentBag 实现原理分析  当前主流数据库连接池实现方式大都用两个阻塞队列来实现。一个用于保存空闲数据库连接的队列 idle另一个用于保存忙碌数据库连接的队列 busy获取连接时将空闲的数据库连接从 idle 队列移动到 busy 队列而关闭连接时将数据库连接从 busy 移动到 idle。这种方案将并发问题委托给了阻塞队列实现简单但是性能并不是很理想。因为 Java SDK 中的阻塞队列是用锁实现的而高并发场景下锁的争用对性能影响很大。 HiKariCP 并没有使用 Java SDK 中的阻塞队列而是自己实现了一个叫做 ConcurrentBag 的并发容器在连接池多线程数据交互的实现上具有比LinkedBlockingQueue和LinkedTransferQueue更优越的性能。 ConcurrentBag 中最关键的属性有 4 个分别是用于存储所有的数据库连接的共享队列 sharedList、线程本地存储 threadList、等待数据库连接的线程数 waiters 以及分配数据库连接的工具 handoffQueue。其中handoffQueue 用的是 Java SDK 提供的 SynchronousQueueSynchronousQueue 主要用于线程之间传递数据。 ConcurrentBag 中的关键属性 // 存放共享元素用于存储所有的数据库连接 private final CopyOnWriteArrayListT sharedList; // 在 ThreadLocal 缓存线程本地的数据库连接避免线程争用 private final ThreadLocalListObject threadList; // 等待数据库连接的线程数 private final AtomicInteger waiters; // 接力队列用来分配数据库连接 private final SynchronousQueueT handoffQueue; ConcurrentBag 保证了全部的资源均只能通过 add() 方法进行添加当线程池创建了一个数据库连接时通过调用 ConcurrentBag 的 add() 方法加入到 ConcurrentBag 中并通过 remove() 方法进行移出。下面是 add() 方法和 remove() 方法的具体实现添加时实现了将这个连接加入到共享队列 sharedList 中如果此时有线程在等待数据库连接那么就通过 handoffQueue 将这个连接分配给等待的线程。 ConcurrentBag 的 add() 与 remove() 方法 public void add(final T bagEntry) {if (closed) {LOGGER.info(ConcurrentBag has been closed, ignoring add());throw new IllegalStateException(ConcurrentBag has been closed, ignoring add());}// 新添加的资源优先放入sharedListsharedList.add(bagEntry);// 当有等待资源的线程时将资源交到等待线程 handoffQueue 后才返回while (waiters.get() 0 bagEntry.getState() STATE_NOT_IN_USE !handoffQueue.offer(bagEntry)) {yield();} } public boolean remove(final T bagEntry) {// 如果资源正在使用且无法进行状态切换则返回失败if (!bagEntry.compareAndSet(STATE_IN_USE, STATE_REMOVED) !bagEntry.compareAndSet(STATE_RESERVED, STATE_REMOVED) !closed) {LOGGER.warn(Attempt to remove an object from the bag that was not borrowed or reserved: {}, bagEntry);return false;}// 从sharedList中移出/*fin查看线程本地存储 threadList 中是否有空闲连接如果有则返回一个空闲的连接如果线程本地存储中无空闲连接则从共享队列 sharedList 中获取如果共享队列中也没有空闲的连接则请求线程需要等待。*/if (!removed !closed) {LOGGER.warn(Attempt to remove an object from the bag that does not exist: {}, bagEntry);}return removed; } 同时ConcurrentBag通过提供的 borrow() 方法来获取一个空闲的数据库连接并通过requite()方法进行资源回收borrow() 的主要逻辑是 查看线程本地存储 threadList 中是否有空闲连接如果有则返回一个空闲的连接如果线程本地存储中无空闲连接则从共享队列 sharedList 中获取如果共享队列中也没有空闲的连接则请求线程需要等待。 ConcurrentBag 的 borrow() 与 requite() 方法 // 该方法会从连接池中获取连接, 如果没有连接可用, 会一直等待timeout超时 public T borrow(long timeout, final TimeUnit timeUnit) throws InterruptedException {// 首先查看线程本地资源threadList是否有空闲连接final ListObject list threadList.get();// 从后往前反向遍历是有好处的, 因为最后一次使用的连接, 空闲的可能性比较大, 之前的连接可能会被其他线程提前借走了for (int i list.size() - 1; i 0; i--) {final Object entry list.remove(i);SuppressWarnings(unchecked)final T bagEntry weakThreadLocals ? ((WeakReferenceT) entry).get() : (T) entry;// 线程本地存储中的连接也可以被窃取 所以需要用CAS方法防止重复分配if (bagEntry ! null bagEntry.compareAndSet(STATE_NOT_IN_USE, STATE_IN_USE)) {return bagEntry;}}// 当无可用本地化资源时遍历全部资源查看可用资源并用CAS方法防止资源被重复分配final int waiting waiters.incrementAndGet();try {for (T bagEntry : sharedList) {if (bagEntry.compareAndSet(STATE_NOT_IN_USE, STATE_IN_USE)) {// 因为可能“抢走”了其他线程的资源因此提醒包裹进行资源添加if (waiting 1) {listener.addBagItem(waiting - 1);}return bagEntry;}}listener.addBagItem(waiting);timeout timeUnit.toNanos(timeout);do {final long start currentTime();// 当现有全部资源都在使用中时等待一个被释放的资源或者一个新资源final T bagEntry handoffQueue.poll(timeout, NANOSECONDS);if (bagEntry null || bagEntry.compareAndSet(STATE_NOT_IN_USE, STATE_IN_USE)) {return bagEntry;}timeout - elapsedNanos(start);} while (timeout 10_000);return null;}finally {waiters.decrementAndGet();} }public void requite(final T bagEntry) {// 将资源状态转为未在使用bagEntry.setState(STATE_NOT_IN_USE);// 判断是否存在等待线程若存在则直接转手资源for (int i 0; waiters.get() 0; i) {if (bagEntry.getState() ! STATE_NOT_IN_USE || handoffQueue.offer(bagEntry)) {return;}else if ((i 0xff) 0xff) {parkNanos(MICROSECONDS.toNanos(10));}else {yield();}}// 否则进行资源本地化处理final ListObject threadLocalList threadList.get();if (threadLocalList.size() 50) {threadLocalList.add(weakThreadLocals ? new WeakReference(bagEntry) : bagEntry);} } borrow() 方法可以说是整个 HikariCP 中最核心的方法它是我们从连接池中获取连接的时候最终会调用到的方法。需要注意的是 borrow() 方法只提供对象引用不移除对象因此使用时必须通过 requite() 方法进行放回否则容易导致内存泄露。requite() 方法首先将数据库连接状态改为未使用之后查看是否存在等待线程如果有则分配给等待线程否则将该数据库连接保存到线程本地存储里 ConcurrentBag 实现采用了queue-stealing的机制获取元素首先尝试从ThreadLocal中获取属于当前线程的元素来避免锁竞争如果没有可用元素则再次从共享的CopyOnWriteArrayList中获取。此外ThreadLocal和CopyOnWriteArrayList在ConcurrentBag中都是成员变量线程间不共享避免了伪共享(false sharing)的发生。同时因为线程本地存储中的连接是可以被其他线程窃取的在共享队列中获取空闲连接所以需要用 CAS 方法防止重复分配。 总结 本文首先对为什么使用数据库连接池做介绍通过分析HiKariCP官网介绍及其源码可以发现HiKariCP主要通过对字节码进行精简、优化代理和拦截器、自定义数组类型 FastList 及自定义并发集合类型 ConcurrentBag 等内容进行优化文中重点讲解了FastList 与ConcurrentBag 的优化原理FastList 适用于逆序删除场景而 ConcurrentBag 本质上是通过 ThreadLocal 将连接池中的连接按照线程做一次预分配避免直接竞争共享资源减少并发CAS带来的CPU CACHE的频繁失效从而提高性能非常适合池化资源的分配达到显著提升数据库连接池性能的效果。需要注意的是threadLocal可能带来连接池关闭时引用还存在的情况有可能导致内存泄露因此一定要使用requite()方法来进行资源回收处理。 Hikari 作为 SpringBoot2.0默认的连接池目前在行业内使用范围非常广对于大部分业务来说都可以实现快速接入使用做到高效连接。
http://www.huolong8.cn/news/72164/

相关文章:

  • 在县城怎么做网站公司网站开发英文翻译
  • php做网站流程wordpress关闭伪静态
  • 浪子做的阿哲喊麦网站多少企业网站 更新 seo
  • 1元涨1000粉丝网站鞍山58
  • 电商网站如何避免客户信息泄露图形化html编辑器
  • 肥西县城乡建设局网站有关网站建设的知识
  • 学做网站视频论坛沈阳专门做网站
  • 好的ppt模板免费下载网站网站建设费用做做什么科目
  • 购物网站分为几个模块优化手机软件
  • 网站建设 软件服务建站公司经营
  • 简洁的网站建设合同怎么网上推广自己的门店
  • 团购网站建站广州中国建设银行网站首页
  • 传统网站设计的缺点wordpress怎么实现社交
  • 网站备案号规则怎么做关于梦想的网站免费的
  • 做网站流量钱谁给专门做团购的网站
  • 网站建设详细流程请人做网站 我需要知道哪几点
  • 如何设置一个网站wordpress 数据库插件
  • 有机生态农业网站模板做情侣网站
  • 服务类网站建设湖州设计公司
  • php学校网站模板wordpress和论坛整合
  • 沧州网站建设网海申莱芜新闻联播
  • 沭阳哪里可以做网站深圳网络推广网站
  • 深色调网站快速建站介绍
  • 做网站设计需要多少钱做seo排名好的公司
  • 摄影网站采用照片做宣传_版权费是多少?百度关键字怎么搜到公司网站
  • 网站系统接口500异常网站建设 新要求
  • 佛山网站定制简易手工制作
  • 手机版官方网站的建设做外贸的国际网站有哪些
  • 服务器做视频网站吗怎样做网站外部样式
  • 西安网站制作工商网站建设先进个人自荐