JPA Transaction - CrudRepository #save(List) not rolled back
我正在将Spring Boot 1.5.9与spring-boot-starter-data-jpa和Camel 2.20.1一起使用。
作为输入,我得到一个带有一系列元素的XML文件,我将其与JAXB解组,然后将它们聚合到元素列表中。
为此,我定义了一个Element类,在其中我为JAXB关联了一个根元素,并将其注释为JPA实体。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | @Entity @Table (name="tblElement", schema="comp") @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Element implements Serializable { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id; @Column (name="name") @XmlElement(required = true) private String name; public void Element(){} //getter and setter methods ... } |
因此我的骆驼路线处理了要存储到MySQL数据库(版本:5.1.73)的条目列表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | @Component public class CompRoute extends RouteBuilder { @Autowired private ElementDao elementDao; @Override public void configure() throws Exception { DataFormat jaxbDataFormat = new JaxbDataFormat("com.comp.beans"); from(file:src/test/resources/input) .convertBodyTo(byte[].class,"UTF-8") .split().tokenizeXML("element") .unmarshal(jaxbDataFormat) .setProperty("SplitSize", simple("${header.CamelSplitSize}")) .aggregate(constant(true), new ArrayListAggregationStrategy()) .completionSize(simple("${property.SplitSize}")) .bean(elementDao,"insertElementList"); } } |
我对JPA和事务管理器不太熟悉,因此我根据以下文档进行了配置:
https://spring.io/guides/gs/accessing-data-jpa/
https://docs.spring.io/spring-data/jpa/docs/1.5.0.RELEASE/reference/html/jpa.repositories.html
application.properties
1 2 3 4 | spring.datasource.url=jdbc:mysql://compserver:3306/comp spring.datasource.username=user spring.datasource.password=password spring.datasource.driver-class-name=com.mysql.jdbc.Driver |
JpaConfig.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | @Configuration @EnableTransactionManagement @EnableJpaRepositories(basePackageClasses = CompApplication.class) class JpaConfig { @Autowired DataSource dataSource; @Bean public EntityManagerFactory entityManagerFactory() { HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); vendorAdapter.setGenerateDdl(false); LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean(); factory.setJpaVendorAdapter(vendorAdapter); String entities = ClassUtils.getPackageName(CompApplication.class); factory.setPackagesToScan(entities); factory.setDataSource(dataSource); factory.afterPropertiesSet(); return factory.getObject(); } @Bean @Qualifier (value ="jpaTransactionManager") public PlatformTransactionManager transactionManager() { JpaTransactionManager txManager = new JpaTransactionManager(); txManager.setEntityManagerFactory(entityManagerFactory()); return txManager; } } |
CompApplication.java
1 2 3 4 5 6 7 | @SpringBootApplication public class CompApplication { public static void main(String[] args) { SpringApplication app = new SpringApplication(CompApplication.class); app.setBannerMode(Banner.Mode.OFF); app.run(args); } |
} ??
ElementDao.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | @Service public class ElementDao { @Autowired ElementRepository elementRepository; @Transactional (transactionManager ="jpaTransactionManager", readOnly = false, propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class) public void insertElementList(Exchange exchange) { if(exchange.getIn().getBody() instanceof List) { List<Element> elements= convertListToElementList(exchange.getIn().getBody(List.class)); if (elements != null) { elementRepository.save(elements); } } } } |
ElementRepository.java
1 2 3 4 |
但是我的交易配置无法正常工作。因为如果发生错误,例如在存储第5个元素时,不会回滚整个事务。它不应插入任何元素。但是仍然存储并提交了前4个元素。
我不理解这种行为?如何在数据库存储过程中发生异常时将服务#insertElementList设置为事务性,以便整个操作回滚?
pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | <?xml version="1.0" encoding="UTF-8"?> <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.company</groupId> company</artifactId> <version>0.0.1</version> <parent> <groupId>org.springframework.boot</groupId> spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <camel.version>2.20.1</camel.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.apache.camel</groupId> camel-spring-boot-starter</artifactId> <version>${camel.version}</version> </dependency> <dependency> <groupId>org.apache.camel</groupId> camel-jdbc</artifactId> <version>${camel.version}</version> </dependency> <dependency> <groupId>mysql</groupId> mysql-connector-java</artifactId> <version>5.1.45</version> </dependency> <dependency> <groupId>org.apache.camel</groupId> camel-jaxb</artifactId> <version>2.20.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> spring-boot-starter-artemis</artifactId> </dependency> <dependency> <groupId>org.apache.camel</groupId> camel-jms</artifactId> <version>${camel.version}</version> </dependency> <dependency> <groupId>com.ibm</groupId> com.ibm.mq.allclient</artifactId> <version>9.0.0.1</version> </dependency> <dependency> <groupId>net.logstash.logback</groupId> logstash-logback-encoder</artifactId> <version>4.8</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> logback-core</artifactId> <version>1.1.8</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>commons-io</groupId> commons-io</artifactId> <version>2.5</version> </dependency> </dependencies> </project> |
我找到了解决方案。问题是数据库而不是我的配置。 MySql表的类型为MyISAM,它不支持事务并回滚。因此,我将表转换为InnoDB,现在它可以工作-当事务失败时,所有表都将回滚。
根据Spring文档。
@Transactional在定义了相同应用程序上下文中的bean上。这意味着,如果在WebApplicationContext中为DispatcherServlet放置注释,则它将仅在控制器中检查@Transactional bean,而不在服务中进行检查。 >
因此,您的保存方法不是事务性的,请在其中包含该软件包
保存方法已定义。