《java与模式》读书笔记之七----序列键生成器与单例模式及多例模式(二)

 

上一章中,我们实现了序列器生成器的功能,并成功运用了单例模式。细心的你可能也发现了一个问题:每次获取键值时都要去查询数据库,这样会带来一个性能的问题,那有没有办法优化列?答案是肯定的。做法就是我们常在处理数据库操作时用到的:缓存。

 

思路是这样的:给整个表做一个缓存,在每次取值的时候先去缓存中获取数据,如果获取不以,将去数据库中查询,注意这些我们不会递增,而是一次性出N个值出来,N的大小可以根据系统的吞吐量来决定,就算我们系统在使用中,突然Down掉了,你也不用怕,无非就是浪费了几个序列键而已。在本例中,为了演示效果,我们将N 将为5。

 

我们创建一个Bean来保存数据库中的一条记录的相关信息。

 

 

package com.pattern.id.generator; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; /** * 保存数据库中一条记录的相关信息 */ public class KeyInfo { /**缓存中的最大值*/ private int keyMax; /**缓存中的最小值,也是就是每次从数据库中取值以后的第一个值*/ private int keyMin; private int nextKey; /**缓存多少个*/ private int poolSize; /**键名**/ private String keyName; /** * 构造函数 * @param poolSize * @param keyName */ public KeyInfo(int poolSize,String keyName){ this.poolSize = poolSize; this.keyName = keyName; retrieveFromDB(); } /** * 从数据库获取数据 */ private void retrieveFromDB(){ Connection conn = null; try { //一次从数据库中取poolSize出来 Class.forName("com.mysql.jdbc.Driver"); conn = DriverManager .getConnection("jdbc:mysql://localhost:3306/frameworkdb?user=root&password=123456"); String updateSql = "update id_gen set GEN_VALUE = GEN_VALUE+ " + this.poolSize + " where keyName = ? "; PreparedStatement upateStmt = conn.prepareStatement(updateSql); upateStmt.setString(1, this.keyName); upateStmt.execute(); String sql = "select GEN_VALUE from id_gen where GEN_KEY = ? "; PreparedStatement stmt = conn.prepareStatement(sql); stmt.setString(1, this.keyName); ResultSet rs = stmt.executeQuery(); //赋值 while (rs.next()) { this.keyMax = rs.getInt(1); this.keyMin = this.keyMax - this.poolSize+1; this.nextKey = this.keyMin; } } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ try { conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * 获取下一个键值 * @return */ public int getNextKey() { //缓存中使用完以后,再重新获取 if(nextKey > keyMax){ retrieveFromDB(); } //返回nextKey,并将nextKey+1 return nextKey++; } public String getKeyName() { return keyName; } public int getKeyMax() { return keyMax; } public int getKeyMin() { return keyMin; } public int getPoolSize() { return poolSize; } }

 

 

 

接下来,我们看看序列键生成器的代码:

 

package com.pattern.id.generator; import java.util.HashMap; import java.util.Map; public class KeyGenerator { private static KeyGenerator keyGen = new KeyGenerator(); private static final int POOL_SIZE = 5; private Map<String,KeyInfo> keyList = new HashMap<String,KeyInfo>(); private KeyGenerator() { }; /** * 工厂方法 * * @return */ public static KeyGenerator getInstance() { return keyGen; } /** * 获取下一个value * * @return */ public synchronized int getNextKey(String keyName) { KeyInfo key = keyList.get(keyName); if(key==null){ key = new KeyInfo(POOL_SIZE,keyName); } return key.getNextKey(); } }

 

 

大家可以看到,我们把获取数据库的操作转移到KeyInfo中,每条记录对自己负责,我们在序列键生成器中,只需要调用各自记录的Bean,就能获取到相关信息。当第一次获取某条记录的时候相关信息时,首先我们是去缓存中查询,如果查询不到,我们就会创建该记录的Bean,并缓存起来。如果查询到,我们则直接调查用相关方法,获取我们需要的信息(下一个键值),每条记录对自己负责,而生成器,刚相当于成了一完全的缓存对象,他的所有操作都委托给相应记录的Bean自己处理。

 

同时,我还在想,这例可不可以用多例模式来做列? 我们将map 放到KeyInfo类中,让KeyInfo类,变成多例模式,这样KeyGenarator就可以省去,这样做也是行得通。但是我个人觉得: 从逻辑上来讲,一个序列键管理器负责管理多条记录更说通。

应该说,两种设计都行通,看个人喜好吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值