May 16, 2021 MyBatis
MyBatis's profile contains settings and properties that affect myBatis's behavior.
These properties are externally configurable and dynamically replaceable, available neither in a typical Java property file nor passed through the child elements of the properties element. For example:
<properties resource="org/mybatis/example/config.properties">
<property name="username" value="dev_user"/>
<property name="password" value="F2Fa3!33TYyg"/>
</properties>
The properties can be used throughout the profile to replace property values that need to be dynamically configured. Like what:
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
The username and password in this example will be replaced by the appropriate values set in the properties element. T he driver and url properties will be replaced by the values corresponding to the config.properties file. This provides a number of flexible options for configuration.
Properties can also be passed to the SqlSessionBuilder.build() method. For example:
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, props);
// ... or ...
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment, props);
If the property is configured in more than one place, MyBatis loads in the following order:
Therefore, properties passed through method parameters have the highest priority, second to the profile specified in the resource/url property, and the lowest priority is the property specified in the properties property.
This is an extremely important adjustment setting in MyBatis that changes MyBatis' runtime behavior. The following table describes the intent, default values, and so on for each item in the settings.
Set the parameters | Describe | The valid value | The default |
---|---|---|---|
cacheEnabled | This configuration affects the global switch of the cache configured in all map factors. | true,false | true |
lazyLoadingEnabled |
A global switch that delays loading. W
hen on, all associated objects are delayed loading.
In a particular association, the switch state of the item can be overwritten by setting the
fetchType
property.
|
true,false | false |
aggressiveLazyLoading | When enabled, a call to any delayed property causes the object with the deferred load property to load completely; | true,false | |
multipleResultSetsEnabled | Whether to allow a single statement to return a multi-result set (compatibility drive required). | true,false | true |
useColumnLabel | Use column labels instead of column names. Different drivers will behave differently in this regard, referred to the relevant driver documentation or by testing these two different modes to observe the results of the drivers used. | true,false | true |
useGeneratedKeys | Allowing JDBC to support the automatic generation of primary keys requires driver compatibility. If set to true, this setting forces the automatic generation of primary keys, which work even though some drivers are not compatible (such as Derby). | true,false | False |
autoMappingBehavior | Specify how MyBatis should automatically map columns to fields or properties. N ONE means unmapped automatically; PARTIAL automatically maps only the result set that does not have a nested result set map defined. FULL automatically maps any complex set of results, whether nested or not. | NONE, PARTIAL, FULL | PARTIAL |
defaultExecutorType | Configure the default executor. SIMPLE is a normal executor; reuse executors reuse preprocessed statements; BATCH executors reuse statements and perform bulk updates. | SIMPLE REUSE BATCH | SIMPLE |
defaultStatementTimeout | Set the timeout, which determines the number of seconds that drive the wait for the database to respond. | Any positive integer | Not Set (null) |
safeRowBoundsEnabled | Allows the use of RowBounds in nested statements. | true,false | False |
mapUnderscoreToCamelCase | Whether to turn on automatic hump naming rule mapping, a similar mapping from the classic database column name A_COLUMN to the classic Java property name aColumn. | true, false | False |
localCacheScope | MyBatis uses the Local Cache mechanism to prevent circular references and speed up repeated nested queries. T he default is SESSION, in which case all queries executed in a session are cached. If you set the value to STATEMENT, the local session is used only for statement execution, and different calls to the same SqlSesion will not share data. | SESSION,STATEMENT | SESSION |
jdbcTypeForNull | When a specific JDBC type is not provided for the parameter, the JDBC type is specified for the empty value. Some drivers require the JDBC type of the specified column, most of which can be used directly with a general type, such as NULL, VARCHAR, or OTHER. | JdbcType enumeration. Most common are: NULL, VARCHAR and OTHER | OTHER |
lazyLoadTriggerMethods | The method that specifies which object triggers a lazy load. | A method name list separated by commas | equals,clone,hashCode,toString |
defaultScriptingLanguage | Specifies the default language for dynamic SQL generation. | A type alias or fully qualified class name. | org.apache.ibatis.scripting.xmltags.XMLDynamicLanguageDriver |
callSettersOnNulls | It is useful to specify whether the setter method of the mapping object is called when the result set value is null, which is useful when there is a Map.keySet() dependency or null value initialization. Note that the base type (int, boolean, etc.) cannot be set to null. | true,false | false |
logPrefix | Specify the prefix that MyBatis adds to the log name. | Any String | Not set |
logImpl | Specify the specific implementation of the log used by MyBatis, which will be looked up automatically when not specified. | SLF4J,LOG4J,LOG4J2,JDK_LOGGING,COMMONS_LOGGING,STDOUT_LOGGING,NO_LOGGING | Not set |
proxyFactory
|
Specifies the proxy tool used by Mybatis to create objects with late load capabilities. | CGLIB JAVASSIST |
CGLIB
|
vfslmpl
|
Specifies the implementation of VFS | The class of the implementation of the custom VFS is fully qualified and separated by a comma. |
no set
|
useActualParamName
|
The name in the method signature is allowed as the statement argument name. I
n order to use this feature, your project must be compiled in Java 8, with
-parameters
option.
(Added to 3.4.1)
|
true | false |
true
|
configurationFactory
|
Specify a class that
Configuration
instance. T
his returned Configuration instance is used to load the lazy load property value of the antiserated object. T
his class must contain a method
static Configuration getConfiguration()
(Added to 3.2.3)
|
Type alias or full class name. |
no set
|
An example of a fully configured settings element is as follows:
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="false"/>
<setting name="autoMappingBehavior" value="PARTIAL"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25"/>
<setting name="safeRowBoundsEnabled" value="false"/>
<setting name="mapUnderscoreToCamelCase" value="false"/>
<setting name="localCacheScope" value="SESSION"/>
<setting name="jdbcTypeForNull" value="OTHER"/>
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>
The type alias is a short name for the Java type. I t is only related to XML configuration, and its meaning is only used to reduce redundancy of fully qualified names for classes. For example:
<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
<typeAlias alias="Comment" type="domain.blog.Comment"/>
<typeAlias alias="Post" type="domain.blog.Post"/>
<typeAlias alias="Section" type="domain.blog.Section"/>
<typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>
When configured in this way,
Blog
can be used
domain.blog.Blog
use.
You can also specify a package name, under which MyBatis searches for the Java Beans you need, such as:
<typeAliases>
<package name="domain.blog"/>
</typeAliases>
Each Java bean
domain.blog
package, without annotations, uses the bean's initials lowercase unqualified class name as its alias.
domain.blog.Author
alias
author
Take a look at the following example:
@Alias("author")
public class Author {
...
}
Appropriate type aliases have been built into many common Java types. They are all case insensitive, and it is important to note that special handling is caused by the repetition of the base type name.
Alias | Mapping type |
---|---|
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
object | Object |
map | Map |
hashmap | HashMap |
list | List |
arraylist | ArrayList |
collection | Collection |
iterator | Iterator |
Whether MyBatis sets a parameter in a prepared statement or takes a value out of the result set, the type processor converts the obtained value into a Java type in an appropriate way. The following table describes some of the default type processors.
Type processor | Java type | JDBC type |
---|---|---|
BooleanTypeHandler
|
java.lang.Boolean
,
boolean
|
Database-compatible
BOOLEAN
|
ByteTypeHandler
|
java.lang.Byte
,
byte
|
Database-compatible
NUMERIC
or
BYTE
|
ShortTypeHandler
|
java.lang.Short
,
short
|
Database-compatible
NUMERIC
or
SHORT INTEGER
|
IntegerTypeHandler
|
java.lang.Integer
,
int
|
Database-compatible
NUMERIC
INTEGER
|
LongTypeHandler
|
java.lang.Long
,
long
|
Database-compatible
NUMERIC
or
LONG INTEGER
|
FloatTypeHandler
|
java.lang.Float
,
float
|
Database-compatible
NUMERIC
or
FLOAT
|
DoubleTypeHandler
|
java.lang.Double
,
double
|
Database-compatible
NUMERIC
or
DOUBLE
|
BigDecimalTypeHandler
|
java.math.BigDecimal
|
Database-compatible
NUMERIC
DECIMAL
|
StringTypeHandler
|
java.lang.String
|
CHAR
,
VARCHAR
|
ClobTypeHandler
|
java.lang.String
|
CLOB
,
LONGVARCHAR
|
NStringTypeHandler
|
java.lang.String
|
NVARCHAR
,
NCHAR
|
NClobTypeHandler
|
java.lang.String
|
NCLOB
|
ByteArrayTypeHandler
|
byte[]
|
The type of byte stream that the database is compatible with |
BlobTypeHandler
|
byte[]
|
BLOB
,
LONGVARBINARY
|
DateTypeHandler
|
java.util.Date
|
TIMESTAMP
|
DateOnlyTypeHandler
|
java.util.Date
|
DATE
|
TimeOnlyTypeHandler
|
java.util.Date
|
TIME
|
SqlTimestampTypeHandler
|
java.sql.Timestamp
|
TIMESTAMP
|
SqlDateTypeHandler
|
java.sql.Date
|
DATE
|
SqlTimeTypeHandler
|
java.sql.Time
|
TIME
|
ObjectTypeHandler
|
Any |
OTHER
unseeded type
|
EnumTypeHandler
|
Enumeration Type | VARCHAR - any compatible string type that stores the name of the enumeration (not the index) |
EnumOrdinalTypeHandler
|
Enumeration Type |
Any compatible
NUMERIC
DOUBLE
stores enumered indexes instead of names.
|
You can override the type processor or create your own type processor to handle unsupported or non-standard types. T
his can be done
org.apache.ibatis.type.TypeHandler
interface, or
org.apache.ibatis.type.BaseTypeHandler
and then selectively mapping it to a JDBC type.
Like what:
// ExampleTypeHandler.java
@MappedJdbcTypes(JdbcType.VARCHAR)
public class ExampleTypeHandler extends BaseTypeHandler {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, parameter);
}
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
return rs.getString(columnName);
}
@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return rs.getString(columnIndex);
}
@Override
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return cs.getString(columnIndex);
}
}
<!-- mybatis-config.xml -->
<typeHandlers>
<typeHandler handler="org.mybatis.example.ExampleTypeHandler"/>
</typeHandlers>
Using this type processor overrides the type processor that already exists that handles the String type properties of Java and the VARCHAR parameters and results. N ote that MyBatis does not spy on database metadata to determine which type to use, so you must indicate in the parameters and results map that it is a field of the VARCHAR type so that it can be bound to the correct type processor. This is because MyBatis does not know the data type until the statement is executed.
With the generics of a type processor, MyBatis can know the Java type that the type processor handles, but this behavior can be changed in two ways:
javaType
property (e.g.,
javaType="String"
to the configuration element of the type processor ( typeHandler element);
@MappedTypes
to specify a list of Java types associated with it.
If it is also specified in the
javaType
property, the annotation method is ignored.
There are two ways to specify the type of JDBC that is associated:
javaType
property to the configuration element of the type processor (e.g.,
javaType="VARCHAR"
@MappedJdbcTypes
to specify the list of JDBC types associated with it.
If it is also specified in the
javaType
property, the annotation method is ignored.
Finally, let MyBatis find the type processor for you:
<!-- mybatis-config.xml -->
<typeHandlers>
<package name="org.mybatis.example"/>
</typeHandlers>
Note That when using autodiscovery, the type of JDBC can only be specified by annotation.
You can create a generic type processor that can handle more than one class. To do this, you need to add a constructor that receives the class as an argument so that MyBatis will pass in a specific class when constructing a type processor.
//GenericTypeHandler.java
public class GenericTypeHandler extends BaseTypeHandler {
private Class type;
public GenericTypeHandler(Class type) {
if (type == null) throw new IllegalArgumentException("Type argument cannot be null");
this.type = type;
}
...
EnumTypeHandler
EnumOrdinalTypeHandler
are both generic type processors, which we'll explore in more detail in the next section.
To map
Enum
you need to choose one from
EnumTypeHandler
or
EnumOrdinalTypeHandler
to use.
Let's say we want to store rounding patterns that are used when taking approximations.
By default, MyBatis uses
EnumTypeHandler
convert
Enum
to their corresponding names.
Note
EnumTypeHandler
in a sense special, with other processors targeting only a particular class, and it's different in that it handles
Enum
However, we may not want to store names, but instead our DBAs insist on using plastic value code.
It's just as easy:
EnumOrdinalTypeHandler
typeHandlers
so that
RoundingMode
to the corresponding shaping by their sequentium values.
<!-- mybatis-config.xml -->
<typeHandlers>
<typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="java.math.RoundingMode"/>
</typeHandlers>
But how can the same
Enum
mapped to both strings and shaping?
Auto-mapper automatically uses
EnumOrdinalTypeHandler
so if we want to use
EnumTypeHandler
we don't have to explicitly set the type processor to use for those SQL statements.
(The next section doesn't start talking about mapping files until the next section, so if you're reading the document for the first time, you might want to go through this step and look at it later.) )
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.apache.ibatis.submitted.rounding.Mapper">
<resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="funkyNumber" property="funkyNumber"/>
<result column="roundingMode" property="roundingMode"/>
</resultMap>
<select id="getUser" resultMap="usermap">
select * from users
</select>
<insert id="insert">
insert into users (id, name, funkyNumber, roundingMode) values (
#{id}, #{name}, #{funkyNumber}, #{roundingMode}
)
</insert>
<resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap2">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="funkyNumber" property="funkyNumber"/>
<result column="roundingMode" property="roundingMode" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
</resultMap>
<select id="getUser2" resultMap="usermap2">
select * from users2
</select>
<insert id="insert2">
insert into users2 (id, name, funkyNumber, roundingMode) values (
#{id}, #{name}, #{funkyNumber}, #{roundingMode, typeHandler=org.apache.ibatis.type.EnumTypeHandler}
)
</insert>
</mapper>
Note that the select statement here enforces
resultMap
instead
resultType
Each time MyBatis creates a new instance of a result object, it uses an ObjectFactory instance to complete it. A ll the default object factory needs to do is instantiate the target class, either by the default construction method or by the parameter construct method when the parameter map exists. I f you want to override the default behavior of an object factory, you can do so by creating your own object factory. Like what:
// ExampleObjectFactory.java
public class ExampleObjectFactory extends DefaultObjectFactory {
public Object create(Class type) {
return super.create(type);
}
public Object create(Class type, List constructorArgTypes, List constructorArgs) {
return super.create(type, constructorArgTypes, constructorArgs);
}
public void setProperties(Properties properties) {
super.setProperties(properties);
}
public boolean isCollection(Class type) {
return Collection.class.isAssignableFrom(type);
}}
<!-- mybatis-config.xml -->
<objectFactory type="org.mybatis.example.ExampleObjectFactory">
<property name="someProperty" value="100"/>
</objectFactory>
The ObjectFactory interface is simple and contains two methods for creation, one for handling the default construction method and the other for the construction method with parameters. Finally, the setProperties method can be used to configure ObjectFactory, and after initializing your ObjectFactory instance, the properties defined in the objectFactory element body are passed to the setProperties method.
MyBatis allows you to intercept calls at some point during the execution of a mapped statement. By default, MyBatis allows method calls intercepted using plug-ins to include:
Details of the methods in these classes can be found by looking at the signatures of each method, or by looking directly at the source code in MyBatis' distribution package. A ssuming that you want to do more than just monitor the call to a method, you should have a good understanding of the behavior of the method being rewritten. B ecause if you're trying to modify or rewrite the behavior of an existing method, you're probably breaking myBatis's core module. These are lower-level classes and methods, so be especially careful when using plug-ins.
With the powerful mechanisms provided by MyBatis, it's easy to use plug-ins, simply implement the Interceptor interface and specify the method signature you want to block.
// ExamplePlugin.java
@Intercepts({@Signature(
type= Executor.class,
method = "update",
args = {MappedStatement.class,Object.class})})
public class ExamplePlugin implements Interceptor {
public Object intercept(Invocation invocation) throws Throwable {
return invocation.proceed();
}
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
public void setProperties(Properties properties) {
}
}
<!-- mybatis-config.xml -->
<plugins>
<plugin interceptor="org.mybatis.example.ExamplePlugin">
<property name="someProperty" value="100"/>
</plugin>
</plugins>
The plug-in above blocks all "update" method calls in the Executor instance, where Executor is the internal object responsible for executing low-level mapping statements.
NOTE overrides the configuration class
In addition to modifying myBatis core behavior with plug-ins, you can do this by completely overwriting the configuration class. S imply inherit and overwrite each of these methods and pass it to the sqlSessionFactoryBuilder.build (myConfig) method. Again, this could seriously affect MyBatis' behavior, so be careful.
MyBatis can be configured to accommodate multiple environments, a mechanism that helps to apply SQL mapping to multiple databases for a variety of reasons. F or example, a development, test, and production environment requires different configurations, or multiple production databases that share the same Schema and want to use the same SQL mapping. Many similar use cases.
Keep in mind, however, that although multiple environments can be configured, each SqlSessionFactory instance can only select one of them.
So if you want to connect two databases, you need to create two SqlSesionFactory instances, one for each database. And if it's three databases, you need three instances, and so on, it's easy to remember:
To specify which environment to create, simply pass it as an optional parameter to sqlSessionFactoryBuilder. The two method signatures that can accept environment configuration are:
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment);
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment,properties);
If the environment parameters are ignored, the default environment will be loaded as follows:
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader);
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader,properties);
Environment elements define how the environment is configured.
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="..." value="..."/>
</transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
Note the key points here:
The default environment and environment ID is at a glance. As soon as you name it, just make sure that the default environment matches one of the environment IDs.
Transaction Manager
There are two types of transaction managers in MyBatis (i.e., type""|" MANAGED]"):
<transactionManager type="MANAGED">
<property name="closeConnection" value="false"/>
</transactionManager>
NOTE If you're using Spring and MyBatis, there's no need to configure The Transaction Manager, because the Spring module uses its own manager to override the previous configuration.
Neither transaction manager type requires any properties. They are nothing more than type aliases, in other words, you can replace them with fully qualified or type aliases for the implementation class of the TransactionFactory interface.
public interface TransactionFactory {
void setProperties(Properties props);
Transaction newTransaction(Connection conn);
Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);
}
Any properties configured in XML will be passed to the setProperties() method after instantiation. You also need to create an implementation class for the Transaction interface, which is also simple:
public interface Transaction {
Connection getConnection() throws SQLException;
void commit() throws SQLException;
void rollback() throws SQLException;
void close() throws SQLException;
}
Using these two interfaces, you can fully customize MyBatis' handling of transactions.
DataSource
The dataSource element uses the standard JDBC data source interface to configure the resources of the JDBC connection object.
There are three built-in data source types (i.e., type" (UNPOOLED| P OOLED| JNDI]"):
UNPOOLED - The implementation of this data source is simply to open and close the connection each time it is requested. A lthough a little slow, it's a good choice for simple applications that don't have performance requirements for timely available connections. D ifferent databases behave differently in this regard, so it is not important for some databases to use a connection pool, and this configuration is ideal. UnPOOLED-type data sources only need to configure the following 5 properties:
driver
- This is the fully qualified name of the Java class driven by JDBC (not the data source class that might be included in the JDBC driver).
url
- This is the JDBC URL address of the database.
username
user name that logs on to the database.
password
the password to log on to the database.
defaultTransactionIsolationLevel
the default level of connection transaction isolation.
As an option, you can also pass properties to the database driver. To do this, the property is prefixed with "driver.", for example:
driver.encoding=UTF8
This will pass the
encoding
property with a value of
UTF8
to the database driver via the DriveManager.getConnection (url, driverProperties) method.
POOLED - This implementation of this data source leverages the concept of a "pool" to organize JDBC connection objects, avoiding the initialization and authentication times necessary to create new connection instances. This is a popular way for a compliable web app to respond quickly to requests.
In addition to the properties mentioned above under UNPOOLED, there are more properties to configure poolED's data sources:
poolMaximumActiveConnections
active (i.e. in use) connections that can exist at any time, default: 10
poolMaximumIdleConnections
The number of idle connections that may exist at any time.
poolMaximumCheckoutTime
- Checked out of pool connection time before being forced back, default: 20,000 milliseconds (i.e. 20 seconds)
poolTimeToWait
an underlying setting that, if it takes a considerable amount of time to get a connection, prints the status log to the connection pool and tries again to get a connection (avoiding a failure that has been quiet in the event of misconfiguration), with a default value of 20,000 milliseconds (i.e. 20 seconds).
poolPingQuery
reconnaissance query sent to a database to verify that the connection is in normal working order and ready to accept the request.
The default is NO PING QUERY SET, which causes most database drivers to fail with an appropriate error message.
poolPingEnabled
Whether to enable reconnaissance queries.
If turned on, you must also set the
poolPingQuery
property (preferably a very fast SQL) with an executable SQL statement, the default: false.
poolPingConnectionsNotUsedFor
- Configure the frequency of use of PoolPingQuery.
This can be set to match specific database connection timeouts to avoid unnecessary detection, with a default value of 0 (i.e. all connections are detected at every moment - of course only when PoolPingEnabled is true).
JNDI - This data source is implemented to be used in containers such as EJBs or application servers, which can centrally or externally configure the data source and then place a reference to the JNDI context. This data source configuration requires only two properties:
initial_context
This property is used to find context in InitialContext (i.e., initialContext.lookup (initial_context).
This is an optional property, and if ignored, data_source property will be looked for directly from InitialContext.
data_source
is the path to the context that refers to the location of the data source instance.
Provides initial_context is looked up in the context it returns when configured, and in InitialContext when it is not provided.
Similar to other data source configurations, you can add the prefix "env." P ass the property directly to the initial context. Like what:
env.encoding=UTF8
This passes the encoding property with a value of
UTF8
to its construction method when the initial context (InitialContext) is
encoding
Any third-party data source can also be used by using the interface
org.apache.ibatis.datasource.DataSourceFactory
which requires an implementation interface:
public interface DataSourceFactory {
void setProperties(Properties props);
DataSource getDataSource();
}
org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory
be used as a parent class to build a new data source adapter, such as the following code necessary to insert a C3P0 data source:
import org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class C3P0DataSourceFactory extends UnpooledDataSourceFactory {
public C3P0DataSourceFactory() {
this.dataSource = new ComboPooledDataSource();
}
}
To make it work, add a property to each setter method that requires a MyBatis call. Here's an example of connecting to a PostgreSQL database:
<dataSource type="org.myproject.C3P0DataSourceFactory">
<property name="driver" value="org.postgresql.Driver"/>
<property name="url" value="jdbc:postgresql:mydb"/>
<property name="username" value="postgres"/>
<property name="password" value="root"/>
</dataSource>
MyBatis can execute different statements depending on the database vendor, and this multi-vendor support is based on the
databaseId
statement. M
yBatis loads all statements without
databaseId
property and with the
databaseId
the current database databaseId. I
f you find the
databaseId
and without
databaseId
the latter is discarded.
To support multi-vendor features, simply include
databaseIdProvider
.xml mybatis-config file as below:
<databaseIdProvider type="DB_VENDOR" />
The DB_VENDOR here is set by the string returned by
DatabaseMetaData#getDatabaseProductName()
Because this string is usually very long and different versions of the same product return different values, it's a good idea to make it shorter by setting a property alias, as follows:
<databaseIdProvider type="DB_VENDOR">
<property name="SQL Server" value="sqlserver"/>
<property name="DB2" value="db2"/>
<property name="Oracle" value="oracle" />
</databaseIdProvider>
When there are properties, DB_VENDOR databaseIdProvider is set to the value of the first property key that matches the name of the database product, and if there is no matching property, it is set to "null".
In this example,
getDatabaseProductName()
returns Oracle DataDirect, the databaseId will be set to Oracle.
You can build your own DatabaseIdProvider by implementing the interface
org.apache.ibatis.mapping.DatabaseIdProvider
and .xml in the mybatis-config database:
public interface DatabaseIdProvider {
void setProperties(Properties p);
String getDatabaseId(DataSource dataSource) throws SQLException;
}
Now that myBatis' behavior has been configured by the above elements, we are now defining sql mapping statements. B
ut first we need to tell MyBatis where to find these statements. J
ava doesn't provide a good way to find it automatically, so the best way is to tell MyBatis where to find the mapping file. Y
ou can use resource references relative to class paths, or fully qualify resource
file:///
or class names and package names, and so on.
For example:
<!-- Using classpath relative resources -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- Using url fully qualified paths -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
<!-- Using mapper interface classes -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
<!-- Register all interfaces in a package as mappers -->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
These configurations tell MyBatis where to look for mapping files, and the rest of the details should be each SQL mapping file, which is what we'll discuss next.