web-dev-qa-db-ja.com

メソッドのSpring @Transactionalアノテーションに関するいくつかの明確化

私はSpringの世界ではまったく新しいので、Spring 3.2.1とHibernate 4.1.9を使用してDAOを実装する簡単なプロジェクトを開発しました。プロジェクトは正常に動作しますが、このDAOのCRUDメソッドでの@ TransactionalSpringアノテーションの使用については疑問があります。

これは、プロジェクトのCRUD操作を実装するクラスのコード全体です。

package org.andrea.myexample.HibernateOnSpring.dao;

import Java.util.List;

import org.andrea.myexample.HibernateOnSpring.entity.Person;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.springframework.transaction.annotation.Transactional;

public class PersonDAOImpl implements PersonDAO {

    // Factory per la creazione delle sessioni di Hibernate:
    private static SessionFactory sessionFactory;

    // Metodo Setter per l'iniezione della dipendenza della SessionFactory:
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    /** CREATE CRUD Operation:
     * Aggiunge un nuovo record rappresentato nella tabella rappresentato
     * da un oggetto Person
     */
    @Transactional(readOnly = false)
    public Integer addPerson(Person p) {

        System.out.println("Inside addPerson()");

        Session session = sessionFactory.openSession();

        Transaction tx = null;
        Integer personID = null;

        try {
            tx = session.beginTransaction();

            personID = (Integer) session.save(p);
            tx.commit();
        } catch (HibernateException e) {
            if (tx != null)
                tx.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }

        return personID;

    }

    // READ CRUD Operation (legge un singolo record avente uno specifico id):
    public Person getById(int id) {

        System.out.println("Inside getById()");

        Session session = sessionFactory.openSession();

        Transaction tx = null;          
        Person retrievedPerson = null;  

        try {
            tx = session.beginTransaction();
            retrievedPerson = (Person) session.get(Person.class, id);
            tx.commit();
        }catch (HibernateException e) { 
            if (tx != null)                 
                tx.rollback();          
            e.printStackTrace();
        } finally {                 
            session.close();
        }

        return retrievedPerson;
    }

    // READ CRUD Operation (recupera la lista di tutti i record nella tabella):
    @SuppressWarnings("unchecked")
    public List<Person> getPersonsList() {

        System.out.println("Inside getPersonsList()");

        Session session = sessionFactory.openSession();
        Transaction tx = null;
        List<Person> personList = null;

        try {
            tx = session.beginTransaction();
            Criteria criteria = session.createCriteria(Person.class);
            personList = criteria.list();
            System.out.println("personList: " + personList);
            tx.commit();
        }catch (HibernateException e) { 
            if (tx != null)                 
                tx.rollback();          
            e.printStackTrace();
        } finally {
            session.close();
        }
        return personList;
    }

    // DELETE CRUD Operation (elimina un singolo record avente uno specifico id):
    public void delete(int id) {

        System.out.println("Inside delete()");

        Session session = sessionFactory.openSession();
        Transaction tx = null;

        try {
            tx = session.beginTransaction();
            Person personToDelete = getById(id);
            session.delete(personToDelete);
            tx.commit();
        }catch (HibernateException e) { 
            if (tx != null)                 
                tx.rollback();          
            e.printStackTrace();
        } finally {
            session.close();
        }

    }

    @Transactional
    public void update(Person personToUpdate) {

        System.out.println("Inside update()");

        Session session = sessionFactory.openSession();
        Transaction tx = null;

        try {
            System.out.println("Insite update() method try");
            tx = session.beginTransaction();
            session.update(personToUpdate);

            tx.commit();
        }catch (HibernateException e) { 
            if (tx != null)                 
                tx.rollback();          
            e.printStackTrace();
        } finally {
            session.close();
        }   

    }

}

わかりましたように、@ Transactional注釈を使用していくつかのメソッドに注釈が付けられています。

私はここで公式ドキュメントを読んでいます http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/transaction.html 上のこのアノテーションの使用についてメソッドとそれを参照してください:@ Transactionalを使用して注釈を付けたメソッドは、トランザクションセマンティクスを持っている必要がありますが、トランザクションセマンティクスとはどういう意味ですか?

メトスの実行は、トランザクションの実行と見なされる必要があるということですか?したがって、メソッド操作は、成功または失敗につながる可能性のある単一の操作と見なされる必要があることを意味します。成功した場合、操作の結果は永続的である必要があります。トランザクションの開始。

これはメソッドの使用@ Transactionalアノテーションの意味ですか?

そして、addPerson()メソッドの@TransactionalアノテーションのreadOnly = false属性の正確な意味は何ですか?つまり、データベースにレコードを書き込むことができます(それを読み取るだけでなく)または何ですか?デフォルトでは、@ Transactionalアノテーションを使用して定義されたトランザクションはread/writeであり、読み取りだけではなく... (readOnly = false)属性であり、引き続き機能します(データベーステーブルに新しいレコードを挿入します)

「@Transactionalアノテーションを使用していくつかのメソッドに注釈を付け、他のメソッドには注釈を付けないのはなぜですか?@Transactionalを使用してALL CRUDメソッドに注釈を付けるのは良い方法ですか?」

Tnx

アンドレア

38
AndreaNobili

まず第一に、DAOメソッドをトランザクションではなく、サービスメソッドにする必要があります。

第二に、Transactionalを使用すると、Springがトランザクションを開始およびコミット/ロールバックできるようになります。したがって、トランザクションを自分で開始してコミットしないでください。

3番目:これは、Hibernateセッションをトランザクション(通常、HibernateTransactionManager)に関連付ける方法を知っているトランザクションマネージャーを使用する場合にのみ機能します。セッションファクトリもSpringによって処理され、DAOにSpringによって挿入される必要があります。 DAOのコードは次のようになります。

4番目:新しいセッションを開くべきではなく、Springによって現在のトランザクションに関連付けられている現在のセッションを取得する必要があります。

public class PersonDAOImpl implements PersonDAO {

    @Autowired
    private SessionFactory sessionFactory;

    public Integer addPerson(Person p) {
        Session session = sessionFactory.getCurrentSession();
        Integer personID = (Integer) session.save(p);
        return personID;
    }

    public Person getById(int id) {
        Session session = sessionFactory.getCurrentSession();
        Person retrievedPerson = (Person) session.get(Person.class, id);
        return retrievedPerson;
    }

    @SuppressWarnings("unchecked")
    public List<Person> getPersonsList() {
        Session session = sessionFactory.getCurrentSession();
        Criteria criteria = session.createCriteria(Person.class);
        return criteria.list();
    }

    public void delete(int id) {
        Session session = sessionFactory.getCurrentSession();
        Person personToDelete = getById(id);
        session.delete(personToDelete);
    }

    public void update(Person personToUpdate) {
        Session session = sessionFactory.getCurrentSession();
        session.update(personToUpdate);
    }
}

詳細については、 ドキュメント をお読みください。

71
JB Nizet

@Transactionalはメソッドで使用されます。

メソッドレベルで宣言し、最初にトランザクションを開き、操作を実行して、トランザクションを閉じます。

操作が失敗した場合はロールバックされ、操作が成功した場合は自動的にコミットされます

これは約@Transactionalアノテーション最終的に&ショート。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context" 
    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/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        ">

    <!-- Scans the classpath for annotated components that will be auto-registered as Spring beans -->
    <context:component-scan base-package="hu.daniel.hari.learn.spring" />
    <!-- Activates various annotations to be detected in bean classes e.g: @Autowired -->
    <context:annotation-config />


    <!-- creating the internal datasource object -->

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="org.hsqldb.jdbcDriver" />
        <property name="url" value="jdbc:hsqldb:mem://productDb" />
        <property name="username" value="sa" />
        <property name="password" value="" />
    </bean>

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
            p:packagesToScan="hu.daniel.hari.learn.spring.orm.model"
            p:dataSource-ref="dataSource"
            >
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="generateDdl" value="true" />
                <property name="showSql" value="true" />

            </bean>
        </property>
    </bean>

    <!-- Transactions -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
    <tx:annotation-driven transaction-manager="transactionManager" />

</beans>
package hu.daniel.hari.learn.spring.orm.main;

import hu.daniel.hari.learn.spring.orm.model.Product;
import hu.daniel.hari.learn.spring.orm.service.ProductService;

import Java.util.Arrays;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.dao.DataAccessException;

public class SpringOrmMain {

    public static void main(String[] args) {

        //Create Spring application context
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/spring.xml");

        //Get service from context. (service's dependency (ProductDAO) is autowired in ProductService)
        ProductService productService = ctx.getBean(ProductService.class);

        //Do some data operation

        productService.add(new Product(1, "Bulb"));
        productService.add(new Product(2, "Dijone mustard"));

        System.out.println("listAll: " + productService.listAll());

        //Test transaction rollback (duplicated key)

        try {
            productService.addAll(Arrays.asList(new Product(3, "Book"), new Product(4, "Soap"), new Product(1, "Computer")));
        } catch (DataAccessException dataAccessException) {
        }

        //Test element list after rollback
        System.out.println("listAll: " + productService.listAll());

        ctx.close();
    }
}
3