2

現在、Spring MVC アプリケーションを開発しています。JDBC TransactionManager を構成し、AOP XML を使用して宣言型トランザクション管理を行っています。ただし、読み取り専用 = true で実行するようにメソッドを構成しても、トランザクションはコミットされます。

データベース: オラクル 10g

私のdatabase-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 を実行すると、トランザクションのアドバイスが呼び出されることに注意してください。また、スレッドをスリープ状態にしてクエリのタイムアウトを試してみましたが、それでも機能しませんが、タイムアウトは実際のクエリの可能性があると考えているので、問題ありません。前もって感謝します!

4

4 に答える 4

2

アドバイスread-onlyはただのアドバイスです。基盤となるトランザクション管理システムが、何かがマークされたときに書き込みを防止するread-only必要はありません。これは、このメソッドが読み取り専用であるという最適化のヒントとしての意味があり、変更について心配する必要はありません。読み取り専用トランザクションに変更が加えられた場合、一部のトランザクションマネージャは文句を言いますが、そうでないものもあります。通常、datasourceJNDIを介して取得されたsはそうではありません。read-onlyいずれの場合も、変更がディスクに書き戻されないようにするアドバイス に頼るべきではありません。

変更が永続化されないようにするためのオプションは次のとおりです。

  • トランザクションをマークするrollback onlyか、同じ効果を持つ例外をスローします

  • オブジェクトを変更する前に、トランザクションセッションからオブジェクトをデタッチ/削除します

  • オブジェクトのクローンを作成し、クローンを使用します

于 2012-05-07T06:05:00.497 に答える
1

読み取り専用の動作は厳密にドライバー固有です。Oracle ドライバーは、このフラグを完全に無視します。たとえば、Oracle で実行された同じ更新ステートメントは、読み取り専用トランザクションで実行された場合にデータベースを変更しますが、HSQL2 では db レベルの例外が発生していました。

Oracleでのコミットを防ぐために、APIまたは例外を介した明示的なロールバック以外の方法はありません。また、このようにして、コードは異なるドライバーとデータベース間で移植可能になります。

于 2012-05-07T11:30:10.113 に答える
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そのため、ロギング フレームワークを設定して、クラスのログ レベルを DEBUG に設定できます。

または、この場所にブレークポイントを設定して手動でデバッグすることもできます。


この記事によると、それSET TRANSACTION READ ONLYはあなたの Oracle 接続で実行されると思います。


また、Oracle のドキュメントから、成功した場合に得られる利点を確認できます。

デフォルトでは、Oracle の整合性モデルはステートメント レベルの読み取りの一貫性を保証しますが、トランザクション レベルの読み取りの一貫性 (反復可能な読み取り) は保証しません。トランザクション レベルの読み取りの一貫性が必要で、トランザクションが更新を必要としない場合は、読み取り専用トランザクションを指定できます。トランザクションが読み取り専用であることを示した後、任意のデータベース テーブルに対して好きなだけクエリを実行できます。読み取り専用トランザクションの各クエリの結果は、特定の時点に関して一貫性があることがわかっています。

于 2012-05-07T06:18:15.977 に答える
0

答えはSpring MVC Mybatisト​​ランザクションコミットにあります

詳細なスタック トレースも利用できます。要約する、

  1. 読み取り専用は単なるアドバイスであり、何も保証するものではありません。Spring ドキュメントがこれについて更新されることを本当に望んでいます。
  2. Mybatis を使用して Oracle でクエリが実行されるときは常に、Mybatis によって自動的に開始、コミット (または実行が発生した場合はロールバック)、およびクローズされるトランザクションのコンテキスト内にあります。
  3. アプリケーションをログに記録することは良い考えであり、実際のトランザクションがどのように開始されるかなどを知るのに役立ちました

.

于 2012-05-08T04:10:06.800 に答える