2012-05-07 78 views
2

我目前正在开发一个Spring MVC应用程序。我配置了一个JDBC TransactionManager,并且正在使用AOP XML进行声明式事务管理。但是,即使将该方法配置为以只读= true运行,它仍然提交事务。Spring MVC JDBC DataSourceTransactionManager:甚至在readonly = true之后提交的数据

数据库:Oracle 10g的

我的数据库-config.xml中

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation=" 
http://www.springframework.org/schema/beans 
http://www.springframework.org/schem...ring-beans.xsd 
http://www.springframework.org/schema/tx 
http://www.springframework.org/schema/tx/spring-tx.xsd 
http://www.springframework.org/schema/aop 
http://www.springframework.org/schema/aop/spring-aop.xsd"> 


    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" 
     destroy-method="close"> 
     <property name="driverClassName" value="${driver}" /> 
     <property name="url" value="${url}" /> 
     <property name="username" value="${username}" /> 
     <property name="password" value="${password}" /> 
     <property name="defaultAutoCommit" value="false" /> 
    </bean> 

    <bean id="txManager" 
     class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
     <property name="dataSource" ref="dataSource" /> 
    </bean> 

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 
     <property name="dataSource" ref="dataSource" /> 
     <property name="mapperLocations" value="classpath:com/mybatis/mappers/*.xml" /> 
    </bean> 


    <!-- 
     the transactional advice (what 'happens'; see the <aop:advisor/> bean 
     below) 
    --> 
    <tx:advice id="txAdvice" transaction-manager="txManager"> 
     <!-- the transactional semantics... --> 
     <tx:attributes> 
      <!-- all methods starting with 'get' are read-only --> 
      <tx:method name="get*" read-only="true" /> 
      <!-- other methods use the default transaction settings (see below) --> 
      <tx:method name="*" read-only="true" rollback-for="RuntimeException"/> 
     </tx:attributes> 
    </tx:advice> 

    <!-- 
     ensure that the above transactional advice runs for any execution of 
     an operation defined by the FooService interface 
    --> 
    <aop:config> 
     <aop:pointcut id="fooServiceOperation" 
      expression="execution(* com.service.EmployeeService.*(..))" /> 
     <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation" /> 
    </aop:config> 


</beans> 

我控制器

package com.service; 

import java.util.List; 

import com.mybatis.dao.EmployeeMapperInterface; 
import com.spring.model.Employee; 

public class EmployeeService implements EmployeeBaseService{ 

    EmployeeMapperInterface employeeMapper; 

    public EmployeeMapperInterface getEmployeeMapper() { 
     return employeeMapper; 
    } 

    public void setEmployeeMapper(EmployeeMapperInterface employeeMapper) { 
     this.employeeMapper = employeeMapper; 
    } 

    @Override 
    public Employee getEmployeeById(long empId){ 
     //retrieve from database 
     List empList = employeeMapper.getEmployeeWithId(empId); 
     if(empList != null && empList.size()>0){ 
      return (Employee) empList.get(0); 
     } 
     return null; 

    } 




     @Override 
    public long saveEmployee(Employee employee){ 
     long empId = 0l; 
     if(employee.getEmpId()==0){ 
      empId = new Long(employeeMapper.insertEmployee(employee)); 
     }else{ 
      employeeMapper.updateEmployee(employee); 
      empId = employee.getEmpId(); 
     } 
     try { 
      System.out.println("gonna sleep"); 
      Thread.sleep(10); 

     } catch (InterruptedException e) { 

      e.printStackTrace(); 
     } 
     return empId; 
    } 

如何防止自动提交我也注意到即使我没有放置任何交易管理代码,代码仍然会提交。但是,事务建议是在我为RuntimeException放置一个no-rollback-for的情况下调用的,然后执行1/0,则它会正确提交数据并回滚,如果我将其设置为rollback-for。 我也尝试了将线程置于睡眠状态的查询超时,即使这不起作用,但我认为超时可能是针对实际查询的,所以这很好。 在此先感谢!

回答

0

答案是Spring MVC Mybatis transaction commit

详细的堆栈跟踪也可提供。 总之,

  1. 只读仅仅是一个建议,且保证什么,我会 真的很喜欢春天文档到这个更新。
  2. 无论何时在Oracle中使用Mybatis执行查询,它都在自动启动的事务上下文中提交(或回滚,如果引发了execption) ,并且由 Mybatis关闭。
  3. 登录该应用是一个好主意,它帮助我找出实际发生的交易是如何开始等

2

建议read-only只是建议。当某些东西被标记为read-only时,底层事务管理系统不会阻止写入,它的意思更多的是作为优化提示,并说这种方法是只读的,所以您不必担心它会改变事情。如果在只读事务中进行更改,则某些事务管理器会投诉,但有些不会。通常,通过JNDI获取的datasource不会。在任何情况下,您都不应该依赖read-only建议来防止将更改写回到磁盘。

你的,用于防止持续的变化选项:

  • 马克交易rollback only或抛出具有相同效果的

  • 拆离异常/驱逐出你改变之前的事务会话对象它

  • 克隆的对象,并使用克隆

+0

感谢老临的答案。我已经尝试过选项1,因为你可以看到我的回滚属性。但是,我仍然不能100%确定只读属性只是一个建议。通过http://static.springsource.org/spring/docs/2.5.x/reference/transaction.html,它明确指出只读状态:只读事务不会修改任何数据。在某些情况下,只读事务可以是有用的优化(例如使用Hibernate时)。 Achow

+0

要添加,我该如何去2&3?我想运行一个更新,而不是看到在另一个会话中反映的结果,即所有。 – Achow

1

DataSourceTransactionManager开始与doBegin交易方法。
从这个方法调用DataSourceUtils.prepareConnectionForTransaction
在此方法中,你可以看到下面的代码块:

if (definition != null && definition.isReadOnly()) { 
     try { 
      if (logger.isDebugEnabled()) { 
       logger.debug("Setting JDBC Connection [" + con + "] read-only"); 
      } 
      con.setReadOnly(true); 
     } 
     catch (SQLException ex) { 

所以,你可以配置你的日志框架设置日志级别到调试的DataSourceUtils类。

或者你可以在这个地方设置断点并手动调试。


根据这一article我希望SET TRANSACTION READ ONLY将您的Oracle连接上执行。


而且从Oracle docs我们可以看到,你在成功的情况下得到的好处:

默认情况下,用于Oracle的一致性模型保证语句级读一致性,但不保证事务级读取一致性(可重复读取)。如果您希望事务级读取一致性,并且您的事务不需要更新,那么您可以指定一个只读事务。在指出您的事务处于只读状态后,您可以针对任何数据库表执行尽可能多的查询,并知道只读事务中每个查询的结果与单个时间点一致。

+0

正是我期待的,那就是为什么它如此莫名其妙!如果我们做一个SET TRANSACTION READ ONLY,我们不能在同一个事务上做任何更新/插入,那么为什么它在这里允许? – Achow

+0

正如我在我的回答中写的 - 尝试调试。也许建议不起作用。 –

+0

不,建议正在工作,因为回滚和不回滚 - 工作得很好。 – Achow

1

只读行为严格限制驱动程序。 Oracle驱动程序完全忽略该标志。例如,如果在只读事务中运行,在Oracle中执行的相同更新语句将修改数据库,而在HSQL2中,我正在获取数据库级异常。

除了通过api或异常进行显式回滚以外,我不知道其他任何方式,以防止在Oracle中提交。这样你的代码也可以在不同的驱动程序和数据库之间移植。

相关问题