【问题标题】:Why data wasn't saved when I use @Transactional annotation?为什么我使用 @Transactional 注释时没有保存数据?
【发布时间】:2017-01-12 01:22:53
【问题描述】:

同事,你能帮我注解@Transactional吗?我的目标是将数据库事务管理传递给 Spring,并在当前情况下将数据保存在数据库中。

我在 DAO 类中有两个方法:

@Component
    public class OdValuesDAO
    {


           static final Logger LOG = 

Logger.getLogger(OdValuesDAO.class.getName());
        @Autowired
        // @PersistenceContext(unitName = "PersistenceUnit")
        @Qualifier("emR")
        private EntityManager em;
    public void addOdValue (OdValuesEntity odValuesEntity) {
        LOG.info(odValuesEntity.toString());
        //EntityTransaction tx = em.getTransaction(); Data will be saved DB if uncomment this code.
        ///tx.begin();
        //LOG.info(tx.isActive());
        em.persist(odValuesEntity);
        ///tx.commit();

    }


    public List<OdValuesEntity> getShare (OdValuesEntity odValuesEntity) {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<OdValuesEntity> criteriaQuery = cb.createQuery(OdValuesEntity.class);
        Root<OdValuesEntity> entityRoot = criteriaQuery.from(OdValuesEntity.class);

        Predicate criteria = cb.conjunction();
        if (odValuesEntity.getId() != null) .........

        criteriaQuery.where(criteria);
        List<OdValuesEntity> result = em.createQuery(criteriaQuery).getResultList();

        return result;

    }

及服务方式:

    @Component
    public class OdValuesService {

        static final Logger LOG = Logger.getLogger(OdValuesService.class.getName());

        @Autowired
        private OdValuesDAO odValuesDAO;

    /**
     * Read data from table.
     * @param odValuesEntity
     * @return
     */

    @Transactional (readOnly = true, value = "txtxManagerR")
    public List<OdValuesEntity> getShare (OdValuesEntity odValuesEntity) {
        odValuesDAO.getShare(odValuesEntity);
        return odValuesDAO.getShare(odValuesEntity);

    }
    /** Add record to the table
    */
    @Transactional (value = "txtxManagerR") /*I have two transaction managers for two different DataSources/
    public void addOdValue (OdValuesEntity odValuesEntity) {
        odValuesDAO.addOdValue(odValuesEntity);
    }

}

我有一个调用这两种方法的测试。我可以使用getShare 方法从表中读取数据。但是调用方法addOdValue后没有保存数据。这是我的问题。 当我在addOdValue 中取消注释事务相关代码时,一切正常。据我了解,在这种情况下,Spring 事务管理器不起作用。

如何更正 addOdValue 方法,或者可能是 spring 配置文件,以使用 Spring @Transactional 注释将数据保存在数据库中(打开和提交事务)?

我的 Spring 配置(上下文)包含下一个要使用 DB 的 bean:

@Configuration
@EnableBatchProcessing
@EnableTransactionManagement
@ComponentScan
public class AppConfig {

    @Bean
    public BasicDataSource specRDataSource() {
        BasicDataSource specRDataSource = new BasicDataSource();
        specRDataSource.setDriverClassName("org.firebirdsql.jdbc.FBDriver");
        specRDataSource.setUrl(specRDbUrl);
        specRDataSource.setUsername(specRDbUser);
        specRDataSource.setPassword(specRDbPassword);
        specRDataSource.setMaxIdle(30);
        specRDataSource.setMaxWaitMillis(10000);
        specRDataSource.setValidationQuery("select 1 from rdb$database");
        specRDataSource.setTestOnBorrow(false);
        specRDataSource.setTestWhileIdle(true);
        specRDataSource.setDefaultAutoCommit(true);

        return specRDataSource;
    }



    @Bean
    public BasicDataSource bortDataSource() {
        BasicDataSource bortDataSource = new BasicDataSource();
        bortDataSource.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
        bortDataSource.setUrl(bortDbUrl);
        bortDataSource.setUsername(bortDbUser);
        bortDataSource.setPassword(bortDbPassword);
        bortDataSource.setMaxIdle(2);
        bortDataSource.setMaxWaitMillis(10000);
        bortDataSource.setValidationQuery("select 1");
        bortDataSource.setTestOnBorrow(true);
        bortDataSource.setTestWhileIdle(true);
        bortDataSource.setDefaultAutoCommit(true);
        return bortDataSource;
    }



    @Bean
    public  LocalContainerEntityManagerFactoryBean entityManagerFactory (BasicDataSource bortDataSource) {
        LocalContainerEntityManagerFactoryBean localConnectionFactoryBean = new LocalContainerEntityManagerFactoryBean();
        localConnectionFactoryBean.setPersistenceXmlLocation("classpath:META-INF/persistence.xml");
        localConnectionFactoryBean.setDataSource(bortDataSource);
        localConnectionFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        return localConnectionFactoryBean;
    }


    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactorySpec (BasicDataSource specRDataSource) {
        LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
        emf.setPersistenceXmlLocation("classpath:META-INF/persistence.xml");
        emf.setDataSource(specRDataSource);
        Map<String, Object> properties = new HashMap<String, Object>();
        properties.put("hibernate.dialect", "org.hibernate.dialect.FirebirdDialect");
        emf.setJpaPropertyMap(properties);
        HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
        hibernateJpaVendorAdapter.setGenerateDdl(true);
        hibernateJpaVendorAdapter.setShowSql(true);
        emf.setJpaVendorAdapter(hibernateJpaVendorAdapter);

        return emf;
    }


    @Bean
    public EntityManager emR (@Qualifier("entityManagerFactorySpec") EntityManagerFactory entityManagerFactorySpec) {
        return entityManagerFactorySpec.createEntityManager();
    }


    @Bean
    public EntityManager embort (@Qualifier("entityManagerFactory") EntityManagerFactory entityManagerFactory ) {
        return entityManagerFactory.createEntityManager();
    }




    @Bean
    public  JpaTransactionManager txtxManagerR (@Qualifier("entityManagerFactorySpec") EntityManagerFactory entityManagerFactorySpec) {
         JpaTransactionManager txManager = new JpaTransactionManager();
         txManager.setEntityManagerFactory(entityManagerFactorySpec);
         return txManager;
    }


    @Bean
    public  JpaTransactionManager txManagerbort (@Qualifier("entityManagerFactory") EntityManagerFactory entityManagerFactory) {
        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(entityManagerFactory);
        return txManager;
    }

}

我的 persistence.xml 看起来像(如果需要):

<persistence-unit name="PersistenceUnit" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <class>com.acap.app.JpaEntities.OdDocsEntity</class>
        <class>com.acap.app.JpaEntities.OdValuesEntity</class>
    .......
        <class>com.acap.app.JpaEntities.OdOSharesEntity</class>
        <properties>
            <property name="hibernate.connection.url"
                      value="connection string"/>
            <property name="hibernate.connection.driver_class" value="org.firebirdsql.jdbc.FBDriver"/>
            <property name="hibernate.connection.username"/>
            <property name="hibernate.connection.password"/>
            <property name = "hibernate.show_sql" value = "false" />
           <property name = "hibernate.format_sql" value = "false" />
        </properties>

    </persistence-unit>

堆栈跟踪没有显示任何错误。感谢您的帮助。

更新 试运行:

   @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = AppConfig.class, loader = AnnotationConfigContextLoader.class)
    public class OdValuesServiceTest {
            static final Logger LOG = Logger.getLogger(OdValuesServiceTest.class.getName());

            @Autowired
            OdValuesService odValuesService;
            @Autowired
            DBCommonsService dbCommonsService;

@Commit       
@Test
            public void addOdValue() throws Exception {

                OdValuesEntity odValuesEntity = new OdValuesEntity();
                odValuesEntity.setId(dbCommonsService.getNextDocOD("OD_VALUES_ID_GEN"));
                odValuesEntity.setSysname("Name" + DataGenerator.getRandomISIN());
                odValuesEntity.setName("Name");
                odValuesEntity.setIsIn((short) 1);
                odValuesEntity.setvType(2);
                odValuesEntity.setMfu((short) 0);
                odValuesEntity.setIsin("AU000A0JP922");
                odValuesEntity.setCfi("");
               odValuesService.addOdValue(odValuesEntity);
          }
      }

【问题讨论】:

  • odValuesDAO.addOdValue(odValuesEntity);plz 的代码
  • @Antoniossss,我在问题正文中添加了更新。谢谢。
  • 删除EntityManager@Bean 声明,您必须使用@PersistenceContext 而不是@Autowired 注入实体管理器。

标签: java spring hibernate transactional


【解决方案1】:

来自spring documentation

15.2.3 事务管理

[..]默认情况下,框架会创建和回滚一个事务 每个测试.[..]

所以,如果您的“问题”是,在使用@Transactional 时,您的测试中没有数据写入数据库,那么这完全没有问题,这就是 spring 默认的工作方式。如果这不是你想要的......

如果您希望事务提交 — 不寻常,但偶尔有用 当您希望特定测试填充或修改 数据库 — 可以指示 TestContext 框架导致 通过@Commit 注解提交事务而不是回滚。

【讨论】:

  • 弗洛里安,谢谢。我在测试方法中添加了注解@Commit @Test,但数据仍然没有保存。
  • 您的测试不是事务性的,因此添加 @Commit 不会做任何事情(仅当您的测试是 @Transactional 时)。
  • 我在@Test 中添加了@Transactional 注释并有新的异常java.lang.IllegalStateException: To use the default BatchConfigurer the context must contain no more than one DataSource, found 2。我需要限定数据源 bean 还是要做什么?
猜你喜欢
  • 2018-05-28
  • 2020-01-26
  • 2014-02-28
  • 2021-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-26
相关资源
最近更新 更多