论坛首页 Java企业应用论坛

只读查询是否需要启动事务管理,兼论只读事务

浏览 30210 次
该帖已经被评为精华帖
作者 正文
   发表时间: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>
0 请登录后投票
   发表时间:2004-11-30  
引用
<prop key="findUsers">PROPAGATION_REQUIRED, readOnly</prop>       
<prop key="loadUserById">PROPAGATION_REQUIRED, readOnly</prop>


这两行只要注释掉,就飚红

如果改成Oracle9i,则总是飚绿。问题似乎只在MySQL4.1上面出现。
0 请登录后投票
   发表时间:2004-11-30  
听说mysql的驱动不管读什么都会把整个表一次读到内存里,也许不启动事务就刷新不到是因为这个缘故?
0 请登录后投票
   发表时间:2004-11-30  
我个人觉得大概和InnoDB的运行方式有关。
0 请登录后投票
   发表时间: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 不正常
0 请登录后投票
   发表时间: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呆了, 比原来的界面, 功能做得友好多了.
0 请登录后投票
   发表时间:2004-11-30  
又用你的最初那个写得不怎么好的测试代码试了一下, 也是无论怎么改都无法重现你的错误......
0 请登录后投票
   发表时间: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版也不错。
0 请登录后投票
   发表时间:2004-11-30  
好奇怪呀, 好奇怪, 偶下载你的代码以后, 确实是跑不通......

不过, 修改一下connection provider就OK了:

hibernate.connection.provider_class net.sf.hibernate.connection.DBCPConnectionProvider

看起来是N个因素作用在里面, 偶的小脑袋是彻底迷糊了, 今天不搞了......

明天写一个简化版的, 看看有没有错误, 再提交到spring那边去.....
0 请登录后投票
   发表时间:2004-11-30  
我换成了C3P0果然也好了,曾经怀疑过是DataSource的问题,不过当时没有去试了。Hibernate built-in的DataSource是一个非常简单的DataSource,我也没有发现有什么不对的地方,不知道为何在这种特定情况下出现这种特定的问题。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics