Framework Java MyBatis

Java 常用类库Bibliothèques de classes Java courantes


MyBatis est un excellent framework de persistance qui simplifie l'interaction entre les applications Java et les bases de données relationnelles. MyBatis mappe les requêtes SQL vers des objets Java via XML ou des annotations, évitant ainsi une grande quantité de code répétitif dans la programmation JDBC traditionnelle.


Fonctionnalités clés de MyBatis

1. Séparation du SQL et du code

MyBatis permet aux développeurs de séparer les requêtes SQL du code Java, en les stockant dans des fichiers XML ou des annotations, ce qui rend le code plus clair et plus facile à maintenir.

2. Mappage automatique

MyBatis peut automatiquement mapper les résultats des requêtes de base de données vers des objets Java, réduisant considérablement la charge de conversion des données.

3. SQL dynamique

MyBatis fournit de puissantes capacités de SQL dynamique, permettant de générer différentes instructions SQL en fonction de différentes conditions.

4. Mécanisme de mise en cache

MyBatis dispose de caches de premier et de second niveau intégrés, qui peuvent améliorer efficacement les performances des applications.

Architecture de base de MyBatis

1. Composants principaux

  • SqlSessionFactoryClasse de fabrique pour créer SqlSession
  • SqlSessionInterface principale pour exécuter des commandes SQL
  • Interface MapperDéfinit les méthodes pour les opérations de base de données
  • Mapper XMLFichier de configuration contenant des instructions SQL

2. Flux de travail

  1. L'application crée SqlSessionFactory via SqlSessionFactoryBuilder.
  2. SqlSessionFactory crée SqlSession.
  3. SqlSession obtient une instance de l'interface Mapper.
  4. Appeler les méthodes du Mapper pour effectuer des opérations sur la base de données.
  5. Valider la transaction et fermer SqlSession.

Configuration MyBatis

1. Fichier de configuration principal (mybatis-config.xml)

Exemple

<?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. Exemple de fichier Mapper

Exemple

<?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>

Utilisation de base de MyBatis

1. Obtention de SqlSession

Exemple

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

2. Exécution d'une requête

Exemple

// Méthode 1 : utiliser SqlSession directement
User user = session.selectOne("com.example.mapper.UserMapper.getUserById", 1);

// Méthode 2 : via l'interface Mapper
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.getUserById(1);

3. Exécution d'une insertion

Exemple

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

int rows = mapper.insertUser(newUser);
session.commit(); // Valider la transaction

SQL dynamique dans MyBatis

MyBatis fournit une variété d'éléments SQL dynamiques, qui peuvent générer dynamiquement des instructions SQL en fonction de différentes conditions :

1. L'élément if

Exemple

<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. Les éléments choose/when/otherwise

Exemple

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

3. L'élément foreach

Exemple

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

Requêtes d'association MyBatis

1. Association un-à-un

Exemple

<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. Association un-à-plusieurs

Exemple

<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>

Mécanisme de cache MyBatis

1. Cache de premier niveau

Le cache de premier niveau est un cache de niveau SqlSession, activé par défaut. Au sein d'une même SqlSession, la même requête n'exécutera le SQL qu'une seule fois.

Fonctionnalités :

  • Portée :SqlSessionNiveau (activé par défaut, ne peut pas être désactivé)

  • Cycle de vie : avec laSqlSessioncréation de SqlSession il est créé ; avec laSqlSessionfermeture de SqlSession il est détruit.

  • Scénarios qui déclenchent le vidage :

    • ExecuteINSERT/UPDATE/DELETEopérations

    • AppelsqlSession.clearCache()

    • Effectuer un rollback de transaction

    • Configurer un autreStatement ID(même si le SQL est le même)

Notes :

Exemple

// Exemple : la même requête n'est exécutée qu'une seule fois dans la même SqlSession
User user1 = sqlSession.selectOne("getUserById", 1);  // Exécuter la requête SQL
User user2 = sqlSession.selectOne("getUserById", 1);  // Récupéré depuis le cache

2. Cache de second niveau

Le cache de second niveau est un cache au niveau du Mapper, et plusieurs SqlSessions peuvent partager le cache. Il doit être activé dans le fichier de configuration :

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

Et configurez-le dans le fichier Mapper :

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

Comparaison des stratégies de cache :

StratégieDescriptionScénario applicable
LRUMoins récemment utiliséUtilisation régulière
FIFOPremier entré, premier sortiAccès à ordre fixe
SOFTRéférence douceScénarios sensibles à la mémoire
WEAKRéférence faibleExtrêmement sensible à la mémoire

Intégration de MyBatis avec Spring

1. Configuration des dépendances (recommandée pour Spring Boot moderne)

Exemple

<!-- pom.xml -->
<dependencies>
    <!-- Solution d'intégration Spring Boot Starter (recommandée) -->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>3.0.3</version>
    </dependency>

    <!-- Ou à utiliser dans les projets Spring traditionnels -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>3.0.3</version>
    </dependency>
   
    <!-- Sélectionnez le pilote de base de données en fonction de la situation réelle -->
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.0.33</version>
    </dependency>
</dependencies>

2. Approches de configuration (trois méthodes courantes)

Approche 1 : Auto-configuration Spring Boot (la plus simple)

Exemple

# application.yml
mybatis
:
  mapper-locations
: classpath*:mapper/**/*.xml
  type-aliases-package
: com.example.model
  configuration
:
    map-underscore-to-camel-case
: true  # Conversion automatique en camel case

Approche 2 : Configuration complète Java Config (contrôle fin)

Exemple

@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");
       
        // Configuration personnalisée (exemple)
        org.apache.ibatis.session.Configuration config = new Configuration();
        config.setMapUnderscoreToCamelCase(true);
        config.setDefaultFetchSize(100);
        factory.setConfiguration(config);
       
        // Configuration du plugin (exemple)
        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); // Restreindre l'analyse des annotations
        return scanner;
    }
}

Approche 3 : Configuration XML traditionnelle (compatible avec les projets hérités)

Exemple

<!-- 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. Configuration de la gestion des transactions

Exemple

@Configuration
@EnableTransactionManagement
public class TransactionConfig {
   
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
   
    // On peut définir un modèle de transaction
    @Bean
    public TransactionTemplate transactionTemplate(PlatformTransactionManager manager) {
        return new TransactionTemplate(manager);
    }
}

4. Directives d'utilisation et bonnes pratiques

Définition de l'interface Mapper :

Exemple

@Repository // Spécifier les annotations de la couche 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);
}

Exemple de couche de service :

Exemple

@Service
@Transactional(readOnly = true) // En lecture seule par défaut
public class UserService {
   
    private final UserMapper userMapper;
   
    @Autowired // L'injection par constructeur est recommandée
    public UserService(UserMapper userMapper) {
        this.userMapper = userMapper;
    }
   
    @Transactional // Ouvrir des transactions séparément pour les opérations d'écriture
    public User createUser(String name) {
        User user = new User();
        user.setName(name);
        userMapper.insert(user);
        return userMapper.selectById(user.getId());
    }
}

5. Intégration des fonctionnalités avancées

Configuration dynamique des sources de données :

Exemple

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

Gestion des transactions multi-sources de données :

Exemple

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

Bonnes pratiques pour MyBatis

  1. Utilisez les interfaces Mapper au lieu d'utiliser directement SqlSession: Cela rend le code plus sûr au niveau des types et plus facile à maintenir.
  2. Utilisez le SQL dynamique de manière appropriée: Évitez les risques d'injection SQL et préservez la lisibilité du SQL.
  3. Opérations par lots: Pour les opérations sur de grands lots de données, utilisez le traitement par lots pour améliorer les performances.
  4. Utilisez la mise en cache de manière appropriée: Configurez des stratégies de mise en cache adaptées aux besoins métier.
  5. Optimisation SQL: Écrivez des instructions SQL efficaces dans le Mapper XML.

MyBatis est un framework ORM flexible et puissant. Utilisé correctement, il peut grandement améliorer l'efficacité du développement et les performances des applications. J'espère que cet article vous aidera à comprendre et à utiliser le framework MyBatis.

Java 常用类库Bibliothèques de classes Java courantes

Autres extensions