我的主要目标是尽可能多地利用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
正如我所说,当所有这些都运行时没有错误,也没有持久性。顺便说一句,我用主要的Application类祝福了pom(在属性下):
<start-class>com.xxxxxcorp.xxxxxpoint.Application</start-class>
所以我确定我没有启动两个上下文或两个应用程序或其他任何类似的东西。谁能告诉我哪里出错?
答案 0 :(得分:2)
导入器运行时,没有活动处于活动状态。您应该将其设为@Bean
并标记其importContent()
方法@Transactional
。从CommandlineRunner
调用方法。
另外,如果您的主要目标是尽可能多地使用Spring Boot应用程序基础架构,那么为什么不抛弃其余的JPA和{{1配置(它在Boot中重复了几个字节的字节)?
答案 1 :(得分:0)
我以为我会回复有效的解决方案。基本上我说的那个班错了......错了。感谢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;
}
}
}