- 浏览: 595027 次
- 性别:
- 来自: 杭州
文章分类
- 全部博客 (268)
- ext基础 (72)
- Java基础 (68)
- jquery (14)
- oracle (21)
- sqlserver (7)
- linux (2)
- webserver (1)
- C/C++ (1)
- sql (9)
- IDE (2)
- java 智能卡 (1)
- mysql (6)
- ibatis (2)
- struts2 (3)
- cvs (1)
- 服务器 (1)
- html (11)
- freemarker (4)
- liferay (2)
- jMS (1)
- iphone (1)
- c# (1)
- Android (11)
- wince (6)
- javascript (4)
- ps (1)
- hibernate (1)
- 其他 (3)
最新评论
-
ilyq:
请问,px.gif 在哪里
斜线表头 -
jisang:
没看懂,第一个org.js和最后的js什么关系,可否发我一份完 ...
用ExtJS 实现动态载入树(Load tree) -
JavaStudyEye:
我去,能否搞个正确点的,,,
<#list ...
freemarker 遍历map 对象 -
PangSir:
大爱,简直是大爱!!困扰这么久以来的问题,虽然知道是CSS的问 ...
ExtJs checkbox radiobox 问题 汇总 -
skynet_java:
有demo嘛!邮箱:think_world@foxmail.c ...
消息推送服务需求 - 服务器开发、客户端开发
前几天和朋友讨论数据库Cache的时候,谈到了iBatis框架不支持一级缓存,后来尝试作了一些扩展来支持一级缓存,放出来大家探讨一下。
首先让我们简单回顾一下缓存的概念。直白的说,缓存就是把从数据库里查出来的数据放到内存中,供后续操作使用。例如,某个应用需要让业务人员查询前日的数据报表,可能同时有很多人在查询该数据,并且数据没有实时的要求,则可以在第一次查询的时候把结果放到缓存中,以提高后续操作的效率。缓存分为一级缓存和二级缓存,所谓一级缓存通常是指在一次数据库事物范围内的缓存,当数据库事物提交,连接被释放后,该缓存就被销毁了;所谓二级缓存通常指存在时间比较长,例如1天等。一级缓存通常在事物开启的时候建立,在事物提交或回滚的时候销毁。Hibernate对一级缓存和二级缓存都支持的很好,而ibatis则只对应用二级缓存提供了内置的支持。因此本文重点讨论如何为ibatis提供一级缓存功能。
先介绍一下我的环境:Spring1.2.6 + iBatis2.1.3 + MySql5.0。Spring已经成为事实上的标准,对iBatis提供了非常好的支持。因此我们在此讨论如何在Spring环境下提供对iBatis的一级缓存支持。Spring对iBatis的封装主要是通过SqlMapClientTemplate来实现的,而事物方面这是通过TransactionTemplate来提供支持,因此要提供一级缓存的功能,就要在这两个类上做一些文章。 当前事物的缓存可以放在当前的线程(ThreadLocal)中,看下面的代码:
接下来扩展TransactionTemplate,实现在开启和结束事物的时候创建和销毁CacheModel:
上面的代码重写了TransactionTemplate的 execute方法,加入了对CacheModel的支持。接下来再扩展SqlMapClientTemplate,并重写query方法:
类扩展写好了,下面我们看一下如何配置:
经过上面的扩展,执行queryForObject和queryForList方法的时候,查询出来的数据将在当前事物内缓存起来,可以看一下下面的测试代码:
首先让我们简单回顾一下缓存的概念。直白的说,缓存就是把从数据库里查出来的数据放到内存中,供后续操作使用。例如,某个应用需要让业务人员查询前日的数据报表,可能同时有很多人在查询该数据,并且数据没有实时的要求,则可以在第一次查询的时候把结果放到缓存中,以提高后续操作的效率。缓存分为一级缓存和二级缓存,所谓一级缓存通常是指在一次数据库事物范围内的缓存,当数据库事物提交,连接被释放后,该缓存就被销毁了;所谓二级缓存通常指存在时间比较长,例如1天等。一级缓存通常在事物开启的时候建立,在事物提交或回滚的时候销毁。Hibernate对一级缓存和二级缓存都支持的很好,而ibatis则只对应用二级缓存提供了内置的支持。因此本文重点讨论如何为ibatis提供一级缓存功能。
先介绍一下我的环境:Spring1.2.6 + iBatis2.1.3 + MySql5.0。Spring已经成为事实上的标准,对iBatis提供了非常好的支持。因此我们在此讨论如何在Spring环境下提供对iBatis的一级缓存支持。Spring对iBatis的封装主要是通过SqlMapClientTemplate来实现的,而事物方面这是通过TransactionTemplate来提供支持,因此要提供一级缓存的功能,就要在这两个类上做一些文章。 当前事物的缓存可以放在当前的线程(ThreadLocal)中,看下面的代码:
public class CacheModel { private static final Log logger = LogFactory.getLog(CacheModel.class); private static final ThreadLocal<Map<Object, Object>> cacheModel = new ThreadLocal<Map<Object, Object>>(); synchronized static boolean exist() { returncacheModel.get() != null; } public synchronized static void add(Object key, Object value) { if (exist()) { cacheModel.get().put(key, value); } } public synchronized static Object get(Object key) { if (exist()) { returncacheModel.get().get(key); } returnnull; } public synchronized static void initial() { if (!exist()) { cacheModel.set(new HashMap<Object, Object>()); logger.info("Initial current transaction's Cache."); } else { thrownew RuntimeException("Current transaction's CacheModel allready initial!"); } } public synchronized static void destroy() { cacheModel.set(null); logger.info("Destroy current transaction's Cache."); } }
接下来扩展TransactionTemplate,实现在开启和结束事物的时候创建和销毁CacheModel:
publicclass CacheTransactionTemplate extends TransactionTemplate { privatestaticfinallongserialVersionUID = 489621858441822688L; privateboolean cacheable = true; privateboolean isInitialized = false; /* (non-Javadoc) * @see org.springframework.transaction.support.TransactionTemplate#afterPropertiesSet() */ @Override publicvoid afterPropertiesSet() { super.afterPropertiesSet(); isInitialized = true; } /* (non-Javadoc) * @see org.springframework.transaction.support.TransactionTemplate#execute(org.springframework.transaction.support.TransactionCallback) */ @Override public Object execute(TransactionCallback action) throws TransactionException { TransactionStatus status = getTransactionManager().getTransaction(this); initialCacheModel(status); Object result = null; try { result = action.doInTransaction(status); logger.debug(action); } catch (RuntimeException ex) { // transactional code threw application exception -> rollback rollbackOnException(status, ex); throw ex; } catch (Error err) { // transactional code threw error -> rollback rollbackOnException(status, err); throw err; } try { getTransactionManager().commit(status); } finally { destoryCacheModel(status); } return result; } /** *Performarollback,handlingrollbackexceptionsproperly. * *@paramstatusobjectrepresentingthetransaction * *@paramexthethrownapplicationexceptionorerror * *@throwsTransactionExceptionincaseofarollbackerror */ privatevoid rollbackOnException(TransactionStatus status, Throwable ex) throws TransactionException { logger.debug("Initiating transaction rollback on application exception", ex); try { getTransactionManager().rollback(status); } catch (RuntimeException ex2) { logger.error("Application exception overridden by rollback exception", ex); throw ex2; } catch (Error err) { logger.error("Application exception overridden by rollback error", ex); throw err; } finally { destoryCacheModel(status); } } /** *Initailcurrenttransaction'sCacheModel. * *<p> *MustbeanewTransaction. * *Currenttransaction'sCacheModelmusthavenotbeeninitialized. *</p> * *@paramstatus */ privatevoid initialCacheModel(TransactionStatus status) { if (cacheable && status != null && status.isNewTransaction()) { if (!CacheModel.exist()) { CacheModel.initial(); } } } /** *Destroycurrenttransaction'sCacheModel. * *<p> *MustbeanewTransaction. * *Currenttransaction'sCacheModelmusthavebeeninitialized. *</p> * *@paramstatus */ privatevoid destoryCacheModel(TransactionStatus status) { if (cacheable && status != null && status.isNewTransaction()) { if (CacheModel.exist()) { CacheModel.destroy(); } } } /** * *@paramcacheable */ publicvoid setCacheable(boolean cacheable) { if (!isInitialized) { this.cacheable = cacheable; } } }
上面的代码重写了TransactionTemplate的 execute方法,加入了对CacheModel的支持。接下来再扩展SqlMapClientTemplate,并重写query方法:
publicclass CacheSqlMapClientTemplate extends SqlMapClientTemplate { privatestaticfinal Log logger = LogFactory .getLog(CacheSqlMapClientTemplate.class); privatestaticfinal String DEFAULT_SPARATOR = "_"; /* (non-Javadoc) * @see org.springframework.orm.ibatis.SqlMapClientTemplate#queryForList(java.lang.String, java.lang.Object, int, int) */ @Override public List queryForList(String statementName, Object parameterObject, int skipResults, int maxResults) throws DataAccessException { String key = statementName + DEFAULT_SPARATOR + generateKeyPart(parameterObject) + skipResults + maxResults; List result = queryDataFromCacheModel(key, List.class); if (result != null) { return result; } result = super.queryForList(statementName, parameterObject, skipResults, maxResults); addDataToCacheModel(key, result); return result; } /* (non-Javadoc) * @see org.springframework.orm.ibatis.SqlMapClientTemplate#queryForList(java.lang.String, java.lang.Object) */ @Override public List queryForList(String statementName, Object parameterObject) throws DataAccessException { String key = statementName + DEFAULT_SPARATOR + generateKeyPart(parameterObject); List result = queryDataFromCacheModel(key, List.class); if (result != null) { return result; } result = super.queryForList(statementName, parameterObject); addDataToCacheModel(key, result); return result; } /* (non-Javadoc) * @see org.springframework.orm.ibatis.SqlMapClientTemplate#queryForObject(java.lang.String, java.lang.Object, java.lang.Object) */ @Override public Object queryForObject(String statementName, Object parameterObject, Object resultObject) throws DataAccessException { String key = statementName + DEFAULT_SPARATOR + generateKeyPart(parameterObject) + DEFAULT_SPARATOR + generateKeyPart(resultObject); Object result = queryDataFromCacheModel(key, Object.class); if (result != null) { return result; } result = super.queryForObject(statementName, parameterObject, resultObject); addDataToCacheModel(key, result); return result; } /* (non-Javadoc) * @see org.springframework.orm.ibatis.SqlMapClientTemplate#queryForObject(java.lang.String, java.lang.Object) */ @Override public Object queryForObject(String statementName, Object parameterObject) throws DataAccessException { String key = statementName + DEFAULT_SPARATOR + generateKeyPart(parameterObject); Object result = queryDataFromCacheModel(key, Object.class); if (result != null) { return result; } result = super.queryForObject(statementName, parameterObject); addDataToCacheModel(key, result); return result; } private <T> T queryDataFromCacheModel(Object key, Class<T> type) { if (CacheModel.exist()) { logger.info("Look up data from current transaction's CacheModel , KEY={" + key + "}"); Object value = CacheModel.get(key); if (value != null) { return type.cast(value); } else { logger .info("Current transaction's CacheModel dosen't contain any data relate with {" + key + "}"); } } returnnull; } private <T> void addDataToCacheModel(Object key, T value) { if (null == value) { return; } if (CacheModel.exist()) { CacheModel.add(key, value); logger.info("Add data to current transaction's CacheModel , KEY={" + key + "}"); } } private String generateKeyPart(Object source) { if (source == null) { return""; } elseif (source instanceof String) { return (String) source; } elseif (source instanceof Map) { return generate((Map) source); } else { try { return generate(BeanUtils.describe(source)); } catch (Exception e) { return source.toString(); } } } private String generate(Map props) { try { Iterator iProps = props.keySet().iterator(); StringBuffer retBuffer = new StringBuffer(); while (iProps.hasNext()) { String key = (String) iProps.next(); if ("class".equals(key)) { continue; } retBuffer.append(key).append("=[").append(props.get(key)).append("]"); if (iProps.hasNext()) { retBuffer.append(", "); } } return retBuffer.toString(); } catch (Exception e) { return""; } } }
类扩展写好了,下面我们看一下如何配置:
<beans default-autowire="byName"> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/batchtest"/> <property name="username" value="root"/> <property name="password" value="foxdesign"/> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"/> <bean id="transactionTemplate" class="com.company.CacheTransactionTemplate"> <property name="cacheable"> <value>true</value> </property> </bean> <bean id="customSqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"> <property name="configLocation" value="SqlMapConfig.xml"/> </bean> <bean id="sqlMapClientTemplate" class="com.company.CacheSqlMapClientTemplate"> <property name="sqlMapClient" ref="customSqlMapClient"/> </bean> <bean id="userCacheDAO" class="com.company.imp.UserCacheDAOImpl"> </bean> </beans>
经过上面的扩展,执行queryForObject和queryForList方法的时候,查询出来的数据将在当前事物内缓存起来,可以看一下下面的测试代码:
publicvoid testWithTrans() { transactionTemplate.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus arg0) { userCacheDAO.getUserByName("Tony"); userCacheDAO.getUserByName("Tony"); userCacheDAO.getUserByName("Aroma"); returnnull; } }); }
发表评论
-
springboot 发布
2022-01-08 16:53 245java -jar spring-boot-druid-0.0 ... -
List 边遍历,边删除?
2020-07-17 16:51 504新手常犯的错误 可能很 ... -
servlet 文件上传
2012-08-10 10:52 1141org.apache.commons.fileupload 文 ... -
pdf 简单连接servlet
2012-07-25 10:05 1103protected void doGet(HttpSe ... -
应用 HttpClient 来对付各种顽固的WEB服务器
2012-04-11 17:38 985一般的情况下我们都是使用IE或者Navigator浏览器来访问 ... -
MAVEN2入门学习心得(4)-知识汇集
2012-01-11 14:16 1008一、创建Spring+Hibernate+Activiti+V ... -
MAVEN2入门学习心得(3)-仓库管理器Nexus相关
2012-01-11 14:11 1333以前觉得Nexus搭建太简单,没有留下学习重点,重新温习起来又 ... -
MAVEN2入门学习心得(2)-仓库相关
2012-01-11 14:08 1283MAVEN2的仓库基本可以分为主机仓库、代理仓库、本地仓库。 ... -
MAVEN2入门学习心得(1)-插件相关
2012-01-11 14:02 1155MAVEN2涉及到很多插件,掌握插件的学习方式很重要,要不然接 ... -
restful webserice
2011-08-11 20:06 943package com.onetown.action.admi ... -
java.lang.OutOfMemoryError: PermGen space及其解决方法
2011-08-05 10:00 869这个问题是我的工程中 ... -
内存溢出的解决
2011-01-28 15:07 1076内存溢出虽然很棘手 ... -
oracle sql 基础
2010-12-25 14:52 888视图; create or replace view my_v ... -
计算 上一个 工作日的 自定义函数
2010-09-06 10:31 1814算法描述 1.获取日期参数,然后自减一 2.判断该日期是否是 ... -
Java 简单 计算任意两个日期之间的工作天数
2010-09-06 09:20 1771主要思路: 对于任意2个日期比如:date_start=201 ... -
java file
2010-09-05 21:37 1280追加文件尾部 public void testPrintWri ... -
验证码
2010-08-31 09:07 1039package com.pa.util; import ... -
java List与Array 转换
2010-08-31 08:57 35482public static void main(String[ ... -
java property 配置文件 用法
2010-08-14 18:12 4976在我们平时写程序的时候,有些参数是经常改变的,而这种改变不是我 ... -
防止 session 被 篡改
2010-06-27 14:27 1756public String login() { ...
相关推荐
首先,iBATIS的缓存分为两种类型:一级缓存和二级缓存。一级缓存是SqlSession级别的,它是默认开启的,每次SqlSession内的查询结果都会被存储在一级缓存中,如果同一SqlSession内再次执行相同的SQL,会直接从缓存中...
iBATIS支持两种级别的缓存:一级缓存(默认缓存)和二级缓存。本文主要关注的是二级缓存,因为它提供了更高级别的控制和定制选项。 #### 二、缓存模型的配置 在iBATIS中,可以通过`<cacheModel>`元素来定义一个...
在深入理解iBatis的Cache概念之前,首先需要知道iBatis是一个轻量级的持久层框架,它将SQL映射与Java代码分离,提供了更灵活的数据库操作方式。 **Cache概述** iBatis 提供了本地数据缓存功能,用于存储查询结果集...
一级缓存是iBatis默认提供的,它存在于SqlSession级别,同一SqlSession内的多次查询会共享结果,避免了重复的数据库访问。然而,跨SqlSession的查询无法利用一级缓存,这时二级缓存就显得尤为重要。二级缓存是基于...
iBatis提供了本地缓存和二级缓存,通过CachingExecutor实现。缓存策略可以在全局配置文件中配置,也可以在每个Mapper中单独设置。源码中`org.apache.ibatis.cache.Cache`接口定义了缓存的基本操作,而具体的缓存实现...
7. **缓存机制**:Ibatis内置了本地缓存和二级缓存,可以提高数据读取速度。本地缓存作用于单个SqlSession,而二级缓存则可以在多个SqlSession之间共享,但需要注意并发控制和数据一致性问题。 8. **插件支持**:...
而`OSCache`则是一个高性能的第三方缓存组件,提供了更强大的缓存功能。 总之,《ibatis开发指南》是一本详尽介绍了ibatis框架的教材,不仅涵盖了ibatis的基础概念和核心组件,还深入探讨了其高级特性和应用场景。...
Ibatis提供了本地缓存和二级缓存两种机制,可以提高数据读取的效率。本地缓存默认开启,作用于单个SqlSession,二级缓存则可配置为全局,共享给多个SqlSession。 六、事务管理 Ibatis支持手动和自动事务管理。默认...
4. **缓存机制**:Ibatis 内置了缓存功能,分为一级缓存(SqlSession 级别)和二级缓存(Mapper 级别),可以有效减少数据库的访问次数,提升系统性能。 **三、Java API 与 XML 配置** 1. **...
5. **缓存**:IBATIS支持本地缓存和全局缓存,可以有效减少数据库访问,提高性能。 6. **事务管理**:讲解了如何使用IBATIS的事务管理功能,包括手动和自动提交、回滚以及事务隔离级别设置。 7. **插件**:IBATIS...
Ibatis 是一款优秀的持久层框架,它简化了 Java 开发者与数据库之间的交互过程。本文将详细介绍 ibatis 的一些高级特性,包括数据关联、延迟加载、动态映射以及事务管理等方面的知识点。 #### 二、数据关联 在实际...
6. 缓存:Ibatis提供了本地缓存和二级缓存机制,有助于提高性能。 7. 执行性能:提供优化建议,如批处理、缓存使用等,以提升应用程序的运行效率。 总之,Ibatis是一个强大且灵活的Java持久层框架,其API、文档和...
8. **缓存机制**:了解iBatis的本地缓存和二级缓存,以及如何在实际项目中合理利用缓存提高性能。 9. **最佳实践**:学习如何编写高效的iBatis代码,避免潜在的问题,提升项目的可维护性和扩展性。 通过系统学习并...
5. 缓存机制:Ibatis 提供了本地缓存和二级缓存功能,可以提高数据读取的效率,减少数据库的负载。开发者可以自定义缓存策略,以满足不同场景的需求。 6. 事务管理:Ibatis 提供了基于Spring的事务管理,可以在不...
iBatis是一个轻量级的Java持久层框架,它提供了SQL映射框架,将SQL语句与Java代码分离,使得数据库访问更为灵活和可控。在本压缩包中,你将找到一系列关于iBatis的学习资源,包括PDF文档、实例代码等,这些都是深入...
默认情况下,一级缓存是SqlSession级别的,二级缓存是全局的,可以通过配置启用和定制。 6. **插件支持**:iBatis允许开发者自定义插件,拦截SQL执行过程,实现如性能监控、日志记录等功能。 在Java项目中使用...
8. **缓存**:Ibatis提供了本地缓存和二级缓存功能,这个jar包可能包含了缓存相关的类和接口。 9. **事务管理**:Ibatis提供了基于JDBC的事务控制,这个包可能包含了事务相关的类。 10. **插件支持**:Ibatis允许...
iBatis提供了本地缓存和二级缓存,能够有效减少对数据库的访问,提高性能。本地缓存作用于单个SqlSession,而二级缓存则可以跨SqlSession共享数据。 7. **事务管理** iBatis支持JDBC和Spring的事务管理,可以根据...
10. **缓存机制**:解析iBatis的缓存功能,包括本地缓存和二级缓存,如何配置和使用,以及缓存的生命周期和更新策略。 11. **动态SQL**:详细阐述如何利用iBatis的动态SQL特性,通过`<if>`, `<choose>`, `<when>`, ...
6. **缓存机制**:Ibatis提供了一级缓存和二级缓存,可以提高数据读取的效率。一级缓存是SqlSession级别的,而二级缓存则是全局的,可以在多个SqlSession之间共享。 7. **事务管理**:Ibatis通过SqlSession对象来...