forked from mybatis/mybatis-3
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgetting-started.html
650 lines (532 loc) · 25.6 KB
/
getting-started.html
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
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
<!DOCTYPE html>
<!--
| Generated by Apache Maven Doxia at 10 octubre 2014
| Rendered using Apache Maven Fluido Skin 1.3.1
-->
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="es" lang="es">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="author" content="Clinton Begin" />
<meta name="author" content="Eduardo Macarron" />
<meta name="Date-Revision-yyyymmdd" content="20141010" />
<meta http-equiv="Content-Language" content="es" />
<title>MyBatis -
MyBatis 3 | Primeros pasos</title>
<link rel="stylesheet" href="./css/apache-maven-fluido-1.3.1.min.css" />
<link rel="stylesheet" href="./css/site.css" />
<link rel="stylesheet" href="./css/print.css" media="print" />
<script type="text/javascript" src="./js/apache-maven-fluido-1.3.1.min.js"></script>
</head>
<body class="topBarDisabled">
<div class="container-fluid">
<div id="banner">
<div class="pull-left">
<div id="bannerLeft">
<h2>MyBatis</h2>
</div>
</div>
<div class="pull-right"> <a href="../../" id="bannerRight" title="MyBatis logo">
<img src="http://mybatis.github.io/images/mybatis-logo.png" alt="MyBatis logo"/>
</a>
</div>
<div class="clear"><hr/></div>
</div>
<div id="breadcrumbs">
<ul class="breadcrumb">
<li id="publishDate">Publicado el: 10 octubre 2014
<span class="divider">|</span>
</li>
<li id="projectVersion">Versión: 3.2.8
</li>
</ul>
</div>
<div class="row-fluid">
<div id="leftColumn" class="span3">
<div class="well sidebar-nav">
<ul class="nav nav-list">
<li class="nav-header">Manual de Referencia</li>
<li>
<a href="index.html" title="Introducción">
<i class="none"></i>
Introducción</a>
</li>
<li class="active">
<a href="#"><i class="none"></i>Primeros pasos</a>
</li>
<li>
<a href="configuration.html" title="Configuración">
<i class="icon-chevron-right"></i>
Configuración</a>
</li>
<li>
<a href="sqlmap-xml.html" title="Ficheros XML de mapeo">
<i class="icon-chevron-right"></i>
Ficheros XML de mapeo</a>
</li>
<li>
<a href="dynamic-sql.html" title="SQL dinámico">
<i class="none"></i>
SQL dinámico</a>
</li>
<li>
<a href="java-api.html" title="Java API">
<i class="icon-chevron-right"></i>
Java API</a>
</li>
<li>
<a href="statement-builders.html" title="La clase SQL">
<i class="none"></i>
La clase SQL</a>
</li>
<li>
<a href="logging.html" title="Logging">
<i class="none"></i>
Logging</a>
</li>
<li class="nav-header">Documentación del proyecto</li>
<li>
<a href="project-info.html" title="Información del proyecto">
<i class="icon-chevron-right"></i>
Información del proyecto</a>
</li>
<li>
<a href="project-reports.html" title="Informes del proyecto">
<i class="icon-chevron-right"></i>
Informes del proyecto</a>
</li>
</ul>
<hr />
<div id="poweredBy">
<div class="clear"></div>
<div class="clear"></div>
<div class="clear"></div>
<div class="clear"></div>
<a href="http://maven.apache.org/" title="Generado por Maven" class="poweredBy">
<img class="builtBy" alt="Generado por Maven" src="./images/logos/maven-feather.png" />
</a>
</div>
</div>
</div>
<div id="bodyColumn" class="span9" >
<!-- Copyright 2010-2012 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. --><!-- version: $Id $ -->
<div class="section">
<h2>Primeros pasos<a name="Primeros_pasos"></a></h2>
<div class="section">
<h3>Instalación<a name="Instalacin"></a></h3>
<p>
Para usar MyBatis sólo tienes que incluir el fichero
<tt>
mybatis-x.x.x.jar
</tt>
en el classpath.
</p>
<p>
Si usas Maven añade esta dependencia en tu pom.xml:
</p>
<div class="source">
<pre>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>x.x.x</version>
</dependency></pre></div>
</div>
<div class="section">
<h3>Cómo crear un SqlSessionFactory a partir de XML<a name="Cmo_crear_un_SqlSessionFactory_a_partir_de_XML"></a></h3>
<p>
Una aplicación que usa MyBatis debe utilizar una instancia de
SqlSessionFactory. Se puede obtener una instancia de
SqlSessionFactory mediante un SqlSessionFactoryBuilder. Un
SqlSessionFactoryBuilder
puede construir una instancia de SqlSessionFactory a partir de un fichero
de configuración XML o de una
instancia personalizada de la clase Configuration.
</p>
<p>
Crear una instancia SqlSessionFactory desde un fichero xml es muy
sencillo. Se recomienda usar un
classpath resource, pero es posible usar cualquier InputStream, incluso
creado con un path de fichero o una
URL de tipo file://. MyBatis proporciona una clase de utilidad,
llamada Resources, que contiene métodos
que simplifican la carga de recursos desde el classpath u otras
ubicaciones.
</p>
<div class="source">
<pre>
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);</pre></div>
<p>
El fichero de configuración XML contiene la configuración del
<i>core</i>
de MyBatis, incluyendo el DataSource
para obtener instancias de conexión a la base de datos y también un
TransactionManager para
determinar cómo deben controlarse las transacciones. Los detalles completos
de la configuración XML
se describen más adelante en este documento, pero continuación se
muestra un ejemplo sencillo:
</p>
<div class="source">
<pre><?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<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>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration></pre></div>
<p>
Aunque hay mucha más información sobre el fichero de configuración XML,
el ejemplo anterior contiene
las partes más importantes. Observa que hay una cabecera XML,
requerida para validar el fichero XML.
El cuerpo del elemento environment contiene la configuración de la
gestión de transacciones
correspondiente al entorno. El elemento mappers contiene la lista de mappers – Los
ficheros XML que
contienen las sentencias SQL y las definiciones de mapeo.
</p>
</div>
<div class="section">
<h3>Cómo crear un SqlSessionFactory sin XML<a name="Cmo_crear_un_SqlSessionFactory_sin_XML"></a></h3>
<p>
Si lo prefieres puedes crear la configuración directamente desde
Java, en lugar de desde XML, o crear tu
propio
<i>builder</i>
. MyBatis dispone una clase Configuration que proporciona las
mismas opciones de
configuración que el fichero XML.
</p>
<div class="source">
<pre>DataSource dataSource = BlogDataSourceFactory.getBlogDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(BlogMapper.class);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);</pre></div>
<p>
Puedes observar que en este caso la configuración está añadiendo una
clase mapper. Las clases mapper
son clases Java que contienen anotaciones de mapeo SQL que permiten
evitar el uso de XML. Sin
embargo el XML sigue siendo necesario en ocasiones, debido a ciertas
limitaciones de las anotaciones
Java y la complejidad que pueden alcanzar los mapeos (ej. mapeos
anidados de Joins). Por esto, MyBatis
siempre busca si existe un fichero XML asociado a la clase mapper (en este
caso, se buscará un fichero
con nombre BlogMapper.xml cuyo nombre deriva del classpath y nombre de
BlogMapper.class).
Hablaremos más sobre esto más adelante.
</p>
</div>
<div class="section">
<h3>Cómo obtener un SqlSession a partir del SqlSessionFactory<a name="Cmo_obtener_un_SqlSession_a_partir_del_SqlSessionFactory"></a></h3>
<p>
Ahora que dispones de un SqlSessionFactory, tal y como su nombre indica,
puedes adquirir una instancia
de SqlSession. SqlSession contiene todos los métodos necesarios para
ejecutar sentencias SQL contra la
base de datos. Puedes ejecutar mapped statements con la instancia de
SqlSession de la siguiente forma:
</p>
<div class="source">
<pre>SqlSession session = sqlSessionFactory.openSession();
try {
Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
} finally {
session.close();
}</pre></div>
<p>
Aunque esta forma de trabajar con la SqlSession funciona correctamente y
les será familiar a aquellos que han usado las versiones anteriores
de MyBatis, actualmente existe una opción más recomendada. Usar un
interface (ej. BlogMapper.class) que describe tanto el parámetro de
entrada como el de retorno para una sentencia. De esta forma
tendrás un código más sencillo y type safe, sin castings ni
literales de tipo String que son fuente frecuente de errores.
</p>
<p>
Por ejemplo:
</p>
<div class="source">
<pre>SqlSession session = sqlSessionFactory.openSession();
try {
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);
} finally {
session.close();
}</pre></div>
<p>
Vemos con detalle cómo funciona esto.
</p>
</div>
<div class="section">
<h3>Cómo funcionan los Mapped Statements<a name="Cmo_funcionan_los_Mapped_Statements"></a></h3>
<p>
Te estarás preguntando qué se está ejecutando en SqlSession o en la
clase Mapper. Los
<i>Mapped Statements</i>
son una materia muy densa, y será el tema que domine la mayor parte
de esta documentación. Pero, para que te hagas una idea de qué se
está ejecutando realmente proporcionaremos un par de ejemplos.
</p>
<p>
En cualquiera de los ejemplos a continuación podrían haberse usado
indistintamente XML o anotaciones. Veamos primero el XML. Todas las
opciones de configuración de MyBatis pueden obtenerse mediante el
lenguaje de mapeo XML que ha popularizado a MyBatis durante años.
Si ya has usado MyBatis antes el concepto te será familiar, pero
verás que hay numerosas mejoras en los ficheros de mapeo XML que
iremos explicando más adelante. Por ejemplo este mapped statement
en XML haría funcionar correctamente la llamada al SqlSession que
hemos visto previamente.
</p>
<div class="source">
<pre><?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.mybatis.example.BlogMapper">
<select id="selectBlog" resultType="Blog">
select * from Blog where id = #{id}
</select>
</mapper></pre></div>
<p>
Aunque pudiera parecer que hay excesivo XML para un ejemplo tan simple,
en realidad no hay tanto. Puedes definir tantos mapped statements
en un solo fichero XML como quieras así que rentabilizarás las
líneas XML extra que corresponden a la cabecera XML y a la
declaración de doctype. El resto del fichero se explica por sí
mismo. Define un nombre para el mapped statement “selectBlog”, en
un namespace (espacio de nombres) “org.mybatis.example.BlogMapper”,
que permite realizar una llamada especificando el nombre completo
(fully qualified) “org.mybatis.example.BlogMapper.selectBlog” tal y
como muestra el código a continuación:
</p>
<div class="source">
<pre>Blog blog = session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);</pre></div>
<p>
Observa el gran parecido que hay entre esta llamada y la llamada a una
clase java y hay una razón para eso. Este literal puede mapearse
con una clase que tenga el mismo nombre que el namespace, con un
método que coincida con el nombre del statement, y con parámetros
de entrada y retorno iguales que los del statement. Esto permite
que puedas hacer la misma llamada contra una interfaz Mapper tal y
como se muestra a continuación:
</p>
<div class="source">
<pre>BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);</pre></div>
<p>
Este segunda forma de llamada tiene muchas ventajas. Primeramente, no
se usan literales de tipo String lo cual es mucho más seguro dado
que los errores se detectan en tiempo de compilación. Segundo, si
tu IDE dispone de autocompletado de código podrás aprovecharlo.
</p>
<hr />
<p>
<span class="label important">NOTA</span>
<b>Una nota sobre los namespaces.</b>
</p>
<p>
<b>Los namespaces (espacios de nombres)</b>
eran opcionales en versiones anteriores de MyBatis, lo cual creaba
confusión y era de poca ayuda. Los namespaces son ahora
obligatorios y tienen un propósito más allá de la clasificación de
statements.
</p>
<p>
Los namespaces permiten realizar el enlace con los interfaces como se
ha visto anteriormente, e incluso si crees que no los vas a usar a
corto plazo, es recomendable que sigas estas prácticas de
organización de código por si en un futuro decides hacer lo
contrario. Usar un namespace y colocarlo en el paquete java que
corresponde con el namespace hará tu código más legible y mejorará
la usabilidad de MyBatis a largo plazo.
</p>
<p>
<b>Resolución de nombres:</b>
Para reducir la cantidad de texto a escribir MyBatis usa las
siguientes normas de resolución de nombres para todos los elementos
de configuración, incluidos statements, result maps, cachés, etc.
</p>
<ul>
<li>Primeramente se buscan directamente los nombres completamente
cualificados (fully qualified names) (ej.
“com.mypackage.MyMapper.selectAllThings”).
</li>
<li>Pueden usarse los nombres cortos (ej. “selectAllThings”)
siempre que no haya ambigüedad. Sin embargo, si hubiera dos o más
elementos (ej. “com.foo.selectAllThings" y
"com.bar.selectAllThings”), entonces obtendrás un error indicando
que el nombre es ambiguo y que debe ser “fully qualified”.
</li>
</ul>
<hr />
<p>
Hay otro aspecto importante sobre las clases Mapper como BlogMapper.
Sus mapped statements pueden no estar en ningún fichero XML. En su
lugar, pueden usarse anotaciones. Por ejemplo, el XML puede ser
eliminado y reemplazarse por:
</p>
<div class="source">
<pre>package org.mybatis.example;
public interface BlogMapper {
@Select("SELECT * FROM blog WHERE id = #{id}")
Blog selectBlog(int id);
}</pre></div>
<p>
Las anotaciones son mucho más claras para sentencias sencillas, sin
embargo, las anotaciones java son limitadas y más complicadas de
usar para sentencias complejas. Por lo tanto, si tienes que hacer
algo complejo, es mejor que uses los ficheros XML.
</p>
<p>
Es decisión tuya y de tu proyecto cuál de los dos métodos usar y cómo
de importante es que los mapped statements estén definidos de forma
consistente. Dicho esto, no estás limitado a usar un solo método,
puedes migrar fácilmente de los mapped statements basados en
anotaciones a XML y viceversa.
</p>
</div>
<div class="section">
<h3>Ámbito y ciclo de vida<a name="ambito_y_ciclo_de_vida"></a></h3>
<p>Es muy importante entender los distintos ámbitos y ciclos de vida
de las clases de las que hemos hablado hasta ahora. Usarlas de
forma incorrecta puede traer serias complicaciones.</p>
<hr />
<p>
<span class="label important">NOTA</span>
<b>Ciclo de vida de los objetos y frameworks de inyección de
dependencias</b>
</p>
<p>
Los frameworks de inyección de dependencias pueden crear
SqlSessions y mappers
<i>thread safe</i>
(reeentrante) y
transaccionales, e inyectarlos directmaente en tus beans de forma que puedes
olvidarte de su ciclo de vida.
Echa un vistazo a los sub-projectos MyBatis-Spring o MyBatis-Guice para
conocer más detalles sobre cómo usar
MyBatis con estos frameworks.
</p>
<hr />
<div class="section">
<h4>SqlSessionFactoryBuilder<a name="SqlSessionFactoryBuilder"></a></h4>
<p>Esta clase puede instanciarse, usarse y desecharse. No es
necesario mantenerla una vez que ya has creado la
SqlSessionFactory. Por lo tanto el mejor ámbito para el
SqlSessionFactoryBuilder es el método (ej. una variable local de
método). Puedes reusar el SqlSessionFactoryBuilder para construir
más de una instancia de SqlSessionFactory, pero aun así es
recomendable no conservar el objeto para asegurarse de que todos
los recursos utilizados para el parseo de XML se han liberado
correctamente y están disponibles para temas más importantes.
</p>
</div>
<div class="section">
<h4>SqlSessionFactory<a name="SqlSessionFactory"></a></h4>
<p>Una vez creado, el SqlSessionFactory debería existir durante toda
la ejecución de tu aplicación. No debería haber ningún o casi
ningún motivo para eliminarlo o recrearlo. Es una buena práctica el
no recrear el SqlSessionFactory en tu aplicación más de una vez. Y
lo contrario debería considerarse código sospechoso. Por tanto el
mejor ámbito para el SqlSessionFactory es el ámbito de aplicación.
Esto puede conseguirse de muchas formas. Lo más sencillo es usar el
patrón Singleton o el Static Singleton. </p>
</div>
<div class="section">
<h4>SqlSession<a name="SqlSession"></a></h4>
<p>Cada thread (hilo de ejecución) debería tener su propia instancia
de SqlSession. Las instancias de SqlSession no son thread safe y no
deben ser compartidas. Por tanto el ámbito adecuado es el de
petición (request) o bien el método. No guardes nunca instancias de
SqlSession en un campo estático o incluso en una propiedad de
instancia de una clase. Nunca guardes referencias a una SqlSession
en ningún tipo de ámbito gestionado como la HttpSession. Si estás
usando un framework web considera que el SqlSession debería tener
un ámbito similar al HttpRequest. Es decir, cuando recibas una
petición http puedes abrir una SqlSession y cerrarla cuando
devuelvas la respuesta. Cerrar la SqlSession es muy importante.
Deberías asegurarte de que se cierra con un bloque finally. A
continuación se muestra el patrón estándar para asegurarse de que
las sesiones se cierran correctamente.</p>
<div class="source">
<pre>SqlSession session = sqlSessionFactory.openSession();
try {
// do work
} finally {
session.close();
}</pre></div>
<p>Usando este patrón en todo el código se asegura que los recursos
de base de datos se liberarán correctamente.</p>
</div>
<div class="section">
<h4>Instancias de mapper<a name="Instancias_de_mapper"></a></h4>
<p>Los mappers son interfaces que creas como enlace con los mapped
statements. Las instancias de mappers se obtienen de una
SqlSession. Y por tanto, técnicamente el mayor ámbito de una
instancia de Mapper es el mismo que el de la SqlSession de la que
fueron creados. Sin embargo el ámbito más recomendable para una
instancia de mapper es el ámbito de método. Es decir, deberían ser
obtenidos en el método que vaya a usarlos y posteriormente
descartarlos. No es necesario que sean cerrados explícitamente.
Aunque no es un problema propagar estos objetos por varias clases
dentro de una misma llamada, debes tener cuidado porque puede que
la situación se te vaya de las manos. Hazlo fácil (keep it simple)
y mantén los mappers en el ámbito de método. Este ejemplo muestra
esta práctica:</p>
<div class="source">
<pre>SqlSession session = sqlSessionFactory.openSession();
try {
BlogMapper mapper = session.getMapper(BlogMapper.class);
// do work
} finally {
session.close();
}
</pre></div>
</div></div>
</div>
</div>
</div>
</div>
<hr/>
<footer>
<div class="container-fluid">
<div class="row-fluid">
<p >Copyright © 2010–2014
<a href="http://www.mybatis.org/">MyBatis.org</a>.
All rights reserved.
</p>
</div>
</div>
</footer>
</body>
</html>