/
java-api.xml
627 lines (573 loc) · 44.3 KB
/
java-api.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2009-2020 the original author or authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<document xmlns="http://maven.apache.org/XDOC/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/XDOC/2.0 http://maven.apache.org/xsd/xdoc-2.0.xsd">
<properties>
<title>MyBatis 3 | Java API</title>
<author email="clinton.begin@gmail.com">Clinton Begin</author>
<author email="eduardo.macarron@gmail.com">Eduardo Macarron</author>
</properties>
<body>
<section name="Java API" id="javaApi">
<p>Ahora que ya conoces cómo configurar MyBatis y crear mapeos estás listo para lo mejor. El API Java es donde obtendrás los mejores frutos de tus esfuerzos. Como verás, comparado con JDBC, MyBatis simplifica enormemente tu código y lo mantiene limpio, de fácil comprensión y mantenimiento. MyBatis 3 incorpora muchas mejoras significativas para hacer que el trabajo con SQL Maps sea aun mejor.</p>
<subsection name="Directory Structure" id="directoryStructure">
<p>Antes de zambullirnos en el propio API Java , es importante comprender las mejores prácticas relativas a la estructura de directorios. MyBatis es muy flexible, y puedes hacer casi cualquier cosa con tus ficheros. Pero como en cualquier otro framework, hay una forma recomendable.</p>
<p>Veamos una estructura de directorios típica:</p>
<pre>/my_application
/bin
/devlib
<strong>/lib <tt><-- Los ficheros .jar de MyBatis van aqui.</tt></strong>
/src
/org/myapp/
/action
<strong>/data <tt><-- Los artefactos de MyBatis van aqui, lo que incluye, mappers, configuración XML, y ficheros de mapeo XML.</tt></strong>
/mybatis-config.xml
/BlogMapper.java
/BlogMapper.xml
/model
/service
/view
<strong>/properties <tt><-- Las Properties incluidas en tu configuración XML van aqui.</tt></strong>
/test
/org/myapp/
/action
/data
/model
/service
/view
/properties
/web
/WEB-INF
/web.xml</pre>
<p>Recuerda, esto son prefierncias no requisitos, pero habrá otros que te agradecerán que uses una estructura de directorios conún.</p>
<p>Los ejemplos restantes en esta sección asumen que estás utilizando esta estructura de directorios.</p>
</subsection>
<subsection name="SqlSessions" id="sqlSessions">
<p>El interfaz principal para trabajar con MyBatis es el SqlSession. A través de este interfaz puedes ejecutar comandos, obtener mappers y gestionar transacciones. Hablaremos más sobre el propio SqlSession en breve, pero primero veamos cómo obtener una instancia de SqlSession. Las SqlSessions se crean por una instancia de SqlSessionFactory. La SqlSessionFactory contiene métodos para crear instancias de SqlSessions de distintas formas. La SqlSessionFactory en si misma se crea por la SqlSessionFactoryBuilder que puede crear una SqlSessionFactory a partir de XML, anotaciones o un objeto Configuration creado por código.</p>
<p><span class="label important">NOTE</span> When using MyBatis with a dependency injection framework like Spring or Guice, SqlSessions are created and injected by the DI framework so you don't need to use the SqlSessionFactoryBuilder or SqlSessionFactory and can go directly to the SqlSession section. Please refer to the MyBatis-Spring or MyBatis-Guice manuals for further info.</p>
<h4>SqlSessionFactoryBuilder</h4>
<p>El SqlSessionFactoryBuilder tiene cinco métodos build(), cada cual permite construir una SqlSessionFactory desde un origen distinto.</p>
<source>SqlSessionFactory build(InputStream inputStream)
SqlSessionFactory build(InputStream inputStream, String environment)
SqlSessionFactory build(InputStream inputStream, Properties properties)
SqlSessionFactory build(InputStream inputStream, String env, Properties props)
SqlSessionFactory build(Configuration config)</source>
<p>Los primeros cuatro métodos son los más comunes, dado que reciben una instancia de InputStream que referencia a un documento XML, o más específicamente, al fichero SqlMapConfig.xml comentado anteriormente. Los parámetros opcionales son environment y properties. Environment determina qué entorno cargar, incluyendo el datasource y el gestor de transacciones. Por ejemplo:</p>
<source><![CDATA[<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
...
<dataSource type="POOLED">
...
</environment>
<environment id="production">
<transactionManager type="MANAGED">
...
<dataSource type="JNDI">
...
</environment>
</environments>]]></source>
<p>Si llamas al método build que recibe el parámetro environment, entonces MyBatis usará la configuración de dicho entorno. Por supuesto, si especificas un entorno inválido, recibirás un error. Si llamas a alguno de los métodos que no reciben el parámetro environment, entonces se utilizará el entorno por defecto (que es el especificado como default=”development” en el ejemplo anterior).</p>
<p>Si llamas a un método que recibe una instancia de properties, MyBatis cargará dichas properties y las hará accesibles desde tu configuración. Estas propiedades pueden usarse en lugar de la gran mayoría de los valores utilizando al sintaxis: ${propName}</p>
<p>Recuerda que las propiedades pueden también referenciarse desde el fichero SqlMapConfig.xml, o especificarse directamente en él. Por lo tanto es importante conocer las prioridades. Lo mencionamos anteriormente en este documento, pero lo volvemos a mencionar para facilitar la referencia.</p>
<hr/>
<p>Si una propiedad existe en más de un lugar, MyBatis la carga en el siguiente orden:</p>
<ul>
<li>Las propiedades especificadas en el cuerpo del elemento properties se cargan al principio.</li>
<li>Las propiedades cargadas desde los atributos resource/url del elemento properties se leen a continuación, y sobrescriben cualquier propiedad duplicada que hubiera sido cargada anteriormente.</li>
<li>Las propiedades pasadas como argumento se leen al final, y sobrescriben cualquier propiedad duplicada que hubiera sido cargada anteriormente.</li>
</ul>
<p>Por lo tanto la prioridad mayor es la de las propiedades pasadas como parámetro, seguidas por las especificadas en el atributo resource/url y finalmente las propiedades especificadas en el cuerpo del elemento properties.</p>
<hr/>
<p>Por tanto, para resumir, los primeros cuatro métodos son casi iguales pero te permiten opcionalmente especificar el environment y/o las propiedades. Aquí hay un ejemplo de cómo se construye un SqlSessionFactory desde un fichero mybatis-config.xml.</p>
<source>String <strong>resource</strong> = "org/mybatis/builder/mybatis-config.xml";
InputStream <strong>inputStream</strong> = Resources.getResourceAsStream(resource);
SqlSessionFactoryBuilder <strong>builder</strong> = new SqlSessionFactoryBuilder();
SqlSessionFactory <strong>factory</strong> = builder.build(inputStream);</source>
<p>Observa que estamos usando la clase de utilidad Resources, que está ubicada en el paquete org.mybatis.io. La clase Resources, tal y como su nombre indica, te ayuda a cargar recursos desde el classpath, el sistema de ficheros o desde una web o URL. Con un vistazo rápido al código fuente en tu IDE descubrirás un conjunto bastante obvio de métodos. Rápidamente:</p>
<source>URL getResourceURL(String resource)
URL getResourceURL(ClassLoader loader, String resource)
InputStream getResourceAsStream(String resource)
InputStream getResourceAsStream(ClassLoader loader, String resource)
Properties getResourceAsProperties(String resource)
Properties getResourceAsProperties(ClassLoader loader, String resource)
Reader getResourceAsReader(String resource)
Reader getResourceAsReader(ClassLoader loader, String resource)
File getResourceAsFile(String resource)
File getResourceAsFile(ClassLoader loader, String resource)
InputStream getUrlAsStream(String urlString)
Reader getUrlAsReader(String urlString)
Properties getUrlAsProperties(String urlString)
Class classForName(String className)</source>
<p>El último método build() recibe una instancia de Configuration. La clase Configuration contiene todo lo que posiblemente necesites conocer de la instancia de SqlSessionFactory. La clase Configuración es útil para investigar la configuración, incluido añadir o modificar SQL maps (no es recomendable una vez la aplicación ha comenzado a aceptar peticiones). La clase Configuration tiene todas las opciones de configuración que hemos visto ya pero expuestas como una API Java. A continuación se muestra un ejemplo simple de cómo instanciar manualmente un objeto Configuration y pasarlo al método build() para crear un SqlSessionFactory.</p>
<source>DataSource dataSource = BaseDataTest.createBlogDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.setLazyLoadingEnabled(true);
configuration.setEnhancementEnabled(true);
configuration.getTypeAliasRegistry().registerAlias(Blog.class);
configuration.getTypeAliasRegistry().registerAlias(Post.class);
configuration.getTypeAliasRegistry().registerAlias(Author.class);
configuration.addMapper(BoundBlogMapper.class);
configuration.addMapper(BoundAuthorMapper.class);
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(configuration);</source>
<p>Ahora tienes un SqlSessionFactory, que puede utilizarse para crear interfaces SqlSession.</p>
<h4>SqlSessionFactory</h4>
<p>SqlSessionFactory tiene seis métodos que se usan para crear instancias de SqlSession. En general, las decisiones que deberás tomar cuando tengas qué elegir de entre alguno de estos métodos son:</p>
<ul>
<li><strong>Transaction</strong>: ¿Quieres usar un ámbito transaccional para esta sesión o utilizar auto-commit (lo cual equivale a no usar transacción en la mayoría de las bases de datos y/o JDBC drivers)?</li>
<li><strong>Connection</strong>: ¿Quieres que MyBatis obtenga una conexión de un datasource o quieres proporcionar tu propia conexión?</li>
<li><strong>Execution</strong>: ¿Quieres que MyBatis reúse PreparedStatements y/o haga batch updates (incluyendo inserts y deletes)?</li>
</ul>
<p>El conjunto de métodos sobrecargados openSession te permiten seleccionar una combinación de estas opciones que tenga sentido.</p>
<source>SqlSession openSession()
SqlSession openSession(boolean autoCommit)
SqlSession openSession(Connection connection)
SqlSession openSession(TransactionIsolationLevel level)
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level)
SqlSession openSession(ExecutorType execType)
SqlSession openSession(ExecutorType execType, boolean autoCommit)
SqlSession openSession(ExecutorType execType, Connection connection)
Configuration getConfiguration();</source>
<p>El método openSession() por defecto que recibe parámetros crea una SqlSession con las siguientes características:</p>
<ul>
<li>Se arranca una transacción (NO auto-commit)</li>
<li>Se obtiene una conexión de una instancia de DataSource configurada en el environment activo.</li>
<li>El nivel de aislamiento transaccional será el que la base de datos tenga establecido por defecto.</li>
<li>No se reusaran PreparedStatements y no se realizarán actualizaciones batch.</li>
</ul>
<p>La mayoría de los métodos son auto explicativos. Para habilitar el auto-commit, pasa el valor “true” al parámetro opcional autoCommit. Para proporcionar tu propia conexión pasa una instancia de conexión al parámetro conexión. Ten en cuenta que no hay método para proporcionar tanto la conexión como el auto-commit porque MyBatis utilizará las opciones que esté usando actualmente la conexión suministrada. MyBatis usa una enumeration para indicar los niveles de aislamiento denominado TransactionIsolationLevel, pero funcionan como se espera de ellos y tiene los 5 niveles soportados por JDBC (NONE, READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE).</p>
<p>El único parámetro que puede ser nuevo para ti es el ExecutorType. Esta enumeración define tres valores:</p>
<ul>
<li><code>ExecutorType.SIMPLE</code>: Este tipo de executor no hace nada en especial. Crea un PreparedStatement para cada sentencia a ejecutar.</li>
<li><code>ExecutorType.REUSE</code>: Este tipo de executor reusará PreparedStatements.</li>
<li><code>ExecutorType.BATCH</code>: Este executor hará batch de todos las sentencias de actualización.</li>
</ul>
<p><span class="label important">NOTE</span> Hay un método más del SqlSessionFactory que no hemos mencionado y es getConfiguration(). Este método devuelve una instancia de Configuration que puedes usar para introspeccionar la configuración de MyBatis en tiempo de ejecución.</p>
<p><span class="label important">NOTE</span> Si has usado una versión anterior de MyBatis recordarás que las sesiones, transacciones y batches eran cosas separadas. Esto ya no es así, todas ellas están contenidas en el interfaz SqlSession. No tienes que gestionar las transacciones o los batches de forma separada para obtener todo su potencial.</p>
<h4>SqlSession</h4>
<p>Como hemos comentado anteriormente, la instancia de SqlSession es la clase más potente de MyBatis. Es donde encontrarás todos los métodos para ejecutar sentencias, hacer commit o rollback de transacciones y obtener mappers.</p>
<p>Hay más de veinte métodos en la clase SqlSession, así que vayamos dividiéndolos en grupo fáciles de digerir.</p>
<h5>Métodos de ejecución de sentencias</h5>
<p>Estos métodos se usan para ejecutar las sentencias SELECT, INSERT, UPDATE y DELETE que se hayan definido en los ficheros xml de mapeo SQL. Son bastante auto explicativos, cada uno recibe el ID del statement y el objeto de parámetro, que puede ser una primitiva, un JavaBean, un POJO o un Map.</p>
<source><![CDATA[<T> T selectOne(String statement, Object parameter)
<E> List<E> selectList(String statement, Object parameter)
<T> Cursor<T> selectCursor(String statement, Object parameter)
<K,V> Map<K,V> selectMap(String statement, Object parameter, String mapKey)
int insert(String statement, Object parameter)
int update(String statement, Object parameter)
int delete(String statement, Object parameter)]]></source>
<p>La diferencia entre selectOne y selectList es que selectOne debe devolver sólo un objeto. Si hay más de uno se lanzará una excepción. Si no hay ninguno se devolverá null. Si no sabes cuantos objetos esperas recibir, usa selectList. Si quieres comprobar la existencia de un objeto sería mejor que devuelvas un count(). SelectMap es un caso especial diseñado para convertir una lista de resultados en un Map basado en las propiedades de los objetos recibidos. Como no todas las sentencias requieren un parámetro, estos métodos han sido sobrecargados de forma que se proporcionan versiones que no reciben el parámetro objeto.</p>
<p>El valor devuelto por los métodos insert, update and delete indica el número de filas afectadas por la sentencia.</p>
<source><![CDATA[<T> T selectOne(String statement)
<E> List<E> selectList(String statement)
<T> Cursor<T> selectCursor(String statement)
<K,V> Map<K,V> selectMap(String statement, String mapKey)
int insert(String statement)
int update(String statement)
int delete(String statement)]]></source>
<p>A Cursor offers the same results as a List, except it fetches data lazily using an Iterator.</p>
<source><![CDATA[try (Cursor<MyEntity> entities = session.selectCursor(statement, param)) {
for (MyEntity entity:entities) {
// process one entity
}
}]]></source>
<p>Finalmente hay tres versiones avanzadas de los métodos select que te permiten restringir el rango de filas devueltas, o proporcionar lógica de tratamiento de resultados personalizada, normalmente para grandes cantidades de datos.</p>
<source><![CDATA[<E> List<E> selectList (String statement, Object parameter, RowBounds rowBounds)
<T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds)
<K,V> Map<K,V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowbounds)
void select (String statement, Object parameter, ResultHandler<T> handler)
void select (String statement, Object parameter, RowBounds rowBounds, ResultHandler<T> handler)]]></source>
<p>El parámetro RowBounds hace que MyBatis salte los registros especificados y que limite los resultados devueltos a cierto número. La clase RowBounds tiene un constructor que recibe ambos el offset y el limit, y es inmutable.</p>
<source>int offset = 100;
int limit = 25;
RowBounds rowBounds = new RowBounds(offset, limit);</source>
<p>El rendimiento de algunos drivers puede variar mucho en este aspecto. Para un rendimiento optimo, usa tipos de ResultSet SCROLL_SENSITIVE o SCROLL_INSENSITIVE (es decir, no FORWARD_ONLY)</p>
<p>El parámetro ResultHandler te permite manejar cada fila como tú quieras. Puedes añadirla a una lista, crear un Map, un Set, o descartar cada resultado y guardar solo cálculos. Puedes hacer casi todo lo que quieras con un ResultHandler, de hecho, es lo que MyBatis usa internamente para construir listas de ResultSets.</p>
<p>Since 3.4.6, ResultHandler passed to a CALLABLE statement is used on every REFCURSOR output parameter of the stored procedure if there is any.</p>
<p>La interfaz es muy sencilla:</p>
<source><![CDATA[package org.apache.ibatis.session;
public interface ResultHandler<T> {
void handleResult(ResultContext<? extends T> context);
}]]></source>
<p>El parámetro ResultContext te da acceso al objeto resultado en sí mismo, un contador del número de objetos creados y un método booleano stop() que te permite indicar a MyBatis que pare la carga de datos.</p>
<p>Using a ResultHandler has two limitations that you should be aware of:</p>
<ul>
<li>Data got from an method called with a ResultHandler will not be cached.</li>
<li>When using advanced resultmaps MyBatis will probably require several rows to build an object. If a ResultHandler is used you may be given an object whose associations or collections are not yet filled.</li>
</ul>
<h5>Batch update statement Flush Method</h5>
<p>There is method for flushing(executing) batch update statements that stored in a JDBC driver class at any timing. This method can be used when you use the <code>ExecutorType.BATCH</code> as <code>ExecutorType</code>.</p>
<source><![CDATA[List<BatchResult> flushStatements()]]></source>
<h5>Métodos de control de transacción</h5>
<p>El parámetro ResultContext te da acceso al objeto resultado en sí mismo, un contador del número de objetos creados y un método booleano stop() que te permite indicar a MyBatis que pare la carga de datos.</p>
<source>void commit()
void commit(boolean force)
void rollback()
void rollback(boolean force)</source>
<p>Por defecto MyBatis no hace un commit a no ser que haya detectado que la base de datos ha sido modificada por una insert, update o delete. Si has realizado cambios sin llamar a estos métodos, entonces puedes pasar true en al método de commit() y rollback() para asegurar que se realiza el commit (ten en cuenta que aun así no puedes forzar el commit() en modo auto-commit o cuando se usa un gestor de transacciones externo). La mayoría de las veces no tendrás que llamar a rollback() dado que MyBatis lo hará por ti en caso de que no hayas llamado a commit(). Sin embargo, si necesitas un control más fino sobre la sesión, donde puede que haya varios commits, tienes esta opción para hacerlo posible.</p>
<p><span class="label important">NOTA</span> MyBatis-Spring y MyBatis-Guice proporcionan gestión de transacción declarativa. Por tanto si estás usando MyBatis con Spring o Guice consulta sus manuales específicos.</p>
<h5>Local Cache</h5>
<p>MyBatis utliza dos cachés: la caché local y la caché de segundo nivel.</p>
<p>Cada vez que se crea una sesión MyBatis crea una cache local y la asocia a dicha sesión. Cualquier query que se ejecute en la sesión será cacheada de forma que si en el futuro se vuelve a lanzar la misma query con los mismos parámetros de entrada los datos se obtendrán de la caché y no se accederá a la base de datos. La caché local se vacía cuando se ejecuta cupdate, commit, rollback y close.</p>
<p>Por defecto la cache local se utiliza durante toda la duración de la sesión. Esta cache es necesaria para resolver dependencias circulares y para acelerar consultas anidadas repetidas asi que no puede desactivarse, pero puede configurarse para que se utilize sólo durante la duración de la ejecución de una sentencia infomando el parámetro de configuración localCacheScope=STATEMENT.</p>
<p>Cuando localCacheScope está informado a SESSION (valor por defecto) MyBatis devuelve referencias a objetos objetos almacenados en la caché. Cualquier modificación de un objeto (listas etc.) influye en el contenido de la caché y en los valores que serán retornados posteriormente durante la existencia de la sessión. Por lo tanto, como mejor práctica, evita modificaciones sobre los objetos devueltos por MyBatis.</p>
<p>Puedes borrar el contenido de la caché local en el momento que desees invocando:</p>
<source>void clearCache()</source>
<h5>Asegurarse de que la SqlSession se cierra</h5>
<source>void close()</source>
<p>El punto más importante del que debes asegurarte es que cierras todas las sesiones que abres. La mejor forma de asegurarse es usar el patrón mostrado a continuación:</p>
<source>try (SqlSession session = sqlSessionFactory.openSession()) {
// following 3 lines pseudocod for "doing some work"
session.insert(...);
session.update(...);
session.delete(...);
session.commit();
}</source>
<p><span class="label important">NOTE</span> Al igual que con SqlSessionFactory, puedes obtener la instancia de Configuration que está usando al SqlSession llamando al método getConfiguration().</p>
<source>Configuration getConfiguration()</source>
<h5>Uso de Mappers</h5>
<source><![CDATA[<T> T getMapper(Class<T> type)]]></source>
<p>Aunque los métodos insert, update, delete y select son potentes, también son muy verbosos, no hay seguridad de tipos (type safety) y no son tan apropiados para tu IDE o tus pruebas unitarias como pudieran ser. Ya hemos visto un ejemplo de uso de mappers en la sección de primeros pasos.</p>
<p>Por lo tanto, una forma más común de ejecutar mapped statements es utilizar clases Mapper. Un mapper es simplemente una interfaz con definiciones de métodos que se hacen encajar con métodos de SqlSession. El ejemplo siguiente demuestra algunas firmas de método y como se asignan a una SqlSession.</p>
<source><![CDATA[public interface AuthorMapper {
// (Author) selectOne("selectAuthor",5);
Author selectAuthor(int id);
// (List<Author>) selectList(“selectAuthors”)
List<Author> selectAuthors();
// (Map<Integer,Author>) selectMap("selectAuthors", "id")
@MapKey("id")
Map<Integer, Author> selectAuthors();
// insert("insertAuthor", author)
int insertAuthor(Author author);
// updateAuthor("updateAuthor", author)
int updateAuthor(Author author);
// delete("deleteAuthor",5)
int deleteAuthor(int id);
}]]></source>
<p>En resumen, cada firma de método de mapper se asigna al método de la SqlSession al que está asociado pero sin parámetro ID. En su lugar el nombre del método debe ser el mismo que el ID del mapped statement.</p>
<p>Además, el tipo devuelto debe ser igual que el result type del mapped statement. Todos los tipos habituales se soportan, incluyendo primitivas, mapas, POJOs y JavaBeans.</p>
<p><span class="label important">NOTA</span> Los mappers no necesitan implementar ninguna interfaz o extender ninguna clase. Sólo es necesario que la firma de método pueda usarse para identificar unívocamente el mapped statement correspondiente.</p>
<p><span class="label important">NOTA</span> Los mappers pueden extender otras interfaces. Asegúrate que tienes tus statements en los namespaces adecuados en tu fichero XML. Además, la única limitación es que no puedes tener el mismo método, con la misma firma, en dos interfaces de la jerarquía (una mala idea en cualquier caso).</p>
<p>Puedes pasar más de un parámetro a un método de un mapper. Si lo haces, se usará como nombre el literal "param" seguido de su posición en la lista de parámetros, por ejemplo: #{param1}, #{param2} etc. Si quieres cambiar su nombre (solo en caso de parámetros múltiples) puedes usar la notación @Param(“paramName”).</p>
<p>También puedes pasar una instancia de RowBounds al método para limitar los resultados.</p>
<h5>Anotaciones de mappers</h5>
<p>Desde sus comienzos, MyBatis ha sido siempre un framework XML. La configuración se basa en XML y los mapped statements se definen en XML. Con MyBatis 3, hay más opciones. MyBatis 3 se ha desarrollado sobre una exhaustiva y potente API de configuración Java. Este API es el fundamento de la configuración basada en XML y también de la nueva configuración basada en anotaciones. Las anotaciones simplemente ofrecen una forma más sencilla de implementar los mapped statements sin introducir un montón de sobrecarga.</p>
<p><span class="label important">NOTE</span> Las anotaciones Java son desafortunadamente muy limitadas en su flexibilidad y expresividad. A pesar de haber dedicado mucho tiempo a la investigación, diseño y pruebas, los mapeos más potentes de MyBatis simplemente no es posible construirlos con anotaciones. Los atributos C# (por ejemplo) no sufren de las mismas limitaciones y por tanto MyBatis.NET podrá construir una alternativa mucho más rica al XML. Dicho esto, la configuración basada en anotaciones Java también tiene sus ventajas.</p>
<p><strong>Las anotaciones son las siguientes:</strong></p>
<table>
<thead>
<tr>
<th>Anotación</th>
<th>Target</th>
<th>XML equivalente</th>
<th>Descripción</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>@CacheNamespace</code></td>
<td><code>Class</code></td>
<td><code><cache></code></td>
<td>Configura la cache para un namespace (una clase). Atributos: implementation, eviction, flushInterval, size, readWrite, blocking and properties.</td>
</tr>
<tr>
<td><code>@Property</code></td>
<td>N/A</td>
<td><code><property></code></td>
<td>Specifies the property value or placeholder(can replace by configuration properties that defined at the <code>mybatis-config.xml</code>). Attributes: <code>name</code>, <code>value</code>. (Available on MyBatis 3.4.2+)</td>
</tr>
<tr>
<td><code>@CacheNamespaceRef</code></td>
<td><code>Class</code></td>
<td><code><cacheRef></code></td>
<td>
Referencia una cache de otro namespace. Note that caches declared in an XML mapper file are considered a separate namespace, even if they share the same FQCN. Atributos: <code>value</code> and <code>name</code>.
If you use this annotation, you should be specified either <code>value</code> or <code>name</code> attribute.
For the <code>value</code> attribute specify a java type indicating the namespace(the namespace name become a FQCN of specified java type),
and for the <code>name</code> attribute(this attribute is available since 3.4.2) specify a name indicating the namespace.
</td>
</tr>
<tr>
<td><code>@ConstructorArgs</code></td>
<td><code>Method</code></td>
<td><code><constructor></code></td>
<td>Agrupa un conjunto de resultados que serán pasados al constructor de un objeto de resultado. Atributos: value, que es un array de Args.</td>
</tr>
<tr>
<td><code>@Arg</code></td>
<td>N/A</td>
<td>
<ul>
<li><code><arg></code></li>
<li><code><idArg></code></li>
</ul>
</td>
<td>Un argumento que es parte de un ConstructorArgs. Atributos: id, column, javaType, jdbcType, typeHandler, select and resultMap. El atributo id es un valor booleano que identifica la propiedad que será usada en las comparaciones, parecido al elemento XML <idArg>. Since 3.5.4, it can be used as repeatable annotation.</td>
</tr>
<tr>
<td><code>@TypeDiscriminator</code></td>
<td><code>Method</code></td>
<td><code><discriminator></code></td>
<td>Un grupo de clases que se pueden usar para determinar que mapeo de resultados realizar. Atributos: column, javaType, jdbcType, typeHandler, cases. El atributo cases es un array de Cases.</td>
</tr>
<tr>
<td><code>@Case</code></td>
<td>N/A</td>
<td><code><case></code></td>
<td>Un caso concreto y su mapeo correspondiente. Atributos: value, type, results. El atributo results es un array de Results, por tanto esta anotación Case es similar a un ResultMap, que se especifica mediante la anotación Results a continuación.</td>
</tr>
<tr>
<td><code>@Results</code></td>
<td><code>Method</code></td>
<td><code><resultMap></code></td>
<td>Una lista de Result mapping que contiene los detalles de cómo una columna particular se mapea a una propiedad o campo. Atributos: value, id. El atributo value es un array de anotaciones Result. The id attribute is the name of the result mapping.</td>
</tr>
<tr>
<td><code>@Result</code></td>
<td>N/A</td>
<td>
<ul>
<li><code><result></code></li>
<li><code><id></code></li>
</ul>
</td>
<td>Un result mapping entre una columna y una propiedad o campo. Atributos: : id, column, property, javaType, jdbcType, typeHandler, one, many. El atributo id es un valor booleano que indica que la propiedad debe usarse en comparaciones (similar al <id> de los mapeos XML). El atributo one sirve para asociaciones de simples, similar al <association>, y el atributo many es para colecciones, similar al <collection>. Sus denominaciones son tales para evitar conflictos con nombres de clases. Since 3.5.4, it can be used as repeatable annotation.</td>
</tr>
<tr>
<td><code>@One</code></td>
<td>N/A</td>
<td><code><association></code></td>
<td>
Un mapeo a una propiedad que contiene un tipo complejo. Atributos: select, que contiene el nombre completamente cualificado de un mapped statement (o un método de mapper) que puede cargar la instancia del tipo indicado.
<code>fetchType</code>, que sobrescribe el parámetro global de configuración <code>lazyLoadingEnabled</code> para este mapeo.
<code>resultMap</code>(available since 3.5.5), which is the fully qualified name of a result map that map to a single container object from select result.
Nota: Habrás visto que el mapeo de tipo join no se soporta mediante el API de anotaciones. Esto es debido a las limitaciones de las anotaciones en Java que no permiten referencias circulares.</td>
</tr>
<tr>
<td><code>@Many</code></td>
<td>N/A</td>
<td><code><collection></code></td>
<td>Un mapeo a una propiedad que contiene una colección de tipos complejos. Atributos: select, que contiene el nombre completamente cualificado de un mapped statement (o un método de mapper) que puede cargar la instancia del tipo indicado.
<code>fetchType</code>, que sobrescribe el parámetro global de configuración <code>lazyLoadingEnabled</code> para este mapeo.
<code>resultMap</code>(available since 3.5.5), which is the fully qualified name of a result map that map to collection object from select result.
Nota: Habrás visto que el mapeo de tipo join no se soporta mediante el API de anotaciones. Esto es debido a las limitaciones de las anotaciones en Java que no permiten referencias circulares.</td>
</tr>
<tr>
<td><code>@MapKey</code></td>
<td><code>Method</code></td>
<td> </td>
<td>Se usa en métodos cuyo tipo de retorno es Map. Se usa para convertir una Lista de objetos de resultado a un Map basándose en una propiedad de dichos objetos.</td>
</tr>
<tr>
<td><code>@Options</code></td>
<td><code>Method</code></td>
<td>Attributes of mapped statements.</td>
<td>Esta anotación proporciona acceso a un gran conjunto de opciones de configuración que normalmente aparecen como atributos en los mapped statements. En lugar de complicar cada anotación existente la anotación Options proporciona una forma sencilla y concisa de acceder a estas opciones. Atributos: useCache=true, flushCache=FlushCachePolicy.DEFAULT, resultSetType=DEFAULT, statementType=PREPARED, fetchSize=-1, timeout=-1, useGeneratedKeys=false, keyProperty=“”, keyColumn=“”, resultSets=“”. Es importante comprender que las anotaciones en Java no permiten indicar un valor nulo. Por lo tanto, cuando usas la anotación Options el statement usará todos los valores por defecto. Presta atención a estos valores pro defecto para evitar comportamientos inesperados. La keyColumn solo se requiere para algunas bases de datos (como PostgreSQL) cuando la columna no es la primera columna de la tabla.</td>
</tr>
<tr>
<td>
<ul>
<li><code>@Insert</code></li>
<li><code>@Update</code></li>
<li><code>@Delete</code></li>
<li><code>@Select</code></li>
</ul>
</td>
<td><code>Method</code></td>
<td>
<ul>
<li><code><insert></code></li>
<li><code><update></code></li>
<li><code><delete></code></li>
<li><code><select></code></li>
</ul>
</td>
<td>Cada una de estas anotaciones representa el SQL que debe ejecutarse. Cada una de ellas recibe un array de strings (o un solo string). Si se pasa un array de strings, todos ellos se concatenarán introduciendo un espacio en blanco entre ellos. Esto ayuda a evitar el problema “falta un espacio en blanco” al construir SQL en código Java. Sin embargo, también puedes concatenarlos en un solo string si lo prefieres. Atributos: value, que es el array de String para formar una única sentencia SQL.</td>
</tr>
<tr>
<td>
<ul>
<li><code>@InsertProvider</code></li>
<li><code>@UpdateProvider</code></li>
<li><code>@DeleteProvider</code></li>
<li><code>@SelectProvider</code></li>
</ul>
</td>
<td><code>Method</code></td>
<td>
<ul>
<li><code><insert></code></li>
<li><code><update></code></li>
<li><code><delete></code></li>
<li><code><select></code></li>
</ul>
</td>
<td>Estas anotaciones SQL alternativas te permiten especificar un nombre de clases y un método que devolverán la SQL que debe ejecutarse (Since 3.4.6, you can specify the <code>CharSequence</code> instead of <code>String</code> as a method return type).
Cuando se ejecute el método MyBatis instanciará la clase y ejecutará el método especificados en el provider. You can pass objects that passed to arguments of a mapper method, "Mapper interface type", "Mapper method" and "Database ID"
via the <code>ProviderContext</code>(available since MyBatis 3.4.5 or later) as method argument.(In MyBatis 3.4 or later, it's allow multiple parameters)
Atributos: value, type y method.
El atributo value y type es el nombre completamente cualificado de una clase
(The <code>type</code> attribute is alias for <code>value</code>, you must be specify either one).
El method es el nombre un método de dicha clase
(Since 3.5.1, you can omit <code>method</code> attribute, the MyBatis will resolve a target method via the
<code>ProviderMethodResolver</code> interface.
If not resolve by it, the MyBatis use the reserved fallback method that named <code>provideSql</code>).
Nota: A continuación hay una sección sobre la clase, que puede ayudar a construir SQL dinámico de una forma más clara y sencilla de leer.</td>
</tr>
<tr>
<td><code>@Param</code></td>
<td><code>Parameter</code></td>
<td>N/A</td>
<td>Si tu mapper recibe parámetros múltiples, esta anotación puede aplicarse a cada parámetro para proporcionarle un nombre. En caso contrario, los parámetros múltiples se nombrarán según su posición (sin incluir el parámetro RowBounds), prefijados con "param". Por ejemplo: #{param1}, #{param2} etc. es el defecto. Con @Param(“persona”), el parámetro se llamará #{persona}.</td>
</tr>
<tr>
<td><code>@SelectKey</code></td>
<td><code>Method</code></td>
<td><code><selectKey></code></td>
<td>Esta anotación es igual que la <selectKey> para métodos anotados con @Insert, @InsertProvider, @Update o @UpdateProvider. Se ignora en otros métodos. Si especificas la anotación @SelectKey, entonces MyBatis ignorará todas las propiedades de generación de claves proporcionadas por la anotación @Options, o mediante propiedades de configuración. Atributos: statement un array de strings que contienen la SQL a ejecutar, keyProperty que es la propiedad del objeto parámetro que se actualizará con el Nuevo valor, before que debe valer true o false para indicar si la sentencia SQL debe ejecutarse antes o después de la insert, resultType que es el tipo de la propiedad keyProperty, y statementType=PREPARED.</td>
</tr>
<tr>
<td><code>@ResultMap</code></td>
<td><code>Method</code></td>
<td>N/A</td>
<td>Esta anotación se usa para proporcionar el id de un elemento <resultMap> en un mapper XML a una anotación @Select o @SelectProvider. Esto permite a las selects anotadas reusar resultmaps definidas en XML. Esta anotación sobrescribe las anotaciones @Result o @ConstructorArgs en caso de que se hayan especificado en la select anotada.</td>
</tr>
<tr>
<td><code>@ResultType</code></td>
<td><code>Method</code></td>
<td>N/A</td>
<td>Esta anotación se usa cuando se utiliza un result handler. En ese caso, el tipo devuelto por el método es void y
MyBatis no puede determinar el tipo del objeto que debe construir para cada fila.
Si hay un result map XML entonces se utiliza la anotación @ResultMap. Si el tipo de retorno se especifica en el
elemento <code><select></code> del XML entonces no es necesaria ninguna otra anotación.
En el resto de casos, usa esta anotación. Por ejemplo en un método anotado con @Select con un result handler
el valor de retorno será void y por tanto se requiere incluir esta anotación (o @ResultMap).
La anotación se ignora si el tipo devuelto por el méotdo no es void.</td>
</tr>
<tr>
<td><code>@Flush</code></td>
<td><code>Method</code></td>
<td>N/A</td>
<td>If this annotation is used, it can be called the <code>SqlSession#flushStatements()</code> via method defined at a Mapper interface.(MyBatis 3.3 or above)</td>
</tr>
</tbody>
</table>
<h5>Ejemplos de mappers anotados</h5>
<p>Este ejemplo muestra como se usa la anotación @SelectKey para obtener un valor de una secuencia antes de de una insert:</p>
<source>@Insert("insert into table3 (id, name) values(#{nameId}, #{name})")
@SelectKey(statement="call next value for TestSequence", keyProperty="nameId", before=<strong>true</strong>, resultType=<strong>int.class</strong>)
<strong>int</strong> insertTable3(Name name);</source>
<p>Este ejemplo muestra como se usa la anotación @SelectKey para obtener el valor de una identity después de una insert:</p>
<source>@Insert("insert into table2 (name) values(#{name})")
@SelectKey(statement="call identity()", keyProperty="nameId", before=<strong>false</strong>, resultType=<strong>int.class</strong>)
<strong>int</strong> insertTable2(Name name);</source>
<p>This example shows using the <code>@Flush</code> annotation to call the <code>SqlSession#flushStatements()</code>:</p>
<source><![CDATA[@Flush
List<BatchResult> flush();]]></source>
<p>These examples show how to name a ResultMap by specifying id attribute of @Results annotation.</p>
<source>@Results(id = "userResult", value = {
@Result(property = "id", column = "uid", id = <strong>true</strong>),
@Result(property = "firstName", column = "first_name"),
@Result(property = "lastName", column = "last_name")
})
@Select("select * from users where id = #{id}")
User getUserById(Integer id);
@Results(id = "companyResults")
@ConstructorArgs({
@Arg(column = "cid", javaType = Integer.class, id = <strong>true</strong>),
@Arg(column = "name", javaType = String.class)
})
@Select("select * from company where id = #{id}")
Company getCompanyById(Integer id);</source>
<p>This example shows solo parameter using the Sql Provider annotation:</p>
<source><![CDATA[@SelectProvider(type = UserSqlBuilder.class, method = "buildGetUsersByName")
List<User> getUsersByName(String name);
class UserSqlBuilder {
public static String buildGetUsersByName(final String name) {
return new SQL(){{
SELECT("*");
FROM("users");
if (name != null) {
WHERE("name like #{value} || '%'");
}
ORDER_BY("id");
}}.toString();
}
}]]></source>
<p>This example shows multiple parameters using the Sql Provider annotation:</p>
<source><![CDATA[@SelectProvider(type = UserSqlBuilder.class, method = "buildGetUsersByName")
List<User> getUsersByName(
@Param("name") String name, @Param("orderByColumn") String orderByColumn);
class UserSqlBuilder {
// If not use @Param, you should be define same arguments with mapper method
public static String buildGetUsersByName(
final String name, final String orderByColumn) {
return new SQL(){{
SELECT("*");
FROM("users");
WHERE("name like #{name} || '%'");
ORDER_BY(orderByColumn);
}}.toString();
}
// If use @Param, you can define only arguments to be used
public static String buildGetUsersByName(@Param("orderByColumn") final String orderByColumn) {
return new SQL(){{
SELECT("*");
FROM("users");
WHERE("name like #{name} || '%'");
ORDER_BY(orderByColumn);
}}.toString();
}
}]]></source>
<p>This example shows usage the default implementation of <code>ProviderMethodResolver</code>(available since MyBatis 3.5.1 or later):</p>
<source><![CDATA[@SelectProvider(type = UserSqlProvider.class)
List<User> getUsersByName(String name);
// Implements the ProviderMethodResolver on your provider class
class UserSqlProvider implements ProviderMethodResolver {
// In default implementation, it will resolve a method that method name is matched with mapper method
public static String getUsersByName(final String name) {
return new SQL(){{
SELECT("*");
FROM("users");
if (name != null) {
WHERE("name like #{value} || '%'");
}
ORDER_BY("id");
}}.toString();
}
}]]></source>
<p>This example shows usage the default implementation of <code>ProviderMethodResolver</code>(available since MyBatis 3.5.1 or later):</p>
<source><![CDATA[@SelectProvider(UserSqlProvider.class)
List<User> getUsersByName(String name);
// Implements the ProviderMethodResolver on your provider class
class UserSqlProvider implements ProviderMethodResolver {
// In default implementation, it will resolve a method that method name is matched with mapper method
public static String getUsersByName(final String name) {
return new SQL(){{
SELECT("*");
FROM("users");
if (name != null) {
WHERE("name like #{value} || '%'");
}
ORDER_BY("id");
}}.toString();
}
}]]></source>
</subsection>
</section>
</body>
</document>