복붙노트

[SPRING] 메소드에서 Spring @ Transactional 어노테이션에 대한 설명

SPRING

메소드에서 Spring @ Transactional 어노테이션에 대한 설명

Spring 세상에서 나는 아주 새롭고 Spring 3.2.1과 Hibernate 4.1.9를 사용하여 DAO를 구현하는 간단한 프로젝트를 개발했다. 이 프로젝트는 올바르게 작동하지만이 DAO의 CRUD 메소드에서 @Transactional Spring annotation을 사용하는 데는 의문의 여지가 있습니다.

이것은 내 프로젝트의 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 annotaion을 사용하여 정의 된 트랜잭션이 읽기 / 쓰기 뿐이 아니라 읽음을 이해한다는 점에서 의심의 여지가 있습니다 ... 또한 (readOnly = false) 특성을 삭제하고 여전히 잘 작동하도록 시도했습니다 (데이터베이스 테이블에 새 레코드를 삽입하십시오)

다음과 같은 dout입니다 : "@Transactional 주석과 일부 다른 메소드를 사용하여 일부 메소드를 주석 처리하는 이유는 무엇입니까?" "모든 CRUD 메소드를 주석 처리하는 것이 좋은 방법입니까?"

Txx

안드레아

해결법

  1. ==============================

    1.우선, DAO 메소드를 트랜잭션이 아닌 서비스 메소드로 설정해야합니다.

    우선, DAO 메소드를 트랜잭션이 아닌 서비스 메소드로 설정해야합니다.

    둘째, Transactional을 사용하면 Spring이 트랜잭션을 시작하고 커밋 / 롤백 할 수있게 해준다. 따라서 거래를 직접 시작하고 커밋해서는 안됩니다.

    셋째, Hibernate 세션과 트랜잭션 (일반적으로 HibernateTransactionManager)을 연관시키는 방법을 알고있는 트랜잭션 관리자를 사용하는 경우에만 작동합니다. 세션 팩토리는 Spring에 의해 처리되고 DAO에 Spring에 의해 주입되어야한다. DAO 코드는 다음과 같아야합니다.

    넷째, 새로운 세션을 열지 말고, 현재 세션을 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);
        }
    }
    

    자세한 내용은 설명서를 참조하십시오.

  2. ==============================

    2.@Transactional이 메소드에서 사용됩니다.

    @Transactional이 메소드에서 사용됩니다.

    메소드 레벨에서 먼저 트랜잭션을 열고, 조작을 수행하고 트랜잭션을 닫는다.

    작업이 실패하면 롤백되고, 작업이 성공하면 자동으로 커밋됩니다.

    이것은 @Transactional annotation에 관한 것입니다.

    <?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. from https://stackoverflow.com/questions/15300483/some-clarification-about-spring-transactional-annotation-on-a-method by cc-by-sa and MIT license