缓存,顾名思义,就是将从数据库中查询出来的数据在某个缓冲区域暂时保存起来,在需要数据的时候从该缓冲区中读取,而不是从数据库中读取,从而减少对数据库访问次数,达到减少系统开销,提高性能的目的。
在本文中,我将结合实例讲述ibatis的缓存使用及相关原理。
首先我们来看一个ibatis应用所需要的配置文件:
(注:由于我们只关注ibatis的缓存,所以在ibatis的配置文件中我们只讨论与缓存相关的配置,其它的配置我们将省略!)
1.sql-map的配置,查看配置文件的dtd声明:
<!ELEMENT sqlMap (typeAlias* | cacheModel* | resultMap* | parameterMap* | sql* | statement* | insert* | update* | delete* | select* | procedure*)+>
以上是sql-map配置文件可以使用的元素,其中有些元素还有子元素及属性,这些都可以通过查看ibatis的dtd文件来知晓。在这个dtd声明中有一个cacheModel元素特别耀眼,相信读者已经猜测出来了,的确,该元素即为缓存模型,再看看该元素的子元素及属性:
<!ELEMENT cacheModel (flushInterval?, flushOnExecute*, property*)+> <!ATTLIST cacheModel id CDATA #REQUIRED type CDATA #REQUIRED readOnly (true | false) #IMPLIED serialize (true | false) #IMPLIED >
再看每个子元素的相关属性:
<!ELEMENT flushInterval EMPTY> <!ATTLIST flushInterval milliseconds CDATA #IMPLIED seconds CDATA #IMPLIED minutes CDATA #IMPLIED hours CDATA #IMPLIED > <!ELEMENT flushOnExecute EMPTY> <!ATTLIST flushOnExecute statement CDATA #REQUIRED > <!ELEMENT property EMPTY> <!ATTLIST property name CDATA #REQUIRED value CDATA #REQUIRED >
于是,通过查看ibatis的dtd声明,我们即可得知在ibatis中是如何配置缓存管理的,将以上信息连接起来即可得到如下一段配置:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd"> <sqlMap namespace="User"> <cacheModel id="user-cache" type ="LRU" readOnly="true" serialize="false"> <flushInterval hours="24"/> <flushOnExecute statement=” updateUser”/> <flushOnExecute statement="insertUser"/> <flushOnExecute statement="deleteUser"/> <property value="500" name="size"/> </cacheModel> <!—其他配置信息 --> 。。。。。。。。。。 </sqlMap>
那么这些配置都是什么含义呢?继续:
id:一个标识,在下面的select语句中将引用该标识。
Type: cacheModel的实现类型,目前有如下4种实现:
(1). "MEMORY” (com.ibatis.sqlmap.engine.cache.memory.MemoryCacheController) ,MEMORY cache 实现使用java的软引用类型来管理cache 的行为,使用一个HashMap来保存当前需要缓存的数据对象的引用,当内存不足时,java虚拟机将回收这些引用,从而清除cache。
(2).“LRU” (com.ibatis.sqlmap.engine.cache.lru.LruCacheController) ,LRU Cache 实现用“近期最少使用”原则来确定如何从Cache中清除对象,当Cache溢出时,最近最少使用的对象将被从Cache中清除。
(3).“FIFO” (com.ibatis.sqlmap.engine.cache.fifo.FifoCacheController) ,FIFO Cache 实现用“先进先出”原则来确定如何从 Cache 中清除对象。即最先进入 Cache 的对象将从 Cache 中清除。
(4).“OSCACHE” (com.ibatis.sqlmap.engine.cache.oscache.OSCacheController) ,OSCACHE Cache 实现是OSCache2.0缓存引擎的一个Plugin,它具有高度的可配置性,分布式,高度的灵活性(很推荐使用该类型)OSCache可以通过oscache.properties文件进行缓存的相关配置。
readOnly:readOnly的值表示缓存中的数据对象是否只读。若为true,则当数据对象发生变化时,数据对象就将被从缓存中废除,下次需要重新从数据库读取数据,构造新的数据对象。而若为false,则意味着缓存中的数据对象可更新,不必从数据库中读取。
serialize:如果需要全局的数据缓存,CacheModel的serialize属性必须被设为true。否则数据缓存只对当前Session有效,局部缓存对系统的整体性能提升有限。在serialize="true"的情况下,如果有多个Session同时从Cache 中读取某个数据对象,Cache将为每个Session返回一个对象的复本,也就是说,每个Session将得到包含相同信息的不同对象实例。因而Session可以对其从Cache获得的数据进行存取而无需担心多线程并发情况下的同步冲突。
<flushInterval hours=”24”>:指定多长时间清除缓存,例如指定每24小时强行清空缓存区的所有内容。
<flushOnExecute statement="insertUser"/>:在执行指定的语句时将刷新数据库。
Size:指定Cache的最大容量。
通过在一个SQL Map XML file配置以上信息,我们就可以在一个查询中使用该缓存管理,配置如下:
<select id=”getUserList” resultMap="UserResult" cacheModel=”user-cache”> select * from USER </select>
2.sql-map-config的配置,查看配置文件的dtd声明:
<!ELEMENT sqlMapConfig (properties?, settings?, resultObjectFactory?, typeAlias*, typeHandler*, transactionManager?, sqlMap+)+>
在这个dtd的声明中,有一个settings元素,通过继续查看该元素的属性:
<!ELEMENT settings EMPTY> <!ATTLIST settings classInfoCacheEnabled (true | false) #IMPLIED lazyLoadingEnabled (true | false) #IMPLIED statementCachingEnabled (true | false) #IMPLIED cacheModelsEnabled (true | false) #IMPLIED enhancementEnabled (true | false) #IMPLIED errorTracingEnabled (true | false) #IMPLIED useStatementNamespaces (true | false) #IMPLIED useColumnLabel (true | false) #IMPLIED forceMultipleResultSetSupport (true | false) #IMPLIED maxSessions CDATA #IMPLIED maxTransactions CDATA #IMPLIED maxRequests CDATA #IMPLIED defaultStatementTimeout CDATA #IMPLIED >
显然,属性cacheModelsEnabled就表示是否启用SqlMapClient上的缓存机制。将其设为"true"则标识启用缓存机制,反之则不启用。
通过上面对两个配置文件的分析,我们已经对在ibatis中如何使用缓存有了大致的了解和认识,下面我们将通过一个实例来演示ibatis缓存的使用并检验ibatis的缓存是否已经起作用。
我们的测试方法如下:
1.将数据库中预先插入一些数据(通过控制台或数据库客户端插入数据),然后利用编写好的程序访问数据库,第一次访问数据库时将查询出所有的数据,但当我们通过控制台或数据库客户端(如mysql客户端)再向数据库中插入一些数据,这时再通过编写好的程序去访问数据库,发现通过控制台或数据库客户端新插入的数据并没有被查询出来,说明ibatis读取的是第一次查询所保存在缓存中的数据,这说明测试成功!
2.当我们使用程序而不是控制台或客户端再向数据库插入数据,同时又通过程序访问数据库时,新插入数据库的数据都被查询了出来,而不是从缓存中读取,这说明测试成功,因为我们配置了<flushOnExecute statement="insertUser" />当插入数据时将刷新数据库。
下面就开始我们的测试:
1.建立一个web工程,导入相关的jar包;
2.编写具体代码;
3.做缓存测试;
sql-map文件的配置:User.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd"> <sqlMap namespace="User"> <typeAlias alias="User" type="com.javaeye.hnylj.model.User" /> <!-- 配置缓存模型 --> <cacheModel id="user-cache" type="OSCache" readOnly="true" serialize="true"> <flushInterval hours="24" /> <flushOnExecute statement="insertUser" /> <property value="500" name="size" /> </cacheModel> <resultMap id="UserResult" class="User"> <result property="id" column="ID" /> <result property="name" column="NAME" /> <result property="age" column="AGE" /> </resultMap> <select id="selectAllUser" resultMap="UserResult" cacheModel="user-cache"> SELECT * FROM USER </select> <insert id="insertUser" parameterClass="User"> INSERT INTO USER ( NAME, AGE, PASSWORD) VALUES ( #name#, #age#, #password# ) </insert> </sqlMap>
sql-map-config文件的配置: SqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE sqlMapConfig PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-config-2.dtd"> <sqlMapConfig> <settings lazyLoadingEnabled="true" cacheModelsEnabled="true" maxSessions="30" maxTransactions="100" maxRequests="1000" defaultStatementTimeout="15" /> <transactionManager type="JDBC" commitRequired="false"> <dataSource type="SIMPLE"> <property name="JDBC.Driver" value="com.mysql.jdbc.Driver" /> <property name="JDBC.ConnectionURL" value="jdbc:mysql://127.0.0.1:3306/ibatis" /> <property name="JDBC.Username" value="root" /> <property name="JDBC.Password" value="123" /> </dataSource> </transactionManager> <sqlMap resource="com/javaeye/hnylj/model/User.xml" /> </sqlMapConfig>
接下来就是编写DAO,Action以及jsp页面,在这里,Action层使用了struts2。
Dao代码:UserDAO
package com.javaeye.hnylj.dao; import java.io.IOException; import java.io.Reader; import java.sql.SQLException; import java.util.List; import com.ibatis.common.resources.Resources; import com.ibatis.sqlmap.client.SqlMapClient; import com.ibatis.sqlmap.client.SqlMapClientBuilder; import com.javaeye.hnylj.model.User; public class UserDAO { private static SqlMapClient sqlMapper; static { try { Reader reader = Resources.getResourceAsReader("com/javaeye/hnylj/model/SqlMapConfig.xml"); sqlMapper = SqlMapClientBuilder.buildSqlMapClient(reader); reader.close(); } catch (IOException e) { throw new RuntimeException("building the SqlMapClient instance error."+ e, e); } } public List<?> getAllUser() throws SQLException { List<?> list = sqlMapper.queryForList("selectAllUser"); System.out.println(list.size()); return list; } public void insertUser(User user) throws SQLException { sqlMapper.insert("insertUser", user); } }
Action代码:UserAction
package com.javaeye.hnylj.action; import java.util.List; import com.javaeye.hnylj.dao.UserDAO; import com.javaeye.hnylj.model.User; import com.opensymphony.xwork2.ActionSupport; public class UserAction extends ActionSupport { private static final long serialVersionUID = 4689260572038875931L; private UserDAO userDAO; private List<User> userList; private Integer id; private String name; private Integer age; private String password; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public List<User> getUserList() { return userList; } public void setUserList(List<User> userList) { this.userList = userList; } public String findAllUsers() throws Exception { userDAO = new UserDAO(); userList = (List<User>)userDAO.getAllUser(); if (userList.size() > 0) { return SUCCESS; } return ERROR; } public String add() throws Exception { userDAO = new UserDAO(); User user = new User(); user.setName(name); user.setAge(age); user.setPassword(password); userDAO.insertUser(user); return SUCCESS; } }
还有其他一些代码或配置,在此省略!
将工程部署成功以后,按照上面的测试方法即可进行测试!
本人有一个疑惑,ibatis如何使用ehcache进行缓存管理呢?ibatis好像不支持ehcache缓存,只提供oscache的支持!
据我所知:
oscache 主要是针对页面的缓存,例如将整个页面或者指定网页某一部分缓存起来,同时指定它何时过期。
ehcache主要是针对数据库访问的缓存,相同的查询语句只需查询一次数据库,从而提高性能。
著名的hibernate默认使用的是ehcache,当然也可以使用oscache!
一个Java技术交流群,一起交流,共同进步,扣扣群号:513086638
相关推荐
这意味着对于相同参数的查询结果将会从缓存中获取,而不是每次都查询数据库。 #### 总结 通过合理地配置缓存模型和选择合适的缓存控制器,可以显著提升iBATIS应用程序的性能。开发者可以根据具体的业务需求和数据...
通过设置 `remapResults="true"`,可以强制IBatis每次执行此查询时都重新生成字段映射信息,而不是使用缓存的字段信息。 Java层调用DAO的方法如下: ```java public void getResDataByCondition(Page page) { // ...
在实际应用中,我们可以根据业务需求选择开启一级缓存、二级缓存或者两者都开启。一级缓存适合于短时间内有大量重复查询的情况,而二级缓存则适用于跨多个请求或长时间内需要复用的数据。 在"Test_ibatis"这个测试...
iBatis 数据缓存机制是提高数据库访问性能的重要手段,它允许将查询结果存储在内存中,以便后续相同查询能够快速获取数据,而无需每次都执行SQL查询。在深入理解iBatis的Cache概念之前,首先需要知道iBatis是一个轻...
当使用ibatis的二级缓存时,每次查询都会首先检查缓存中是否存在对应的数据。如果存在,则直接返回缓存中的结果;如果不存在,则从数据库中获取数据,并将其添加到缓存中。这样做的好处是减少了对数据库的访问次数,...
Ibatis,全称为MyBatis,是一个优秀的Java持久层框架,它主要负责SQL映射,使得开发者能够将SQL语句与Java代码分离,...实践是检验真理的唯一标准,所以亲自动手尝试这个ibatis demo,会让你对Ibatis的理解更加深入。
每次数据库交互都应该在一个新的SqlSession实例中完成,完成后记得关闭。 ### 2.4 映射器(Mapper) 映射器接口定义了数据库操作的方法,通过实现这个接口,开发者可以编写Java代码来调用SQL语句。Ibatis会自动将...
5. 学习如何启用和配置Ibatis的缓存功能。 通过深入研究IbatisDemo,开发者可以快速上手Ibatis,为实际项目开发打下坚实基础。在后续的实践中,还可以结合Spring框架,进一步提升开发效率和代码质量。
iBatis是一个优秀的Java持久层框架,它主要负责数据库的交互,通过XML或注解方式配置和映射SQL,使得开发者能够将精力集中在业务逻辑上,而不是...在实际项目中,根据需求选择iBatis或其升级版MyBatis都是不错的选择。
3. **SqlSession**:用于执行SQL的会话对象,每次数据库交互都应使用新的SqlSession实例。 4. **Mapper接口/Mapper XML文件**:Mapper接口定义了数据库操作的方法,Mapper XML文件则包含具体的SQL语句和结果映射。 ...
- 在Ibatis的配置文件`SqlMapConfig.xml`中,可以设置`<settings>`标签内的`defaultExecutorType`属性为`BATCH`或`SIMPLE`,以确保每次执行的SQL都是独立的,避免因缓存导致的编码问题。 - 同时,确保你的项目编码...
iBATIS作为一个轻量级的ORM框架,不仅提供了简单易用的数据库访问接口,还支持动态SQL、缓存等功能,能够有效提高开发效率并优化性能。通过本教程的学习,你可以掌握iBATIS的基本使用方法及高级技巧,为实际项目开发...
6. **避免缓存**:确保在mapper文件中关闭了结果集的缓存,因为缓存会保留旧的查询结果,即使XML文件已经更新。可以在`<resultMap>`标签中设置`cache="false"`,或者在全局配置文件中关闭缓存。 通过以上步骤,你...
通过SqlMapConfig,开发者可以全局配置Ibatis的行为,如数据库连接信息、SQL语句的缓存策略等。 2. **TypeHandler**:TypeHandler是Ibatis处理Java类型和数据库类型之间转换的关键接口。每个数据库字段类型都可能...
在数据库查询优化中,"N+1 选择问题"是一个常见的性能瓶颈,特别是在使用ORM(对象关系映射)框架如iBATIS时。N+1问题发生在当我们执行一系列单独的SQL查询来获取关联数据,而不是一次性加载所有所需数据。这可能...
5. 结果集映射:对于查询结果,Ibatis 支持自动将数据库查询结果转换为Java对象。这可以通过配置结果映射来实现,包括一对一、一对多、多对多等各种复杂关系的映射。 6. 动态SQL:Ibatis 的动态SQL功能允许我们在...
- SqlSession:执行SQL语句的接口,非线程安全,每次数据库操作都需要创建新的实例。 - Mapper接口/Mapper XML文件:定义SQL语句和结果映射,是业务逻辑与数据访问层的桥梁。 3. Ibatis的优势: - 易于使用:SQL...
- **JCS (Java Caching System)**:是一种服务端缓存解决方案,将数据存储在服务器的内存或硬盘中,用户可以直接从服务器获取数据,避免了每次访问都需要查询数据库的情况。虽然这可能增加服务器的负载,但对于提高...
10. **持续集成**:将自定义的Ibatis生成器集成到持续集成流程中,确保每次代码更新后,相关的Java类和配置文件都能自动更新,保持与数据库结构同步。 博客链接提供的内容可能涉及如何创建和使用自定义的Ibatis生成...
5. **缓存机制**:Ibatis内置了第一级缓存和第二级缓存,提高数据访问效率。开发者也可以自定义缓存策略。 6. **接口编程**:Ibatis采用接口编程,与Spring等框架集成方便,使得业务逻辑代码更加清晰。 **Ibatis ...