Spring管理的事务没有启动

时间:2016-11-12 08:15:50

标签: java spring spring-aop spring-transactions

应该由Spring管理的事务尚未启动。

我是Spring的新手,所以很有可能这是一个简单的问题需要解决,但我无法在互联网上找到任何可以指向正确方向的东西。

<?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:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-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
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="123" />

        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="showSql" value="true" />
            </bean>
        </property>
    </bean>

    <bean id="employeeDAO" class="com.lucas.jpalearning.EmployeeDAO" />
        <!--   <property name="entityManagerFactory" ref="entityManagerFactory" /> -->

    <bean id="employeeDAOFactoryInjector" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">

        <property name="targetObject" ref="employeeDAO" />
        <property name="targetMethod" value="setEntityManagerFactory" />
        <property name="arguments">
            <list>
                 <ref bean="entityManagerFactory"/>
            </list>
        </property>

    </bean>

    <tx:advice id="txEmployeeDAO" transaction-manager="txManager">

        <tx:attributes>

            <tx:method name="persist" propagation="REQUIRED"/>

        </tx:attributes>

    </tx:advice>

    <aop:config>
        <aop:pointcut id="employeePersistOperation" expression="execution(* com.lucas.jpalearning.EmployeeDAO.*(..))"/>
        <aop:advisor advice-ref="txEmployeeDAO" pointcut-ref="employeePersistOperation"/>
    </aop:config>

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="org.postgresql.Driver"/>
        <property name="url" value="jdbc:postgresql://localhost:5432/lucas"/>
        <property name="username" value="lucas"/>
        <property name="password" value="XXXXX"/>
    </bean>



    <context:component-scan base-package="com.lucas.jpalearning" />
    <tx:annotation-driven transaction-manager="txManager"/>

    <!-- similarly, don't forget the PlatformTransactionManager -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

</beans>

EmployeeDAO.java:

package com.lucas.jpalearning;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;


public class EmployeeDAO {

    private EntityManagerFactory entityManagerFactory;
    private EntityManager entityManager;

    public EmployeeDAO() {

    }

    //setters for EntityManagerFactory - will be injected by Spring
    public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {

        this.entityManagerFactory = entityManagerFactory;
        this.setEntityManager(this.entityManagerFactory.createEntityManager());

    }

    private EntityManagerFactory getEntityManagerFactory() {
        return entityManagerFactory;
    }

    private void setEntityManager(EntityManager entityManager) {

        this.entityManager = entityManager;

    }

    private EntityManager getEntityManager() {

        return this.entityManager;

    }

    public void persist(Employee employee) {

        this.getEntityManager().persist(employee);

        this.getEntityManager().flush();


    }

}

Main.java:

package com.lucas.jpalearning;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


public class App 
{

    @PersistenceContext
    private static EntityManager em;

    public static void main( String[] args )
    {
        System.out.println( "Hello World!" );

        //EntityManagerFactory emf = Persistence
        //        .createEntityManagerFactory("123");
        //em = emf.createEntityManager();

        ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath*:META-INF/spring/applicationContext.xml");
        EmployeeDAO employeeDAO = ctx.getBean("employeeDAO", EmployeeDAO.class);

        employeeDAO.persist(new Employee(1, "Ravi", "Raj", "Textile"));

        //createEmployee(1, "Ravi", "Raj", "Textile");
        //createEmployee(2, "Amit", "Raj", "IT");
        //createEmployee(3, "Nitish", "Kumar", "Marketing");
    }


}

的pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.lucas</groupId>
  <artifactId>jpalearning</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>jpalearning</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>

        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>3.8.1</version>
          <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>3.0.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>3.0.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.9-atlassian-1</version>
        </dependency>

        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.4-redhat-2</version>
        </dependency>

        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.2.4</version>
        </dependency>


        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>javax.persistence</artifactId>
            <version>2.0.0</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.0-api</artifactId>
            <version>1.0.1.Final</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>4.2.0.Final</version>
        </dependency>

       <dependency>
            <groupId>postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>9.4.1208-jdbc42-atlassian-hosted</version>
        </dependency>

  </dependencies>

  <repositories>

    <repository>
        <id>jBoss-releases-repository</id>
        <name>JBoss Releases Repository</name>
        <url>https://repository.jboss.org/nexus/content/repositories/releases/</url>
    </repository>

    <repository>
        <id>atlassian-3rd-party-repository</id>
        <name>Atlassian 3rd-Party Repository</name>
        <url>https://maven.atlassian.com/3rdparty/</url>
    </repository>

    <repository>
        <id>redhat-ga-repository</id>
        <name>Redhat GA Repository</name>
        <url>https://maven.repository.redhat.com/ga/</url>
    </repository>

  </repositories>

</project>

的persistence.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
             http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
    version="2.0">

    <persistence-unit name="123" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>

        <mapping-file>META-INF/jpa/orm.xml</mapping-file>

        <class>com.lucas.jpalearning.Employee</class>

        <properties>

            <!-- Java Database Connection Specific Properties -->

            <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" />
            <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/lucas" />
            <property name="javax.persistence.jdbc.username" value="lucas" />
            <property name="javax.persistence.jdbc.password" value="XXXX" />

            <!-- Hibernate Specific Properties -->
            <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
            <property name="hibernate.archive.autodetection" value="class" />
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.format_sql" value="true" />
            <property name="hibernate.hbm2ddl.auto" value="update" />

        </properties>
    </persistence-unit>
</persistence>

控制台输出:

Hello World!
Nov 12, 2016 5:56:13 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@306a30c7: startup date [Sat Nov 12 05:56:13 BRST 2016]; root of context hierarchy
Nov 12, 2016 5:56:13 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from URL [file:/home/lucas/workspace/jpalearning/target/classes/META-INF/spring/applicationContext.xml]
Nov 12, 2016 5:56:13 AM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@2ef5e5e3: defining beans [entityManagerFactory,employeeDAO,employeeDAOFactoryInjector,txEmployeeDAO,org.springframework.aop.config.internalAutoProxyCreator,employeePersistOperation,org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0,dataSource,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,txManager]; root of factory hierarchy
Nov 12, 2016 5:56:14 AM org.springframework.orm.jpa.LocalEntityManagerFactoryBean createNativeEntityManagerFactory
INFO: Building JPA EntityManagerFactory for persistence unit '123'
Nov 12, 2016 5:56:14 AM org.hibernate.annotations.common.Version <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {4.0.1.Final}
Nov 12, 2016 5:56:14 AM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core {4.2.0.Final}
Nov 12, 2016 5:56:14 AM org.hibernate.cfg.Environment <clinit>
INFO: HHH000206: hibernate.properties not found
Nov 12, 2016 5:56:14 AM org.hibernate.cfg.Environment buildBytecodeProvider
INFO: HHH000021: Bytecode provider name : javassist
Nov 12, 2016 5:56:14 AM org.hibernate.cfg.Configuration addResource
INFO: HHH000221: Reading mappings from resource: META-INF/jpa/orm.xml
Nov 12, 2016 5:56:14 AM org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
INFO: HHH000402: Using Hibernate built-in connection pool (not for production use!)
Nov 12, 2016 5:56:14 AM org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
INFO: HHH000115: Hibernate connection pool size: 20
Nov 12, 2016 5:56:14 AM org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
INFO: HHH000006: Autocommit mode: true
Nov 12, 2016 5:56:14 AM org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
INFO: HHH000401: using driver [org.postgresql.Driver] at URL [jdbc:postgresql://localhost:5432/lucas]
Nov 12, 2016 5:56:14 AM org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
INFO: HHH000046: Connection properties: {password=****, autocommit=true, release_mode=auto}
Nov 12, 2016 5:56:15 AM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.PostgreSQLDialect
Nov 12, 2016 5:56:15 AM org.hibernate.engine.jdbc.internal.LobCreatorBuilder useContextualLobCreation
INFO: HHH000424: Disabling contextual LOB creation as createClob() method threw error : java.lang.reflect.InvocationTargetException
Nov 12, 2016 5:56:15 AM org.hibernate.engine.transaction.internal.TransactionFactoryInitiator initiateService
INFO: HHH000268: Transaction strategy: org.hibernate.engine.transaction.internal.jdbc.JdbcTransactionFactory
Nov 12, 2016 5:56:15 AM org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory <init>
INFO: HHH000397: Using ASTQueryTranslatorFactory
Nov 12, 2016 5:56:15 AM org.hibernate.tool.hbm2ddl.SchemaUpdate execute
INFO: HHH000228: Running hbm2ddl schema update
Nov 12, 2016 5:56:15 AM org.hibernate.tool.hbm2ddl.SchemaUpdate execute
INFO: HHH000102: Fetching database metadata
Nov 12, 2016 5:56:15 AM org.hibernate.tool.hbm2ddl.SchemaUpdate execute
INFO: HHH000396: Updating schema
Nov 12, 2016 5:56:15 AM org.hibernate.tool.hbm2ddl.TableMetadata <init>
INFO: HHH000261: Table found: public.employee
Nov 12, 2016 5:56:15 AM org.hibernate.tool.hbm2ddl.TableMetadata <init>
INFO: HHH000037: Columns: [firstname, id, dept, lastname]
Nov 12, 2016 5:56:15 AM org.hibernate.tool.hbm2ddl.TableMetadata <init>
INFO: HHH000108: Foreign keys: []
Nov 12, 2016 5:56:15 AM org.hibernate.tool.hbm2ddl.TableMetadata <init>
INFO: HHH000126: Indexes: [employee_pkey]
Nov 12, 2016 5:56:15 AM org.hibernate.tool.hbm2ddl.SchemaUpdate execute
INFO: HHH000232: Schema update complete
Hibernate: 
    select
        nextval ('hibernate_sequence')
Exception in thread "main" javax.persistence.TransactionRequiredException: no transaction is in progress
    at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:993)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:365)
    at com.sun.proxy.$Proxy16.flush(Unknown Source)
    at com.lucas.jpalearning.EmployeeDAO.persist(EmployeeDAO.java:51)
    at com.lucas.jpalearning.EmployeeDAO$$FastClassByCGLIB$$26523180.invoke(<generated>)
    at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:692)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:625)
    at com.lucas.jpalearning.EmployeeDAO$$EnhancerByCGLIB$$93660a78.persist(<generated>)
    at com.lucas.jpalearning.App.main(App.java:29)

编辑:

在使用Spring的log4j之后,我注意到Spring正在启动事务,但是显然没有回滚它。

2016-11-15 02:14:09 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'employeeDAO'
2016-11-15 02:14:09 DEBUG DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'txManager'
2016-11-15 02:14:09 DEBUG JpaTransactionManager:367 - Creating new transaction with name [com.lucas.jpalearning.EmployeeDAO.persist]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2016-11-15 02:14:09 DEBUG JpaTransactionManager:371 - Opened new EntityManager [org.hibernate.ejb.EntityManagerImpl@611f8234] for JPA transaction
2016-11-15 02:14:09 DEBUG AbstractTransactionImpl:158 - begin
2016-11-15 02:14:09 DEBUG LogicalConnectionImpl:212 - Obtaining JDBC connection
2016-11-15 02:14:09 DEBUG LogicalConnectionImpl:218 - Obtained JDBC connection
2016-11-15 02:14:09 DEBUG JdbcTransaction:69 - initial autocommit status: true
2016-11-15 02:14:09 DEBUG JdbcTransaction:71 - disabling autocommit
2016-11-15 02:14:09 DEBUG SQL:104 - 
    select
        nextval ('hibernate_sequence')
Hibernate: 
    select
        nextval ('hibernate_sequence')
2016-11-15 02:14:09 DEBUG LogicalConnectionImpl:212 - Obtaining JDBC connection
2016-11-15 02:14:09 DEBUG DriverManagerConnectionProviderImpl:196 - Opening new JDBC connection
2016-11-15 02:14:09 DEBUG DriverManagerConnectionProviderImpl:219 - Created connection to: jdbc:postgresql://localhost:5432/lucas, Isolation Level: 2
2016-11-15 02:14:09 DEBUG LogicalConnectionImpl:218 - Obtained JDBC connection
2016-11-15 02:14:09 DEBUG SequenceGenerator:127 - Sequence identifier generated: BasicHolder[java.lang.Integer[60]]
2016-11-15 02:14:09 DEBUG AbstractSaveEventListener:130 - Generated identifier: 600, using strategy: org.hibernate.id.SequenceHiLoGenerator
2016-11-15 02:14:10 DEBUG JpaTransactionManager:851 - Initiating transaction rollback
2016-11-15 02:14:10 DEBUG JpaTransactionManager:538 - Rolling back JPA transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl@611f8234]
2016-11-15 02:14:10 DEBUG AbstractTransactionImpl:203 - rolling back
2016-11-15 02:14:10 DEBUG JdbcTransaction:164 - rolled JDBC Connection
2016-11-15 02:14:10 DEBUG JdbcTransaction:126 - re-enabling autocommit
2016-11-15 02:14:10 DEBUG JpaTransactionManager:600 - Closing JPA EntityManager [org.hibernate.ejb.EntityManagerImpl@611f8234] after transaction
2016-11-15 02:14:10 DEBUG EntityManagerFactoryUtils:435 - Closing JPA EntityManager
2016-11-15 02:14:10 DEBUG LogicalConnectionImpl:232 - Releasing JDBC connection
2016-11-15 02:14:10 DEBUG LogicalConnectionImpl:250 - Released JDBC connection
Exception in thread "main" javax.persistence.TransactionRequiredException: no transaction is in progress

2 个答案:

答案 0 :(得分:1)

需要进行一些更改。

applicationContext.xml:使用LocalContainerEntityManagerFactoryBean。我们想要使用数据源的原因(连接池化源)。删除employeeDAOFactoryInjector,因为我们可以通过使用@PersistenceContext注释来自动装配EntityManager,您也不应该手动创建实体管理器。还要将事务管理器类型更改为PlatformTransactionManager(原因:底部的链接)。

<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="123" />
<!--        <property name="packagesToScan" value="com.lucas.jpalearning"/> -->
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="showSql" value="true" />
        </bean>
    </property>
    <property name="dataSource" ref="dataSource"/>
</bean>

<!-- Remove this injector -->
<!--     <bean id="employeeDAOFactoryInjector" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> -->

<!-- Also change transaction manager type -->
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
            <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>

EmployeeDAO类:

public class EmployeeDAO{

@PersistenceContext
private EntityManager entityManager;

//remove setEntityManagerFactory()

}

现在应该可以使用这些更改。

由于您在很少的地方使用注释并启用了事务注释驱动,让我们尝试注释方式。

删除xml中的 tx-advice aop 标记。

将spring注释@Transactional放在EmployeeDAO.persist()方法上。

@Transactional
public void persist(Employee employee) {
    this.getEntityManager().persist(employee);
    this.getEntityManager().flush();
}

注释中的默认事务传播类型为required,如果没有,则会创建事务管理器。

What transaction manager to use? (JPA, Spring)

答案 1 :(得分:0)

您的代码存在两个问题:

(1)您的aop:config expression在您需要添加xml的配置EmployeeDAO中,如下所示:

 <aop:config>
      <aop:pointcut id="createOperation" 
      expression="execution(* com.lucas.jpalearning.EmployeeDAO.persist(..))"/>
      <aop:advisor advice-ref="txAdvice" pointcut-ref="createOperation"/>
   </aop:config>

(2)您不应在this.getEntityManager().flush();中手动执行EmployeeDAO,因为整个目标声明性事务是通过AOP处理事务(打开,写入,提交或回滚)。