我需要在运行时动态切换数据源(读/写多个MariaDB数据库)。我正在使用 多租户概念来实现相同的。
但我无法让它适用于下面的简单场景。对于
myService.persist()
的第一次调用,Spring 请求一个连接,因此与 db1
关联的连接按预期返回。但是,对于第二次调用,不会请求新连接,并且正在使用与 db1
关联的现有连接。
public class MainClass {
..
public void main() {
TenantContext.setCurrentTenant("db1");
myService.persist();
TenantContext.setCurrentTenant("db2");
myService.persist();
}
}
@Service
public class MyService {
..
// Method is correctly declared as public and is being called from another class
// to ensure proxy application
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void persist() {
MyEntity entity = new MyEntity();
entity.setName(UUID.randomUUID().toString());
entity.setLastUpdated(new Date());
repository.save(entity);
}
}
该应用程序基于 Spring Boot 2.7.17 构建,并部署在 JBoss EAP 7.3 容器上。数据源使用 JNDI 进行配置,并在
standalone.xml
中进行以下配置。我没有在代码中显式配置任何事务管理器。
<datasource jta="true" jndi-name="java:/datasources/db1" pool-name="db1" enabled="true" use-ccm="true" statistics-enabled="true">
<connection-url>jdbc:mariadb://myhost:3306/db1</connection-url>
<driver>maria</driver>
<security>
<user-name>*******</user-name>
<password>******</password>
</security>
<validation>
<valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLValidConnectionChecker"/>
<check-valid-connection-sql>select 1</check-valid-connection-sql>
<validate-on-match>true</validate-on-match>
<background-validation>false</background-validation>
<exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLExceptionSorter"/>
</validation>
<timeout>
<set-tx-query-timeout>true</set-tx-query-timeout>
<blocking-timeout-millis>300</blocking-timeout-millis>
<idle-timeout-minutes>10</idle-timeout-minutes>
<query-timeout>300</query-timeout>
<allocation-retry>3</allocation-retry>
<allocation-retry-wait-millis>300</allocation-retry-wait-millis>
</timeout>
</datasource>
我确实看到了以下登录启动日志。会不会跟这有什么关系?
Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
在某些情况下,有必要放弃使用 JPA 存储库提出的 save() 方法;这是关于事务管理的。此方法通常在数据库中执行两个操作,第一个检查要保存的实体是否已存在于数据库中,另一个用于保存或更新(如果您面对大型数据库,这也可能会导致性能问题)。
在您的情况下, save() 似乎用于创建新的数据库资源。我建议在 MyEntityRepository 接口中使用 jpql 查询,如下所示:
@Modifying
@Query(value = "insert into my_entity (name,last_updated) VALUES
(:name,:lastUpdated)", nativeQuery = true)
MyEntity saveMyEntity(String name, String lastUpdated);
使用这种方法,如果 save 可用于更新数据,则需要使用更新 jpql 查询。 (update也可以是delete和insert new的组合,也可以接受)
希望能帮到你。