Java-MyBatis-Framework

Java 常用类库Gängige Java-Klassenbibliotheken


MyBatis ist ein hervorragendes Persistenz-Framework, das die Interaktion zwischen Java-Anwendungen und relationalen Datenbanken vereinfacht. MyBatis bildet SQL-Anweisungen über XML oder Annotationen auf Java-Objekte ab und vermeidet so eine große Menge Boilerplate-Code in der traditionellen JDBC-Programmierung.


Kernfunktionen von MyBatis

1. Trennung von SQL und Code

MyBatis ermöglicht Entwicklern, SQL-Anweisungen vom Java-Code zu trennen und sie in XML-Dateien oder Annotationen zu speichern, wodurch der Code klarer und leichter wartbar wird.

2. Automatisches Mapping

MyBatis kann Datenbankabfrageergebnisse automatisch auf Java-Objekte abbilden, wodurch der Aufwand für die Datenkonvertierung erheblich reduziert wird.

3. Dynamisches SQL

MyBatis bietet leistungsstarke dynamische SQL-Funktionen, wodurch je nach Bedingungen unterschiedliche SQL-Anweisungen generiert werden können.

4. Cache-Mechanismus

MyBatis verfügt über integrierte Caches der ersten und zweiten Ebene, die die Anwendungsleistung effektiv verbessern können.

Grundlegende Architektur von MyBatis

1. Kernkomponenten

  • SqlSessionFactoryFactory-Klasse zum Erstellen von SqlSession
  • SqlSessionHauptschnittstelle zum Ausführen von SQL-Befehlen
  • Mapper-SchnittstelleDefiniert Methoden für Datenbankoperationen
  • Mapper XMLKonfigurationsdatei, die SQL-Anweisungen enthält

2. Arbeitsablauf

  1. Die Anwendung erstellt SqlSessionFactory über SqlSessionFactoryBuilder.
  2. SqlSessionFactory erstellt SqlSession.
  3. SqlSession ruft eine Instanz der Mapper-Schnittstelle ab.
  4. Mapper-Methoden aufrufen, um Datenbankoperationen auszuführen.
  5. Transaktion festschreiben und SqlSession schließen.

MyBatis-Konfiguration

1. Hauptkonfigurationsdatei (mybatis-config.xml)

Beispiel

<?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. Mapper-Datei-Beispiel

Beispiel

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

Grundlegende Verwendung von MyBatis

1. Abrufen von SqlSession

Beispiel

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

2. Ausführen einer Abfrage

Beispiel

// Methode 1: SqlSession direkt verwenden
User user = session.selectOne("com.example.mapper.UserMapper.getUserById", 1);

// Methode 2: Über die Mapper-Schnittstelle
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.getUserById(1);

3. Ausführen eines Insert

Beispiel

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

int rows = mapper.insertUser(newUser);
session.commit(); // Transaktion bestätigen

Dynamisches SQL in MyBatis

MyBatis bietet eine Vielzahl von dynamischen SQL-Elementen, die abhängig von verschiedenen Bedingungen dynamisch SQL-Anweisungen generieren können:

1. Das if-Element

Beispiel

<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. Die choose/when/otherwise-Elemente

Beispiel

<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. Das foreach-Element

Beispiel

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

MyBatis-Assoziationsabfragen

1. Eins-zu-eins-Assoziation

Beispiel

<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. Eins-zu-viele-Assoziation

Beispiel

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

MyBatis-Caching-Mechanismus

1. First-Level-Cache

Der First-Level-Cache ist ein Cache auf SqlSession-Ebene und standardmäßig aktiviert. Innerhalb derselben SqlSession wird dieselbe Abfrage nur einmal als SQL ausgeführt.

Funktionen:

  • Gültigkeitsbereich:SqlSessionEbene (standardmäßig aktiviert, kann nicht deaktiviert werden)

  • Lebenszyklus: mit derSqlSessionErstellung von SqlSession wird er erstellt; mit demSqlSessionSchließen von SqlSession wird er zerstört.

  • Szenarien, die das Leeren auslösen:

    • ExecuteINSERT/UPDATE/DELETEOperationen

    • AufrufsqlSession.clearCache()

    • Transaktions-Rollback durchführen

    • Eine andere konfigurierenStatement ID(auch wenn das SQL identisch ist)

Notizen:

Beispiel

// Beispiel: Dieselbe Abfrage wird in derselben SqlSession nur einmal ausgeführt
User user1 = sqlSession.selectOne("getUserById", 1);  // SQL ausführen
User user2 = sqlSession.selectOne("getUserById", 1);  // Aus dem Cache abgerufen

2. Second-Level-Cache

Der Second-Level-Cache ist ein Cache auf Mapper-Ebene, und mehrere SqlSessions können den Cache gemeinsam nutzen. Er muss in der Konfigurationsdatei aktiviert werden:

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

Und konfigurieren Sie ihn in der Mapper-Datei:

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

Vergleich der Cache-Strategien:

StrategieBeschreibungAnwendungsfall
LRUAm längsten nicht verwendetRegelmäßige Verwendung
FIFOFirst In, First OutZugriff in fester Reihenfolge
SOFTSoft-ReferenzSpeicherempfindliche Szenarien
WEAKWeak-ReferenzÄußerst speicherempfindlich

Integration von MyBatis mit Spring

1. Abhängigkeitskonfiguration (Empfohlen für modernes Spring Boot)

Beispiel

<!-- pom.xml -->
<dependencies>
    <!-- Spring Boot Starter-Integrationslösung (empfohlen) -->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>3.0.3</version>
    </dependency>

    <!-- Oder in traditionellen Spring-Projekten verwenden -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>3.0.3</version>
    </dependency>
   
    <!-- Datenbanktreiber entsprechend der tatsächlichen Situation auswählen -->
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.0.33</version>
    </dependency>
</dependencies>

2. Konfigurationsansätze (Drei gängige Vorgehensweisen)

Ansatz 1: Spring Boot-Autokonfiguration (Am einfachsten)

Beispiel

# application.yml
mybatis
:
  mapper-locations
: classpath*:mapper/**/*.xml
  type-aliases-package
: com.example.model
  configuration
:
    map-underscore-to-camel-case
: true  # Automatische Camel-Case-Konvertierung

Ansatz 2: Vollständige Java-Config-Konfiguration (Feingranulare Steuerung)

Beispiel

@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");
       
        // Benutzerdefinierte Konfiguration (Beispiel)
        org.apache.ibatis.session.Configuration config = new Configuration();
        config.setMapUnderscoreToCamelCase(true);
        config.setDefaultFetchSize(100);
        factory.setConfiguration(config);
       
        // Plugin-Konfiguration (Beispiel)
        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); // Annotation-Scanning einschränken
        return scanner;
    }
}

Ansatz 3: Traditionelle XML-Konfiguration (kompatibel mit Legacy-Projekten)

Beispiel

<!-- 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. Konfiguration der Transaktionsverwaltung

Beispiel

@Configuration
@EnableTransactionManagement
public class TransactionConfig {
   
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
   
    // Kann Transaktions-Template definieren
    @Bean
    public TransactionTemplate transactionTemplate(PlatformTransactionManager manager) {
        return new TransactionTemplate(manager);
    }
}

4. Nutzungsrichtlinien und Best Practices

Mapper-Schnittstellendefinition:

Beispiel

@Repository // DAO-Schicht-Annotationen angeben
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);
}

Beispiel für die Service-Schicht:

Beispiel

@Service
@Transactional(readOnly = true) // Standardmäßig schreibgeschützt
public class UserService {
   
    private final UserMapper userMapper;
   
    @Autowired // Konstruktorinjektion wird empfohlen
    public UserService(UserMapper userMapper) {
        this.userMapper = userMapper;
    }
   
    @Transactional // Transaktionen für Schreibvorgänge separat öffnen
    public User createUser(String name) {
        User user = new User();
        user.setName(name);
        userMapper.insert(user);
        return userMapper.selectById(user.getId());
    }
}

5. Integration erweiterter Funktionen

Konfiguration dynamischer Datenquellen:

Beispiel

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

Transaktionsverwaltung für mehrere Datenquellen:

Beispiel

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

Bewährte Methoden für MyBatis

  1. Mapper-Schnittstellen anstelle der direkten Verwendung von SqlSession: Dies macht den Code typsicherer und einfacher zu warten.
  2. Dynamisches SQL angemessen verwenden: SQL-Injection-Risiken vermeiden und die SQL-Lesbarkeit wahren.
  3. Batch-Operationen: Verwenden Sie für große Batch-Datenoperationen die Batch-Verarbeitung, um die Leistung zu verbessern.
  4. Caching angemessen verwenden: Konfigurieren Sie geeignete Caching-Strategien basierend auf den Geschäftsanforderungen.
  5. SQL-Optimierung: Schreiben Sie effiziente SQL-Anweisungen in der Mapper-XML.

MyBatis ist ein flexibles und leistungsstarkes ORM-Framework. Richtig eingesetzt kann es die Entwicklungseffizienz und Anwendungsleistung erheblich verbessern. Ich hoffe, dieser Artikel hilft Ihnen, das MyBatis-Framework zu verstehen und zu verwenden.

Java 常用类库Gängige Java-Klassenbibliotheken

Andere Erweiterungen