environments

MyBatis can be configured with multiple environments. This helps you to apply your SQL Maps to multiple databases for any number of reasons. For example, you might have a different configuration for your Development, Test and Production environments. Or, you may have multiple production databases that share the same schema, and you’d like to use the same SQL maps for both. There are many use cases.

One important thing to remember though: While you can configure multiple environments, you can only choose ONE per SqlSessionFactory instance.

So if you want to connect to two databases, you need to create two instances of SqlSessionFactory, one for each. For three databases, you’d need three instances, and so on. It’s really easy to remember:

  • One SqlSessionFactory instance per database

To specify which environment to build, you simply pass it to the SqlSessionFactoryBuilder as an optional parameter. The two signatures that accept the environment are:

  1. SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment);
  2. SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties);

If the environment is omitted, then the default environment is loaded, as follows:

  1. SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
  2. SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, properties);

The environments element defines how the environment is configured.

  1. <environments default="development">
  2. <environment id="development">
  3. <transactionManager type="JDBC">
  4. <property name="..." value="..."/>
  5. </transactionManager>
  6. <dataSource type="POOLED">
  7. <property name="driver" value="${driver}"/>
  8. <property name="url" value="${url}"/>
  9. <property name="username" value="${username}"/>
  10. <property name="password" value="${password}"/>
  11. </dataSource>
  12. </environment>
  13. </environments>

Notice the key sections here:

  • The default Environment ID (e.g. default=”development”).
  • The Environment ID for each environment defined (e.g. id=”development”).
  • The TransactionManager configuration (e.g. type=”JDBC”)
  • The DataSource configuration (e.g. type=”POOLED”)

The default environment and the environment IDs are self explanatory. Name them whatever you like, just make sure the default matches one of them.

transactionManager

There are two TransactionManager types (i.e. type=”[JDBC|MANAGED]“) that are included with MyBatis:

  • JDBC – This configuration simply makes use of the JDBC commit and rollback facilities directly. It relies on the connection retrieved from the dataSource to manage the scope of the transaction. By default, it enables auto-commit when closing the connection for compatibility with some drivers. However, for some drivers, enabling auto-commit is not only unnecessary, but also is an expensive operation. So, since version 3.5.10, you can skip this step by setting the “skipSetAutoCommitOnClose” property to true. For example:

    1. <transactionManager type="JDBC">
    2. <property name="skipSetAutoCommitOnClose" value="true"/>
    3. </transactionManager>
  • MANAGED – This configuration simply does almost nothing. It never commits, or rolls back a connection. Instead, it lets the container manage the full lifecycle of the transaction (e.g. a JEE Application Server context). By default it does close the connection. However, some containers don’t expect this, and thus if you need to stop it from closing the connection, set the “closeConnection” property to false. For example:

    1. <transactionManager type="MANAGED">
    2. <property name="closeConnection" value="false"/>
    3. </transactionManager>

NOTE If you are planning to use MyBatis with Spring there is no need to configure any TransactionManager because the Spring module will set its own one overriding any previously set configuration.

Neither of these TransactionManager types require any properties. However, they are both Type Aliases, so in other words, instead of using them, you could put your own fully qualified class name or Type Alias that refers to your own implementation of the TransactionFactory interface.

  1. public interface TransactionFactory {
  2. default void setProperties(Properties props) { // Since 3.5.2, change to default method
  3. // NOP
  4. }
  5. Transaction newTransaction(Connection conn);
  6. Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);
  7. }

Any properties configured in the XML will be passed to the setProperties() method after instantiation. Your implementation would also need to create a Transaction implementation, which is also a very simple interface:

  1. public interface Transaction {
  2. Connection getConnection() throws SQLException;
  3. void commit() throws SQLException;
  4. void rollback() throws SQLException;
  5. void close() throws SQLException;
  6. Integer getTimeout() throws SQLException;
  7. }

Using these two interfaces, you can completely customize how MyBatis deals with Transactions.

dataSource

The dataSource element configures the source of JDBC Connection objects using the standard JDBC DataSource interface.

Most MyBatis applications will configure a dataSource as in the example. However, it’s not required. Realize though, that to facilitate Lazy Loading, this dataSource is required.

There are three built-in dataSource types (i.e. type=”[UNPOOLED|POOLED|JNDI]“):

UNPOOLED – This implementation of DataSource simply opens and closes a connection each time it is requested. While it’s a bit slower, this is a good choice for simple applications that do not require the performance of immediately available connections. Different databases are also different in this performance area, so for some it may be less important to pool and this configuration will be ideal. The UNPOOLED DataSource has the following properties to configure:

  • driver – This is the fully qualified Java class of the JDBC driver (NOT of the DataSource class if your driver includes one).
  • url – This is the JDBC URL for your database instance.
  • username – The database username to log in with.
  • password - The database password to log in with.
  • defaultTransactionIsolationLevel – The default transaction isolation level for connections.
  • defaultNetworkTimeout – The default network timeout value in milliseconds to wait for the database operation to complete. See the API documentation of java.sql.Connection#setNetworkTimeout() for details.

Optionally, you can pass properties to the database driver as well. To do this, prefix the properties with driver., for example:

  • driver.encoding=UTF8

This will pass the property encoding, with the value UTF8, to your database driver via the DriverManager.getConnection(url, driverProperties) method.

POOLED – This implementation of DataSource pools JDBC Connection objects to avoid the initial connection and authentication time required to create a new Connection instance. This is a popular approach for concurrent web applications to achieve the fastest response.

In addition to the (UNPOOLED) properties above, there are many more properties that can be used to configure the POOLED datasource:

  • poolMaximumActiveConnections – This is the number of active (i.e. in use) connections that can exist at any given time. Default: 10
  • poolMaximumIdleConnections – The number of idle connections that can exist at any given time.
  • poolMaximumCheckoutTime – This is the amount of time that a Connection can be “checked out” of the pool before it will be forcefully returned. Default: 20000ms (i.e. 20 seconds)
  • poolTimeToWait – This is a low level setting that gives the pool a chance to print a log status and re-attempt the acquisition of a connection in the case that it’s taking unusually long (to avoid failing silently forever if the pool is misconfigured). Default: 20000ms (i.e. 20 seconds)
  • poolMaximumLocalBadConnectionTolerance – This is a low level setting about tolerance of bad connections got for any thread. If a thread got a bad connection, it may still have another chance to re-attempt to get another connection which is valid. But the retrying times should not more than the sum of poolMaximumIdleConnections and poolMaximumLocalBadConnectionTolerance. Default: 3 (Since: 3.4.5)
  • poolPingQuery – The Ping Query is sent to the database to validate that a connection is in good working order and is ready to accept requests. The default is “NO PING QUERY SET”, which will cause most database drivers to fail with a decent error message.
  • poolPingEnabled – This enables or disables the ping query. If enabled, you must also set the poolPingQuery property with a valid SQL statement (preferably a very fast one). Default: false.
  • poolPingConnectionsNotUsedFor – This configures how often the poolPingQuery will be used. This can be set to match the typical timeout for a database connection, to avoid unnecessary pings. Default: 0 (i.e. all connections are pinged every time – but only if poolPingEnabled is true of course).

JNDI – This implementation of DataSource is intended for use with containers such as EJB or Application Servers that may configure the DataSource centrally or externally and place a reference to it in a JNDI context. This DataSource configuration only requires two properties:

  • initial_context – This property is used for the Context lookup from the InitialContext (i.e. initialContext.lookup(initial_context)). This property is optional, and if omitted, then the data_source property will be looked up against the InitialContext directly.
  • data_source – This is the context path where the reference to the instance of the DataSource can be found. It will be looked up against the context returned by the initial_context lookup, or against the InitialContext directly if no initial_context is supplied.

Similar to the other DataSource configurations, it’s possible to send properties directly to the InitialContext by prefixing those properties with env., for example:

  • env.encoding=UTF8

This would send the property encoding with the value of UTF8 to the constructor of the InitialContext upon instantiation.

You can plug any 3rd party DataSource by implementing the interface org.apache.ibatis.datasource.DataSourceFactory:

  1. public interface DataSourceFactory {
  2. void setProperties(Properties props);
  3. DataSource getDataSource();
  4. }

org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory can be used as super class to build new datasource adapters. For example this is the code needed to plug C3P0:

  1. import org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory;
  2. import com.mchange.v2.c3p0.ComboPooledDataSource;
  3. public class C3P0DataSourceFactory extends UnpooledDataSourceFactory {
  4. public C3P0DataSourceFactory() {
  5. this.dataSource = new ComboPooledDataSource();
  6. }
  7. }

To set it up, add a property for each setter method you want MyBatis to call. Follows below a sample configuration which connects to a PostgreSQL database:

  1. <dataSource type="org.myproject.C3P0DataSourceFactory">
  2. <property name="driver" value="org.postgresql.Driver"/>
  3. <property name="url" value="jdbc:postgresql:mydb"/>
  4. <property name="username" value="postgres"/>
  5. <property name="password" value="root"/>
  6. </dataSource>