我正在编写一个HTTP servlet(托管在Amazon Elastic Beanstalk上),作为我的Android应用程序的应用程序服务器。我的应用程序将从我的servlet请求数据,而servlet将从数据库(SimpleDB)中提取数据。
由于我的客户端请求可能很频繁,我想在我的servlet上实现一个缓存,它将缓存所请求的数据,以减少数据库读取。目前,我只是初始化一个" ServerCache" object作为我的servlet的成员变量。 ServerCache包含缓存数据的列表,我随时填充这些列表。
看起来像这样。
public class ServerCache {
/**
* ServerCache is responsible for caching data on the server.
* Create several data structures on the server to cache buy/sell listings as listing objects.
* For now, we will be able to cache the entirety of the database contents.
* -ES
*
* Only one ServerCache should ever be made, at the init() of this server
*/
private List<BuyListing> listbl; //What is the danger of having this public vs. private
private List<SellListing> listsl;
public String BLlastError;
public String SLlastError;
public ServerCache()
{
this.listbl = new ArrayList<BuyListing>();
this.listsl = new ArrayList<SellListing>();
this.BLlastError = "Initialized";
this.SLlastError = "Initialized";
} //Setters and getters ommitted
它在这里初始化
public class HelloWorld extends HttpServlet {
private SimpleDBConnect SDB; // contains functions for accessing database
private ServerCache Cache;
//Various Constants
private static final String BUY_LISTINGS_DOMAIN = "BuyListings";
private static final String SELL_LISTINGS_DOMAIN = "SellListings";
private static final String USER_ID_DOMAIN = "UserIDs";
private static final String MESSAGES_DOMAIN = "Messages";
public HelloWorld() {
super();
SDB = new SimpleDBConnect();
SDB.createConnection();
Cache = new ServerCache();
Cache.setListbl(SDB.getAllBL());
Cache.setListsl(SDB.getAllSL());
updateSDBStatus();
updateServletStatus("Initialized");
updateCacheStatus();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.getOutputStream().println("Servlet Works \n SimpleDB Status:" + SDB.dbConnectStatus + "\n \n SDB log: " + this.SDBStatus + "\n \n Servlet log: " + this.ServletStatus
+ "\n \n Buy Cache Status: " + this.BLCacheStatus + "\n \n Sell Cache Status: " + this.SLCacheStatus);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// ... Some code ommitted, the following is a relevant part of how I handle request for data
if (packet.getHeader() == Constants.BL_REQUEST || packet.getHeader() == Constants.SL_REQUEST)
{
MsgStruct temp = new MsgStruct();
if (packet.getHeader() == Constants.BL_REQUEST){
temp.setHeader(Constants.BL_REQUEST);
Type listOfTestObject = new TypeToken<List<BuyListing>>(){}.getType();
String s = gson.toJson(Cache.getListbl(), listOfTestObject);
temp.setPayload(s);
receivedString = gson.toJson(temp);
}
有什么理由在我的servlet上缓存数据版本是个坏主意吗?这只是我在黑暗中的刺痛,因为在这种情况下,没有人教过我该做什么。我知道并发是一个问题,但我不认为在这种情况下它应该重要吗?
由于
答案 0 :(得分:0)
在程序中添加缓存会使其复杂化,特别是在您想要修改数据时。在这种情况下,数据库和缓存应始终具有相同的数据,无论收到的是哪个GET
或POST
请求可能会也可能不会写入数据库。
您可能遇到的一个问题是如何使缓存与数据库保持同步。在写入数据库时始终更新缓存至关重要,并确保在使用缓存完成请求时,返回与数据库中包含的数据相同的数据。您确实说过您只缓存了请求的数据,但如果数据被写回数据库,则必须检查缓存的数据是否也已更新。
您提到您只会实例化该类的一个实例。遵循缓存的单例模式可能更有意义,有关详细信息,请参阅Wikipedia页面http://en.wikipedia.org/wiki/Singleton_pattern。基本上,这会导致缓存初始化自己,并确保没有其他代码可以创建另一个实例。构造函数将是私有的,您将编写getInstance()
方法以使缓存返回实例化的ServerCache
对象。
我走这条路的原因是因为总有可能你会编写另一个需要访问数据库的servlet,并且很难在没有缓存的情况下为它提供缓存访问权限单例(更不用说与多次读取相关的多线程问题)。
要记住的另一件事是,您的缓存将占用服务器上的RAM。缓存RAM使用的交易以获取访问时间,并且根据您的计划,您可能会或可能不会有很多空闲时间。您还可以在RAM中复制整个数据库,从而破坏其目的。您将花费大量处理时间来确保更新数据库但从未实际使用它。再说一遍,如果你看到响应能力有所提高,我认为没有问题,只要你管理得好。
为了有效地使用缓存,您必须对缓存对象的数量进行严格限制,删除不太多使用的对象,仅保留非常频繁访问的对象。我想说的最后一点是我注意到你的缓存正在使用ArrayLists。这些不是搜索未排序数据的最有效数据结构。数据库用于数据存储,因此数据库最有可能拥有更高效的存储系统,在您的情况下,这将使缓存仅对非常少量的频繁访问但很少修改的数据有用。