2012-05-07 16 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. Mybatisを使用してOracleでクエリが実行されるたびに、自動的に開始されるトランザクションのコンテキスト内にあり、 がコミットされます(または実行がロールバックされる場合はロールバックされます)。 Mybatisによって閉じられます。アプリケーションのログ
  3. は良いアイデアだったし、実際の取引は、など

開始されている方法を見つけるために私を助けました。

2

アドバイスread-onlyはアドバイスのみです。 read-onlyとマークされているときに、基本的なトランザクション管理システムが書き込みを防止する必要はなく、このメソッドは読み取り専用であるため、変更を心配する必要はありません。一部のトランザクション管理者は、変更が読取り専用トランザクションで行われた場合には不平を言いますが、一部ではそうではありません。一般に、datasourceはJNDI経由で取得されません。いずれにしても、変更がディスクに書き戻されないようにするには、read-onlyアドバイスに頼るべきではありません。

持続されることから、変更を防止するためにあなたのオプションは以下のとおりです。

  • マーク取引rollback onlyまたは同じ効果

  • デタッチ/あなた変更する前に、トランザクションセッションからオブジェクトを立ち退かを持つ例外をスローそれ

  • オブジェクトをクローンしてクローンを使用する

+0

お返事ありがとうございました。私は私のrollback-for属性で見ることができるようにオプション1を試してみました。しかし、私はまだアドバイスであるだけの読み取り専用属性について100%確信していません。 読み取り専用ステータス:読み取り専用トランザクションはデータを変更しないことを明確に示しています。読取り専用トランザクションは、場合によっては(Hibernateを使用する場合など)、有益な最適化となります。 Achow

+0

追加するには、2&3についてはどうすればよいですか?私は更新プログラムを実行し、別のセッションに反映された結果を表示したくありません。 – Achow

1

DataSourceTransactionManagerdoBeginメソッドでトランザクションを開始します。
このメソッドから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ではdbレベル例外を取得していました。

私は、Oracleでのコミットを防止するために、apiまたはexceptionによる明示的なロールバック以外の方法は知りません。また、この方法で、異なるドライバとデータベース間でコードを移植することができます。

関連する問題