无奈自己写了一个简单的JDBC查询缓存,分享一下
2009-12-09 18:52
381 查看
正在做一个项目,因为不是一个人做的,所以很多地方还得用最原始的JDBC技术,享受不了Hibernate的查询缓存,,而且我们用的是Oracle 10G,NND上网查,人家MySQL早就有查询缓存了,Oracle非得11G才支持,无奈自己写了一个简单的基于SQL语句和CachedRowSet名值对的查询缓存。测试了一下性能还不错,大概10:1(其实这是废话,从内存里读当然要比从数据库中查询快了)。
因为简单,没有过多考虑清除缓存的策略,简单地只要有修改就清空缓存。所以应用场合有两个限制:
1、SQL语句的可能性不能无限多(例如如果语句中包含可变的时间日期就不行);
2、读操作远远多于写操作。
我用在权限管理中,肯定是很合适的。
下面是代码:
因为简单,没有过多考虑清除缓存的策略,简单地只要有修改就清空缓存。所以应用场合有两个限制:
1、SQL语句的可能性不能无限多(例如如果语句中包含可变的时间日期就不行);
2、读操作远远多于写操作。
我用在权限管理中,肯定是很合适的。
下面是代码:
package oas.common.cache; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import java.util.logging.Logger; /** * 通用缓存类 * @author shajunxing */ public class Cache<T> { private final static Logger logger = Logger.getLogger(Cache.class.getName()); /** * 缓存 */ private Map<String, T> cache; /** * 访问计数器 */ private long visitedCount; /** * 命中计数器 */ private long hitCount; /** * 构造函数 * @param maxSize 缓存最大容量 */ public Cache(final int maxSize) { cache = new LinkedHashMap<String, T>(1, 0.75F, true) { @Override protected boolean removeEldestEntry(Entry<String, T> eldest) { return size() > maxSize; } }; clear(); } /** * 取出一个值 * @param key 键 * @return 值/空 */ public T get(String key) { if (key == null) { return null; } visitedCount++; if (cache.containsKey(key)) { hitCount++; return cache.get(key); } else { return null; } } /** * 存入一个值 * @param key 键 * @param value 值 */ public synchronized void put(String key, T value) { if ((key == null) || (value == null)) { return; } cache.put(key, value); } /** * 清除缓存,复位计数器 */ public void clear() { cache.clear(); visitedCount = 0; hitCount = 0; } /** * 获取命中计数 * @return 命中计数 */ public long getHitCount() { return hitCount; } /** * 获取访问计数 * @return 访问计数 */ public long getVisitedCount() { return visitedCount; } /** * 执行一个任务,如果在缓存中有对应的值,那么直接返回,否则执行任务并把输出保存入缓存 * @param task 任务 * @return 任务返回值 */ public T doCachedTask(CachedTask<T> task) { String key = task.getKey(); T value = get(key); if (value == null) { value = task.run(); put(key, value); } return value; } /** * 返回缓存内容 * @return 缓存内容 */ @Override public String toString() { StringBuilder str = new StringBuilder("/n"); for (Map.Entry<String, T> entry : cache.entrySet()) { str.append("Key: " + entry.getKey() + "/n"); str.append("Value: " + entry.getValue() + "/n"); } return str.toString(); } }
package oas.common.cache; /** * 通用缓存任务类,执行一个简单的缓存任务 * @author shajunxing */ public abstract class CachedTask<T> { private String key; public String getKey() { return key; } public CachedTask(String key) { this.key = key; } public abstract T run(); }
package oas.common; import com.mchange.v2.c3p0.ComboPooledDataSource; import java.beans.PropertyVetoException; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; import javax.sql.rowset.CachedRowSet; import oas.common.cache.Cache; import oas.common.cache.CachedTask; /** * JDBC助手类 * @author shajunxing */ public class JdbcHelper { private final static Logger logger = Logger.getLogger(JdbcHelper.class.getName()); private static ComboPooledDataSource cpds; private static ThreadLocal<Connection> threadLocal = null; private static Cache<CachedRowSet> queryCache = new Cache<CachedRowSet>(10000); static { try { Class.forName(Utility.getProperty("hibernate.connection.driver_class")); // 初始化C3P0 cpds = new ComboPooledDataSource(); cpds.setDriverClass(Utility.getProperty("hibernate.connection.driver_class")); cpds.setJdbcUrl(Utility.getProperty("hibernate.connection.url")); cpds.setUser(Utility.getProperty("hibernate.connection.username")); cpds.setPassword(Utility.getProperty("hibernate.connection.password")); logger.info("连接池大小:" + cpds.getMaxPoolSize()); cpds.setMaxPoolSize(100); cpds.setMaxStatements(10); // 初始化线程局部变量 threadLocal = new ThreadLocal<Connection>(); } catch (ClassNotFoundException ex) { logger.severe("JDBC驱动加载失败:" + ex); cpds = null; System.exit(-1); } catch (PropertyVetoException ex) { logger.severe("C3P0初始化失败:" + ex); cpds = null; System.exit(-1); } } /** * 获取连接 * @return 可用的连接 * @throws java.sql.SQLException */ public static Connection getConnection() throws SQLException { Connection conn = threadLocal.get(); if (conn == null) { conn = cpds.getConnection(); // conn = DriverManager.getConnection( // Utility.getProperty("hibernate.connection.url"), // Utility.getProperty("hibernate.connection.username"), // Utility.getProperty("hibernate.connection.password")); conn.setAutoCommit(false); threadLocal.set(conn); } return conn; } /** * 关闭连接 * @param conn 连接 */ public static void closeConnection() { Connection conn = threadLocal.get(); threadLocal.set(null); if (conn != null) { try { conn.close(); } catch (SQLException ex) { logger.severe("关闭Connection失败:" + ex); } } } /** * 提交事务 * @throws java.sql.SQLException */ public static void commit() throws SQLException { getConnection().commit(); } /** * 回滚事务 */ public static void rollback() { try { getConnection().rollback(); } catch (SQLException ex) { logger.severe("事务回滚异常:" + ex); } } /** * 关闭声明 * @param stmt 声明 */ public static void close(Statement stmt) { if (stmt != null) { try { stmt.close(); } catch (SQLException ex) { logger.severe("关闭Statement失败:" + ex); } } } /** * 关闭结果集 * @param rs 结果集 */ public static void close(ResultSet rs) { if (rs != null) { try { rs.close(); } catch (SQLException ex) { logger.severe("关闭ResultSet失败:" + ex); } } } /** * 获取一个缓存行集对象 * @return 缓存行集对象 */ private static CachedRowSet getCachedRowSet() { CachedRowSet ret = null; try { ret = (CachedRowSet) Class.forName("com.sun.rowset.CachedRowSetImpl").newInstance(); } catch (InstantiationException ex) { logger.severe(ex.toString()); } catch (IllegalAccessException ex) { logger.severe(ex.toString()); } finally { return ret; } } /** * 查询 * @param sql SQL语句 * @return 查询结果 */ public static CachedRowSet query(String sql) { CachedRowSet crs = getCachedRowSet(); if (crs == null) { return null; } Connection conn = null; Statement stmt = null; ResultSet rs = null; try { conn = getConnection(); stmt = conn.createStatement(); rs = stmt.executeQuery(sql); crs.populate(rs); return crs; } catch (SQLException ex) { logger.severe(ex.toString()); return null; } finally { close(rs); close(stmt); closeConnection(); } } /** * 缓存查询 * @param sql SQL语句 * @return 查询结果 */ public static CachedRowSet cachedQuery(final String sql) { return queryCache.doCachedTask(new CachedTask<CachedRowSet>(sql) { @Override public CachedRowSet run() { return query(sql); } }); } public static void clearCache() { queryCache.clear(); } public static long getCacheHitCount() { return queryCache.getHitCount(); } public static long getCacheVisitedCount() { return queryCache.getVisitedCount(); } public static void main(String[] args) throws SQLException { for (int i = 0; i < 1000; i++) { Thread th = new Thread(new Runnable() { @Override public void run() { CachedRowSet rs = JdbcHelper.query("select classid from mta_class order by classid"); if (rs != null) { try { List<String> ids = new ArrayList<String>(); while (rs.next()) { ids.add(rs.getString("classid")); } logger.info(ids.toString()); } catch (SQLException ex) { logger.severe(ex.toString()); } } } }); th.start(); } } }
相关文章推荐
- 分享自己做的一个简单的查询表达式模拟(ESQL,Linq)(3)
- 分享自己做的一个简单的查询表达式模拟(ESQL,Linq)(3)
- 分享一个小巧简单的基金查询工具(自己写的)
- 分享自己做的一个简单的查询表达式模拟(ESQL,Linq)(1)
- 分享自己做的一个简单的查询表达式模拟(ESQL,Linq)(1)
- 分享自己做的一个简单的查询表达式模拟(ESQL,Linq)(2)
- 分享一个小巧简单的基金查询工具(自己写的)
- 分享自己做的一个简单的查询表达式模拟(ESQL,Linq)(2)
- 分享一个自己写的简单的javascript分页组件
- 一个JDBC简单的查询步骤
- 分享一个自己写的简单的自动轮播的的函数
- spring对JDBC整合的时候,要注意自己写一个映射,继承RowMapper,查询的时候会用到,将返回的ResultSet一条对应一个Employee对象。
- 写了一个PHP版本的MONGODB语法解析器,可以通过类似SQL的语法来进行MONGODB的查询,不知道有人需要不,分享一下吧
- 【C#】对异步请求处理程序IHttpAsyncHandler的理解和分享一个易用性封装 【手记】走近科学之为什么明明实现了IEnumerable<T>的类型却不能调用LINQ扩展方法 【手记】手机网页弹出层后屏蔽底层的滑动响应 【手记】ASP.NET提示“未能创建类型”处理 【Web】一个非常简单的移动web消息框 【手记】解决EXCEL跑SQL遇“查询无法运行或数据库表无法打开...”
- 分享一个自己写的简单的javascript分页组件
- 咱们在讨论的时候能不能先确定一个明确的范围呢?最好能把自己的经历简单说一下。
- 用JDBC实现简单的数据库查询的一个例子
- 最近在写导出excel表格的代码,发现网上大部分代码都是导出简单格式的excel,所以自己顺便就写了一个导出复杂表格的工具类,有些代码是借鉴网友的,同时也谢谢分享代码的朋友们.
- 咱们在讨论的时候能不能先确定一个明确的范围呢?最好能把自己的经历简单说一下。
- 分享一下自己写的一个vscode-leetcode插件