精华内容
下载资源
问答
  • mysql支不支持binary型的,如何用blob存取图片,能给出实例代码吗?大哥们给出一些实例呗Connectionconn=null;...conn=DriverManager.getCo... mysql支不支持binary型的,如何用blob存取...你们看看这段代码错误吗 展开

    mysql支不支持binary型的,如何用blob存取图片,能给出实例代码吗?大哥们给出一些实例呗Connectionconn=null;try{Class.forName("com.mysql.jdbc.Driver");conn=DriverManager.getCo...

    mysql支不支持binary型的,如何用blob存取图片,能给出实例代码吗? 大哥们给出一些实例呗

    Connection conn=null;

    try {

    Class.forName("com.mysql.jdbc.Driver");

    conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/photo","root","root");

    } catch (ClassNotFoundException e) {

    e.printStackTrace();

    } catch (SQLException e) {

    e.printStackTrace();

    }

    String id=request.getParameter("id");

    String fileName=request.getParameter("image");

    FileInputStream str=new FileInputStream(fileName);

    String sql="insert into photo(id,photo)values(?,?)";

    PreparedStatement pstmt=conn.prepareStatement(sql);

    pstmt.setString(1,id);

    pstmt.setBlob(2,str,str.available());

    pstmt.execute();

    pstmt.close();

    out.println("恭喜,已经将新的数据库添加到数据库中");你们看看这段代码有错误吗

    展开

    展开全文
  • 原文:浏览器存储的不同类型简介浏览器许多选项可用于存储数据。根据Chrome团队的建议,我们的首选存储应该是IndexedDB,它是异步存储足够的空间来存储我们想要的任何东西。不鼓励使用 localStorage,但它比 ...
    原文:浏览器存储的不同类型简介浏览器有许多选项可用于存储数据。根据Chrome团队的建议,我们的首选存储应该是IndexedDB,它是异步存储,有足够的空间来存储我们想要的任何东西。不鼓励使用 localStorage,但它比 IndexedDB 更易于使用。Cookies是与服务器共享客户端状态的一种好方法,但通常用于身份验证。

    在后端开发中,存储是工作的常见部分。应用程序数据存储在数据库中,文件存储在对象存储中,瞬态数据存储在高速缓存中……似乎存在无限种存储任何类型数据的可能性。但是,数据存储不仅限于后端,前端(浏览器)还具有许多存储数据的选项。我们可以通过利用这种存储方式来提升我们的应用性能,保存用户的偏好,在多个会话,甚至不同的计算机上保持应用状态。

    在本文中,我们将通过不同的可能性在浏览器中存储数据。我们将涵盖每种方法的三个用例,以掌握其利弊。最后,你将能够决定什么存储是最适合你的用例。

    让我们开始吧!

    localStorage API

    localStorage 是浏览器中最受欢迎的存储选项之一,也是许多开发人员的首选。数据跨会话存储,从不与服务器共享,并且可用于同一协议和域下的所有页面。存储空间限制为〜5MB。

    令人惊讶的是,谷歌Chrome团队并不建议使用这个选项,因为它屏蔽了主线程,而且web workers和service workers无法访问。他们推出了一个实验:KV Storage,作为一个更好的版本,但这只是一个试验,似乎还没有任何进展。

    localStorage API 可作为 window.localStorage 使用,并且只能保存UTF-16字符串。在将数据保存到 localStorage 之前,我们必须确保将其转换为字符串。主要的三个功能是:

    • setItem('key', 'value')
    • getItem('key')
    • removeItem('key')

    它们都是同步的,因此使用起来很简单,但是它们会阻塞主线程。

    值得一提的是,localStorage 有一个称为 sessionStorage 的双胞胎。唯一的区别是,存储在 sessionStorage 中的数据将仅持续当前会话,但API相同。

    这个太简单了,相信大家都用过。

    IndexedDB API

    IndexedDB是浏览器中的现代存储解决方案。它可以存储大量的结构化数据,甚至文件和Blob。和每一个数据库一样,IndexedDB对数据进行索引,以便高效地运行查询。使用IndexedDB比较复杂,我们必须创建一个数据库,表,并使用事务。

    localStorage 相比,IndexedDB需要更多代码。在例子中,我使用了原生API与Promise包装器,但我强烈建议使用第三方库来帮助你。我推荐的是localForage,因为它使用了同样的 localStorage API,但实现方式是逐步增强的,也就是说,如果你的浏览器支持IndexedDB,就会使用它;如果不支持,就会退回到 localStorage

    让我们来编写代码,前往我们的用户偏好示例吧!

    <input type="checkbox" id="darkTheme" name="darkTheme" onclick='onChange(this);'>
    <label for="darkTheme">Dark theme</label><br>
    let db;
    
    function toggle(on) {
      if (on) {
        document.documentElement.classList.add('dark'); 
      } else {
        document.documentElement.classList.remove('dark');    
      }
    }
    
    async function save(on) {
      const tx = db.transaction('preferences', 'readwrite');
      const store = tx.objectStore('preferences');
      store.put({key: 'darkTheme', value: on});
      return tx.complete;
    }
    
    async function load() {
      const tx = db.transaction('preferences', 'readonly');
      const store = tx.objectStore('preferences');
      const data = await store.get('darkTheme');
      return data && data.value;
    }
    
    async function onChange(checkbox) {
      const value = checkbox.checked;
      toggle(value);
      await save(value);
    }
    
    function openDatabase() {
      return idb.openDB('my-db', 1, {
        upgrade(db) {
          db.createObjectStore('preferences', {keyPath: 'key'});
        },
      });
    }
    
    openDatabase()
      .then((_db) => {
        db = _db;
        return load();
      })
      .then((initialValue) => {
        toggle(initialValue);
        document.querySelector('#darkTheme').checked = initialValue;
      });

    效果

    8782f691c06baa88f90cbfa16e8bc2c8.png

    idb 是我们使用的Promise包装器,而不是使用基于事件的低级API。首先要注意的是,对数据库的每次访问都是异步的,这意味着我们不会阻塞主线程,与 localStorage 相比,这是一个主要优势。

    我们需要打开与数据库的连接,以便在整个应用程序中都可以使用它进行读写。我们给数据库起一个名字 my-db,一个模式版本 1,以及一个更新函数,以在版本之间应用更改,这与数据库迁移非常相似。我们的数据库架构很简单:只有一个object store preferences。object store 等效于SQL表,要写入或读取数据库,必须使用事务,这是使用IndexedDB的乏味部分。看一下演示中新的 saveload 功能。

    毫无疑问,IndexedDB具有更多的开销,并且与 localStorage 相比,学习曲线更陡峭。对于键值的情况,使用 localStorage 或第三方库可能更有意义,它们将帮助我们提高效率。

    <div id="loading">loading...</div>
    <ul id="list">
    </ul>
    let db;
    
    async function loadPokemons() {
      const res = await fetch('https://pokeapi.co/api/v2/pokemon?limit=10');
      const data = await res.json();
      return data.results;
    }
    
    function removeLoading() {
      const elem = document.querySelector('#loading');
      if (elem) {
        elem.parentNode.removeChild(elem); 
      }
    }
    
    function appendPokemon(pokemon) {
      const node = document.createElement('li');
      const textnode = document.createTextNode(pokemon.name);
      node.appendChild(textnode);
      document.querySelector('#list').appendChild(node);
    }
    
    function clearList() {
      const list = document.querySelector('#list');
      while (list.firstChild) {
        list.removeChild(list.lastChild);
      }
    }
    
    function saveToCache(pokemons) {
      const tx = db.transaction('pokemons', 'readwrite');
      const store = tx.objectStore('pokemons');
      pokemons.forEach(pokemon => store.put(pokemon));
      return tx.complete;
    }
    
    function loadFromCache() {
      const tx = db.transaction('pokemons', 'readonly');
      const store = tx.objectStore('pokemons');
      return store.getAll();
    }
    
    function openDatabase() {
      return idb.openDB('my-db2', 1, {
        upgrade(db) {
          db.createObjectStore('pokemons', {keyPath: 'name'});
        },
      });
    }
    
    openDatabase()
      .then((_db) => {
        db = _db;
        return loadFromCache();
      })
      .then((cachedPokemons) => {
        if (cachedPokemons) {
          removeLoading();
          cachedPokemons.forEach(appendPokemon);
          console.log('loaded from cache!');
        }
        return loadPokemons();
      })
      .then((pokemons) => {
        removeLoading();
        saveToCache(pokemons);
        clearList();
        pokemons.forEach(appendPokemon);
        console.log('loaded from network!');
      });

    效果

    be2833719c0cfda93fcecf39c15fbed1.png

    你可以在此数据库中存储数百兆甚至更多。您可以将所有Pokémon存储在IndexedDB中,并使其脱机甚至建立索引!这绝对是用于存储应用程序数据的一种选择。

    我跳过了第三个示例的实现,因为与 localStorage 相比,IndexedDB在这种情况下没有任何区别。即使使用 IndexedDB,用户仍然不会与他人分享所选页面,也不会将其作为书签供将来使用。它们都不适合这个用例。

    Cookies

    使用cookies是一种独特的存储方式,这是唯一的与服务器共享的存储方式。Cookies作为每次请求的一部分被发送。它可以是当用户浏览我们的应用程序中的页面或当用户发送Ajax请求时。这样我们就可以在客户端和服务器之间建立一个共享状态,也可以在不同子域的多个应用程序之间共享状态。本文中介绍的其他存储选项无法实现。需要注意的是:每个请求都会发送 cookie,这意味着我们必须保持 cookie 较小,以保持适当的请求大小。

    Cookies的最常见用途是身份验证,这不在本文的讨论范围之内。就像 localStorage 一样,cookie只能存储字符串。这些cookie被连接成一个以分号分隔的字符串,并在请求的cookie头中发送。你可以为每个cookie设置很多属性,比如过期、允许的域名、允许的页面等等。

    在例子中,我展示了如何通过客户端来操作cookie,但也可以在你的服务器端应用程序中改变它们。

    <input type="checkbox" id="darkTheme" name="darkTheme" onclick='onChange(this);'>
    <label for="darkTheme">Dark theme</label>
    function getCookie(cname) {
      const name = cname + '=';
      const decoded = decodeURIComponent(document.cookie);
      const split = decoded.split(';');
      const relevantCookie = split.find((cookie) => cookie.indexOf(`${cname}=`) === 0);
      if (relevantCookie) {
        return relevantCookie.split('=')[1];
      }
      return null;
    }
    
    function toggle(on) {
      if (on) {
        document.documentElement.classList.add('dark'); 
      } else {
        document.documentElement.classList.remove('dark');    
      }
    }
    
    function save(on) {
      document.cookie = `dark_theme=${on.toString()}; max-age=31536000; SameSite=None; Secure`;
    }
    
    function load() {
      return getCookie('dark_theme') === 'true';
    }
    
    function onChange(checkbox) {
      const value = checkbox.checked;
      toggle(value);
      save(value);
    }
    
    const initialValue = load();
    toggle(initialValue);
    document.querySelector('#darkTheme').checked = initialValue;

    效果还是跟前面一样

    8782f691c06baa88f90cbfa16e8bc2c8.png

    将用户的喜好保存在cookie中,如果服务器能够以某种方式利用它,就可以很好地满足用户的需求。例如,在主题用例中,服务器可以交付相关的CSS文件,并减少潜在的捆绑大小(在我们进行服务器端渲染的情况下)。另一个用例可能是在没有数据库的情况下,在多个子域应用之间共享这些偏好。

    用JavaScript读写cookie并不像您想象的那么简单。要保存新的cookie,您需要设置 document.cookie ——在上面的示例中查看 save 函数。我设置了 dark_theme cookie,并给它添加了一个 max-age 属性,以确保它在关闭标签时不会过期。另外,我添加 SameSiteSecure 属性。这些都是必要的,因为CodePen使用iframe来运行这些例子,但在大多数情况下你并不需要它们。读取一个cookie需要解析cookie字符串。

    Cookie字符串如下所示:

    key1=value1;key2=value2;key3=value3

    因此,首先,我们必须用分号分隔字符串。现在,我们有一个形式为 key1=value1 的Cookie数组,所以我们需要在数组中找到正确的元素。最后,我们将等号分开并获得新数组中的最后一个元素。有点繁琐,但一旦你实现了 getCookie 函数(或从我的例子中复制它:P),你就可以忘记它。

    将应用程序数据保存在cookie中可能是个坏主意!它将大大增加请求的大小,并降低应用程序性能。此外,服务器无法从这些信息中获益,因为它是数据库中已有信息的陈旧版本。如果你使用cookies,请确保它们很小。

    分页示例也不适合cookie,就像 localStorageIndexedDB 一样。当前页面是我们想要与他人共享的临时状态,这些方法都无法实现它。

    URL storage

    URL本身并不是存储设备,但它是创建可共享状态的好方法。实际上,这意味着将查询参数添加到当前URL中,这些参数可用于重新创建当前状态。最好的例子是搜索查询和过滤器。如果我们在CSS-Tricks上搜索术语flexbox,则URL将更新为https://css-tricks.com/?s=flexbox。看看我们使用URL后,分享搜索查询有多简单?另一个好处是,你只需点击刷新按钮,就可以获得更新的查询结果,甚至可以将其收藏。

    我们只能在URL中保存字符串,它的最大长度是有限的,所以我们没有那么多的空间。我们将不得不保持我们的状态小,没有人喜欢又长又吓人的网址。

    同样,CodePen使用iframe运行示例,因此您看不到URL实际更改。不用担心,因为所有的碎片都在那里,所以你可以在任何你想要的地方使用它。

    <input type="checkbox" id="darkTheme" name="darkTheme" onclick='onChange(this);'>
    <label for="darkTheme">Dark theme</label>
    function toggle(on) {
      if (on) {
        document.documentElement.classList.add('dark'); 
      } else {
        document.documentElement.classList.remove('dark');    
      }
    }
    
    function save(on) {
      const params = new URLSearchParams(window.location.search);
      params.set('dark_theme', on.toString());
      history.pushState(null, null, `?${params.toString()}`);
    }
    
    function load() {
      const params = new URLSearchParams(window.location.search);
      return params.get('dark_theme') === 'true';
    }
    
    function onChange(checkbox) {
      const value = checkbox.checked;
      toggle(value);
      save(value);
    }
    
    const initialValue = load();
    toggle(initialValue);
    document.querySelector('#darkTheme').checked = initialValue;

    效果还是一样

    8782f691c06baa88f90cbfa16e8bc2c8.png

    我们可以通过 window.location.search 访问查询字符串,幸运的是,可以使用 URLSearchParams 类对其进行解析,无需再应用任何复杂的字符串解析。当我们想读取当前值时,可以使用 get 函数,当我们想写时,可以使用 set。仅设置值是不够的,我们还需要更新URL。这可以使用 history.pushStatehistory.replaceState 来完成,取决于我们想要完成的行为。

    我不建议将用户的偏好保存在URL中,因为我们必须将这个状态添加到用户访问的每一个URL中,而且我们无法保证;例如,如果用户点击了谷歌搜索的链接。

    就像Cookie一样,由于空间太小,我们无法在URL中保存应用程序数据。而且即使我们真的设法存储它,网址也会很长,而且不吸引人点击。可能看起来像是钓鱼攻击的一种。

    <div>Select page:</div>
    <div id="pages">
      <button onclick="updatePage(0)">0</button>
      <button onclick="updatePage(1)">1</button>
      <button onclick="updatePage(3)">3</button>
      <button onclick="updatePage(4)">4</button>
      <button onclick="updatePage(5)">5</button>
    </div>
    <ul id="list">
    </ul>
    async function loadPokemons(page) {
      const res = await fetch(`https://pokeapi.co/api/v2/pokemon?limit=10&offset=${page * 10}`);
      const data = await res.json();
      return data.results;
    }
    
    function appendPokemon(pokemon) {
      const node = document.createElement('li');
      const textnode = document.createTextNode(pokemon.name);
      node.appendChild(textnode);
      document.querySelector('#list').appendChild(node);
    }
    
    function clearList() {
      const list = document.querySelector('#list');
      while (list.firstChild) {
        list.removeChild(list.lastChild);
      }
    }
    
    function savePage(page) {
      const params = new URLSearchParams(window.location.search);
      params.set('page', page.toString());
      history.pushState(null, null, `?${params.toString()}`);
    }
    
    function loadPage() {
      const params = new URLSearchParams(window.location.search);
      if (params.has('page')) {
        return parseInt(params.get('page'));
      }
      return 0;
    }
    
    async function updatePage(page) {
      clearList();
      savePage(page);
      const pokemons = await loadPokemons(page);
      pokemons.forEach(appendPokemon);
    }
    
    const page = loadPage();
    updatePage(page);

    效果

    9e8746dcd72398578d2542d211414945.png

    就像我们的分页例子一样,临时应用状态是最适合URL查询字符串的。同样,你无法看到URL的变化,但每次点击一个页面时,URL都会以 ?page=x 查询参数更新。当网页加载时,它会查找这个查询参数,并相应地获取正确的页面。现在,我们可以把这个网址分享给我们的朋友,让他们可以享受我们最喜欢的神奇宝贝。

    Cache API

    Cache API是网络级的存储,它用于缓存网络请求及其响应。Cache API非常适合service worker,service worker可以拦截每一个网络请求,使用 Cache API 它可以轻松地缓存这两个请求。service worker也可以将现有的缓存项作为网络响应返回,而不是从服务器上获取。这样,您可以减少网络负载时间,并使你的应用程序即使处于脱机状态也能正常工作。最初,它是为service worker创建的,但在现代浏览器中,Cache API也可以在窗口、iframe和worker上下文中使用。这是一个非常强大的API,可以极大地改善应用的用户体验。

    就像IndexedDB一样,Cache API的存储不受限制,您可以存储数百兆字节,如果需要甚至可以存储更多。API是异步的,所以它不会阻塞你的主线程,而且它可以通过全局属性 caches 来访问。

    Browser extension

    如果你建立一个浏览器扩展,你有另一个选择来存储你的数据,我在进行扩展程序daily.dev时发现了它。如果你使用Mozilla的polyfill,它可以通过 chrome.storagebrowser.storage 获得。确保在你的清单中申请一个存储权限以获得访问权。

    有两种类型的存储选项:local和sync。local存储是不言而喻的,它的意思是不共享,保存在本地。sync存储是作为谷歌账户的一部分同步的,你在任何地方用同一个账户安装扩展,这个存储都会被同步。两者都有相同的API,所以如果需要的话,来回切换超级容易。它是异步存储,因此不会像 localStorage 这样阻塞主线程。不幸的是,我不能为这个存储选项创建一个演示,因为它需要一个浏览器扩展,但它的使用非常简单,几乎和 localStorage 一样。有关确切实现的更多信息,请参阅Chrome文档。

    结束

    浏览器有许多选项可用于存储数据。根据Chrome团队的建议,我们的首选存储应该是IndexedDB,它是异步存储,有足够的空间来存储我们想要的任何东西。不鼓励使用 localStorage,但它比 IndexedDB 更易于使用。Cookies是与服务器共享客户端状态的一种好方法,但通常用于身份验证。

    如果你想创建具有可共享状态的页面,如搜索页面,请使用URL的查询字符串来存储这些信息。最后,如果你建立一个扩展,一定要阅读关于 chrome.storage

    展开全文
  • 浏览器许多选项可用于存储数据。...应用程序数据存储在数据库中,文件存储在对象存储中,瞬态数据存储在高速缓存中……似乎存在无限种存储任何类型数据的可能性。但是,数据存储不仅限于后端,前端(浏览器..

    在这里插入图片描述

    浏览器有许多选项可用于存储数据。根据Chrome团队的建议,我们的首选存储应该是IndexedDB,它是异步存储,有足够的空间来存储我们想要的任何东西。不鼓励使用 localStorage,但它比 IndexedDB 更易于使用。Cookies是与服务器共享客户端状态的一种好方法,但通常用于身份验证。阅读原文

    在后端开发中,存储是工作的常见部分。应用程序数据存储在数据库中,文件存储在对象存储中,瞬态数据存储在高速缓存中……似乎存在无限种存储任何类型数据的可能性。但是,数据存储不仅限于后端,前端(浏览器)还具有许多存储数据的选项。我们可以通过利用这种存储方式来提升我们的应用性能,保存用户的偏好,在多个会话,甚至不同的计算机上保持应用状态。

    在本文中,我们将通过不同的可能性在浏览器中存储数据。我们将涵盖每种方法的三个用例,以掌握其利弊。最后,你将能够决定什么存储是最适合你的用例。

    让我们开始吧!

    localStorage API

    localStorage 是浏览器中最受欢迎的存储选项之一,也是许多开发人员的首选。数据跨会话存储,从不与服务器共享,并且可用于同一协议和域下的所有页面。存储空间限制为〜5MB。

    令人惊讶的是,谷歌Chrome团队并不建议使用这个选项,因为它屏蔽了主线程,而且web workers和service workers无法访问。他们推出了一个实验:KV Storage,作为一个更好的版本,但这只是一个试验,似乎还没有任何进展。

    localStorage API 可作为 window.localStorage 使用,并且只能保存UTF-16字符串。在将数据保存到 localStorage 之前,我们必须确保将其转换为字符串。主要的三个功能是:

    • setItem('key', 'value')
    • getItem('key')
    • removeItem('key')

    它们都是同步的,因此使用起来很简单,但是它们会阻塞主线程。

    值得一提的是,localStorage 有一个称为 sessionStorage 的双胞胎。唯一的区别是,存储在 sessionStorage 中的数据将仅持续当前会话,但API相同。

    这个太简单了,相信大家都用过。

    IndexedDB API

    IndexedDB是浏览器中的现代存储解决方案。它可以存储大量的结构化数据,甚至文件和Blob。和每一个数据库一样,IndexedDB对数据进行索引,以便高效地运行查询。使用IndexedDB比较复杂,我们必须创建一个数据库,表,并使用事务。

    localStorage 相比,IndexedDB需要更多代码。在例子中,我使用了原生API与Promise包装器,但我强烈建议使用第三方库来帮助你。我推荐的是localForage,因为它使用了同样的 localStorage API,但实现方式是逐步增强的,也就是说,如果你的浏览器支持IndexedDB,就会使用它;如果不支持,就会退回到 localStorage

    让我们来编写代码,前往我们的用户偏好示例吧!

    <input type="checkbox" id="darkTheme" name="darkTheme" onclick='onChange(this);'>
    <label for="darkTheme">Dark theme</label><br>
    
    let db;
    
    function toggle(on) {
      if (on) {
        document.documentElement.classList.add('dark'); 
      } else {
        document.documentElement.classList.remove('dark');    
      }
    }
    
    async function save(on) {
      const tx = db.transaction('preferences', 'readwrite');
      const store = tx.objectStore('preferences');
      store.put({key: 'darkTheme', value: on});
      return tx.complete;
    }
    
    async function load() {
      const tx = db.transaction('preferences', 'readonly');
      const store = tx.objectStore('preferences');
      const data = await store.get('darkTheme');
      return data && data.value;
    }
    
    async function onChange(checkbox) {
      const value = checkbox.checked;
      toggle(value);
      await save(value);
    }
    
    function openDatabase() {
      return idb.openDB('my-db', 1, {
        upgrade(db) {
          db.createObjectStore('preferences', {keyPath: 'key'});
        },
      });
    }
    
    openDatabase()
      .then((_db) => {
        db = _db;
        return load();
      })
      .then((initialValue) => {
        toggle(initialValue);
        document.querySelector('#darkTheme').checked = initialValue;
      });
    

    效果

    idb 是我们使用的Promise包装器,而不是使用基于事件的低级API。首先要注意的是,对数据库的每次访问都是异步的,这意味着我们不会阻塞主线程,与 localStorage 相比,这是一个主要优势。

    我们需要打开与数据库的连接,以便在整个应用程序中都可以使用它进行读写。我们给数据库起一个名字 my-db,一个模式版本 1,以及一个更新函数,以在版本之间应用更改,这与数据库迁移非常相似。我们的数据库架构很简单:只有一个object store preferences。object store 等效于SQL表,要写入或读取数据库,必须使用事务,这是使用IndexedDB的乏味部分。看一下演示中新的 saveload 功能。

    毫无疑问,IndexedDB具有更多的开销,并且与 localStorage 相比,学习曲线更陡峭。对于键值的情况,使用 localStorage 或第三方库可能更有意义,它们将帮助我们提高效率。

    <div id="loading">loading...</div>
    <ul id="list">
    </ul>
    
    let db;
    
    async function loadPokemons() {
      const res = await fetch('https://pokeapi.co/api/v2/pokemon?limit=10');
      const data = await res.json();
      return data.results;
    }
    
    function removeLoading() {
      const elem = document.querySelector('#loading');
      if (elem) {
        elem.parentNode.removeChild(elem); 
      }
    }
    
    function appendPokemon(pokemon) {
      const node = document.createElement('li');
      const textnode = document.createTextNode(pokemon.name);
      node.appendChild(textnode);
      document.querySelector('#list').appendChild(node);
    }
    
    function clearList() {
      const list = document.querySelector('#list');
      while (list.firstChild) {
        list.removeChild(list.lastChild);
      }
    }
    
    function saveToCache(pokemons) {
      const tx = db.transaction('pokemons', 'readwrite');
      const store = tx.objectStore('pokemons');
      pokemons.forEach(pokemon => store.put(pokemon));
      return tx.complete;
    }
    
    function loadFromCache() {
      const tx = db.transaction('pokemons', 'readonly');
      const store = tx.objectStore('pokemons');
      return store.getAll();
    }
    
    function openDatabase() {
      return idb.openDB('my-db2', 1, {
        upgrade(db) {
          db.createObjectStore('pokemons', {keyPath: 'name'});
        },
      });
    }
    
    openDatabase()
      .then((_db) => {
        db = _db;
        return loadFromCache();
      })
      .then((cachedPokemons) => {
        if (cachedPokemons) {
          removeLoading();
          cachedPokemons.forEach(appendPokemon);
          console.log('loaded from cache!');
        }
        return loadPokemons();
      })
      .then((pokemons) => {
        removeLoading();
        saveToCache(pokemons);
        clearList();
        pokemons.forEach(appendPokemon);
        console.log('loaded from network!');
      });
    

    效果

    你可以在此数据库中存储数百兆甚至更多。您可以将所有Pokémon存储在IndexedDB中,并使其脱机甚至建立索引!这绝对是用于存储应用程序数据的一种选择。

    我跳过了第三个示例的实现,因为与 localStorage 相比,IndexedDB在这种情况下没有任何区别。即使使用 IndexedDB,用户仍然不会与他人分享所选页面,也不会将其作为书签供将来使用。它们都不适合这个用例。

    Cookies

    使用cookies是一种独特的存储方式,这是唯一的与服务器共享的存储方式。Cookies作为每次请求的一部分被发送。它可以是当用户浏览我们的应用程序中的页面或当用户发送Ajax请求时。这样我们就可以在客户端和服务器之间建立一个共享状态,也可以在不同子域的多个应用程序之间共享状态。本文中介绍的其他存储选项无法实现。需要注意的是:每个请求都会发送 cookie,这意味着我们必须保持 cookie 较小,以保持适当的请求大小。

    Cookies的最常见用途是身份验证,这不在本文的讨论范围之内。就像 localStorage 一样,cookie只能存储字符串。这些cookie被连接成一个以分号分隔的字符串,并在请求的cookie头中发送。你可以为每个cookie设置很多属性,比如过期、允许的域名、允许的页面等等。

    在例子中,我展示了如何通过客户端来操作cookie,但也可以在你的服务器端应用程序中改变它们。

    <input type="checkbox" id="darkTheme" name="darkTheme" onclick='onChange(this);'>
    <label for="darkTheme">Dark theme</label>
    
    function getCookie(cname) {
      const name = cname + '=';
      const decoded = decodeURIComponent(document.cookie);
      const split = decoded.split(';');
      const relevantCookie = split.find((cookie) => cookie.indexOf(`${cname}=`) === 0);
      if (relevantCookie) {
        return relevantCookie.split('=')[1];
      }
      return null;
    }
    
    function toggle(on) {
      if (on) {
        document.documentElement.classList.add('dark'); 
      } else {
        document.documentElement.classList.remove('dark');    
      }
    }
    
    function save(on) {
      document.cookie = `dark_theme=${on.toString()}; max-age=31536000; SameSite=None; Secure`;
    }
    
    function load() {
      return getCookie('dark_theme') === 'true';
    }
    
    function onChange(checkbox) {
      const value = checkbox.checked;
      toggle(value);
      save(value);
    }
    
    const initialValue = load();
    toggle(initialValue);
    document.querySelector('#darkTheme').checked = initialValue;
    

    效果还是跟前面一样

    将用户的喜好保存在cookie中,如果服务器能够以某种方式利用它,就可以很好地满足用户的需求。例如,在主题用例中,服务器可以交付相关的CSS文件,并减少潜在的捆绑大小(在我们进行服务器端渲染的情况下)。另一个用例可能是在没有数据库的情况下,在多个子域应用之间共享这些偏好。

    用JavaScript读写cookie并不像您想象的那么简单。要保存新的cookie,您需要设置 document.cookie ——在上面的示例中查看 save 函数。我设置了 dark_theme cookie,并给它添加了一个 max-age 属性,以确保它在关闭标签时不会过期。另外,我添加 SameSiteSecure 属性。这些都是必要的,因为CodePen使用iframe来运行这些例子,但在大多数情况下你并不需要它们。读取一个cookie需要解析cookie字符串。

    Cookie字符串如下所示:

    key1=value1;key2=value2;key3=value3
    

    因此,首先,我们必须用分号分隔字符串。现在,我们有一个形式为 key1=value1 的Cookie数组,所以我们需要在数组中找到正确的元素。最后,我们将等号分开并获得新数组中的最后一个元素。有点繁琐,但一旦你实现了 getCookie 函数(或从我的例子中复制它:P),你就可以忘记它。

    将应用程序数据保存在cookie中可能是个坏主意!它将大大增加请求的大小,并降低应用程序性能。此外,服务器无法从这些信息中获益,因为它是数据库中已有信息的陈旧版本。如果你使用cookies,请确保它们很小。

    分页示例也不适合cookie,就像 localStorageIndexedDB 一样。当前页面是我们想要与他人共享的临时状态,这些方法都无法实现它。

    URL storage

    URL本身并不是存储设备,但它是创建可共享状态的好方法。实际上,这意味着将查询参数添加到当前URL中,这些参数可用于重新创建当前状态。最好的例子是搜索查询和过滤器。如果我们在CSS-Tricks上搜索术语flexbox,则URL将更新为https://css-tricks.com/?s=flexbox。看看我们使用URL后,分享搜索查询有多简单?另一个好处是,你只需点击刷新按钮,就可以获得更新的查询结果,甚至可以将其收藏。

    我们只能在URL中保存字符串,它的最大长度是有限的,所以我们没有那么多的空间。我们将不得不保持我们的状态小,没有人喜欢又长又吓人的网址。

    同样,CodePen使用iframe运行示例,因此您看不到URL实际更改。不用担心,因为所有的碎片都在那里,所以你可以在任何你想要的地方使用它。

    <input type="checkbox" id="darkTheme" name="darkTheme" onclick='onChange(this);'>
    <label for="darkTheme">Dark theme</label>
    
    function toggle(on) {
      if (on) {
        document.documentElement.classList.add('dark'); 
      } else {
        document.documentElement.classList.remove('dark');    
      }
    }
    
    function save(on) {
      const params = new URLSearchParams(window.location.search);
      params.set('dark_theme', on.toString());
      history.pushState(null, null, `?${params.toString()}`);
    }
    
    function load() {
      const params = new URLSearchParams(window.location.search);
      return params.get('dark_theme') === 'true';
    }
    
    function onChange(checkbox) {
      const value = checkbox.checked;
      toggle(value);
      save(value);
    }
    
    const initialValue = load();
    toggle(initialValue);
    document.querySelector('#darkTheme').checked = initialValue;
    

    效果还是一样

    我们可以通过 window.location.search 访问查询字符串,幸运的是,可以使用 URLSearchParams 类对其进行解析,无需再应用任何复杂的字符串解析。当我们想读取当前值时,可以使用 get 函数,当我们想写时,可以使用 set。仅设置值是不够的,我们还需要更新URL。这可以使用 history.pushStatehistory.replaceState 来完成,取决于我们想要完成的行为。

    我不建议将用户的偏好保存在URL中,因为我们必须将这个状态添加到用户访问的每一个URL中,而且我们无法保证;例如,如果用户点击了谷歌搜索的链接。

    就像Cookie一样,由于空间太小,我们无法在URL中保存应用程序数据。而且即使我们真的设法存储它,网址也会很长,而且不吸引人点击。可能看起来像是钓鱼攻击的一种。

    <div>Select page:</div>
    <div id="pages">
      <button onclick="updatePage(0)">0</button>
      <button onclick="updatePage(1)">1</button>
      <button onclick="updatePage(3)">3</button>
      <button onclick="updatePage(4)">4</button>
      <button onclick="updatePage(5)">5</button>
    </div>
    <ul id="list">
    </ul>
    
    async function loadPokemons(page) {
      const res = await fetch(`https://pokeapi.co/api/v2/pokemon?limit=10&offset=${page * 10}`);
      const data = await res.json();
      return data.results;
    }
    
    function appendPokemon(pokemon) {
      const node = document.createElement('li');
      const textnode = document.createTextNode(pokemon.name);
      node.appendChild(textnode);
      document.querySelector('#list').appendChild(node);
    }
    
    function clearList() {
      const list = document.querySelector('#list');
      while (list.firstChild) {
        list.removeChild(list.lastChild);
      }
    }
    
    function savePage(page) {
      const params = new URLSearchParams(window.location.search);
      params.set('page', page.toString());
      history.pushState(null, null, `?${params.toString()}`);
    }
    
    function loadPage() {
      const params = new URLSearchParams(window.location.search);
      if (params.has('page')) {
        return parseInt(params.get('page'));
      }
      return 0;
    }
    
    async function updatePage(page) {
      clearList();
      savePage(page);
      const pokemons = await loadPokemons(page);
      pokemons.forEach(appendPokemon);
    }
    
    const page = loadPage();
    updatePage(page);
    

    效果

    就像我们的分页例子一样,临时应用状态是最适合URL查询字符串的。同样,你无法看到URL的变化,但每次点击一个页面时,URL都会以 ?page=x 查询参数更新。当网页加载时,它会查找这个查询参数,并相应地获取正确的页面。现在,我们可以把这个网址分享给我们的朋友,让他们可以享受我们最喜欢的神奇宝贝。

    Cache API

    Cache API是网络级的存储,它用于缓存网络请求及其响应。Cache API非常适合service worker,service worker可以拦截每一个网络请求,使用 Cache API 它可以轻松地缓存这两个请求。service worker也可以将现有的缓存项作为网络响应返回,而不是从服务器上获取。这样,您可以减少网络负载时间,并使你的应用程序即使处于脱机状态也能正常工作。最初,它是为service worker创建的,但在现代浏览器中,Cache API也可以在窗口、iframe和worker上下文中使用。这是一个非常强大的API,可以极大地改善应用的用户体验。

    就像IndexedDB一样,Cache API的存储不受限制,您可以存储数百兆字节,如果需要甚至可以存储更多。API是异步的,所以它不会阻塞你的主线程,而且它可以通过全局属性 caches 来访问。

    Browser extension

    如果你建立一个浏览器扩展,你有另一个选择来存储你的数据,我在进行扩展程序daily.dev时发现了它。如果你使用Mozilla的polyfill,它可以通过 chrome.storagebrowser.storage 获得。确保在你的清单中申请一个存储权限以获得访问权。

    有两种类型的存储选项:local和sync。local存储是不言而喻的,它的意思是不共享,保存在本地。sync存储是作为谷歌账户的一部分同步的,你在任何地方用同一个账户安装扩展,这个存储都会被同步。两者都有相同的API,所以如果需要的话,来回切换超级容易。它是异步存储,因此不会像 localStorage 这样阻塞主线程。不幸的是,我不能为这个存储选项创建一个演示,因为它需要一个浏览器扩展,但它的使用非常简单,几乎和 localStorage 一样。有关确切实现的更多信息,请参阅Chrome文档。

    结束

    浏览器有许多选项可用于存储数据。根据Chrome团队的建议,我们的首选存储应该是IndexedDB,它是异步存储,有足够的空间来存储我们想要的任何东西。不鼓励使用 localStorage,但它比 IndexedDB 更易于使用。Cookies是与服务器共享客户端状态的一种好方法,但通常用于身份验证。

    如果你想创建具有可共享状态的页面,如搜索页面,请使用URL的查询字符串来存储这些信息。最后,如果你建立一个扩展,一定要阅读关于 chrome.storage

    展开全文
  • 一、存储协议类型1.1、协议概况通过上一章节的学习,应该对数据中心存储协议了比较基础的了解,我们知道了现在的数据中心已经变为SAN为主流的部署模式。下面我们来更深层次的从协议的角度了解存储协议类型存储...

    一、存储协议类型

    1.1、协议概况

    通过上一章节的学习,应该对数据中心存储协议有了比较基础的了解,我们知道了现在的数据中心已经变为SAN为主流的部署模式。下面我们来更深层次的从协议的角度了解存储协议类型。

    0a2b32102e09aa01b1a61445fe90406a.png

    存储协议

    首先,虽然上图显示了很多的存储协议类型,但是如下图所示主要的存储协议其实只有两种:

    FC协议和iSCSI协议,分别对应了两种SAN网络类型:FC SAN(FC协议)和IP SAN(iSCSI协议),在FC和iSCSI协议下面的我们可以称之为"承载协议"。

    362bafde3050fe16da270c60c38c0a6e.png

    承载协议只有FC和iSCSI

    1.2、常见存储协议的类型

    在常见的存储协议类型中最常用的存储协议和承载协议有三种组合分别为:

    1、 FC 存储协议使用FC的承载协议,也就是我们所说的传统FC SAN。

    07bb74352bbaf4bf4ddc0f9208438a49.png

    黄色框选中为FC协议的协议栈

    FC协议是为了摆脱SCSI线缆线路长度过短且并行传输有干扰,是对SCSI应用协议的扩展,使之通过光纤使用串行标准使SCSI数据块流量能传输在网络中。FC协议支持16M的设备编址。

    2、 iSCSI存储协议使用TCP/IP的承载协议,也就是我们所说的IP SAN

    b6fcf31195271365d37649f3717e7ee1.png

    黄色框选中为iSCSI协议的协议栈

    iSCSI把存储网络带入了一个没有FC协议的架构中,它封装SCSI控制和数据信息到TCP/IP协议栈中,使用的是TCP/协议,默认的TCP端口是860和3260。使用TCP的重传机制处理IP数据包和以太网帧丢失的传输错误。

    3、FC 存储协议用FCoE封装使用以太网协议作为承载协议,就是我们所说FCoE。

    bdfe6d0b54dab2c85cd570c8405fae6c.png

    黄色框选中为FCoE协议的协议栈

    FCoE上层使用的还是FC存储协议,只把FC协议的FC0(物理层)和FC1(数据链路层),修改为以太网协议,做到FC存储数据协议也可运行在TCP/IP协议栈内,同时出现的iSCSI协议将上层的FC存储协议也给替换掉了,简直不给FC协议栈活路,世上竟有如此厚颜无耻之协议栈。

    知识扩展:众所周知,以太网协议和IP协议一样是一个允许丢包的协议,将FC存储协议承载在以太网上如何做到不丢包,这就是FCoE封装的最主要作用。

    还有三种相对不常用的存储技术,FCIP、IFCP和IB SAN:

    1、FCIP

    46ef8f017c8463cc03e6f7b3598c8e35.png

    黄色框选中为FCIP协议的协议栈

    FCIP也是IP SAN的一种,是类似于传统数据网络中GRE隧道的一种技术,但与GRE不同的是FCIP协议是TCP的一种隧道,而GRE是IP协议的一种隧道,之所以使用TCP是因为数据中心网络不允许丢包,使用TCP协议就算产生丢包也会重传,对于上层的FC存储协议来说等同于不丢包。

    2、IFCP

    fd006b60efccf999dae4c607f92645c7.png

    黄色框选中为IFCP协议的协议栈

    FCIP也是IP SAN的一种,是类似于传统数据网络中NAT-PT技术,NAT-PT可以将IPv4地址和IPv4地址做一个映射,而FCIP是将FCID和IP地址做一个映射。

    3、IB SAN

    5b4a0c4b4efa6d70defe26a06f44b620.png

    黄色框选中为IB协议的协议栈

    IB协议(InfiniBand),翻译过来就是"无限带宽",名字很牛X,有可能成为未来网络存储的发展趋势但现在不常用,该协议常用于高性能计算,可通过SRP存储协议承载SCSI的数据块。

    以上内容均为本人对所掌握知识总结归纳所创作的原创文章,希望能给大家的学习过程带来帮助,如有技术理解错误希望能够得到大家的指正,大家共同学习,共同进步。

    欢迎关注我的头条号,私信交流,学习更多网络技术!

    展开全文
  • 展开全部1、MyISAM使用这个存储引擎,每个MyISAM在磁盘上存储成62616964757a686964616fe4b893e5b19e31333433663033三个文件。(1)frm文件:存储表的定义数据(2)MYD文件:存放表具体记录的数据(3)MYI文件:存储索引frm...
  • 现在对于绝大多数的相机来说,存储卡并不是标准配件,买相机的时候一般不附存储卡,入手...一、相机存储卡的类型相机的存储:SD卡、CF卡、TF卡,但使用最广泛的还是SD卡,SD卡根据容量不同名称或为SDHC或SDXC卡...
  • 今天我们所讲的变量只在数据库mysql中进行,在使用范围上小伙伴们不要弄错了,下面就变量在mysql存储的几种类型为大家带来介绍。变量的使用变量可以在子程序中声明并使用,这些变量的作用范围是在begin...and之间。...
  • 存储引擎是数据库管理系统用来从数据库创建,读取和更新数据...那么MySQL存储引擎有哪些?区别是什么?其实关于MySQL 存储引擎有九大类型,但是区别却只有两个,以下是详细介绍。MySQL 存储引擎有哪些?1、InnoDB这...
  • 其中 7 种基本数据类型 : Null、Undefined、Boolean、Number、String、Symbol (ES6新增,表示独一无二的值) 和 BigInt (ES 10 新增) 。 1 种引用数据类型,即 Object 。Object 里面包含 Function、Array、Date、...
  • 需求描述:  在备份数据库的时候,使用mysqldump进行数据库的备份,如果库中仅仅... 所以,备份数据库前,要查清楚,某个要备份的数据库下,表的存储引擎有哪些 操作过程: 1.查看测试库下,表的存储类型 SELECT DIS...
  • 存储有哪些

    2020-07-09 14:25:01
    auto 存储类(Storage Class) auto是c++11以后的新特性,编译器可以自行推导数据类型,这一切都是编译器的功劳 auto PI = 3.14; //double auto msg("hello"); // const char* auto val = new auto(9); // int* auto ...
  • 存储引擎是数据库管理系统用来从数据库创建、读取和更新数据的软件...那么mysql存储引擎有哪些?一、InnoDB这是MySQL 5.5或更高版本的默认存储引擎。它提供了事务安全(ACID兼容)表,支持外键引用完整性约束。它支...
  • JavaScript一共8种数据类型,其中7种基本数据类型:Undefined、Null、Boolean、Number、String、Symbol(es6新增,表示独一无二的值)和BigInt(es10新增); 1种引用数据类型——Object(Object本质上是由一组...
  • mysql中的索引类型有哪些,可以从哪些角度来看?回答从数据结构角度1、B+树索引(O(log(n))):关于B+树索引,可以参考 MySQL索引背后的数据结构及算法原理2、hash索引:a 仅仅能满足”=”,”IN”和”<=>”查询...
  • C51存储器类型有bit sbit data xdata bdata pdata sfr code等,可能不全面有遗漏对应的物理存储器是:bit,即位数据:数据存储器位寻址区,即20H~2FH的范围,共16个字节,16*8=128个位,位地址00h~7fh,连续的。...
  • js的数据类型有基本类型和引用类型 1.基本数据类型(BS3N) 1.Boolean(B) 2.String(S) 3.underfined(N) 4.Null(N) 5.Number(N) 6.symbol(ES6的) 基本数据类型都储存在栈中(stack),栈是有结构的,每个区块都是按照...
  • 一些数据是要存储为数字的,数字当中有些是要存储为整数、小数、日期型等...二、MYSQL常见数据类型MySQL支持多种类型,大致可以分为四类:数值型、浮点型、日期/时间和字符串(字符)类型。1、数值类型MySQL支持所有...
  • 工作中经常见到一些设计粗糙的数据库,其中将数字...所以,这里简单总结一下,在数据库系统中,将数字类型存储成字符类型有哪些不好的地方。以关系型数据库MySQL示例。  ①字符类型往往比数字类型占用更多的存储...
  • 存储引擎是数据库管理系统用来从数据库创建、读取和更新数据的软件...那么mysql存储引擎有哪些?一、InnoDB这是MySQL 5.5或更高版本的默认存储引擎。它提供了事务安全(ACID兼容)表,支持外键引用完整性约束。它支...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,916
精华内容 1,166
关键字:

存储类型有哪些