Tomcat + JPA多数据源实现

本文详细介绍了如何在应用中配置多个数据源,并通过JNDI和JPA持久化单元进行关联。包括Tomcat配置、项目中关联JNDI和JPA持久化单元的方法,以及Java代码实现多数据源操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如果能实现单个数据源的配置, 配置多个其实并没有什么难度, 无非是同一套配置写两遍用两个不同的命名。


1.  Tomcat配置两个JNDI数据源, 细节请参照我的另外一篇关于单一数据源的文章 

<Resource name="playDS" auth="Container" type="javax.sql.DataSource"
maxTotal="100" maxIdle="30" maxWaitMillis="10000" username="root"
password="Aa12345" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/play" />

<Resource name="multiPlayDS" auth="Container" type="javax.sql.DataSource"
maxTotal="100" maxIdle="30" maxWaitMillis="10000" username="root"
password="Aa12345" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/multiplay" />


2.  项目中关联JNDI和JPA 持久化单元

2.1 resource-ref in web.xml

	<resource-ref>
		<description>DB Connection</description>
		<res-ref-name>JNDI_NAME</res-ref-name>
		<res-type>javax.sql.DataSource</res-type>
		<res-auth>Container</res-auth>
	</resource-ref>

	<resource-ref>
		<description>DB Connection</description>
		<res-ref-name>JNDI_NAME</res-ref-name>
		<res-type>javax.sql.DataSource</res-type>
		<res-auth>Container</res-auth>
	</resource-ref>
如果在JSP页面中用sql语句访问, 直接访问JND即可, 在java代码中必须要在web.xml做关联或者加入@Resource(name="JNDI")注解


3. JPA配置文件Persistence.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="playPU" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<non-jta-data-source>java:comp/env/playDS</non-jta-data-source>
<class>play.entities.BasicUser</class>
</persistence-unit>

<persistence-unit name="multiPlayPU" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<non-jta-data-source>java:comp/env/multiPlayDS</non-jta-data-source>
<class>play.entities.BasicUser</class>
</persistence-unit>
</persistence>

4. Java代码
public class PersistentBean {
@Resource(name="playDS")
public void saveBasicUser() {
EntityManagerFactory factory = Persistence.createEntityManagerFactory("playPU");
EntityManager manager = factory.createEntityManager();
EntityTransaction tran = manager.getTransaction();
tran.begin();
BasicUser ower = new BasicUser();
ower.setPassword("exigen");
ower.setUserName("wpeng_8g");
manager.persist(ower);
tran.commit();
}

@Resource(name="multiPlayDS")
public void multiSaveBasicUser() {
EntityManagerFactory factory = Persistence.createEntityManagerFactory("multiPlayPU");
EntityManager manager = factory.createEntityManager();
EntityTransaction tran = manager.getTransaction();
tran.begin();
BasicUser ower = new BasicUser();
ower.setPassword("multiexigen");
ower.setUserName("multiwpeng_8g");
manager.persist(ower);
tran.commit();
}
}
<think>好的,我现在需要帮助用户了解如何在JPA中使用多数据源实现分布式事务。首先,我得回忆一下JPA和分布式事务的基本概念。JPA是Java持久化API,用于管理关系型数据库的数据。分布式事务涉及多个资源,比如多个数据库,需要确保所有操作要么全部提交,要么全部回滚,即满足ACID特性。 用户提到多数据源,所以首先要配置多个数据源。每个数据源对应不同的数据库实例。在Spring Boot中,通常通过配置文件定义数据源,比如使用application.properties或application.yml。但多数据源的情况下,可能需要手动配置每个数据源的Bean,并指定不同的持久化单元。 接下来是事务管理。用户的问题涉及到分布式事务,也就是跨多个数据源的事务。普通的本地事务(如使用@Transactional)只能处理单个数据源,而分布式事务需要JTA(Java Transaction API)的支持。JTA可以协调多个资源管理器,实现全局事务。 根据引用[2],当使用JTA时,无论使用哪种数据访问技术,事务管理器的配置都是一样的,因为JTA事务是全局事务,可以管理任何事务资源。因此,用户需要配置一个支持JTA的事务管理器,比如Atomikos或Bitronix。这些事务管理器实现了JTA的接口,能够处理分布式事务。 引用[3]提到,在Tomcat服务器中使用Atomikos事务管理器处理分布式事务时,如果一个事务抛出异常,整个分布式事务都会回滚。这说明在配置JTA事务管理器时,需要确保正确设置,以便在出现异常时能够正确回滚所有参与的资源。 引用[4]提到,如果事务只涉及单一资源,事务管理器可能使用优化来避免两阶段提交(2PC)的开销。但在多数据源的情况下,必须使用2PC来保证事务的一致性。因此,用户需要配置事务管理器以支持多资源事务。 现在,我需要整理实现步骤。首先,配置多个数据源和对应的EntityManagerFactory。每个数据源应该有不同的持久化单元。然后,配置JTA事务管理器,例如Atomikos,并将其注入到Spring容器中。之后,使用@Transactional注解来标记需要分布式事务的方法,确保所有数据源的操作都在同一个全局事务中。 在代码示例中,需要展示如何定义两个数据源的配置类,每个配置类创建自己的LocalContainerEntityManagerFactoryBean和JpaTransactionManager(但实际使用中,JTA事务管理器会替代这些)。不过,当使用JTA时,通常不需要单独配置JpaTransactionManager,而是由JTA事务管理器统一管理。可能需要调整配置,将JTA事务管理器作为主事务管理器。 另外,需要注意依赖的添加。例如,使用Atomikos需要引入相应的starter依赖,如spring-boot-starter-jta-atomikos。同时,需要禁用Spring Boot的自动数据源配置,因为要手动配置多个数据源。 在配置过程中,还需要确保每个EntityManagerFactory使用不同的持久化单元名称,并且指定对应的包路径,以避免实体类扫描冲突。此外,JTA事务管理器的配置需要正确设置,包括事务超时、日志路径等参数。 最后,测试时,可以编写一个服务方法,调用两个不同的数据源进行数据操作,并抛出异常以验证事务是否回滚。如果配置正确,当异常发生时,两个数据源的操作都应回滚,保持数据一致性。 可能遇到的问题包括数据源配置冲突、事务管理器未正确注入、依赖缺失等。需要确保所有配置类正确,并且事务管理器被Spring容器正确识别和使用。 总结一下,实现步骤大致如下: 1. 添加JTA事务管理器依赖(如Atomikos)。 2. 配置多个数据源,每个对应不同的数据库。 3. 为每个数据源配置EntityManagerFactory,指定持久化单元和包路径。 4. 配置JTA事务管理器,替换默认的事务管理器。 5. 使用@Transactional注解管理分布式事务。 6. 测试验证事务的原子性。 需要确保引用中的信息正确应用,比如引用[2]关于JTA事务管理器的统一配置,引用[3]中的异常处理和事务回滚,以及引用[4]中关于多资源事务的2PC处理。</think>在JPA中通过多数据源实现分布式事务需要依赖JTA(Java Transaction API)来协调跨多个资源的事务管理。以下是具体实现步骤和关键点: --- ### 1. **添加依赖** 需引入JTA实现(如Atomikos或Bitronix)和JPA适配器: ```xml <!-- Atomikos JTA --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jta-atomikos</artifactId> </dependency> <!-- JPA支持 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> ``` --- ### 2. **配置多数据源与JTA** 在`application.properties`中定义多个数据源,并禁用自动配置: ```properties # 禁用自动数据源配置 spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration # 数据源1 spring.datasource.primary.jta.url=jdbc:mysql://localhost:3306/db1 spring.datasource.primary.jta.username=user1 spring.datasource.primary.jta.password=pass1 # 数据源2 spring.datasource.secondary.jta.url=jdbc:mysql://localhost:3306/db2 spring.datasource.secondary.jta.username=user2 spring.datasource.secondary.jta.password=pass2 ``` --- ### 3. **配置JPA实体管理器工厂** 为每个数据源创建独立的`EntityManagerFactory`,并绑定到JTA: ```java @Configuration @EnableTransactionManagement public class DataSourceConfig { // 数据源1配置 @Bean(name = "primaryDataSource") @ConfigurationProperties(prefix = "spring.datasource.primary.jta") public DataSource primaryDataSource() { return new AtomikosDataSourceBean(); } @Bean(name = "primaryEntityManagerFactory") public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory( EntityManagerFactoryBuilder builder, @Qualifier("primaryDataSource") DataSource dataSource) { return builder .dataSource(dataSource) .packages("com.example.model.primary") .persistenceUnit("primaryPU") .jta(true) // 启用JTA .build(); } // 数据源2配置(类似结构) // ... } ``` --- ### 4. **配置JTA事务管理器** JTA事务管理器会统一管理所有资源: ```java @Bean(initMethod = "init", destroyMethod = "close") public UserTransactionManager userTransactionManager() { UserTransactionManager manager = new UserTransactionManager(); manager.setForceShutdown(false); return manager; } @Bean public JtaTransactionManager transactionManager() { JtaTransactionManager manager = new JtaTransactionManager(); manager.setUserTransaction(userTransactionManager()); return manager; } ``` --- ### 5. **使用分布式事务** 在业务方法上使用`@Transactional`注解,JTA会自动管理跨数据源的事务: ```java @Service public class OrderService { @Autowired @Qualifier("primaryEntityManagerFactory") private EntityManager primaryEntityManager; @Autowired @Qualifier("secondaryEntityManagerFactory") private EntityManager secondaryEntityManager; @Transactional // 触发全局事务 public void createOrder(Order order, Payment payment) { primaryEntityManager.persist(order); secondaryEntityManager.persist(payment); // 若此处抛出异常,两个操作均回滚 } } ``` --- ### 关键机制 - **两阶段提交(2PC)**:JTA通过2PC协议保证多个资源的事务一致性[^4]。 - **全局事务ID**:所有操作绑定到同一事务上下文,确保原子性[^2]。 - **异常回滚**:任一资源失败时,全部操作回滚[^3]。 --- ### 常见问题 1. **性能影响**:2PC会增加延迟,建议仅在必要时使用分布式事务。 2. **资源限制**:确保事务管理器(如Atomikos)的日志存储路径可访问。 3. **兼容性**:验证数据库驱动是否支持XA协议。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值