Is it a good practice to have transaction manager bean as Prototype scoped

982 Views Asked by At

I want to connect different databases based on User login, So I am having the TransactionManager bean as Prototype scope and it is creating transacionManager bean everytime, and works well. But , Is it good when the scope of the application increases and how stable it will be?

Any ideas ? Thanks.

@Bean(initMethod = "init", destroyMethod = "destroy")
@Scope(value = "prototype")
public PlatformTransactionManager transactionManager() {
1

There are 1 best solutions below

7
On

Using it as prototype is a not a good practice. This actually means that each time transactionManager() is called, a new TransactionManager is created, which is redundant resource consuming, as a single instance for each TransactionManager configuration is enough.

Instead, create some factory bean, you can call it TransactionManagerFactory, which exposes a getter such as PlatformTransactionManager getUserTxManager(SomeRelevantUserDetails). This factory will create the various PlatformTransactionManagers for the various DB vendors only once each and return it to the caller according to SomeRelevantUserDetails.

TransactionManagerFactory class:

@Component
public class TransactionManagerFactory {

    private final PlatformTransactionManager mySqlTxManager;
    private final PlatformTransactionManager db2TxManager;
    private final PlatformTransactionManager hsqlTxManager;

    @Autowired
    protected TransactionManagerFactory(
        @Qualifier("mySqlTxManager") PlatformTransactionManager mySqlTxManager
        @Qualifier("db2TxManager") PlatformTransactionManager db2TxManager
        @Qualifier("hsqlTxManager") PlatformTransactionManager hsqlTxManager) {

        this.mySqlTxManager = mySqlTxManager;
        this.db2TxManager = db2TxManager;
        this.hsqlTxManager = hsqlTxManager;
    }

    public PlatformTransactionManager getUserTxManager(SomeRelevantUserDetails userDetails) {
        PlatformTransactionManager userTxManager = // put here logic to determine
        return userTxManager;
    }
}

Other service that requires a user-dependent transaction manager:

@Component
public class UsesTxManagerFactory {

    private final TransactionManagerFactory txManagerFactory;

    @Autowired
    protected UsesTxManagerFactory(TransactionManagerFactory txManagerFactory) {
        this.txManagerFactory = txManagerFactory;
    }

    public void someMethod() {
        SomeRelevantUserDetails userDetails = // create the relevant details
        PlatformTransactionManager txManager = getUserTxManager(userDetails);
        // perform transaction
    }
}