Java MyBatis Framework

Java 常用类库Librerías de uso común en Java


MyBatis es un excelente framework de capa de persistencia que simplifica la interacción entre las aplicaciones Java y las bases de datos relacionales. MyBatis mapea sentencias SQL con objetos Java mediante XML o anotaciones, evitando gran cantidad de código repetitivo (boilerplate) en la programación tradicional con JDBC.


Características principales de MyBatis

1. Separación de SQL y código

MyBatis permite a los desarrolladores separar las sentencias SQL del código Java, almacenándolas en archivos XML o anotaciones, lo que hace que el código sea más claro y fácil de mantener.

2. Mapeo automático

MyBatis puede mapear automáticamente los resultados de las consultas de la base de datos a objetos Java, reduciendo considerablemente el trabajo de conversión de datos.

3. SQL dinámico

MyBatis proporciona potentes funciones de SQL dinámico, que permiten generar diferentes sentencias SQL según distintas condiciones.

4. Mecanismo de caché

MyBatis incluye caché de primer nivel y caché de segundo nivel, lo que puede mejorar eficazmente el rendimiento de la aplicación.

Arquitectura básica de MyBatis

1. Componentes principales

  • SqlSessionFactory: clase de fábrica que crea SqlSession
  • SqlSession: interfaz principal para ejecutar comandos SQL
  • Interfaz Mapper: define los métodos de operación de la base de datos
  • Mapper XML: archivo de configuración que contiene sentencias SQL

2. Flujo de trabajo

  1. La aplicación crea SqlSessionFactory mediante SqlSessionFactoryBuilder
  2. SqlSessionFactory crea SqlSession
  3. SqlSession obtiene la instancia de la interfaz Mapper
  4. Llame a los métodos del Mapper para ejecutar operaciones de base de datos
  5. Confirmar la transacción y cerrar SqlSession

Configuración de MyBatis

1. Archivo de configuración principal (mybatis-config.xml)

Ejemplo

<?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>
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis_db"/>
                <property name="username" value="root"/>
                <property name="password" value="password"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/example/mapper/UserMapper.xml"/>
    </mappers>
</configuration>

2. Ejemplo de archivo Mapper

Ejemplo

<?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="com.example.mapper.UserMapper">
    <select id="getUserById" parameterType="int" resultType="com.example.model.User">
        SELECT * FROM users WHERE id = #{id}
    </select>
   
    <insert id="insertUser" parameterType="com.example.model.User">
        INSERT INTO users(name, email) VALUES(#{name}, #{email})
    </insert>
</mapper>

Uso básico de MyBatis

1. Obtener SqlSession

Ejemplo

String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();

2. Ejecutar consulta

Ejemplo

// Método 1: usar SqlSession directamente
User user = session.selectOne("com.example.mapper.UserMapper.getUserById", 1);

// Método 2: a través de la interfaz Mapper
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.getUserById(1);

3. Ejecutar inserción

Ejemplo

User newUser = new User();
newUser.setName("Zhang San");
newUser.setEmail("[email protected]");

int rows = mapper.insertUser(newUser);
session.commit(); // Confirmar la transacción

SQL dinámico de MyBatis

MyBatis proporciona varios elementos de SQL dinámico que pueden generar dinámicamente sentencias SQL según diferentes condiciones:

1. Elemento if

Ejemplo

<select parameterType="map" resultType="User">
    SELECT * FROM users
    WHERE 1=1
    <if test="name != null">
        AND name = #{name}
    </if>
    <if test="email != null">
        AND email = #{email}
    </if>
</select>

2. Elementos choose/when/otherwise

Ejemplo

<select parameterType="map" resultType="User">
    SELECT * FROM users
    WHERE status = 'ACTIVE'
    <choose>
        <when test="name != null">
            AND name like #{name}
        </when>
        <when test="email != null">
            AND email = #{email}
        </when>
        <otherwise>
            AND 1=1
        </otherwise>
    </choose>
</select>

3. Elemento foreach

Ejemplo

<select parameterType="list" resultType="User">
    SELECT * FROM users
    WHERE id IN
    <foreach item="id" collection="list" open="(" separator="," close=")">
        #{id}
    </foreach>
</select>

Consultas de asociación en MyBatis

1. Asociación uno a uno

Ejemplo

<resultMap type="User">
    <id property="id" column="user_id"/>
    <result property="name" column="user_name"/>
    <association property="address" javaType="Address">
        <id property="id" column="address_id"/>
        <result property="street" column="street"/>
        <result property="city" column="city"/>
    </association>
</resultMap>

<select resultMap="userWithAddress">
    SELECT
        u.id as user_id, u.name as user_name,
        a.id as address_id, a.street, a.city
    FROM users u
    LEFT JOIN addresses a ON u.address_id = a.id
    WHERE u.id = #{id}
</select>

2. Asociación uno a muchos

Ejemplo

<resultMap type="User">
    <id property="id" column="user_id"/>
    <result property="name" column="user_name"/>
    <collection property="orders" ofType="Order">
        <id property="id" column="order_id"/>
        <result property="orderDate" column="order_date"/>
        <result property="amount" column="amount"/>
    </collection>
</resultMap>

<select resultMap="userWithOrders">
    SELECT
        u.id as user_id, u.name as user_name,
        o.id as order_id, o.order_date, o.amount
    FROM users u
    LEFT JOIN orders o ON u.id = o.user_id
    WHERE u.id = #{id}
</select>

Mecanismo de caché de MyBatis

1. Caché de primer nivel

La caché de primer nivel es una caché a nivel de SqlSession, habilitada de forma predeterminada. En el mismo SqlSession, la misma consulta solo ejecuta SQL una vez.

Características:

  • Alcance:SqlSessionNivel (activado por defecto, no se puede desactivar)

  • Ciclo de vida: asociado a laSqlSessioncreación de SqlSession, y se destruye con suSqlSessioncierre.

  • Situaciones que desencadenan la limpieza:

    • EjecutarINSERT/UPDATE/DELETEla operación

    • LlamarsqlSession.clearCache()

    • Ejecutar el rollback de la transacción

    • Configurar un SqlSession diferenteStatement ID(incluso si el SQL es el mismo)

Notas:

Ejemplo

// Ejemplo: la misma consulta en el mismo SqlSession solo se ejecuta una vez
User user1 = sqlSession.selectOne("getUserById", 1);  // Ejecutar SQL
User user2 = sqlSession.selectOne("getUserById", 1);  // Obtener de la caché

2. Caché de segundo nivel

La caché de segundo nivel es una caché a nivel de Mapper y varios SqlSession pueden compartirla. Debe habilitarse en el archivo de configuración:

<settings>
    <setting name="cacheEnabled" value="true"/>  <!-- 默认true可省略 -->
</settings>

y configurarse en el archivo Mapper:

<cache
  eviction="LRU"                <!-- 淘汰策略(默认LRU) -->
  flushInterval="60000"         <!-- 刷新间隔(毫秒) -->
  size="512"                    <!-- 缓存对象数量 -->
  readOnly="true"/>             <!-- 只读模式(性能更优) -->

Comparación de estrategias de caché:

EstrategiaDescripciónEscenario aplicable
LRUMenos usado recientementeUso habitual
FIFOPrimero en entrar, primero en salirAcceso en orden fijo
SOFTReferencia suaveEscenarios sensibles a la memoria
WEAKReferencia débilExtremadamente sensible a la memoria

Integración de MyBatis con Spring

1. Configuración de dependencias (recomendado para Spring Boot moderno)

Ejemplo

<!-- pom.xml -->
<dependencies>
    <!-- Solución de integración Spring Boot Starter (recomendada) -->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>3.0.3</version>
    </dependency>

    <!-- O usar en un proyecto Spring tradicional -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>3.0.3</version>
    </dependency>
   
    <!-- Elija el controlador de la base de datos según el caso real -->
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.0.33</version>
    </dependency>
</dependencies>

2. Esquemas de configuración (tres métodos principales)

Opción 1: Configuración automática de Spring Boot (la más sencilla)

Ejemplo

# application.yml
mybatis
:
  mapper-locations
: classpath*:mapper/**/*.xml
  type-aliases-package
: com.example.model
  configuration
:
    map-underscore-to-camel-case
: true  # Conversión automática a camelCase

Opción 2: Configuración completa con Java Config (control detallado)

Ejemplo

@Configuration
public class MyBatisConfig {
   
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setTypeAliasesPackage("com.example.model");
       
        // Configuración personalizada (ejemplo)
        org.apache.ibatis.session.Configuration config = new Configuration();
        config.setMapUnderscoreToCamelCase(true);
        config.setDefaultFetchSize(100);
        factory.setConfiguration(config);
       
        // Configuración de plugins (ejemplo)
        factory.setPlugins(
            new MyBatisInterceptor(),
            new PaginationInterceptor()
        );
       
        return factory.getObject();
    }

    @Bean
    public MapperScannerConfigurer mapperScanner() {
        MapperScannerConfigurer scanner = new MapperScannerConfigurer();
        scanner.setBasePackage("com.example.mapper");
        scanner.setAnnotationClass(Repository.class); // Restringir el escaneo de anotaciones
        return scanner;
    }
}

Opción 3: Configuración tradicional con XML (compatible con proyectos antiguos)

Ejemplo

<!-- applicationContext.xml -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.example.mapper"/>
</bean>

3. Configuración de la gestión de transacciones

Ejemplo

@Configuration
@EnableTransactionManagement
public class TransactionConfig {
   
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
   
    // Se puede definir una plantilla de transacción
    @Bean
    public TransactionTemplate transactionTemplate(PlatformTransactionManager manager) {
        return new TransactionTemplate(manager);
    }
}

4. Normas de uso y mejores prácticas

Definición de la interfaz Mapper:

Ejemplo

@Repository // Explicitar la anotación de la capa DAO
public interface UserMapper {
    @Select("SELECT * FROM users WHERE id = #{id}")
    User selectById(@Param("id") int id);
   
    @Options(useGeneratedKeys = true, keyProperty = "id")
    @Insert("INSERT INTO users(name) VALUES(#{name})")
    int insert(User user);
}

Ejemplo de la capa Service:

Ejemplo

@Service
@Transactional(readOnly = true) // Por defecto, solo lectura
public class UserService {
   
    private final UserMapper userMapper;
   
    @Autowired // Se recomienda la inyección por constructor
    public UserService(UserMapper userMapper) {
        this.userMapper = userMapper;
    }
   
    @Transactional // Abrir transacción separada para operaciones de escritura
    public User createUser(String name) {
        User user = new User();
        user.setName(name);
        userMapper.insert(user);
        return userMapper.selectById(user.getId());
    }
}

5. Integración de funciones avanzadas

Configuración dinámica de fuente de datos:

Ejemplo

@Bean
@Primary
public DataSource dynamicDataSource() {
    DynamicDataSource ds = new DynamicDataSource();
    ds.setDefaultTargetDataSource(primaryDataSource());
    ds.setTargetDataSources(Map.of(
        "master", primaryDataSource(),
        "slave", secondaryDataSource()
    ));
    return ds;
}

Gestión de transacciones con múltiples fuentes de datos:

Ejemplo

@Bean
public PlatformTransactionManager transactionManager() {
    return new ChainedTransactionManager(
        new JpaTransactionManager(entityManagerFactory()),
        new DataSourceTransactionManager(dataSource())
    );
}

Mejores prácticas de MyBatis

  1. Usar interfaces Mapper en lugar de usar SqlSession directamente: Esto hace que el código sea más seguro en cuanto a tipos y más fácil de mantener.
  2. Usar SQL dinámico de forma razonable: Evitar el riesgo de inyección SQL y mantener la legibilidad del SQL.
  3. Operaciones por lotes: Para operaciones con grandes volúmenes de datos, utilice el procesamiento por lotes para mejorar el rendimiento.
  4. Usar caché de forma razonable: Configure una estrategia de caché adecuada según las necesidades del negocio.
  5. Optimización de SQL: Escriba sentencias SQL eficientes en el XML del Mapper.

MyBatis es un marco ORM flexible y potente. Su uso adecuado puede mejorar enormemente la eficiencia del desarrollo y el rendimiento de las aplicaciones. Espero que este artículo te ayude a comprender y utilizar el marco MyBatis.

Java 常用类库Librerías comunes de Java

Otras extensiones