MyBatis包含一个强大的事务查询缓存特性,可以进行灵活的配置和自定义。在MyBatis 3的缓存实现中进行了许多改进,使其更加强大且更易于配置。
默认情况下,仅启用了本地会话缓存,该缓存仅用于缓存会话期间的数据。要启用全局的第二级缓存,您只需在SQL映射文件中添加一行代码:
确实如此。这个简单的语句的效果如下:
请注意,缓存仅适用于包含缓存标签的映射文件中声明的语句。如果您在使用Java API时同时使用XML映射文件,那么在配套接口中声明的语句默认情况下不会被缓存。您需要使用@CacheNamespaceRef注释来引用缓存区域。
所有这些属性都可以通过cache元素的属性进行修改。例如:
这种更高级的配置创建了一个FIFO(先进先出)缓存,每隔60秒刷新一次,最多存储512个结果对象或列表的引用,返回的对象被视为只读,因此在不同线程中对其进行修改可能会导致调用者之间发生冲突。
可用的驱逐策略有:
默认的驱逐策略是LRU。
flushInterval可以设置为任意正整数,并且应该表示以毫秒为单位的合理时间间隔。默认情况下,默认值未设置,因此不会使用刷新间隔,缓存仅在调用语句时才会刷新。
size可以设置为任何正整数,但请考虑您缓存的对象大小以及环境中可用的内存资源。默认值是1024。由于不同的应用场景和系统环境可能存在差异,您可以根据实际情况来调整缓存大小,以确保合理利用内存资源。
readOnly属性可以设置为true或false。设置为true时,缓存将对所有调用者返回相同的缓存对象实例。因此,这些对象不应该被修改。尽管如此,这样的设置可以提供显著的性能优势。而将readOnly属性设置为false时,缓存将通过序列化返回缓存对象的副本。虽然这种方式较慢,但更安全,因此默认值是false。根据您的需求,您可以适当选择是否使用只读缓存或读写缓存。
注意:二级缓存是事务性的。这意味着当一个SqlSession在提交(commit)或回滚(rollback)时,二级缓存会更新,但没有执行带有flushCache=true的插入/删除/更新操作。
除了通过上述方式自定义缓存之外,您还可以通过实现自己的缓存或创建适配器来完全覆盖缓存行为,以及与第三方缓存解决方案进行集成。
这个示例演示了如何使用自定义缓存实现。在type属性中指定的类必须实现org.apache.ibatis.cache.Cache接口,并提供一个构造函数,该构造函数接受一个字符串id作为参数。这个接口是MyBatis框架中比较复杂的接口之一,但考虑到它的功能,实现起来还是比较简单的。
public interface Cache {
String getId();
int getSize();
void putObject(Object key, Object value);
Object getObject(Object key);
boolean hasKey(Object key);
Object removeObject(Object key);
void clear();
}
要配置缓存,只需向您的缓存实现中添加公共JavaBeans属性,并通过缓存元素传递属性值。例如,以下内容将调用您缓存实现中名为setCacheFile(String file)的方法。
你可以使用所有简单类型的JavaBeans属性,MyBatis会进行自动转换。并且你可以在配置属性中指定一个占位符(例如${cache.file}),来替换实际的值。
自从3.4.2版本开始,MyBatis支持在设置完所有属性后调用初始化方法。如果您想使用这个功能,请在自定义缓存类上实现org.apache.ibatis.builder.InitializingObject接口。
public interface InitializingObject {
void initialize() throws Exception;
}
注意,上述部分中的缓存设置(如清除策略、读写等)在使用自定义缓存时不会被应用。如果您需要自定义缓存的设置,您需要在自定义缓存实现中进行相应的配置和处理。
请记住,缓存配置和缓存实例与SQL Map文件的命名空间相关联。因此,与缓存相同命名空间中的所有语句都会受到缓存的影响。语句可以通过使用两个简单的属性,在逐个语句的基础上修改它们与缓存的交互方式或完全排除自己。默认情况下,语句的配置如下所示:
由于这是默认设置,您显然不应该明确地按照这种方式配置语句。相反,只有在您想要更改默认行为时,才设置flushCache和useCache属性。例如,在某些情况下,您可能希望从缓存中排除特定的SELECT语句结果,或者希望SELECT语句刷新缓存。同样地,您可能会有一些更新语句在执行时不需要刷新缓存。
回顾前面的部分,只有在同一命名空间中的语句才会使用或清除该特定命名空间的缓存。但是,在某些情况下,您可能希望在不同的命名空间之间共享相同的缓存配置和实例。在这种情况下,您可以使用`cache-ref`元素引用另一个缓存。通过`cache-ref`元素,您可以指定要在当前命名空间中重用的其他缓存。