2013-02-28 3 views
5

Я пытаюсь реализовать это руководство по декларативной транзакции в приложении Spring Framework, но не работает, потому что когда я пытаюсь выполнить команду MainApp класса, чтобы проверить поведение приложения я получаю сообщение об ошибке:

http://www.tutorialspoint.com/spring/declarative_management.htm

Так я имею интерфейс StudentDAO в Wich я только определить метод CRUD, что я хочу:

package org.andrea.myexample.myDeclarativeTransactionSpring; 

import java.util.List; 

import javax.sql.DataSource; 

/** Interfaccia che definisce i metodi che implementano le operazioni di CRUD 
* che vogliamo implementare nel nostro DAO: 
*/ 
public interface StudentDAO { 

    /** 
    * Questo metodo viene usato per inizializzare le risorse del database cioè 
    * la connessione al database: 
    */ 
    public void setDataSource(DataSource ds); 

    /** 
    * Questo metodo serve a creare un record nella tabella Student e nella 
    * tabella Marks: 
    */ 
    public void create(String name, Integer age, Integer marks, Integer year); 

    /** 
    * Questo metodo serve ad elencare tutti i record all'interno della tabella 
    * Studend e della tabella Marks 
    */ 
    public List<StudentMarks> listStudents(); 
} 

Тогда я StudentMark класса, rappresent моей сущности сохраняться на 2 таблицы в базе данных:

package org.andrea.myexample.myDeclarativeTransactionSpring; 

// Rappresenta l'entity: 
public class StudentMarks { 

    // Proprietà: 
    private Integer age; 
    private String name; 
    private Integer id; 
    private Integer marks; 
    private Integer year; 
    private Integer sid; 

    // Metodi Getter & Setter: 
    public void setAge(Integer age) { 
     this.age = age; 
    } 

    public Integer getAge() { 
     return age; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public String getName() { 
     return name; 
    } 

    public void setId(Integer id) { 
     this.id = id; 
    } 

    public Integer getId() { 
     return id; 
    } 

    public void setMarks(Integer marks) { 
     this.marks = marks; 
    } 

    public Integer getMarks() { 
     return marks; 
    } 

    public void setYear(Integer year) { 
     this.year = year; 
    } 

    public Integer getYear() { 
     return year; 
    } 

    public void setSid(Integer sid) { 
     this.sid = sid; 
    } 

    public Integer getSid() { 
     return sid; 
    } 
} 

Тогда у меня есть класс StudentMarksMapper, которые реализуют интерфейса RowMapper:

package org.andrea.myexample.myDeclarativeTransactionSpring; 

import java.sql.ResultSet; 
import java.sql.SQLException; 
import org.springframework.jdbc.core.RowMapper; 


/** Classe che implementa l'interfaccia RowMapper. Si tratta di un'interfaccia 
* usata da JdbcTemplate per mappare le righe di un ResultSet (oggetto che 
* contiene l'insieme delle righe restituite da una query SQL) riga per riga. 
* Le implementazioni di questa interfaccia mappano ogni riga su di un oggetto 
* risultante senza doversi preoccupare della gestione delle eccezioni poichè 
* le SQLException saranno catturate e gestite dalla chiamata a JdbcTemplate. 
*/ 
public class StudentMarksMapper implements RowMapper<StudentMarks> { 

    /** Implementazione del metodo dell'interfaccia RowMapper che mappa una 
    * specifica riga della tabella su di un oggetto Student 
    * 
    * @param Un oggetto ResultSet contenente l'insieme di tutte le righe 
    *   restituite dalla query 
    * 
    * @param L'indice che indentifica una specifica riga 
    * 
    * @return Un nuovo oggetto Student rappresentante la riga selezionata 
    *   all'interno dell'oggetto ResultSet 
    * 
    * @see org.springframework.jdbc.core.RowMapper#mapRow(java.sql.ResultSet, int) 
    */ 
    public StudentMarks mapRow(ResultSet rs, int rowNum) throws SQLException { 

     StudentMarks studentMarks = new StudentMarks(); 

     studentMarks.setId(rs.getInt("id")); 
     studentMarks.setName(rs.getString("name")); 
     studentMarks.setAge(rs.getInt("age")); 
     studentMarks.setSid(rs.getInt("sid")); 
     studentMarks.setMarks(rs.getInt("marks")); 
     studentMarks.setYear(rs.getInt("year")); 

     return studentMarks; 
    } 
} 

Рядом с ним thi s является StudentJDBCTemplate класс, интерфейс StudentDAO:

package org.andrea.myexample.myDeclarativeTransactionSpring; 

import java.util.List; 
import javax.sql.DataSource; 
import org.springframework.dao.DataAccessException; 
import org.springframework.jdbc.core.JdbcTemplate; 

/** 
* Classe che fornisce l'implementazione per il nostro DAO le cui funzionalità 
* di CRUD sono state definite tramite l'interfaccia StudentDAO 
*/ 
public class StudentJDBCTemplate implements StudentDAO { 

    // Utility per l'accesso alla sorgente dati 
    private JdbcTemplate jdbcTemplateObject; 

    /** 
    * Metodo Setter per l'Injection della dipendenza relativa alla sorgente 
    * dati. Tale metodo inoltre costruisce anche l'oggetto istanza di 
    * JdbcTemplate usato per interagire con i dati nel database. 
    * 
    * @param la sorgente dati 
    */ 
    public void setDataSource(DataSource dataSource) { 
     this.jdbcTemplateObject = new JdbcTemplate(dataSource); 
    } 

    /** 
    * Metodo relativo all'operazione di CREATE che inserisce un nuovo record 
    * all'interno della tabella Student ed un correlato nuovo record nella 
    * tabella Marks. 
    */ 
    public void create(String name, Integer age, Integer marks, Integer year) { 

     try { 
      // Query che inserisce nome ed età nella tabella Student: 
      String SQL1 = "insert into Student (name, age) values (?, ?)"; 
      // Esegue la query passandogli anche i valori effettivi da inserire: 
      jdbcTemplateObject.update(SQL1, name, age); 

      // Seleziona l'ultimo studente inserito nella tabella Marks: 
      String SQL2 = "select max(id) from Student"; 
      // Esegue la query e mette il risultato (l'ID) in sid: 
      int sid = jdbcTemplateObject.queryForInt(SQL2); 

      /** 
      * Query che inserisce un nuovo record nella tabella Marks. Il 
      * record rappresenta il voto per l'ultimo studente inserito nella 
      * tabella Student: 
      */ 
      String SQL3 = "insert into Marks(sid, marks, year) " 
        + "values (?, ?, ?)"; 
      // Esegue la query passandogli anche i valori effettivi da inserire: 
      jdbcTemplateObject.update(SQL3, sid, marks, year); 

      System.out.println("Created Name = " + name + ", Age = " + age); 

      // SIMULA UNA RuntimeExceptio: 
      throw new RuntimeException("Simulazione di una condizione d'errore"); 
     } catch (DataAccessException e) {  // GESTIONE DELL'ECCEZIONE 
      System.out.println("Errore nella creazione dei record, esegue rollback"); 
      throw e; 
     } 
    } 

    /** 
    * Metodo relativo all'operazione di READ che recupera la lista degli 
    * studenti e dei relativi voti 
    * 
    * @return La lista di oggetti che rappresentano uno studente ed i suoi voti 
    *   correlati 
    */ 
    public List<StudentMarks> listStudents() { 

     /** 
     * Query che estrae la lista di tutti i record nella tabella Student e 
     * che per ogni record in tale tabella estrae i relativi record 
     * correlati nella tabella Marks 
     */ 
     String SQL = "select * from Student, Marks where Student.id=Marks.sid"; 

     /** 
     * Ottengo la lista degli oggetti StudentMarks, corrispondenti ognuno ad 
     * un record della tabella Student con i correlati vori rappresentati 
     * dai record della tabella Marks, invocando il metodo query 
     * sull'oggetto JdbcTemplate passandogli i seguenti parametri. 
     * 
     * @param La query per creare il preparated statement 
     * @param Un oggetto che implementa RowMapper che viene usato per 
     *  mappare una singola riga della tabella su di un oggetto Java 
     */ 
     List<StudentMarks> studentMarks = jdbcTemplateObject.query(SQL, 
                new StudentMarksMapper()); 
     return studentMarks; 
    } 
} 

Тогда это MainApp класс для тестирования приложения:

package org.andrea.myexample.myDeclarativeTransactionSpring; 

import java.util.List; 
import org.springframework.context.ApplicationContext; 
import org.springframework.context.support.ClassPathXmlApplicationContext; 

// Classe principale: 
public class MainApp { 

    public static void main(String[] args) { 

     /** 
     * Crea il contesto in base alle impostazioni dell'applicazione definite 
     * nel file Beans.xml 
     */ 
     ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml"); 

     /** 
     * Recupera un bean avente id="studentJDBCTemplate" nel file di 
     * configurazione Beans.xml 
     */ 
     StudentJDBCTemplate studentJDBCTemplate = (StudentJDBCTemplate) context.getBean("studentJDBCTemplate"); 

     System.out.println("------Creazione dei record--------"); 
     // Creo i record nelle tabelle Studend e Marks: 
     studentJDBCTemplate.create("Zara", 11, 99, 2010); 
     studentJDBCTemplate.create("Nuha", 20, 97, 2010); 
     studentJDBCTemplate.create("Ayan", 25, 100, 2011); 

     System.out.println("------Elenca tutti i record--------"); 
     // Recupera la lista degli studenti con i voti ad essi associati: 
     List<StudentMarks> studentMarks = studentJDBCTemplate.listStudents(); 

     for (StudentMarks record : studentMarks) {  // e li stampa 
      System.out.print("ID : " + record.getId()); 
      System.out.print(", Name : " + record.getName()); 
      System.out.print(", Marks : " + record.getMarks()); 
      System.out.print(", Year : " + record.getYear()); 
      System.out.println(", Age : " + record.getAge()); 
     } 
    } 
} 

Finnally это мой beans.xml файл конфигурации:

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

    <!-- Initializazione della sorgente dati: --> 
    <bean id="dataSource" 
     class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
     <property name="driverClassName" value="com.mysql.jdbc.Driver" /> 
     <property name="url" value="jdbc:mysql://localhost:3306/SpringTestDb" /> 
     <property name="username" value="root" /> 
     <property name="password" value="aprile12" /> 
    </bean> 

    <tx:advice id="txAdvice" transaction-manager="transactionManager"> 
     <tx:attributes> 
      <tx:method name="create" /> 
     </tx:attributes> 
    </tx:advice> 

    <aop:config> 
     <aop:pointcut id="createOperation" 
      expression="execution(* org.andrea.myexample.myDeclarativeTransactionSpring.StudentJDBCTemplate.create(..))" /> 
     <aop:advisor advice-ref="txAdvice" pointcut-ref="createOperation" /> 
    </aop:config> 

    <!-- Inizializzazione del Transaction Manager: --> 
    <bean id="transactionManager" 
     class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
     <property name="dataSource" ref="dataSource" /> 
    </bean> 

    <!-- Definizione del bean che rappresenta il DAO studentJDBCTemplate: --> 
    <bean id="studentJDBCTemplate" class="org.andrea.myexample.myDeclarativeTransactionSpring.StudentJDBCTemplate"> 
     <property name="dataSource" ref="dataSource" /> 
    </bean> 

</beans> 

prrob Лем в том, что, когда я пытаюсь запустить мой MainApp класса я получаю следующее messate об ошибке:

INFO: Loaded JDBC driver: com.mysql.jdbc.Driver 
Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to org.andrea.myexample.myDeclarativeTransactionSpring.StudentJDBCTemplate 
    at org.andrea.myexample.myDeclarativeTransactionSpring.MainApp.main(MainApp.java:22) 

В этом сообщении об ошибке сказать, что проблема находится на линии 22 класса MainApp ... это просто, когда Я пытаюсь получить bean с идентификатором = "studentJDBCTemplate:

StudentJDBCTemplate studentJDBCTemplate = (StudentJDBCTemplate) context.getBean("studentJDBCTemplate"); 

Где проблема? Как я могу решить?

Tnx

Andrea

+3

Я не очень свеж на прокси-серверах Spring, но я думаю, что прокси-сервер будет реализовывать интерфейс 'StudentDAO', а не расширять' StudentJDBCTemplate'. Поэтому, когда вы запрашиваете этот компонент, из «ApplciationContext», вы, вероятно, захотите отдать его на «StudentDAO». –

+0

@ nicholas.hauschild - Спасибо, это сработало. Интересно, почему он работает так, как он? +1 для подсказки, и я думаю, что это должен быть ответ –

ответ

10

Вариант 1, изменить конфигурацию, чтобы ввести операции на уровне интерфейса:

<aop:config> 
    <aop:pointcut id="createOperation" 
     expression="execution(* org.andrea.myexample.myDeclarativeTransactionSpring.StudentDAO.create(..))" /> 
    <aop:advisor advice-ref="txAdvice" pointcut-ref="createOperation" /> 
</aop:config> 

и получить боб как экземпляр этого интерфейса:

StudentDAO studentDao = (StudentDAO) context.getBean("studentJDBCTemplate"); 

Вариант 2 указывает, что прокси-сервер должен распространять целевые группы с с помощью proxy-target-class атрибута:

<aop:config proxy-target-class="true"> 
    ... 
</aop:config> 

Первый вариант является уборщик один, но, честно говоря, я бы предпочел использовать @Transactional аннотаций, а не деклараций АОП в Spring боба XML. Иногда бывает сложно получить последнее правильно, и если у вас нет конкретных тестов на транзакцию на ваших компонентах, вы будете не обязательно заметить, что что-то неверно.

+0

нормально, теперь он работает ... – AndreaNobili

2

Вы должны использовать тип интерфейса в выражении АОП Pointcut т.е. в следующей строке: -

expression="execution(* org.andrea.myexample.myDeclarativeTransactionSpring.StudentJDBCTemplate.create(..))" /> 

использовать следующий код: -

expression="execution(* org.andrea.myexample.myDeclarativeTransactionSpring.StudentDAO.create(..))" /> 

Spring поддерживает AOP через прокси, который имеет два типа Интерфейс (Proxy реализует все интерфейсы, реализованные целевым классом) и Class based (достигается путем подклассификации целевого класса).

2

Я смог выполнить без изменения <aop:config>, просто получив экземпляр bean из интерфейса StudentDAO.

<aop:config> 
     <aop:pointcut id="createOperation" 
     expression="execution(* com.tutorialspoint.StudentJDBCTemplate.create(..))"/> 
     <aop:advisor advice-ref="txAdvice" pointcut-ref="createOperation"/> 
</aop:config> 

StudentDAO studentJDBCTemplate = (StudentDAO)context.getBean("studentJDBCTemplate"); 
Смежные вопросы