赞
踩
一、实例描述和实体模型
我们想在同一时间两个不同的数据库保存两个实体,这个操作需要事务。因此,在这个例子中,我们有一个Customer实体,它将第一个持久化到数据库中,而Order实体将被持久化到第二个数据库中。这两个实体非常简单,这个实例仅仅是一个示范。
这个结果实现如下:值得注意的是,它是属于两个不同的包,原因有两点:
1、项目呈现上下级逻辑分离的
2、每一个repository将扫描包含实体的包,并且进行管理。
- package com.at.mul.domain.customer;
-
- import javax.persistence.Column;
- import javax.persistence.Entity;
- import javax.persistence.GeneratedValue;
- import javax.persistence.GenerationType;
- import javax.persistence.Id;
- import javax.persistence.Table;
-
- import lombok.Data;
- import lombok.EqualsAndHashCode;
-
- @Entity
- @Table(name = "customer")
- @Data
- @EqualsAndHashCode(exclude = { "id" })
- public class Customer {
-
- @Id
- @GeneratedValue(strategy = GenerationType.AUTO)
- private Integer id;
-
- @Column(name = "name", nullable = false)
- private String name;
-
- @Column(name = "age", nullable = false)
- private Integer age;
-
- }
- package com.at.mul.domain.order;
-
- import javax.persistence.Column;
- import javax.persistence.Entity;
- import javax.persistence.GeneratedValue;
- import javax.persistence.GenerationType;
- import javax.persistence.Id;
- import javax.persistence.Table;
-
- import lombok.Data;
- import lombok.EqualsAndHashCode;
-
- @Entity
- @Table(name = "orders")
- @Data
- @EqualsAndHashCode(exclude = { "id" })
- public class Order {
-
- @Id
- @GeneratedValue(strategy = GenerationType.AUTO)
- private Integer id;
-
- @Column(name = "code", nullable = false)
- private Integer code;
-
- @Column(name = "quantity", nullable = false)
- private Integer quantity;
-
- }
对于注解@Data和@EqualsAndHashCode请看Lombok
二、写repositories接口
在这个事例中它是一个标准,这里是需要注意的是我写了两个接口在两个不同的包,这个原因在下一个步骤将会解释:
- package com.at.mul.repository.customer;
-
- import org.springframework.data.jpa.repository.JpaRepository;
-
- import com.at.mul.domain.customer.Customer;
-
- public interface CustomerRepository extends JpaRepository<Customer, Integer> {
-
- }
- package com.at.mul.repository.order;
-
- import org.springframework.data.jpa.repository.JpaRepository;
-
- import com.at.mul.domain.order.Order;
-
- public interface OrderRepository extends JpaRepository<Order, Integer> {
-
- }
三、写配置类:
这里有一点有兴趣的事,@DependsOn("transactionManager")注解不是强制的,但是在测试启动时我需要去掉若干的警告,像logs里面的WARNING: transaction manager not running?。下一个注解@EnableJpaRepositories才是重要的。
1、情况一是对于注解组件进行包扫描(repository接口),并且在我的实例中,我想仅仅repositories
customer (相反的就是repositories order)
2、情况二是实体管理者去管理实体,在我的实例中,customerEntityManager管理customer相关操作并且orderEntityManager管理order的相关操作
3、情况三是事务管理器被使用,在我的实例中transactionManager定义在MainConfig类中。这是需要对于每一个@EnableJpaRepositories 获取的工作事务都是同一个。
- package com.at.mul;
-
- import java.util.HashMap;
-
- import javax.sql.DataSource;
-
- import org.h2.jdbcx.JdbcDataSource;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.boot.context.properties.EnableConfigurationProperties;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.context.annotation.DependsOn;
- import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
- import org.springframework.orm.jpa.JpaVendorAdapter;
- import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
-
- import com.at.mul.repository.customer.CustomerDatasourceProperties;
- import com.atomikos.jdbc.AtomikosDataSourceBean;
-
- @Configuration
- @DependsOn("transactionManager")
- @EnableJpaRepositories(basePackages = "com.at.mul.repository.customer", entityManagerFactoryRef = "customerEntityManager", transactionManagerRef = "transactionManager")
- @EnableConfigurationProperties(CustomerDatasourceProperties.class)
- public class CustomerConfig {
-
- @Autowired
- private JpaVendorAdapter jpaVendorAdapter;
-
- @Autowired
- private CustomerDatasourceProperties customerDatasourceProperties;
-
- @Bean(name = "customerDataSource", initMethod = "init", destroyMethod = "close")
- public DataSource customerDataSource() {
- JdbcDataSource h2XaDataSource = new JdbcDataSource();
- h2XaDataSource.setURL(customerDatasourceProperties.getUrl());
-
- AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
- xaDataSource.setXaDataSource(h2XaDataSource);
- xaDataSource.setUniqueResourceName("xads1");
- return xaDataSource;
- }
-
- @Bean(name = "customerEntityManager")
- @DependsOn("transactionManager")
- public LocalContainerEntityManagerFactoryBean customerEntityManager() throws Throwable {
-
- HashMap<String, Object> properties = new HashMap<String, Object>();
- properties.put("hibernate.transaction.jta.platform", AtomikosJtaPlatform.class.getName());
- properties.put("javax.persistence.transactionType", "JTA");
-
- LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
- entityManager.setJtaDataSource(customerDataSource());
- entityManager.setJpaVendorAdapter(jpaVendorAdapter);
- entityManager.setPackagesToScan("com.at.mul.domain.customer");
- entityManager.setPersistenceUnitName("customerPersistenceUnit");
- entityManager.setJpaPropertyMap(properties);
- return entityManager;
- }
-
- }
- package com.at.mul;
-
- import java.util.HashMap;
-
- import javax.sql.DataSource;
-
- import org.h2.jdbcx.JdbcDataSource;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.boot.context.properties.EnableConfigurationProperties;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.context.annotation.DependsOn;
- import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
- import org.springframework.orm.jpa.JpaVendorAdapter;
- import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
-
- import com.at.mul.repository.order.OrderDatasourceProperties;
- import com.atomikos.jdbc.AtomikosDataSourceBean;
-
- @Configuration
- @DependsOn("transactionManager")
- @EnableJpaRepositories(basePackages = "com.at.mul.repository.order", entityManagerFactoryRef = "orderEntityManager", transactionManagerRef = "transactionManager")
- @EnableConfigurationProperties(OrderDatasourceProperties.class)
- public class OrderConfig {
-
- @Autowired
- private JpaVendorAdapter jpaVendorAdapter;
-
- @Autowired
- private OrderDatasourceProperties orderDatasourceProperties;
-
- @Bean(name = "orderDataSource", initMethod = "init", destroyMethod = "close")
- public DataSource orderDataSource() {
- JdbcDataSource h2XaDataSource = new JdbcDataSource();
- h2XaDataSource.setURL(orderDatasourceProperties.getUrl());
-
- AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
- xaDataSource.setXaDataSource(h2XaDataSource);
- xaDataSource.setUniqueResourceName("xads2");
- return xaDataSource;
- }
-
- @Bean(name = "orderEntityManager")
- public LocalContainerEntityManagerFactoryBean orderEntityManager() throws Throwable {
-
- HashMap<String, Object> properties = new HashMap<String, Object>();
- properties.put("hibernate.transaction.jta.platform", AtomikosJtaPlatform.class.getName());
- properties.put("javax.persistence.transactionType", "JTA");
-
- LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
- entityManager.setJtaDataSource(orderDataSource());
- entityManager.setJpaVendorAdapter(jpaVendorAdapter);
- entityManager.setPackagesToScan("com.at.mul.domain.order");
- entityManager.setPersistenceUnitName("orderPersistenceUnit");
- entityManager.setJpaPropertyMap(properties);
- return entityManager;
- }
-
- }
另一个重要的事,这里LocalContainerEntityManagerFactoryBean的定义:
1、@bean注解有获取一个name,他是在@EnableJpaRepositories注解中进行指定的。
2、你需要设置一些属性到JpaPropertyMap中,详细的说,你需要标注transaction是JTA和JTA平台是AtomikosJtaPlatform.class.getName()
我的实例不能正常执行的就是我为什么不设置第二个属性的原因。Dave Syer写道"我看了Atomikos范围之外Hibernate4不能工作",因此你需要实现类去设置hibernate.transaction.jta.platform属性,依我看来,这不是一个很好的文档,但是庆幸Oliver Gierke发现了另一个关于这个标题的文章 StackOverflow discussion 。如果你是用的是另一个JTA提供者,这个可能对你有用this useful.
四、写一个AbstractJtaPlatform实现
注意:文章到这里还没有完,由于篇幅限制,完整内容请到hongfu951博客上查看
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。