How do you organize db and caching layer?

agolangf · · 291 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>I&#39;m writing a web application. I&#39;ve got my database layer (CouchDB but it can be anything) and I&#39;ve got a separate caching layer (Redis but again can be anything). How do you structure your code?</p> <p>Here is a gist which shows how I do it. <a href="https://gist.github.com/zemirco/49e6bebd8f281bce349136931d939cad">https://gist.github.com/zemirco/49e6bebd8f281bce349136931d939cad</a>. As you can see I&#39;m using a wrapper around my DatabaseInterface and my CacheInterface. My handlers have access to this wrapper.</p> <p>Is that too complicated? Especially the part where I need the pure database layer inside my handlers.</p> <p>I have to use interfaces to be able to test my code without real database and caching infrastructure.</p> <hr/>**评论:**<br/><br/>nuunien: <pre><p>I&#39;m using something like this</p> <pre><code>type Store interface { GetFollowers(userID string) ([]models.User, error) } type DatabaseStore struct { // wrap sql connection // or any other driver that your database needs } func (s *DatabaseStore) GetFollowers(userID string) ([]models.User, error) { // get users from db // can be any db, e.g. PostgreSQL, CouchDB, MongoDB return users, nil } type CacheStore struct { // embed any other store // this also makes unimplemented store methods just pass through Store // cache internals } func (s *CacheStore) GetFollowers(userID string) ([]models.User, error) { // return user from cache if it&#39;s there // if not, get from underlying store user, err = s.Store.GetFollowers(userID) // error check // add user to cache return users, nil } // easily instantiate any configuration you need store := CacheStore{DatabaseStore{DB: db}} </code></pre> <p>This configuration also makes testing and mocking a lot easier</p></pre>madman2233: <pre><p>I&#39;ve done it two ways before. </p> <p> </p> <p>First is one struct for data access that has both caching and database interfaces in it. I used boltdb with an auto expiring cache system. Simple API and allows for auto handling of cache misses, distributing load, and quick integration. I used &#34;parallel access&#34; so cache misses didn&#39;t add to the db access time. This one was low turnover and small amounts of data.</p> <p> </p> <p>Second one was a cache layer that also handles the database. This was larger amounts of data, with very high turnover. I used batched writing on the database and a cache only read system for performance.</p> <p> </p> <p>Both were a single struct and used an api like data, err := db.Get(key) and err := db.Store(key, data), and everything else was internal to the package. I eventually added Write and Read functions so I could use it for simple io.</p></pre>adelowo: <pre><p>Interfaces are the way to go.. I don&#39;t see anything really complicated there..</p> <p>You could have an <code>App</code> struct that takes in the <code>Wrapper</code>, then inject it into your handlers like [1] func createPost(a *app) http.HandlerFunc {</p> <pre><code>return func(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() } //app could look like this app struct { Cache CacheInterface DB WhateverInterface } </code></pre> <p>//Then on initialization of this struct, you do <code>wrapper.GetXX</code> for the corresponding properties.</p> <p>[1] <a href="https://github.com/adelowo/mockdemo/blob/master/main.go#L92-L96" rel="nofollow">https://github.com/adelowo/mockdemo/blob/master/main.go#L92-L96</a></p> <p>Shameless plug <a href="https://lanreadelowo.com/blog/2017/07/06/mocking-go/" rel="nofollow">https://lanreadelowo.com/blog/2017/07/06/mocking-go/</a> (talks about isolation of the database)</p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

291 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传