El fichero de configuración XML contiene parámetros y configuraciones que tienen un efecto crucial en cómo se comporta MyBatis. A alto nivel contiene:
Contiene propiedades externalizables y sustituibles que se pueden configurar en un típico properties de Java o bien puede definirse su contenido directamente mediante subelementos property. Por ejemplo:
<properties resource="org/mybatis/example/config.properties"> <property name="username" value="dev_user"/> <property name="password" value="F2Fa3!33TYyg"/> </properties>
Las propiedades pueden usarse a lo largo del fichero de configuración para sustituir valores que deben configurarse dinámicamente. Por ejemplo:
<dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource>
El usuario y password de este ejemplo se reemplazarán por los valores de los elementos de tipo property. El driver y la url se reemplazarán por los valores contenidos en el fichero config.properties. Esto aumenta mucho las posibilidades de configuración.
Las propiedades también pueden pasarse como parámetro al método SqlSessionBuilder.build(). Por ejemplo:
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, props); // ... or ... SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment, props);
Si una propiedad existe en más de un lugar, MyBatis la carga en este orden:
Por tanto las properties más prioritarias son las pasadas como parámetro, seguidas de los atributos tipo classpath/url y finalmente las propiedades especificadas en el elemento properties..
Son muy importantes para definir cómo se comporta MyBatis en ejecución. La siguiente tabla describe las configuraciones (settings), sus significados y sus valores por defecto.
Configuración | Descripción | Valores admitidos | Valor por defecto |
---|---|---|---|
cacheEnabled | Habilita o inhabilita globalmente todas las cachés definidas en el mapper | true | false | true |
lazyLoadingEnabled | Habilita o inhabilita globalmente la carga diferida (lazy loading). Cuando está activo, todas las relaciones se cargan en modo diferido. Este valor se puede sobrescribir en cada relación usando el atributo fetchType. | true | false | false |
aggressiveLazyLoading | Cuando está habilitada, todos los atributos de un objeto con propiedades con carga diferida (lazy loaded) se cargarán cuando se solicite cualquiera de ellos. En caso contrario, cada propiedad es cargada cuando es solicitada. | true | false | true |
multipleResultSetsEnabled | Habilita o inhabilita la obtención de múltiples ResultSets con una sola sentencia (se requiere un driver compatible) | true | false | true |
useColumnLabel | Utiliza la etiqueta de columna (label) en lugar del nombre de conlumna. Algunos drivers se comportan distinto en lo que a esto respecta. Consulta la documentación del driver o prueba ambos modos para descubrir cómo funciona tu driver | true | false | true |
useGeneratedKeys | Habilita el uso del soporte JDBC para claves autogeneradas. Se requiere un driver compatible. Este parámetro fuerza el uso de las claves autogeneradas si está habilitado. Algunos drivers indican que no son compatibles aunque funcionan correctamente (ej. Derby) | true | false | False |
autoMappingBehavior | Especifica cómo deben mapearse de forma automática las columnas a los campos/propiedades. NONE desactiva el mapeo automático. PARTIAL sólo mapea automáticamente los resultados que no contienen result maps anidados en su interior. FULL mapea resultados de cualquier complejidad (contengan anidados o no). | NONE, PARTIAL, FULL | PARTIAL |
defaultExecutorType | Configura el ejecutor (executor) por defecto. SIMPLE no hace nada especial. REUSE reúsa prepared statements. BATCH reúsa statements y ejecuta actualizaciones en batch. | SIMPLE REUSE BATCH | SIMPLE |
defaultStatementTimeout | Establece el número de segundos que debe esperar el driver la respuesta de la base de datos. | Cualquier entero positivo | Sin valor (null) |
safeRowBoundsEnabled | Habilita el uso de RowBounds en statements anidados. | true | false | False |
mapUnderscoreToCamelCase | Mapea automáticamente los nombres clásicos de columnas de base de datos A_COLUMN a nombres clásicos de propiedades Java aColumn. | true | false | False |
localCacheScope | MyBatis usa una cache local para evitar dependencias circulares y acelerar ejecuciones repeticas de queries anidadas. Por defecto (SESSION) todas las queries ejecutadas en una sesión se cachean. Si localCacheScope=STATEMENT la sesión local solo se usará durante la ejecución de un statement, no se comparten datos entre distintas llamadas a SqlSession. | SESSION | STATEMENT | SESSION |
jdbcTypeForNull | Permite especificar el tipo JDBC que Especifica el tipo JDBC para valores nulos cuando no se ha especificado un tipo concreto para el parámetro. Algunos drivers requieren que se indique el tipo JDBC de la columna pero otros permite valores genéricos como NULL, VARCHAR or OTHER. | JdbcType enumeration. Los más comunes son: NULL, VARCHAR and OTHER | OTHER |
lazyLoadTriggerMethods | Permite especificar qué métodos de Object disparan la carga diferida | Lista de métodos separados por comas | equals,clone,hashCode,toString |
defaultScriptingLanguage | Permite especificar que lenguaje se usará en el SQL dinámico. | Un type alias o una nombre de clase completamente cualificado | org.apache.ibatis.scripting.xmltags.XMLDynamicLanguageDriver |
callSettersOnNulls | Permite especificar si se invocarán a los setters y a los métodos put de los mapas si el valor obtenido es null. Te en cuenta que si se activa las propiedades que puedan ser informadas con nulos no pueden ser de tipos primitivos. | true | false | false |
logPrefix | Permite especificar el prefijo que MyBatis añadirá a los nombres de logger. | Cualquier cadena | No informado |
logImpl | Permite especificar qué implementación de logging utilizar. Si no está informado la impelmentación se descubrirá automaticamente. | SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING | No informado |
proxyFactory | Permite especificar qué herramienta de generación de proxys se usará para crear los objetos con capacidad de carga lazy. | CGLIB | JAVASSIST | CGLIB |
A continuación se muestra un ejemplo del elemento settings al completo:
<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>
Un type alias es simplemente un alias (un nombre más corto) para un tipo Java. Solo es importante para la configuración XML y existe para reducir la cantidad de texto al teclear nombres de clase cualificados (fully qualified). Por ejemplo:
<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>
Con esta configuración, puede usarse Blog en lugar de domain.blog.Blog
Tambien puedes indicar un paquete para que MyBatis busque beans de tipo alias. Por ejemplo:
<typeAliases> <package name="domain.blog"/> </typeAliases>
Cada bean encontrado en domain.blog, en caso de que no contenga ninguna anotación, se registrará como alias usando su nombre no cualificado en minúsculas. Es decir, domain.blog.Author se registrará como will be registered as author. Si se encuentra la anotación @Alias se usará su valor como alias. Mira el ejemplo a continuación:
@Alias("author") public class Author { ... }
Hay muchos type aliases pre construidos. No son sensibles a mayúsculas/minúsculas. Observa los nombres especiales de los tipos primitivos dadas las colisiones de nombres.
Alias | Tipo mapeado |
---|---|
_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 |
Cuando MyBatis establece el valor de un parámetro de un PreparedStatement u obtiene un valor de un ResultSet, se utiliza un TypeHandler para convertir el valor al tipo Java apropiado. La siguiente tabla recoge los TypeHandlers predefinidos.
Type Handler | Tipos Java | Tipos JDBC |
---|---|---|
BooleanTypeHandler | java.lang.Boolean, boolean | Cualquiera compatible con BOOLEAN |
ByteTypeHandler | java.lang.Byte, byte | Cualquiera compatible con NUMERIC o BYTE |
ShortTypeHandler | java.lang.Short, short | Cualquiera compatible con NUMERIC o SHORT INTEGER |
IntegerTypeHandler | java.lang.Integer, int | Cualquiera compatible con NUMERIC o INTEGER |
LongTypeHandler | java.lang.Long, long | Cualquiera compatible con NUMERIC o LONG INTEGER |
FloatTypeHandler | java.lang.Float, float | Cualquiera compatible con NUMERIC o FLOAT |
DoubleTypeHandler | java.lang.Double, double | Cualquiera compatible con NUMERIC o DOUBLE |
BigDecimalTypeHandler | java.math.BigDecimal | Cualquiera compatible con NUMERIC o 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[] | Cualquiera compatible con byte stream |
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, or unspecified |
EnumTypeHandler | Enumeration Type | VARCHAR Cualquiera compatible con string porque se guarda el código (no el índice). |
EnumOrdinalTypeHandler | Enumeration Type | Cualquiera compatible con NUMERIC o DOUBLE por que se guarda la posición (no el código). |
Es posible sobrescribir los TypeHanders o crear TypeHanders personalizados para tratar tipos no soportados o no estándares. Para ello, debes implementar la interfaz org.apache.ibatis.type.TypeHandler o extender la clase de ayuda org.apache.ibatis.type.BaseTypeHandler y opcionalmente mapear el TypeHandler a un tipo JDBC. Por ejemplo:
// ExampleTypeHandler.java @MappedJdbcTypes(JdbcType.VARCHAR) public class ExampleTypeHandler extends BaseTypeHandler<String> { @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>
Al usar este TypeHandler se sobrescribe el TypeHandler existente para los tipos String y los parámetros y resultados VARCHAR. Observa que MyBatis no introspecciona la base de datos para conocer el tipo así que debes especificar que se trata de un VARCHAR en los mapeos de parámetros y resultados para que se use el TypeHandler adecuado. Esto se debe a que MyBatis no conoce nada sobre los tipos de datos hasta que la sentencia ha sido ejecutada.
MyBatis conoce el tipo Java que quieres gestionar introspecionando tipo genérico del TypeHandler, pero puedes modificar este comportamiento de dos maneras.
El tipo JDBC asociado se puede especificar de dos maneras:
Y finalmente puedes hacer que MyBatis busque tus TypeHandlers:
<!-- mybatis-config.xml --> <typeHandlers> <package name="org.mybatis.example"/> </typeHandlers>
Observa que cuando usas la función de búsqueda los tipos JDBC sólo se pueden especificar usando anotaciones.
Puedes crear un TypeHandler genérico que sea capaz de manejar más de un tipo de clase. Para ello añade un constructor que recibe una clase como parámetro y MyBatis le pasará la clase actual cuando construya el TypeHandler.
//GenericTypeHandler.java public class GenericTypeHandler<E extends MyObject> extends BaseTypeHandler<E> { private Class<E> type; public GenericTypeHandler(Class<E> type) { if (type == null) throw new IllegalArgumentException("Type argument cannot be null"); this.type = type; } ...
EnumTypeHandler y EnumOrdinalTypeHandler son TypeHandlers genéricos. Conoceremos más sobre ellos en la próxima sección.
Si quires mapear un Enum, debes usar bien un EnumTypeHandler o un EnumOrdinalTypeHandler.
Por ejemplo, digamos que quieres guardar el modo de reondeo que debe usarse con un número determinado que debe redondearse. Por defecto MyBatis usa un EnumTypeHandler para comvertir los valores del Enum a sus nombres.
Observa que el EnumTypeHandler es un handler especial en el sentido de que no maneja una clase específica, como los demás handlers sino cualquier clase que extiende de EnumSin embargo, puede que no queramos guardar nombres. Nuestro DBA puede insistir en que usemos un entero en su lugar. Muy sencillo: añade un EnumOrdinalTypeHandler a las sección de typeHandlers de tu fichero de configuración y ahora todos los RoundingMode se mapearán a un entero usando su valor ordinal.
<!-- mybatis-config.xml --> <typeHandlers> <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="java.math.RoundingMode"/> </typeHandlers>
Pero ¿y si quieres mapear el mismo Enum a un string en un sitio pero a un entero en otro?
El mapeo automático siempre usará EnumOrdinalTypeHandler, así que si queremos usar el clásico EnumTypeHandler, debemos indicarlo establiencidolo esplícitamente su uso en los statements.
Los mappers no se tratarán hasta la sección siguiente asi que si esta es tu primera lectura de la documentación quizá prefieras saltarte esta sección por ahora y volver más tarde).
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!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>
Observa que esto nos fuerza a usar un resultMap en lugar de un resultType en nuestros statements tipo select.
Cada vez que MyBatis crea una nueva instancia de un objeto de resultado usa una instancia de ObjectFactory para hacerlo. El ObjectFactory por defecto no hace mucho más que instanciar la clase destino usando su constructor por defecto, o el constructor que se ha parametrizado en su caso. Es posible sobrescribir el comportamiento por defecto creando tu propio ObjectFactory. Por ejemplo:
// ExampleObjectFactory.java public class ExampleObjectFactory extends DefaultObjectFactory { public Object create(Class type) { return super.create(type); } public Object create(Class type, List<Class> constructorArgTypes, List<Object> constructorArgs) { return super.create(type, constructorArgTypes, constructorArgs); } public void setProperties(Properties properties) { super.setProperties(properties); } public <T> boolean isCollection(Class<T> type) { return Collection.class.isAssignableFrom(type); } }
<!-- mybatis-config.xml --> <objectFactory type="org.mybatis.example.ExampleObjectFactory"> <property name="someProperty" value="100"/> </objectFactory>
La interfaz ObjectFactory es muy sencilla. Contiene solo dos métodos de creación, uno para el constructor por defecto y otro para el constructor parametrizado. Adicionalmente el método setProperties sirve para configurar el ObjectFactory. Las propiedades definidas en el cuerpo del elemento objectFactory se pasan al método setProperties después de que el ObjectFactory haya sido inicializado.
MyBatis permite interceptar las llamadas en ciertos puntos de la ejecución de un mapped statement. Por defecto, MyBatis permite incluir plugins que intercepten las llamadas de:
Los detalles de estos métodos se pueden conocer observando sus firmas y el código fuente de los mismos que está disponible en el sitio de MyBatis. Es recomendable que comprendas el funcionamiento del método que estas sobrescribiendo siempre que vayas a hacer algo más complejo que monitorizar llamadas. Ten en cuenta que si modificas el comportamiento de alguno de estos métodos existe la posibilidad de que rompas el funcionamiento de MyBatis. Estas clases son de bajo nivel y por tanto debes usar los plugins con cuidado.
Utilizar un plugin es muy sencillo para la potencia que ofrecen. Simplemente implementa el interfaz Interceptor y asegúrate de especificar las signaturas que quieres interceptar.
// 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>
El plugin anterior interceptará cualquier llamada al método “update” en la instancia de Executor, que es un objeto interno que se encarga de la ejecución a bajo nivel de los mapped statements.
NOTA Acerca de sobrescribir la clase Configuration
Además de modificar el comportamiento de MyBatis mediante los plugins, también es posible sobrescribir la clase Configuración por completo. Extiende la clase, sobrescribe sus métodos y pásala como parámetro en la llamada al método sqlSessionFactoryBuilder.build(myConfig). Nuevamente, ten cuenta que esto puede afectar seriamente al funcionamiento de MyBatis así que úsalo con cuidado.
En MyBatis pueden configurarse varios entornos. De esta forma puedes usar tus SQL Maps en distintas bases de datos por muchos motivos. Por ejemplo puede que tengas una configuración distinta para tus entornos de desarrollo, pruebas y producción. O quizá tengas varias bases de datos en producción que comparten el esquema y quieres usar los mismos SQL maps sobre todas ellas. Como ves, hay muchos casos.
Debes recordar un asunto importante. Cuando configures varios entornos, solo será posible usar UNO por cada instancia de SqlSessionFactory.
Por lo tanto, si quieres conectar a dos bases de datos, deberás crear dos instancias de SqlSessionFactory, una para cada cual. Para el caso de tres bases de datos necesitarás tres instancias y así sucesivamente. Es fácil de recordar:
Para indicar qué entorno debe utilizarse, debes informar el parámetro opcional correspondiente en la llamada al SqlSessionFactoryBuilder. Existen dos métodos que aceptan el entorno:
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment); SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment,properties);
Si se omite el entorno se usará el entorno por defecto:
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader); SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader,properties);
El elemento environments contiene la configuración del entorno:
<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>
Observa que las secciones importantes son:
El ID del entorno por defecto y de los entornos existentes son auto-explicativos. Puedes nombrarlos como más te guste, tan sólo asegúrate de que el valor por defecto coincide con un entorno existente.
transactionManager
MyBatis incluye dos tipos de TransactionManager (ej. type=”[JDBC|MANAGED]”):
<transactionManager type="MANAGED"> <property name="closeConnection" value="false"/> </transactionManager>
NOTA Si estás pensando en usar MyBatis con Spring no necesitas configurar ningún TransactionManager porque el módulo de Spring configurará el suyo propio sobrescribiendo cualquier otra configuración previa.
Ninguno de estos TransactionManagers necesita ninguna propiedad. Sin embargo ambos son Type Aliases, es decir, en lugar de usarlos puedes informar el nombre totalmente cualificado o el Type Alias de tu propia implementación del interfaz TransactionFactory:
public interface TransactionFactory { void setProperties(Properties props); Transaction newTransaction(Connection conn); Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit); }
Todas las propiedades que configures en el XML se pasarán al método setProperties() tras la instanciación de la clase. Tu implementación debe crear una implementación de Transaction, que a su vez es también un interfaz muy sencillo:
public interface Transaction { Connection getConnection() throws SQLException; void commit() throws SQLException; void rollback() throws SQLException; void close() throws SQLException; }
Con estos dos interfaces puedes personalizar por completo la forma en la que MyBatis gestiona las transacciones.
dataSource
El elemento dataSource sirve para configurar la forma de obtener conexiones JDBC mediante la interfaz DataSource JDBC estándar.
Hay tres tipos de dataSources pre-construidos (ej. type=”????”):
UNPOOLED – Esta implementación de DataSource abre y cierra una conexión JDBC cada vez que se solcita una conexión. Aunque es un poco lento, es una buena elección para aplicaciones que no necesitan la velocidad de tener conexiones abiertas de forma inmediata. Las bases de datos tienen un rendimiento distinto en cuanto al rendimiento que aportan con este tipo de DataSource, para algunas de ellas no es muy importante tener un pool y por tanto esta configuración es apropiada. El DataSource UNPOOLED tiene cinco opciones de configuración:
Opcionalmente, puedes también pasar propiedades al driver de la base de datos. Para ello prefija las propiedades con “driver.”, por ejemplo:
Esto pasaría la propiedad “encoding” con el valor “UTF8” al driver de base datos mediante el método DriverManager.getConnection(url, driverProperties).
POOLED – Esta implementación de DataSource hace usa un pool de conexiones para evitar el tiempo necesario en realizar la conexión y autenticación cada vez que se solicita una nueva instancia de conexión. Este es un enfoque habitual en aplicaciones Web concurrentes para obtener el mejor tiempo de respuesta posible.
Además de las propiedades de (UNPOOLED) hay otras muchas propiedades que se pueden usar para configurar el DataSource POOLED:
JNDI – Esta implementación de DataSource está pensada para ser usada en contenedores como Spring o los servidores de aplicaciones JEE en los que es posible configurar un DataSource de forma externa y alojarlo en el contexto JNDI. Esta configuración de DataSource requiere solo dos propiedades:
Al igual que en las otras configuraciones de DataSource. Es posible enviar propiedades directamente al InitialContext prefijando las propiedades con “env.”, por ejemplo:
Enviará la propiedad “encoding” y el valor “UTF-8” al constructor del InitialContext durante su instanciación.
You can plug any 3rd party DataSource by implementing the interface org.apache.ibatis.datasource.DataSourceFactory:
public interface DataSourceFactory { void setProperties(Properties props); DataSource getDataSource(); }
The org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory puede extenderse para crear nuevos adaptadores. Por ejemplo, este es el código necesario para integrar C3P0:
import org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory; import com.mchange.v2.c3p0.ComboPooledDataSource; public class C3P0DataSourceFactory extends UnpooledDataSourceFactory { public C3P0DataSourceFactory() { this.dataSource = new ComboPooledDataSource(); } }
Para configurarlo, añade una propiedad por cada método al que quieres que llame MyBatis. A continuación se muestra una configuración de ejemplo para conectar con una base de datos PostgresSQL:
<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 puede ejeutar sentencias distintas en función del fabricante (vendor) de tu base de datos. El soporte de múltiples bases de datos se basa en el atributo de databaseId de los mapped statements. MyBatis cargará todos los statements que no tengan atributo databaseId attribute o aquellos cuyo databaseId coincida con el valor en curso. Si se encuentra un statement con y sin atributo databaseId el último se descartará. Para activar el soporte de multi vendor añade un databaseIdProvider al fichero mybatis-config.xml file de la siguiente forma:
<databaseIdProvider type="DB_VENDOR" />
La implementación DB_VENDOR del databaseIdProvider establece como databaseId el String devuelto por DatabaseMetaData#getDatabaseProductName(). Como normalmente este string es demasiado largo, y además, distintas versiones del mismo producto devuelven valores similares, puedes traducirlo a un valor más corto añadiendo propiedades de la siguente forma:
<databaseIdProvider type="DB_VENDOR"> <property name="SQL Server" value="sqlserver"/> <property name="DB2" value="db2"/> <property name="Oracle" value="oracle" /> </databaseIdProvider>
Cuando se añaden propiedades, el databaseIdProvider DB_VENDOR devuelve el primer valor que corresponde a la primera clave encontrada en el nombre devuelto por DatabaseMetaData#getDatabaseProductName() o "null" si no se encuentra ninguna. En este caso, si getDatabaseProductName() devuelve "Oracle (DataDirect)" el databaseId se informará con "oracle".
Puedes construir tu propio DatabaseIdProvider implementando la interfaz org.apache.ibatis.mapping.DatabaseIdProvider y registrandolo en el fichero mybatis-config.xml:
public interface DatabaseIdProvider { void setProperties(Properties p); String getDatabaseId(DataSource dataSource) throws SQLException; }
Ahora que se ha configurado el comportamiento de MyBatis con todos los elementos de configuración comentados estamos listos para definir los SQL mapped statements (sentencias SQL mapeadas). Primeramente necesitaremos indicarle a MyBatis dónde encontrarlos. Java no ofrece muchas posibilidades de auto-descubrimiento así que la mejor forma es simplemente decirle a MyBatis donde encontrar los ficheros de mapeo. Puedes utilizar referencias tipo classpath, o tipo path o referencias url completamente cualificadas (incluyendo file:///) . Por ejemplo:
<!-- 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>
Esta configuración sólo indica a MyBatis cuáles son los ficheros de mapeo. El resto de la configuración se encuentra dentro de estos ficheros, y eso es de lo que hablaremos en el siguiente apartado.