锁定老帖子 主题:只读查询是否需要启动事务管理,兼论只读事务
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2004-11-30
写了一个测试用例,预先把数据库里面age字段都改成25,断言一下是否是25,然后都改成21,再断言一下是否是21。如果不启动只读事务,那么飚红,如果启动只读事务,飚绿。
/* * Created on 2004-11-30 * */ package com.javaeye; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import junit.framework.TestCase; import org.springframework.beans.factory.BeanFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @author Robbin Fan * */ public class UserManagerTest extends TestCase { protected static BeanFactory beanFactory; protected static Connection conn = null; /* * @see TestCase#setUp() */ protected void setUp() throws Exception { Class.forName("com.mysql.jdbc.Driver").newInstance(); conn = DriverManager.getConnection("jdbc:mysql://localhost/hibernate","hibernate","hibernate"); conn.setAutoCommit(false); PreparedStatement pstmt = conn.prepareStatement("update test_user set age = ?"); pstmt.setInt(1,25); pstmt.executeUpdate(); pstmt.close(); conn.commit(); if (beanFactory == null) beanFactory = new ClassPathXmlApplicationContext("/applicationContext.xml"); } protected void changeAge(int age) throws Exception { conn.setAutoCommit(false); PreparedStatement pstmt = conn.prepareStatement("update test_user set age = ?"); pstmt.setInt(1,age); pstmt.executeUpdate(); pstmt.close(); conn.commit(); } /* * @see TestCase#tearDown() */ protected void tearDown() throws Exception { conn.close(); } public void testReadOnlyTransaction() throws Exception { UserManager userManager = (UserManager) beanFactory.getBean("userManager"); User user = null; user = (User) userManager.findUsers().get(0); assertEquals(25,user.getAge()); changeAge(21); user = (User) userManager.findUsers().get(0); assertEquals(21,user.getAge()); } } <?xml version="1.0"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean"> <property name="configLocation"> <value>classpath:hibernate.cfg.xml</value> </property> </bean> <bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager"> <property name="sessionFactory"> <ref local="sessionFactory"/> </property> </bean> <bean id="userManagerTarget" class="com.javaeye.impl.UserManagerHibernateImpl" autowire="byName"/> <bean id="userManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager"> <ref local="transactionManager"/> </property> <property name="target"> <ref local="userManagerTarget"/> </property> <property name="transactionAttributes"> <props> <prop key="*User">PROPAGATION_REQUIRED</prop> <prop key="findUsers">PROPAGATION_REQUIRED, readOnly</prop> <prop key="loadUserById">PROPAGATION_REQUIRED, readOnly</prop> </props> </property> </bean> </beans> |
|
返回顶楼 | |
发表时间:2004-11-30
引用 <prop key="findUsers">PROPAGATION_REQUIRED, readOnly</prop>
<prop key="loadUserById">PROPAGATION_REQUIRED, readOnly</prop> 这两行只要注释掉,就飚红 如果改成Oracle9i,则总是飚绿。问题似乎只在MySQL4.1上面出现。 |
|
返回顶楼 | |
发表时间:2004-11-30
听说mysql的驱动不管读什么都会把整个表一次读到内存里,也许不启动事务就刷新不到是因为这个缘故?
|
|
返回顶楼 | |
发表时间:2004-11-30
我个人觉得大概和InnoDB的运行方式有关。
|
|
返回顶楼 | |
发表时间:2004-11-30
把Spring Bean管理的UserManager的findUsers方法分别替换为JDBC实现,和直接使用Hibernate实现,测试结果统统飚绿,特别的,JDBC实现中,查询select之前,我还专门设置了 conn.setAutoCommit(false),来禁用事务。
似乎是Spring配合MySQL的InnoDB的一个bug。 目前的情况是: Spring+Hibernate+Oracle 正常 Hibernate +MySQLInnoDB 正常 JDBC + MySQL InnoDB 正常 Spring+Hibernate + MySQL InnoDB 不正常 |
|
返回顶楼 | |
发表时间:2004-11-30
老大, 偶今天辛辛苦苦地下载了MySql, 把环境换成和你一样, 结果是不能重现你的错误
OS Windows2K Pro Chinese Hibernate-2.1.7 Spring-1.1.2 MySQL-4.1.7 MySQL-JDBC-3.0.16GA 表类型InnoDB 偶是下载了你那个SimpleDemo, 然后改动了这些 把hibernate.properties里面改成: hibernate.hbm2ddl.auto create-drop 这样测试启动的时候能够自动清空数据. 然后把测试代码改成了往表里面先插一条测试数据: package com.javaeye; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import junit.framework.TestCase; import org.springframework.beans.factory.BeanFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; public class UserManagerTest extends TestCase { protected BeanFactory beanFactory; protected Connection conn = null; /* * @see TestCase#setUp(); */ protected void setUp(); throws Exception { beanFactory = new ClassPathXmlApplicationContext("/applicationContext.xml");; Class.forName("com.mysql.jdbc.Driver");.newInstance();; conn = DriverManager.getConnection("jdbc:mysql://localhost/hibernate", "hibernate", "hibernate");; initTestData();; } private void initTestData(); throws SQLException { conn.setAutoCommit(false);; PreparedStatement pstmt = conn.prepareStatement("insert into test_user (age); values (25);");; pstmt.executeUpdate();; pstmt.close();; conn.commit();; } protected void changeAge(int age); throws Exception { conn.setAutoCommit(false);; PreparedStatement pstmt = conn.prepareStatement("update test_user set age = ?");; pstmt.setInt(1, age);; pstmt.executeUpdate();; pstmt.close();; conn.commit();; } /* * @see TestCase#tearDown(); */ protected void tearDown(); throws Exception { conn.close();; } public void testReadOnlyTransaction(); throws Exception { UserManager userManager = (UserManager); beanFactory.getBean("userManager");; User user = null; user = (User); userManager.findUsers();.get(0);; assertEquals(25, user.getAge(););; changeAge(21);; user = (User); userManager.findUsers();.get(0);; assertEquals(21, user.getAge(););; } } 然后无论怎么修改spring的配置, 都是能够通过的...... btw, 偶以前都是用MySql 3.x, 今天下了一堆的4.x东东: mysql administrator, mysal control center, cool呆了, 比原来的界面, 功能做得友好多了. |
|
返回顶楼 | |
发表时间:2004-11-30
又用你的最初那个写得不怎么好的测试代码试了一下, 也是无论怎么改都无法重现你的错误......
|
|
返回顶楼 | |
发表时间:2004-11-30
http://forum.iteye.com/download/SimpleDemo.rar
我更新过了,你再下载测试一把看看,要注意MySQL的表类型必须为InnoDB。 BTW: MySQL Control Center已经停止开发了,这东西很难用的,MySQL Administrator是很不错,我调优MySQL就靠它了,至于MySQL的开发工具,官方网站提供的Control Center和MySQL Query Browser都烂得很,建议你去下载MySQL-Front,这才是最好的,或者Quest公司的TOAD MySQL版也不错。 |
|
返回顶楼 | |
发表时间:2004-11-30
好奇怪呀, 好奇怪, 偶下载你的代码以后, 确实是跑不通......
不过, 修改一下connection provider就OK了: hibernate.connection.provider_class net.sf.hibernate.connection.DBCPConnectionProvider 看起来是N个因素作用在里面, 偶的小脑袋是彻底迷糊了, 今天不搞了...... 明天写一个简化版的, 看看有没有错误, 再提交到spring那边去..... |
|
返回顶楼 | |
发表时间:2004-11-30
我换成了C3P0果然也好了,曾经怀疑过是DataSource的问题,不过当时没有去试了。Hibernate built-in的DataSource是一个非常简单的DataSource,我也没有发现有什么不对的地方,不知道为何在这种特定情况下出现这种特定的问题。
|
|
返回顶楼 | |