From e054db32cdd0fdfc960ffb16430e1fea42f95067 Mon Sep 17 00:00:00 2001
From: Jeremy Landis
- Pero ¿y si quieres mapear el mismo
- El mapeo automático siempre usará
- 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).
- Enum
a un string en un sitio pero a un entero en otro?
- EnumOrdinalTypeHandler
,
- así que si queremos usar el clásico EnumTypeHandler
,
- debemos indicarlo establiencidolo esplícitamente su uso en los statements.
-
+ 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). +
+ -
- Observa que esto nos fuerza a usar un resultMap
- en lugar de un resultType
en nuestros statements tipo select.
-
+ Observa que esto nos fuerza a usar un resultMap
+ en lugar de un resultType
en nuestros statements tipo select.
+
- You can plug any 3rd party DataSource by implementing the interface org.apache.ibatis.datasource.DataSourceFactory
:
-
+ You can plug any 3rd party DataSource by implementing the interface org.apache.ibatis.datasource.DataSourceFactory
:
+
- The org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory
puede extenderse para crear nuevos
- adaptadores. Por ejemplo, este es el código necesario para integrar C3P0:
-
org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory
puede extenderse para crear nuevos
+ adaptadores. Por ejemplo, este es el código necesario para integrar C3P0:
+
-
- 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:
-
+ 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:
+
- 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".
-
+ 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:
-
+ Puedes construir tu propio DatabaseIdProvider implementando la interfaz org.apache.ibatis.mapping.DatabaseIdProvider
+ y registrandolo en el fichero mybatis-config.xml:
+
- 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. -
-- 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. -
-- Si lo prefieres puedes crear la configuración directamente desde - Java, en lugar de desde XML, o crear tu - propio - builder - . MyBatis dispone una clase Configuration que proporciona las - mismas opciones de - configuración que el fichero XML. -
-+ Si lo prefieres puedes crear la configuración directamente desde + Java, en lugar de desde XML, o crear tu + propio + builder + . MyBatis dispone una clase Configuration que proporciona las + mismas opciones de + configuración que el fichero XML. +
+- 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. -
-- 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: -
-+ 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: +
+- 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. -
-- Por ejemplo: -
-+ Por ejemplo: +
+- Vemos con detalle cómo funciona esto. -
-- Te estarás preguntando qué se está ejecutando en SqlSession o en la - clase Mapper. Los - Mapped Statements - 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. -
-- 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. -
-+ Vemos con detalle cómo funciona esto. +
++ Te estarás preguntando qué se está ejecutando en SqlSession o en la + clase Mapper. Los + Mapped Statements + 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. +
++ 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. +
+- 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: -
-- 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: -
-+ 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: +
+- 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. -
-- NOTA - Una nota sobre los namespaces. -
-- Los namespaces (espacios de nombres) - 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. -
-- 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. -
-- Resolución de nombres: - 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. -
-- 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: -
-+ NOTA + Una nota sobre los namespaces. +
++ Los namespaces (espacios de nombres) + 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. +
++ 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. +
++ Resolución de nombres: + 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. +
++ 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: +
+- 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. -
-- 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. -
-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.
-- NOTA - Ciclo de vida de los objetos y frameworks de inyección de - dependencias -
-- Los frameworks de inyección de dependencias pueden crear - SqlSessions y mappers - thread safe - (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. -
-+ 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. +
++ 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. +
+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.
++ NOTA + Ciclo de vida de los objetos y frameworks de inyección de + dependencias +
++ Los frameworks de inyección de dependencias pueden crear + SqlSessions y mappers + thread safe + (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. +
+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. -
-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.
-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.
-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. +
+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.
+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.
+Usando este patrón en todo el código se asegura que los recursos - de base de datos se liberarán correctamente.
-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:
-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:
+- MyBatis es un framework de persistencia que soporta SQL, procedimientos - almacenados y mapeos avanzados. MyBatis elimina casi todo el código JDBC, el establecimiento - manual de parámetros y la obtención de resultados. MyBatis puede configurarse con XML o anotaciones y - permite mapear typos de datos primitivos, objetos de tipo Map y POJOs (Plain Old Java Objects) a registros de base de datos. -
-- Si ves que hay alguna carencia en esta documentación o que falta - alguna característica por documentar, te animamos a que lo investigues y la documentes tu mismo! -
-
- Las fuentes de este manual están disponibles en formato xdoc en el
+ xsi:schemaLocation="http://maven.apache.org/XDOC/2.0 https://maven.apache.org/xsd/xdoc-2.0.xsd">
+
+
+ MyBatis es un framework de persistencia que soporta SQL, procedimientos + almacenados y mapeos avanzados. MyBatis elimina casi todo el código JDBC, el establecimiento + manual de parámetros y la obtención de resultados. MyBatis puede configurarse con XML o anotaciones y + permite mapear typos de datos primitivos, objetos de tipo Map y POJOs (Plain Old Java Objects) a registros de base de datos. +
++ Si ves que hay alguna carencia en esta documentación o que falta + alguna característica por documentar, te animamos a que lo investigues y la documentes tu mismo! +
++ Las fuentes de este manual están disponibles en formato xdoc en el Git del proyecto. Haz un fork, cámbialas y envía un pull request.
-- Eres el mejor candidato para documentar porque los lectores de esta documentación son gente como tú! -
-+ Eres el mejor candidato para documentar porque los lectores de esta documentación son gente como tú! +
+
- 같은 Enum
을 사용해서 어떤 곳에는 문자열로 매핑하고 다른 곳에는 숫자로 매핑해야 한다면 무엇을 해야 하나?
-
- 자동매퍼는 EnumOrdinalTypeHandler
를 자동으로 사용할 것이다.
- 그래서 평범한 순서를 나타내는 EnumTypeHandler
를 사용하고자 한다면 SQL구문에 사용할 타입핸들러를 명시적으로 설정한다.
-
- (매퍼 파일은 다음 절까지는 다루지 않는다. - 그래서 문서를 보면서 처음 봤다면 일단 이 부분은 건너띄고 다음에 다시 볼수도 있다. ) -
-Enum
을 사용해서 어떤 곳에는 문자열로 매핑하고 다른 곳에는 숫자로 매핑해야 한다면 무엇을 해야 하나?
+
+
+ 자동매퍼는 EnumOrdinalTypeHandler
를 자동으로 사용할 것이다.
+ 그래서 평범한 순서를 나타내는 EnumTypeHandler
를 사용하고자 한다면 SQL구문에 사용할 타입핸들러를 명시적으로 설정한다.
+
+ (매퍼 파일은 다음 절까지는 다루지 않는다. + 그래서 문서를 보면서 처음 봤다면 일단 이 부분은 건너띄고 다음에 다시 볼수도 있다. ) +
+
- 여기서 사용한 select구문에서는 resultType
대신에 resultMap
을 사용해야 한다는 점을 알아두자.
-
+ 여기서 사용한 select구문에서는 resultType
대신에 resultMap
을 사용해야 한다는 점을 알아두자.
+
매번 마이바티스는 결과 객체의 인스턴스를 만들기 위해 ObjectFactory를 사용한다. - 디폴트 ObjectFactory 는 디폴트 생성자를 가진 대상 클래스를 인스턴스화하는 것보다 조금 더 많은 작업을 한다. - ObjectFactory 의 디폴트 행위를 오버라이드하고자 한다면 만들 수 있다. - 예를들면:
+ 디폴트 ObjectFactory 는 디폴트 생성자를 가진 대상 클래스를 인스턴스화하는 것보다 조금 더 많은 작업을 한다. + ObjectFactory 의 디폴트 행위를 오버라이드하고자 한다면 만들 수 있다. + 예를들면:ObjectFactory인터페이스는 매우 간단한다. - 두 개의 create메소드를 가지고 있으며 하나는 디폴트 생성자를 처리하고 다른 하나는 파라미터를 가진 생성자를 처리한다. - 마지막으로 setProperties 메소드는 ObjectFactory를 설정하기 위해 사용될 수 있다. - objectFactory엘리먼트에 정의된 프로퍼티는 ObjectFactory인스턴스가 초기화된 후 setProperties에 전달될 것이다.
+ 두 개의 create메소드를 가지고 있으며 하나는 디폴트 생성자를 처리하고 다른 하나는 파라미터를 가진 생성자를 처리한다. + 마지막으로 setProperties 메소드는 ObjectFactory를 설정하기 위해 사용될 수 있다. + objectFactory엘리먼트에 정의된 프로퍼티는 ObjectFactory인스턴스가 초기화된 후 setProperties에 전달될 것이다.마이바티스는 매핑 구문을 실행하는 어떤 시점에 호출을 가로챈다. - 기본적으로 마이바티스는 메소드 호출을 가로채기 위한 플러그인을 허용한다.
+ 기본적으로 마이바티스는 메소드 호출을 가로채기 위한 플러그인을 허용한다.이 클래스들의 메소드는 각각 메소드 시그니처를 통해 찾을 수 있고 소스코드는 마이바티스 릴리즈 파일에서 찾을 수 있다. - 오버라이드할 메소드의 행위를 이해해야만 한다. - 주어진 메소드의 행위를 변경하거나 오버라이드하고자 한다면 마이바티스의 핵심기능에 악영향을 줄 수도 있다. - 이러한 로우레벨 클래스와 메소드들은 주의를 해서 사용해야 한다.
+ 오버라이드할 메소드의 행위를 이해해야만 한다. + 주어진 메소드의 행위를 변경하거나 오버라이드하고자 한다면 마이바티스의 핵심기능에 악영향을 줄 수도 있다. + 이러한 로우레벨 클래스와 메소드들은 주의를 해서 사용해야 한다.플러그인을 사용하도록 처리하는 방법은 간단하다. - Interceptor인터페이스를 구현해서 가로채고(intercept) 싶은 시그니처를 명시해야 한다.
+ Interceptor인터페이스를 구현해서 가로채고(intercept) 싶은 시그니처를 명시해야 한다.플러그인을 사용해서 마이바티스 핵심 행위를 변경하기 위해 Configuration클래스 전체를 오버라이드 할 수 있다. - 이 클래스를 확장하고 내부 메소드를 오버라이드하고 SqlSessionFactoryBuilder.build(myConfig)메소드에 그 객체를 넣어주면 된다. - 다시 얘기하지만 이 작업은 마이바티스에 큰 영향을 줄수 있으니 주의해서 해야 한다.
+ 이 클래스를 확장하고 내부 메소드를 오버라이드하고 SqlSessionFactoryBuilder.build(myConfig)메소드에 그 객체를 넣어주면 된다. + 다시 얘기하지만 이 작업은 마이바티스에 큰 영향을 줄수 있으니 주의해서 해야 한다.마이바티스는 여러 개의 환경으로 설정할 수 있다. - 여러가지 이유로 여러 개의 데이터베이스에 SQL Map을 적용하는데 도움이 된다. - 예를들어, 개발, 테스트, 리얼 환경을 위해 별도의 설정을 가지거나 같은 스키마를 여러 개의 DBMS 제품을 사용할 경우들이다. - 그 외에도 많은 경우가 있을 수 있다.
+ 여러가지 이유로 여러 개의 데이터베이스에 SQL Map을 적용하는데 도움이 된다. + 예를들어, 개발, 테스트, 리얼 환경을 위해 별도의 설정을 가지거나 같은 스키마를 여러 개의 DBMS 제품을 사용할 경우들이다. + 그 외에도 많은 경우가 있을 수 있다.중요하게 기억해야 할 것은 다중 환경을 설정할 수는 있지만 SqlSessionFactory 인스턴스마다 한 개만 사용할 수 있다는 것이다.
두 개의 데이터베이스에 연결하고 싶다면 SqlSessionFactory 인스턴스를 두 개 만들 필요가 있다. - 세 개의 데이터베이스를 사용한다면 역시 세 개의 인스턴스를 필요로 한다. - 기억하기 쉽게
+ 세 개의 데이터베이스를 사용한다면 역시 세 개의 인스턴스를 필요로 한다. + 기억하기 쉽게환경을 명시하기 위해 SqlSessionFactoryBuilder에 옵션으로 추가 파라미터를 주면 된다. - 환경을 선택하는 두가지 시그니처는
+ 환경을 선택하는 두가지 시그니처는마이바티스는 두 가지 타입의 TransactionManager를 제공한다.
TransactionManager 타입은 어떠한 프로퍼티도 필요하지 않다. - 어쨌든 둘다 타입 별칭이 있다. - 즉 TransactionFactory를 위한 클래스 명이나 타입 별칭 중 하나를 사용할 수 있다.
+ 어쨌든 둘다 타입 별칭이 있다. + 즉 TransactionFactory를 위한 클래스 명이나 타입 별칭 중 하나를 사용할 수 있다.XML에 설정된 프로퍼티는 인스턴스를 만든 뒤 setProperties()메소드에 전달할 것이다. - 당신의 구현체가 Transaction구현체를 만들 필요가 있을 것이다.:
+ 당신의 구현체가 Transaction구현체를 만들 필요가 있을 것이다.:UNPOOLED - 이 구현체는 매번 요청에 대해 커넥션을 열고 닫는 간단한 DataSource이다. - 조금 늦긴 하지만 성능을 크게 필요로 하지 않는 간단한 애플리케이션을 위해서는 괜찮은 선택이다. - UNPOOLED DataSource에는 다음과 같은 속성이 있습니다.
+ 조금 늦긴 하지만 성능을 크게 필요로 하지 않는 간단한 애플리케이션을 위해서는 괜찮은 선택이다. + UNPOOLED DataSource에는 다음과 같은 속성이 있습니다.driver
- JDBC드라이버의 패키지 경로를 포함한 결제 자바 클래스명url
- 데이터베이스 인스턴스에 대한 JDBC URL필수는 아니지만 선택적으로 데이터베이스 드라이버에 프로퍼티를 전달할 수도 있다. - 그러기 위해서는 다음 예제처럼 “driver.” 로 시작하는 접두어로 프로퍼티를 명시하면 된다.
+ 그러기 위해서는 다음 예제처럼 “driver.” 로 시작하는 접두어로 프로퍼티를 명시하면 된다.driver.encoding=UTF8
이 설정은 “encoding” 프로퍼티를 “UTF8”로 설정하게 된다. - 이 방법외에도 DriverManager.getConnection(url, driverProperties)메소드를 통해서도 프로퍼티를 설정할 수 있다.
+ 이 방법외에도 DriverManager.getConnection(url, driverProperties)메소드를 통해서도 프로퍼티를 설정할 수 있다.POOLED - DataSource에 풀링이 적용된 JDBC 커넥션을 위한 구현체이다. - 이는 새로운 Connection 인스턴스를 생성하기 위해 매번 초기화하는 것을 피하게 해준다. - 그래서 빠른 응답을 요구하는 웹 애플리케이션에서는 가장 흔히 사용되고 있다.
+ 이는 새로운 Connection 인스턴스를 생성하기 위해 매번 초기화하는 것을 피하게 해준다. + 그래서 빠른 응답을 요구하는 웹 애플리케이션에서는 가장 흔히 사용되고 있다.UNPOOLED DataSource에 비해 많은 프로퍼티를 설정할 수 있다.
poolMaximumActiveConnections
- 주어진 시간에 존재할 수 있는 활성화된(사용중인) 커넥션의 수.
- 디폴트는 10이다.poolMaximumIdleConnections
- 주어진 시간에 존재할 수 있는 유휴 커넥션의 수poolTimeToWait
- 풀이 로그 상태를 출력하고 비정상적으로 긴 경우 커넥션을 다시 얻을려고 시도하는 로우 레벨 설정.
- 디폴트는 20000ms(20 초)poolMaximumLocalBadConnectionTolerance
– 이것은 모든 쓰레드에 대해 bad Connection이 허용되는 정도에 대한 낮은 수준의 설정입니다.
만약 쓰레드가 bad connection 을 얻게 되어도 유효한 또 다른 connection 을 다시 받을 수 있습니다.
하지만 재시도 횟수는 poolMaximumIdleConnections
과 poolMaximumLocalBadConnectionTolerance
의 합보다 많아야 합니다.
디폴트는 3이다. (3.4.5 부터)
poolPingQuery
- 커넥션이 작업하기 좋은 상태이고 요청을 받아서 처리할 준비가 되었는지 체크하기 위해 데이터베이스에 던지는 핑쿼리(Ping Query).
- 디폴트는 “핑 쿼리가 없음” 이다.
- 이 설정은 대부분의 데이터베이스로 하여금 에러메시지를 보게 할수도 있다.poolPingEnabled
- 핑쿼리를 사용할지 말지를 결정.
- 사용한다면 오류가 없는(그리고 빠른) SQL 을 사용하여 poolPingQuery 프로퍼티를 설정해야 한다.
- 디폴트는 false 이다.poolPingConnectionsNotUsedFor
- poolPingQuery가 얼마나 자주 사용될지 설정한다.
- 필요이상의 핑을 피하기 위해 데이터베이스의 타임아웃 값과 같을 수 있다.
- 디폴트는 0이다.
- 디폴트 값은 poolPingEnabled가 true일 경우에만 모든 커넥션이 매번 핑을 던지는 값이다.JNDI - 이 DataSource 구현체는 컨테이너에 따라 설정이 변경되며 JNDI 컨텍스트를 참조한다. - 이 DataSource 는 오직 두 개의 프로퍼티만을 요구한다.
+ 이 DataSource 는 오직 두 개의 프로퍼티만을 요구한다.initial_context
- 이 프로퍼티는 InitialContext 에서 컨텍스트를 찾기(예를 들어 initialContext.lookup(initial_context))위해 사용된다.
- 이 프로퍼티는 선택적인 값이다.
- 이 설정을 생략하면 data_source프로퍼티가 InitialContext에서 직접 찾을 것이다.data_source
- DataSource인스턴스의 참조를 찾을 수 있는 컨텍스트 경로이다.
- initial_context 룩업을 통해 리턴된 컨텍스트에서 찾을 것이다.
- initial_context 가 지원되지 않는다면 InitialContext 에서 직접 찾을 것이다.다른 DataSource설정과 유사하게 다음처럼 “env.”를 접두어로 프로퍼티를 전달할 수 있다.
이 설정은 인스턴스화할 때 InitialContext생성자에 “encoding”프로퍼티를 “UTF8”로 전달한다.
-
- org.apache.ibatis.datasource.DataSourceFactory
인터페이스를 구현해서 또다른 DataSource구현체를 만들수 있다.
-
+ org.apache.ibatis.datasource.DataSourceFactory
인터페이스를 구현해서 또다른 DataSource구현체를 만들수 있다.
+
- org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory
는 새로운 데이터소스를 만들기 위한 상위 클래스처럼 사용할 수 있다.
- 예를 들면 다음의 코드를 사용해서 C3P0를 사용할 수 있다.
-
org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory
는 새로운 데이터소스를 만들기 위한 상위 클래스처럼 사용할 수 있다.
+ 예를 들면 다음의 코드를 사용해서 C3P0를 사용할 수 있다.
+
마이바티스는 데이터베이스 제품마다 다른 구문을 실행할 수 있다.
- 여러 개의 데이터베이스 제품을 가진 업체 제품은 이제 우리는 매핑된 SQL 구문을 정의할 시간이다.
- 하지만 먼저 설정을 어디에 둘지 결정해야 한다.
- 자바는 자동으로 리소스를 찾기 위한 좋은 방법을 제공하지 않는다.
- 그래서 가장 좋은 건 어디서 찾으라고 지정하는 것이다.
- 클래스패스에 상대적으로 리소스를 지정할 수도 있고 url 을 통해서 지정할 수 도 있다.
- 예를 들면databaseId
속성을 사용한 매핑된 구문을 기반으로 지원한다.
+ 여러 개의 데이터베이스 제품을 가진 업체 제품은 databaseId
속성을 사용한 매핑된 구문을 기반으로 지원한다.
마이바티스는 databaseId
속성이 없거나 databaseId
속성을 가진 모든 구문을 로드한다.
같은 구문인데 하나는 databaseId
속성이 있고 하나는 databaseId
속성이 없을때 뒤에 나온 것이 무시된다.
다중 지원을 사용하기 위해서는 mybatis-config.xml파일에 다음처럼 databaseIdProvider
를 추가하라:
@@ -1917,11 +1917,11 @@ public class C3P0DataSourceFactory extends UnpooledDataSourceFactory {
이 경우 마이바티스는 칼럼을 자바빈에 이름 기준으로 매핑하여 ResultMap을 자동으로 생성할 것이다. - 만약 칼럼명이 프로퍼티명과 다르다면 SQL구문에 별칭을 지정할 수 있다. - 예를들면.
+ 만약 칼럼명이 프로퍼티명과 다르다면 SQL구문에 별칭을 지정할 수 있다. + 예를들면.ResultMap에 대한 중요한 내용은 다 보았다. - 하지만 다 본건 아니다. - 칼럼명과 프로퍼티명이 다른 경우에 대해 데이터베이스 별칭을 사용하는 것과 다른 방법으로 명시적인 resultMap 을 선언하는 방법이 있다.
+ 하지만 다 본건 아니다. + 칼럼명과 프로퍼티명이 다른 경우에 대해 데이터베이스 별칭을 사용하는 것과 다른 방법으로 명시적인 resultMap 을 선언하는 방법이 있다.구문에서는 resultMap속성에 이를 지정하여 참조한다. - 예를들면
+ 예를들면마이바티스는 한가지 기준으로 만들어졌다. - 데이터베이스는 당신이 원하거나 필요로 하는 것이 아니다. + 데이터베이스는 당신이 원하거나 필요로 하는 것이 아니다. 정규화 개념 중 3NF나 BCNF가 완벽히 되도록 하는게 좋지만 실제로는 그렇지도 않다. 그래서 하나의 데이터베이스를 모든 애플리케이션에 완벽히 매핑하는 것이 가능하다면 그것이 가장 좋겠지만 그렇지도 않다. 마이바티스가 이 문제를 해결하기 위해 제공하는 답은 결과매핑이다. @@ -726,8 +726,8 @@ public class User { ]]>
아마 Author에 의해 작성되고 Comments 이나 태그를 가지는 많은 포스트를 가진 Blog 를 구성하는 괜찮은 객체 모델에 매핑하고 싶을 것이다. - 이건 복잡한 ResultMap 으로 충분한 예제이다. - 복잡해보이지만 단계별로 살펴보면 지극히 간단하다.
+ 이건 복잡한 ResultMap 으로 충분한 예제이다. + 복잡해보이지만 단계별로 살펴보면 지극히 간단하다.resultMap엘리먼트는 많은 하위 엘리먼트를 가진다. - 다음은 resultMap 엘리먼트의 개념적인 뷰(conceptual view)이다.
+ 다음은 resultMap 엘리먼트의 개념적인 뷰(conceptual view)이다.autoMapping
가장 좋은 형태: 매번 ResultMap 을 추가해서 빌드한다. - 이 경우 단위 테스트가 도움이 될 수 있다. - 한번에 모든 resultMap 을 빌드하면 작업하기 어려울 것이다. - 간단히 시작해서 단계별로 처리하는 것이 좋다. - 프레임워크를 사용하는 것은 종종 블랙박스와 같다. - 가장 좋은 방법은 단위 테스트를 통해 기대하는 행위를 달성하는 것이다. - 이건 버그가 발견되었을때 디버깅을 위해서도 좋은 방법이다.
+ 이 경우 단위 테스트가 도움이 될 수 있다. + 한번에 모든 resultMap 을 빌드하면 작업하기 어려울 것이다. + 간단히 시작해서 단계별로 처리하는 것이 좋다. + 프레임워크를 사용하는 것은 종종 블랙박스와 같다. + 가장 좋은 방법은 단위 테스트를 통해 기대하는 행위를 달성하는 것이다. + 이건 버그가 발견되었을때 디버깅을 위해서도 좋은 방법이다.다음 섹션은 각각의 엘리먼트에 대해 상세하게 살펴볼 것이다.
@@ -845,10 +845,10 @@ public class User {이건 결과 매핑의 가장 기본적인 형태이다. - id와 result 모두 한개의 칼럼을 한개의 프로퍼티나 간단한 데이터 타입의 필드에 매핑한다.
+ id와 result 모두 한개의 칼럼을 한개의 프로퍼티나 간단한 데이터 타입의 필드에 매핑한다.둘 사이의 차이점은 id 값은 객체 인스턴스를 비교할 때 사용되는 구분자 프로퍼티로 처리되는 점이다. - 이 점은 일반적으로 성능을 향상시키지만 특히 캐시와 내포된(nested) 결과 매핑(조인 매핑)의 경우에 더 그렇다.
+ 이 점은 일반적으로 성능을 향상시키지만 특히 캐시와 내포된(nested) 결과 매핑(조인 매핑)의 경우에 더 그렇다.둘다 다수의 속성을 가진다.
@@ -864,34 +864,34 @@ public class User {property
column
javaType
jdbcType
typeHandler
프로퍼티가 데이터 전송 객체(DTO) 타입 클래스로 작동한다. - 변하지 않는 클래스를 사용하고자 하는 경우가 있다. - 거의 변하지 않는 데이터를 가진 테이블은 종종 이 변하지 않는 클래스에 적합하다. - 생성자 주입은 public 메소드가 없어도 인스턴스화할 때 값을 셋팅하도록 해준다. - 마이바티스는 private 프로퍼티와 private 자바빈 프로퍼티를 지원하지만 많은 사람들은 생성자 주입을 선호한다. - constructor엘리먼트는 이러한 처리를 가능하게 한다.
+ 변하지 않는 클래스를 사용하고자 하는 경우가 있다. + 거의 변하지 않는 데이터를 가진 테이블은 종종 이 변하지 않는 클래스에 적합하다. + 생성자 주입은 public 메소드가 없어도 인스턴스화할 때 값을 셋팅하도록 해준다. + 마이바티스는 private 프로퍼티와 private 자바빈 프로퍼티를 지원하지만 많은 사람들은 생성자 주입을 선호한다. + constructor엘리먼트는 이러한 처리를 가능하게 한다.다음의 생성자를 보자.
@@ -1002,41 +1002,41 @@ public class User {column
javaType
jdbcType
typeHandler
select
resultMap
name
association 엘리먼트는 “has-one”타입의 관계를 다룬다. - 예를들어 Blog는 하나의 Author를 가진다. - association 매핑은 다른 결과와 작동한다. - 값을 가져오기 위해 대상 프로퍼티를 명시한다.
+ 예를들어 Blog는 하나의 Author를 가진다. + association 매핑은 다른 결과와 작동한다. + 값을 가져오기 위해 대상 프로퍼티를 명시한다.마이바티스는 관계를 정의하는 두가지 방법을 제공한다.
@@ -1067,7 +1067,7 @@ public class User {먼저 엘리먼트내 프로퍼티들을 보자. - 보이는 것처럼 select와 resultMap 속성만을 사용하는 간단한 결과 매핑과는 다르다.
+ 보이는 것처럼 select와 resultMap 속성만을 사용하는 간단한 결과 매핑과는 다르다.property |
결과 칼럼에 매핑하기 위한 필드나 프로퍼티. - 자바빈 프로퍼티가 해당 이름과 일치한다면 그 프로퍼티가 사용될 것이다. - 반면에 마이바티스는 해당 이름이 필드를 찾을 것이다. - 점 표기를 사용하여 복잡한 프로퍼티 검색을 사용할 수 있다. - 예를들어 “username”과 같이 간단하게 매핑될 수 있거나 “address.street.number” 처럼 복잡하게 매핑될수도 있다. | + 자바빈 프로퍼티가 해당 이름과 일치한다면 그 프로퍼티가 사용될 것이다. + 반면에 마이바티스는 해당 이름이 필드를 찾을 것이다. + 점 표기를 사용하여 복잡한 프로퍼티 검색을 사용할 수 있다. + 예를들어 “username”과 같이 간단하게 매핑될 수 있거나 “address.street.number” 처럼 복잡하게 매핑될수도 있다.
javaType |
패키지 경로를 포함한 클래스 전체명이거나 타입 별칭. - 자바빈을 사용한다면 마이바티스는 타입을 찾아낼 수 있다. - 반면에 HashMap 으로 매핑한다면 기대하는 처리를 명확히 하기 위해 javaType을 명시해야 한다. | + 자바빈을 사용한다면 마이바티스는 타입을 찾아낼 수 있다. + 반면에 HashMap 으로 매핑한다면 기대하는 처리를 명확히 하기 위해 javaType을 명시해야 한다.
jdbcType |
지원되는 타입 목록에서 설명하는 JDBC 타입. - JDBC타입은 insert, update 또는 delete 하는 null 입력이 가능한 칼럼에서만 필요하다. - JDBC의 요구사항이지 마이바티스의 요구사항이 아니다. - JDBC로 직접 코딩을 하다보면 null이 가능한 값에 이 타입을 지정할 필요가 있을 것이다. | + JDBC타입은 insert, update 또는 delete 하는 null 입력이 가능한 칼럼에서만 필요하다. + JDBC의 요구사항이지 마이바티스의 요구사항이 아니다. + JDBC로 직접 코딩을 하다보면 null이 가능한 값에 이 타입을 지정할 필요가 있을 것이다.
typeHandler |
이 문서 앞에서 이미 타입 핸들러에 대해 설명했다. - 이 프로퍼티를 사용하면 디폴트 타입 핸들러를 오버라이드 할 수 있다. - 이 값은 TypeHandler 구현체의 패키지를 포함한 전체 클래스명이나 타입별칭이다. | + 이 프로퍼티를 사용하면 디폴트 타입 핸들러를 오버라이드 할 수 있다. + 이 값은 TypeHandler 구현체의 패키지를 포함한 전체 클래스명이나 타입별칭이다.
column
select
fetchType
여기엔 두개의 select 구문이 있다. - 하나는 Blog를 로드하고 다른 하나는 Author를 로드한다. - 그리고 Blog의 resultMap은 author프로퍼티를 로드하기 위해 “selectAuthor”구문을 사용한다.
+ 하나는 Blog를 로드하고 다른 하나는 Author를 로드한다. + 그리고 Blog의 resultMap은 author프로퍼티를 로드하기 위해 “selectAuthor”구문을 사용한다.다른 프로퍼티들은 칼럼과 프로퍼티명에 일치하는 것들로 자동으로 로드 될 것이다.
이 방법은 간단한 반면에 큰 데이터나 목록에는 제대로 작동하지 않을 것이다. - 이 방법은 “N+1 Selects 문제” 으로 알려진 문제점을 가진다. - N+1 조회 문제는 처리과정의 특이성으로 인해 야기된다.
+ 이 방법은 “N+1 Selects 문제” 으로 알려진 문제점을 가진다. + N+1 조회 문제는 처리과정의 특이성으로 인해 야기된다.이 문제는 수백 또는 수천의 SQL 구문 실행이라는 결과를 야기할 수 있다. - 아마도 언제나 바라는 형태의 처리가 아닐 것이다.
+ 아마도 언제나 바라는 형태의 처리가 아닐 것이다.목록을 로드하고 내포된 데이터에 접근하기 위해 즉시 반복적으로 처리한다면 - 지연로딩으로 호출하고 게다가 성능은 많이 나빠질 것이다.
+ 지연로딩으로 호출하고 게다가 성능은 많이 나빠질 것이다.그래서 다른 방법이 있다.
@@ -1191,18 +1191,18 @@ public class User {resultMap
columnPrefix
위에서 내포된 관계의 매우 복잡한 예제를 보았을 것이다. - 다음은 작동하는 것을 보기 위한 간단한 예제이다. - 개별구문을 실행하는 것 대신에 Blog와 Author테이블을 함께 조인했다.
+ 다음은 작동하는 것을 보기 위한 간단한 예제이다. + 개별구문을 실행하는 것 대신에 Blog와 Author테이블을 함께 조인했다.조인을 사용할 때 결과의 값들이 유일하거나 명확한 이름이 되도록 별칭을 사용하는 것이 좋다. - 이제 결과를 매핑할 수 있다.
+ 이제 결과를 매핑할 수 있다.위 예제에서 Author인스턴스를 로드하기 위한 “authorResult” 결과매핑으로 위임된 Blog의 “author”관계를 볼 수 있을 것이다.
매우 중요 : id 엘리먼트는 내포된 결과 매핑에서 매우 중요한 역할을 담당한다. - 결과 중 유일한 것을 찾아내기 위한 한개 이상의 프로퍼티를 명시해야만 한다. - 가능하면 결과 중 유일한 것을 찾아낼 수 있는 프로퍼티들을 선택하라. - 기본키가 가장 좋은 선택이 될 수 있다.
+ 결과 중 유일한 것을 찾아내기 위한 한개 이상의 프로퍼티를 명시해야만 한다. + 가능하면 결과 중 유일한 것을 찾아낼 수 있는 프로퍼티들을 선택하라. + 기본키가 가장 좋은 선택이 될 수 있다.이제 위 예제는 관계를 매핑하기 위해 외부의 resultMap 엘리먼트를 사용했다. - 이 외부 resultMap은 Author resultMap을 재사용가능하도록 해준다. - 어쨌든 재사용할 필요가 있거나 한개의 resultMap 에 결과 매핑을 함께 위치시키고자 한다면 association 결과 매핑을 내포시킬수 있다. - 다음은 이 방법을 사용한 예제이다.
+ 이 외부 resultMap은 Author resultMap을 재사용가능하도록 해준다. + 어쨌든 재사용할 필요가 있거나 한개의 resultMap 에 결과 매핑을 함께 위치시키고자 한다면 association 결과 매핑을 내포시킬수 있다. + 다음은 이 방법을 사용한 예제이다.지금까지 “has one” 관계를 다루는 방법을 보았다. - 하지만 “has many” 는 어떻게 처리할까? - 그건 다음 섹션에서 다루어보자.
+ 하지만 “has many” 는 어떻게 처리할까? + 그건 다음 섹션에서 다루어보자.collection 엘리먼트는 관계를 파악하기 위해 작동한다. - 사실 이 내용이 중복되는 내용으로 차이점에 대해서만 주로 살펴보자.
+ 사실 이 내용이 중복되는 내용으로 차이점에 대해서만 주로 살펴보자.위 예제를 계속 진행하기 위해 Blog는 오직 하나의 Author를 가진다. - 하지만 Blog는 많은 Post 를 가진다. - Blog 클래스에 다음처럼 처리될 것이다.
+ 하지만 Blog는 많은 Post 를 가진다. + Blog 클래스에 다음처럼 처리될 것이다.List에 내포된 결과를 매핑하기 위해 collection엘리먼트를 사용한다. - association 엘리먼트와는 달리 조인에서 내포된 select나 내포된 결과를 사용할 수 있다.
+ association 엘리먼트와는 달리 조인에서 내포된 select나 내포된 결과를 사용할 수 있다.바로 눈치챌 수 있는 몇가지가 있지만 대부분 앞서 배운 association 엘리먼트와 매우 유사하다. - 먼저 collection 엘리먼트를 사용한 것이 보일 것이다. - 그리고 나서 새로운 “ofType” 속성을 사용한 것을 알아차렸을 것이다. - 이 속성은 자바빈 프로퍼티 타입과 collection 의 타입을 구분하기 위해 필요하다.
+ 먼저 collection 엘리먼트를 사용한 것이 보일 것이다. + 그리고 나서 새로운 “ofType” 속성을 사용한 것을 알아차렸을 것이다. + 이 속성은 자바빈 프로퍼티 타입과 collection 의 타입을 구분하기 위해 필요하다.javaType 속성은 그다지 필요하지 않다. - 마이바티스는 대부분의 경우 이 속성을 사용하지 않을 것이다. - 그래서 간단하게 설정할 수 있다.
+ 마이바티스는 대부분의 경우 이 속성을 사용하지 않을 것이다. + 그래서 간단하게 설정할 수 있다.이 시점에 collection 을 위한 내포된 결과가 어떻게 작동하는지 짐작할 수 있을 것이다. - 왜냐하면 association와 정확히 일치하기 때문이다. - 하지만 “ofType” 속성이 추가로 적용되었다.
+ 왜냐하면 association와 정확히 일치하기 때문이다. + 하지만 “ofType” 속성이 추가로 적용되었다.먼저 SQL을 보자.
@@ -1416,7 +1416,7 @@ public class User { ]]>다시보면 Blog와 Post테이블을 조인했고 간단한 매핑을 위해 칼럼명에 적절한 별칭을 주었다. - 이제 Post의 Collection을 가진 Blog의 매핑은 다음처럼 간단해졌다.
+ 이제 Post의 Collection을 가진 Blog의 매핑은 다음처럼 간단해졌다.참고 associations과 collections에서 내포의 단계 혹은 조합에는 제한이 없다. - 매핑할때는 성능을 생각해야 한다. - 단위테스트와 성능테스트는 애플리케이션에서 가장 좋은 방법을 찾도록 지속해야 한다. - 마이바티스는 이에 수정비용을 최대한 줄이도록 해줄 것이다.
+ 매핑할때는 성능을 생각해야 한다. + 단위테스트와 성능테스트는 애플리케이션에서 가장 좋은 방법을 찾도록 지속해야 한다. + 마이바티스는 이에 수정비용을 최대한 줄이도록 해줄 것이다.복잡한 association 과 collection 매핑은 어려운 주제다. - 문서에서는 여기까지만 설명을 할수 있다. - 연습을 더 하면 명확하게 이해할 수 있을것이다. + 문서에서는 여기까지만 설명을 할수 있다. + 연습을 더 하면 명확하게 이해할 수 있을것이다.
종종 하나의 데이터베이스 쿼리는 많고 다양한 데이터 타입의 결과를 리턴한다. - discriminator엘리먼트는 클래스 상속 관계를 포함하여 이러한 상황을 위해 고안되었다. - discriminator는 자바의 switch와 같이 작동하기 때문에 이해하기 쉽다.
+ discriminator엘리먼트는 클래스 상속 관계를 포함하여 이러한 상황을 위해 고안되었다. + discriminator는 자바의 switch와 같이 작동하기 때문에 이해하기 쉽다.discriminator정의는 colume과 javaType속성을 명시한다. - colume은 마이바티스로 하여금 비교할 값을 찾을 것이다. - javaType은 동일성 테스트와 같은 것을 실행하기 위해 필요하다. - 예를들어
+ colume은 마이바티스로 하여금 비교할 값을 찾을 것이다. + javaType은 동일성 테스트와 같은 것을 실행하기 위해 필요하다. + 예를들어이 예제에서 마이바티스는 결과데이터에서 각각의 레코드를 가져와서 vehicle_type값과 비교한다. - 만약 discriminator비교값과 같은 경우가 생기면 이 경우에 명시된 resultMap을 사용할 것이다. - 해당되는 경우가 없다면 무시된다. - 만약 일치하는 경우가 하나도 없다면 마이바티스는 discriminator블럭 밖에 정의된 resultMap을 사용한다. - carResult가 다음처럼 정의된다면
+ 만약 discriminator비교값과 같은 경우가 생기면 이 경우에 명시된 resultMap을 사용할 것이다. + 해당되는 경우가 없다면 무시된다. + 만약 일치하는 경우가 하나도 없다면 마이바티스는 discriminator블럭 밖에 정의된 resultMap을 사용한다. + carResult가 다음처럼 정의된다면doorCount프로퍼티만이 로드될 것이다. - discriminator경우들의 독립적인 결과를 만들어준다. - 이 경우 우리는 물론 car와 vehicle간의 관계를 알 수 있다. - 그러므로 나머지 프로퍼티들도 로드하길 원하게 된다. - 그러기 위해서는 간단하게 하나만 변경하면 된다.
+ discriminator경우들의 독립적인 결과를 만들어준다. + 이 경우 우리는 물론 car와 vehicle간의 관계를 알 수 있다. + 그러므로 나머지 프로퍼티들도 로드하길 원하게 된다. + 그러기 위해서는 간단하게 하나만 변경하면 된다.vehicleResult와 carResult의 모든 프로퍼티들이 로드 될 것이다.
한가지 더 도처에 설정된 외부 정의를 찾게 될지도 모른다. - 그러므로 간결한 매핑 스타일의 문법이 있다. - 예를들면
+ 그러므로 간결한 매핑 스타일의 문법이 있다. + 예를들면참고 모든 결과 매핑이 있고 모두 명시하고 싶지 않다면 - 마이바티스는 칼럼과 프로퍼티 명으로 자동으로 매핑할 것이다. - 이 예제는 실제로 필요한 내용보다 많이 서술되어 있다.
+ 마이바티스는 칼럼과 프로퍼티 명으로 자동으로 매핑할 것이다. + 이 예제는 실제로 필요한 내용보다 많이 서술되어 있다. @@ -1586,7 +1586,7 @@ public class User {NONE
- 자동매핑을 사용하지 않는다.
- 오직 수동으로 매핑한 프로퍼티만을 설정할것이다.
+ 오직 수동으로 매핑한 프로퍼티만을 설정할것이다.
PARTIAL
- 조인 내부에 정의한 내포된 결과매핑을 제외하고 자동매핑한다.
@@ -1638,10 +1638,10 @@ public class User {
마이바티스는 쉽게 설정가능하고 변경가능한 쿼리 캐싱 기능을 가지고 있다. - 마이바티스 3 캐시 구현체는 강력하고 쉽게 설정할 수 있도록 많은 부분이 수정되었다.
+ 마이바티스 3 캐시 구현체는 강력하고 쉽게 설정할 수 있도록 많은 부분이 수정되었다.성능을 개선하고 순환하는 의존성을 해결하기 위해 필요한 로컬 세션 캐싱을 제외하고 기본적으로 캐시가 작동하지 않는다. - 캐싱을 활성화하기 위해서 SQL 매핑 파일에 한줄을 추가하면 된다.
+ 캐싱을 활성화하기 위해서 SQL 매핑 파일에 한줄을 추가하면 된다.모든 프로퍼티는 cache 엘리먼트의 속성을 통해 변경가능하다. - 예를들면
+ 예를들면많은 프로퍼티가 셋팅된 이 설정은 60 초마다 캐시를 지우는 FIFO 캐시를 생성한다. - 이 캐시는 결과 객체 또는 결과 리스트를 512개까지 저장하고 각 객체는 읽기 전용이다. - 캐시 데이터를 변경하는 것은 개별 쓰레드에서 호출자간의 충돌을 야기할 수 있다.
+ 이 캐시는 결과 객체 또는 결과 리스트를 512개까지 저장하고 각 객체는 읽기 전용이다. + 캐시 데이터를 변경하는 것은 개별 쓰레드에서 호출자간의 충돌을 야기할 수 있다.사용가능한 캐시 전략은 4가지이다.
@@ -1686,18 +1686,18 @@ public class User {디폴트 값은 LRU 이다.
flushInterval 은 양수로 셋팅할 수 있고 밀리세컨드로 명시되어야 한다. - 디폴트는 셋팅되지 않으나 플러시(flush) 주기를 사용하지 않으면 캐시는 오직 구문이 호출될때마다 캐시를 지운다.
+ 디폴트는 셋팅되지 않으나 플러시(flush) 주기를 사용하지 않으면 캐시는 오직 구문이 호출될때마다 캐시를 지운다.size는 양수로 셋팅할 수 있고 캐시에 객체의 크기를 유지하지만 메모리 자원이 충분해야 한다. - 디폴트 값은 1024 이다.
+ 디폴트 값은 1024 이다.readOnly 속성은 true 또는 false 로 설정 할 수 있다. - 읽기 전용 캐시는 모든 호출자에게 캐시된 객체의 같은 인스턴스를 리턴 할 것이다. - 게다가 그 객체는 변경할 수 없다. - 이건 종종 성능에 잇점을 준다. - 읽고 쓰는 캐시는 캐시된 객체의 복사본을 리턴 할 것이다. - 이건 조금 더 늦긴 하지만 안전하다. - 디폴트는 false 이다.
+ 읽기 전용 캐시는 모든 호출자에게 캐시된 객체의 같은 인스턴스를 리턴 할 것이다. + 게다가 그 객체는 변경할 수 없다. + 이건 종종 성능에 잇점을 준다. + 읽고 쓰는 캐시는 캐시된 객체의 복사본을 리턴 할 것이다. + 이건 조금 더 늦긴 하지만 안전하다. + 디폴트는 false 이다.이 예제는 사용자 지정 캐시 구현체를 사용하는 방법을 보여준다. - type속성에 명시된 클래스는 org.apache.ibatis.cache.Cache인터페이스를 반드시 구현해야 한다. - 이 인터페이스는 마이바티스 프레임워크의 가장 복잡한 구성엘리먼트 중 하나이다. - 하지만 하는 일은 간단하다.
+ type속성에 명시된 클래스는 org.apache.ibatis.cache.Cache인터페이스를 반드시 구현해야 한다. + 이 인터페이스는 마이바티스 프레임워크의 가장 복잡한 구성엘리먼트 중 하나이다. + 하지만 하는 일은 간단하다.캐시를 설정하기 위해 캐시 구현체에 public 자바빈 프로퍼티를 추가하고 cache 엘리먼트를 통해 프로퍼티를 전달한다. - 예를들어 다음 예제는 캐시 구현체에서 “setCacheFile(String file)” 를 호출하여 메소드를 호출할 것이다.
+ 예를들어 다음 예제는 캐시 구현체에서 “setCacheFile(String file)” 를 호출하여 메소드를 호출할 것이다.
- 모든 간단한 타입의 자바빈 프로퍼티를 사용할 수 있다. 마이바티스는 변환할 것이다.
+ 모든 간단한 타입의 자바빈 프로퍼티를 사용할 수 있다. 마이바티스는 변환할 것이다.
configuration properties 에 정의된 값을 대체할 placeholder(예: ${cache.file}
) 를 지정할 수 있다.
-
+
3.4.2 부터, MyBatis 는 모든 properties 를 설정한 후 초기화 메서드를 호출하도록 지원한다.
이 기능을 사용하려면, custom 캐시 클래스에서 org.apache.ibatis.builder.InitializingObject
interface 를 구현해야 한다.
-
캐시 설정과 캐시 인스턴스가 SQL Map 파일의 네임스페이스에 묶여지는(bound) 것을 기억하는게 중요하다. - 게다가 같은 네임스페이스내 모든 구문은 묶여진다. - 구문별로 캐시와 상호작동하는 방법을 변경할 수 있거나 두개의 간단한 속성을 통해 완전히 배제될 수도 있다. - 디폴트로 구문은 아래와 같이 설정된다.
+ 게다가 같은 네임스페이스내 모든 구문은 묶여진다. + 구문별로 캐시와 상호작동하는 방법을 변경할 수 있거나 두개의 간단한 속성을 통해 완전히 배제될 수도 있다. + 디폴트로 구문은 아래와 같이 설정된다.이러한 방법으로 구문을 설정하는 하는 방법은 굉장히 좋지 않다. - 대신 디폴트 행위를 변경해야 할 경우에만 flushCache와 useCache 속성을 변경하는 것이 좋다. - 예를들어 캐시에서 특정 select 구문의 결과를 제외하고 싶거나 캐시를 지우기 위한 select 구문을 원할 것이다. - 유사하게 실행할때마다 캐시를 지울 필요가 없는 update구문도 있을 것이다.
+ 대신 디폴트 행위를 변경해야 할 경우에만 flushCache와 useCache 속성을 변경하는 것이 좋다. + 예를들어 캐시에서 특정 select 구문의 결과를 제외하고 싶거나 캐시를 지우기 위한 select 구문을 원할 것이다. + 유사하게 실행할때마다 캐시를 지울 필요가 없는 update구문도 있을 것이다.이전 섹션 내용을 돌이켜보면서 특정 네임스페이스을 위한 캐시는 오직 하나만 사용되거나 같은 네임스페이스내에서는 구문마다 캐시를 지울수 있다. - 네임스페이스간의 캐시 설정과 인스턴스를 공유하고자 할때가 있을 것이다. - 이 경우 cache-ref 엘리먼트를 사용해서 다른 캐시를 참조할 수 있다.
+ 네임스페이스간의 캐시 설정과 인스턴스를 공유하고자 할때가 있을 것이다. + 이 경우 cache-ref 엘리먼트를 사용해서 다른 캐시를 참조할 수 있다.