网站公告列表

  没有公告

加入收藏
设为首页
联系站长
您现在的位置: 网络学院 >> 程序设计 >> Java编程 >> 文章正文
  iBatis一级缓存的探讨            【字体:
iBatis一级缓存的探讨
作者:佚名    文章来源:不详    点击数:    更新时间:2007-9-12    

前几天和朋友讨论数据库Cache的时候,谈到了iBatis框架不支持一级缓存,后来尝试作了一些扩展来支持一级缓存,放出来大家探讨一下。
正在装载数据……

 

首先让我们简单回顾一下缓存的概念。直白的说,缓存就是把从数据库里查出来的数据放到内存中,供后续操作使用。例如,某个应用需要让业务人员查询前日的数据报表,可能同时有很多人在查询该数据,并且数据没有实时的要求,则可以在第一次查询的时候把结果放到缓存中,以提高后续操作的效率。缓存分为一级缓存和二级缓存,所谓一级缓存通常是指在一次数据库事物范围内的缓存,当数据库事物提交,连接被释放后,该缓存就被销毁了;所谓二级缓存通常指存在时间比较长,例如1天等。一级缓存通常在事物开启的时候建立,在事物提交或回滚的时候销毁。Hibernate对一级缓存和二级缓存都支持的很好,而ibatis则只对应用二级缓存提供了内置的支持。因此本文重点讨论如何为ibatis提供一级缓存功能。

 

先介绍一下我的环境:Spring1.2.6 + iBatis2.1.3 + MySql5.0Spring已经成为事实上的标准,对iBatis提供了非常好的支持。因此我们在此讨论如何在Spring环境下提供对iBatis的一级缓存支持。SpringiBatis的封装主要是通过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() {

        return cacheModel.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()) {

            return cacheModel.get().get(key);

        }

        return null;

    }

 

    public synchronized static void initial() {

        if (!exist()) {

            cacheModel.set(new HashMap<Object, Object>());

            logger.info("Initial current transaction's Cache.");

        } else {

            throw new RuntimeException("Current transaction's CacheModel allready initial!");

        }

    }

 

    public synchronized static void destroy() {

        cacheModel.set(null);

        logger.info("Destroy current transaction's Cache.");

    }

 

}

接下来扩展TransactionTemplate,实现在开启和结束事物的时候创建和销毁CacheModel

public class CacheTransactionTemplate extends TransactionTemplate {

    private static final long serialVersionUID = 489621858441822688L;

 

    private boolean           cacheable        = true;

 

    private boolean           isInitialized    = false;

 

    /* (non-Javadoc)

     * @see org.springframework.transaction.support.TransactionTemplate#afterPropertiesSet()

     */

    @Override

    public void 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;

    }

 

    /**

     * Perform a rollback, handling rollback exceptions properly.

     *

     * @param status object redivsenting the transaction

     *

     * @param ex the thrown application exception or error

     *

     * @throws TransactionException in case of a rollback error

     */

    private void 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);

        }

    }

 

    /**

     * Initail current transaction's CacheModel.

     *

     * <p>

     * Must be a new Transaction.

     *

     * Current transaction's CacheModel must have not been initialized.

     * </p>

     *

     * @param status

     */

    private void initialCacheModel(TransactionStatus status) {

        if (cacheable && status != null && status.isNewTransaction()) {

            if (!CacheModel.exist()) {

                CacheModel.initial();

            }

        }

    }

 

    /**

     * Destroy current transaction's CacheModel.

     *

     * <p>

     * Must