签名:love聊网络那点事:http://weibo.com/u/3923942488
1:内存溢出和id自增长测试测试代码如下
save方法执行之后但是没commit之前id也是在自动增加的:说明save访问了数据库并修改了id的值。
<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="300"
overflowToDisk="true"
/>
<!--1:缓存可以存储的总记录量
2:缓存是否永远不销毁
3:当缓存闲置时间超过改时间时自动销毁缓存
4:缓存的存活时间
(如果3,4都设置了实际超时时间是3,4中的最小时间)
5:当缓存中的数据达到最大值时,是否把缓存数据写入磁盘
-->
<cache name="sampleCache1"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="300"
overflowToDisk="true"
/>
</ehcache>
public void testUser(){
long startTime = System.currentTimeMillis();
//加载配置,构造sessionFactory对象
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
//获取会话
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
for(int i = 2000;i < 150000;i ++){
User user = new User();
user.setEmail("aa" + i);
user.setUserIntegral(i);
user.setPassword("a" + i);
session.save(user);
System.out.println("===");
System.out.println(user.getId());
System.out.println("++");
//没有clear当到达120000左右时会出现内存溢出导出插入失败但是数据库中的id却一直在涨,这个暂时没弄明白是怎么回事。
// if(i % 200 == 0){
// session.flush();
// session.clear();
// }
}
transaction.commit();
session.close();
long endTime = System.currentTimeMillis();
System.out.println(endTime - startTime);
}
当在循环过程中通过mysql工具往数据插入数据时id是在增长的,说明save虽然没有将数据插入到数据库中,但是访问过数据库,并修改了id的值。
当commit时数据真正的插入到数据库中了。
2:二级缓存的测试
测试代码如下
//通过将User.hbm.xml中加上和移除 <cache usage="read-only" region="sampleCache1"/>来测试二级缓存的作用
//移除后打印两条查询语句,加上后只有一条查询语句
@Ignore
@Test
public void testTran(){
//加载配置,构造sessionFactory对象
SessionFactory sessionFactory2 = new Configuration().configure().buildSessionFactory();
//获取会话
Session session2 = sessionFactory2.openSession();
User user = (User) session2.load(User.class, 2);
System.out.println(user.getNickname());
//从session缓存即一级缓存中移除user对象
session2.evict(user);
//测试二级缓存超时:超时打印两条sql语句,缩短时间不超时打印一条sql语句,不从session缓存中移除的话超时不超时都打印一条sql语句。
try {
Thread.sleep(120000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("================");
User user2 = (User) session2.load(User.class, 2);
System.out.println(user2.getNickname());
session2.close();
}
encache.xml配置如下
<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="300"
overflowToDisk="true"
/>
<!--1:缓存可以存储的总记录量
2:缓存是否永远不销毁
3:当缓存闲置时间超过改时间时自动销毁缓存
4:缓存的存活时间
(如果3,4都设置了实际超时时间是3,4中的最小时间)
5:当缓存中的数据达到最大值时,是否把缓存数据写入磁盘
-->
<cache name="sampleCache1"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="300"
overflowToDisk="true"
/>
</ehcache>
3.二级缓存并发测试
测试代码:
//不同的线程查询不能使用encache缓存,即不同的线程间encache是无效的。
// @Ignore
@Test
public void test33() throws InterruptedException{
//加上这两句则只执行一次查询否则执行四次查询
User user = (User) session.load(User.class, 2);
System.out.println(user.getNickname());
Thread[] t = new Thread[4];
for(int i = 0;i < t.length; i ++){
t[i] = new Thread(new Runnable() {
public void run() {
search();
}
});
}
for(int i = 0;i < t.length;i ++){
t[i].start();
}
Thread.sleep(8000);
session.close();
}
4:二级缓存更新读取测试:还没有搞清楚 希望高人指点
<cache usage="read-only" region="sampleCache1"/>
修改usage模式也更新失败。java.lang.UnsupportedOperationException: Can't write to a readonly object
测试代码:
@Test
public void test2(){
//加载配置,构造sessionFactory对象
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
//获取会话
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
//二级缓存中缓存了这两个对象
User user1 = (User) session.load(User.class, 2);
User user2 = (User) session.load(User.class, 3);
System.out.println("==============================");
//修改了user2
//load是延迟加载org.hibernate.LazyInitializationException: could not initialize proxy - no Session
//所以需要下面两句输出语句
System.out.println(user1.getEmail());
System.out.println("ddddd:::::" + user2.getEmail());
System.out.println("++++++++++++++");
//将这两个对象从session缓存中清楚避免影响测试
session.evict(user1);
session.evict(user2);
//如果注释掉这两行即可以修改,也就是session缓存是支持修改的。因为session缓存供同一使用者用,而二级缓存是供所有人使用。
user1.setEmailVerify(true);
session.update(user1);
transaction.commit();// java.lang.UnsupportedOperationException: Can't write to a readonly object
// //测试user3也就是user1是否从二级缓存中移除是否在二级缓存中
User user3 = (User) session.load(User.class, 2);
//将user3从session缓存中移除
System.out.println(user3.getEmail() + " user3");
//测试user4也就是user2是否从二级缓存中移除
User user4 = (User) session.load(User.class, 3);
System.out.println(user4.getEmail() + "user4");
session.close();
}
测试结果:二级缓存期间更新失败
log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment).log4j:WARN Please initialize the log4j system properly.
==============================
Hibernate:
select
user0_.id as id112_0_,
user0_.email as email112_0_,
user0_.nickname as nickname112_0_,
user0_.password as password112_0_,
user0_.user_integral as user5_112_0_,
user0_.is_email_verify as is6_112_0_,
user0_.email_verify_code as email7_112_0_,
user0_.last_login_time as last8_112_0_,
user0_.last_login_ip as last9_112_0_
from
dangdang.d_user user0_
where
user0_.id=?
chenhaixin2163@163.com
Hibernate:
select
user0_.id as id112_0_,
user0_.email as email112_0_,
user0_.nickname as nickname112_0_,
user0_.password as password112_0_,
user0_.user_integral as user5_112_0_,
user0_.is_email_verify as is6_112_0_,
user0_.email_verify_code as email7_112_0_,
user0_.last_login_time as last8_112_0_,
user0_.last_login_ip as last9_112_0_
from
dangdang.d_user user0_
where
user0_.id=?
ddddd:::::ddadddd
++++++++++++++
资料整理:
1:在read-write模式下:
我们有一个Order对象,是一个实体对象,对应数据库中order表中的一条记录,经过查询已有n个Order对象被放入二级缓存中。现在我们要修改order表中任意任x条记录,执行以下HQL:
template.bulkUpdate("update Order set owner = ? where id in (?,?,?)");
这时Hibernate会直接将二级缓存中的n个Order对象清除掉。 天啊,居然不是你想像的修改谁就同步更新二级缓存中的谁,而是清除了二级缓存中全部的Order类型的对象。为什么?这一切是为了保证“数据一致性”。你执行了HQL修改了order表中的x条记录,这x条是哪几条?如果sql是子查询:update Order set owner =? where id in(select id from *** ),谁知道你修改了order表中的哪几条记录,你自己都不知道,Hibernate更不知道了。所以为了保证二级缓存中的数据与order表中的数据一致,只能清除了二级缓存中全部的Order类型的对象。二级缓存频繁的载入与清除,这样缓存命中率就会下降。