【问题标题】:Spring Boot: Data loading Application wont persist hibernate/JPASpring Boot:数据加载应用程序不会持续休眠/JPA
【发布时间】:2014-08-05 06:04:10
【问题描述】:

我的主要目标是尽可能多地利用 Spring Boot 应用程序基础设施来读取文件并将一些对象保存到数据库中,经过大量处理。问题是处理发生了,找到了DAO并执行了entityManager.save(),但是没有对象被持久化(没有运行hibernate SQL)。

这是我的加载工具应用程序(可能是错误的):

@Configuration
@EnableAutoConfiguration
@ComponentScan(basePackages = {"com.touchcorp.touchpoint"})
@Transactional
public class ContentImportingApplication {


    @Autowired
    private VoucherTemplateDao voucherTemplateDao;

    public static void main(String[] args) throws Exception {

        SpringApplication app = new SpringApplication(ContentImportingApplication.class);
         // ... customize app settings here
        ApplicationContext ctx = app.run(args);

        ContentImporter importer = new ContentImporter(ctx);

        importer.importContent();

        System.exit(0);
    }

    private static class ContentImporter {
        private ApplicationContext ctx = null;

        public ContentImporter(ApplicationContext ctx) {
            this.ctx = ctx;
        }

        public void importContent() throws Exception {
            String otc = readFileAsString("content-to-import");

            SAXBuilder sb = new SAXBuilder();
            Document jDom = sb.build(new StringReader(otc));

            // lots of processng code here .. this all works
            // ....

            Set<Long> productIds = productDocuments.keySet();
            VoucherTemplateDao dao = (VoucherTemplateDao) ctx.getBean("voucherTemplateDao");
            System.out.println("do we have a dao?: " + dao);
            for(Long productId : productIds) {

                VoucherTemplate vt = VoucherTemplate.make(productId, "RETAILER_GROUP:*|CHANNEL:*|LOCALE:de-AT|INDUSTRY:5499", VoucherTemplate.TemplateSchema.OTC);
                vt.setTemplate(productDocuments.get( productId ));
                // the thing that won't persist
                dao.save(vt);
            }
            jDom.getRootElement().addContent( new Element("w") );

        }

        private void findAndReplaceNestedDocs(Document jDom, Element documentInOtcContent) {
            // ...code omitted: this all works too...
        }

        public String readFileAsString(String name) {
            // ...code omitted: and so does this...

        }

    }

}

它利用了各种配置类,但我认为 PersistenceConfig 是最重要的:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories
@PropertySource({ "classpath:persistence.properties" })
@ComponentScan(basePackages = {"com.xxxxxcorp.xxxxxpoint.model"})
public class PersistenceConfig
{
    @Autowired
    private Environment env;

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
       LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
       em.setDataSource(dataSource());
       em.setPackagesToScan(new String[] { "com.xxxxxcorp.xxxxxpoint.model.domain" });

       JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
       em.setJpaVendorAdapter(vendorAdapter);
       em.setJpaDialect(jpaDialect());
       em.setJpaProperties(hibernateProperties());

       return em;
    }

    @Bean
    public DataSource dataSource()
    {
        // assumes dbcp
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
        dataSource.setUrl(env.getProperty("jdbc.url"));
        dataSource.setUsername(env.getProperty("jdbc.user"));
        dataSource.setPassword(env.getProperty("jdbc.pass"));
        return dataSource;
    }

    @Bean
    public PlatformTransactionManager transactionManager(){
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory( this.entityManagerFactory().getObject() );
        transactionManager.setJpaDialect(this.jpaDialect());
        return transactionManager;
    }

    @Bean
    public JpaDialect jpaDialect() {
        return new HibernateJpaDialect();
    }


    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation()
    {
        return new PersistenceExceptionTranslationPostProcessor();
    }

    Properties hibernateProperties() {
        return new Properties() {
            {
                setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
                setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
                setProperty("hibernate.globally_quoted_identifiers", "true");
            }
        };
    }

}

相关的属性文件:

# jdbc
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/xxxxxxpoint?autoReconnect=true
jdbc.user=root
jdbc.pass=password

# hibernate
hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
hibernate.show_sql=true
hibernate.hbm2ddl.auto=verify

正如我所说,所有这些都运行时没有错误,也没有持久性。顺便说一句,我已经用主应用程序类祝福了 pom(在属性下):

<start-class>com.xxxxxcorp.xxxxxpoint.Application</start-class>

所以我确定我不会启动两个上下文或两个应用程序或任何其他类似的东西。谁能告诉我哪里出错了?

【问题讨论】:

    标签: hibernate jpa spring-boot


    【解决方案1】:

    当您的导入器运行时,没有交易活动。您应该将其设为@Bean 并标记其importContent() 方法@Transactional。可能从CommandlineRunner 调用该方法。

    另外,如果您的“主要目标是尽可能多地利用 Spring Boot 应用程序基础架构”,那么您为什么不丢弃其余的 JPA 和 DataSource 配置(它重复了很多字节用于引导中的字节)?

    【讨论】:

    • 不确定我是否完全理解您的第二点。我认为我需要指向我的实体类和 .properties 文件的 JPA 和数据源。如果 Spring Boot 自动选择这些,那么我如何区分测试、开发和生产环境?
    【解决方案2】:

    我想我会发回有效的解决方案。基本上我说的那门课是错的……是错的。感谢 David Syer 的回答。

    这是修改后的 ContentImportingApplication:

    @Configuration
    @EnableAutoConfiguration
    @ComponentScan(basePackages = {"com.touchcorp.touchpoint"})
    public class ContentImportingApplication {
    
    
        @Autowired
        private VoucherTemplateDao voucherTemplateDao;
    
        public static void main(String[] args) throws Exception {
    
            SpringApplication app = new SpringApplication(ContentImportingApplication.class);
            ApplicationContext ctx = app.run(args);
    
            ContentImporter importer = (ContentImporter) ctx.getBean("contentImporter");
            importer.importContent(ctx);
    
            System.exit(0);
        }
    
        @Bean
        public ContentImporter contentImporter()
        {
            return new ContentImporter();
        }
    
    
        public class ContentImporter {
    
            @Transactional
            public void importContent(ApplicationContext ctx) throws Exception {
                String otc = readFileAsString("content-to-import", ctx);
    
                SAXBuilder sb = new SAXBuilder();
                Document jDom = sb.build(new StringReader(otc));
    
                // first step: associate products to otc documents
                Map<Long,String> productDocumentNames = new HashMap<Long,String>();
                Map<Long,String> productDocuments = new HashMap<Long,String>();
    
                XPathExpression<Element> xpath = XPathFactory.instance().compile("//t", Filters.element());
                List<Element> ts = xpath.evaluate(jDom);
    
                for (Element t : ts) {
                    String documentName = t.getAttributeValue("d");
                    String productId = t.getChild("p").getChild("id").getValue();
    
                    // put it in, if there is a voucher for this product
                    if( documentName != null) {
                        productDocumentNames.put(Long.valueOf(productId), documentName);
                    } else {
                        System.out.println("No voucher associated with productId: " + productId);
                    }
                }
    
                List<Element> ds = jDom.getRootElement().getChildren("d");
                for (Element d : ds) {
                    // for each document we find, we'll replace the document name with the content
                    String documentName = d.getAttributeValue("k");
    
                    Set<Long> productIds = productDocumentNames.keySet();
                    for(Long productId : productIds) {
    
                         if( productDocumentNames.get( productId ).equals( documentName ) ) {
    
                             findAndReplaceNestedDocs( jDom, d );
    
                             productDocuments.put( productId, new XMLOutputter( ).outputString( d.getContent() ) );
                         }
                    }
                }
    
                Set<Long> productIds = productDocuments.keySet();
                for(Long productId : productIds) {
    
                    VoucherTemplate vt = VoucherTemplate.make(productId, "RETAILER_GROUP:*|CHANNEL:*|LOCALE:de-AT|INDUSTRY:5499", VoucherTemplate.TemplateSchema.OTC);
                    vt.setTemplate(productDocuments.get( productId ));
                    voucherTemplateDao.save(vt);
                }
                jDom.getRootElement().addContent( new Element("w") );
    
            }
    
            private void findAndReplaceNestedDocs(Document jDom, Element documentInOtcContent) {
                // find the nested docs
                List<Element> directives = documentInOtcContent.getChildren("w");
                // and replace them
                for(Element directive : directives) {
                    List<Element> docs = jDom.getRootElement().getChildren("d");
                    for (Element doc : docs) {
                        if (directive.getAttributeValue("d").equals(doc.getAttributeValue("k"))) {
    
                            List<Element> docContents = doc.getChildren();
                            List<Element> clones = new ArrayList<Element>();
                            for(Element docContent : docContents) {
                                Element docContentCopy = docContent.clone();
                                docContentCopy.detach();
                                clones.add(docContentCopy);
                            }
    
                            if (documentInOtcContent.indexOf(directive) != -1) {
                                documentInOtcContent.setContent(documentInOtcContent.indexOf(directive), clones);
                            }
    
                        }
                    }
                    break;
                }
            }
    
            public String readFileAsString(String name, ApplicationContext ctx) {
                String output = null;
    
                // working code in here
                return output;
            }
    
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-08-14
      • 1970-01-01
      • 2017-06-13
      • 2018-04-25
      • 2016-02-29
      • 2017-08-03
      • 1970-01-01
      相关资源
      最近更新 更多