Фреймворк Java MyBatis
MyBatis — отличный фреймворк для работы с персистентностью, который упрощает взаимодействие между Java-приложениями и реляционными базами данных. MyBatis сопоставляет SQL-инструкции с объектами Java через XML или аннотации, избегая большого количества шаблонного кода в традиционном программировании JDBC.
Ключевые возможности MyBatis
1. Разделение SQL и кода
MyBatis позволяет разработчикам отделять SQL-инструкции от кода Java, храня их в XML-файлах или аннотациях, что делает код более понятным и простым в поддержке.2. Автоматическое сопоставление
MyBatis может автоматически отображать результаты запросов к базе данных на объекты Java, значительно уменьшая объём работы по преобразованию данных.3. Динамический SQL
MyBatis предоставляет мощные возможности динамического SQL, позволяя генерировать различные SQL-инструкции в зависимости от разных условий.4. Механизм кэширования
MyBatis имеет встроенные кэши первого и второго уровня, которые могут эффективно повысить производительность приложения.Базовая архитектура MyBatis
1. Основные компоненты
- SqlSessionFactoryКласс-фабрика для создания SqlSession
- SqlSessionОсновной интерфейс для выполнения SQL-команд
- Интерфейс MapperОпределяет методы для работы с базой данных
- Mapper XMLКонфигурационный файл, содержащий SQL-инструкции
2. Рабочий процесс
- Приложение создаёт SqlSessionFactory через SqlSessionFactoryBuilder.
- SqlSessionFactory создаёт SqlSession.
- SqlSession получает экземпляр интерфейса Mapper.
- Вызовите методы Mapper для выполнения операций с базой данных.
- Зафиксируйте транзакцию и закройте SqlSession.
Конфигурация MyBatis
1. Основной файл конфигурации (mybatis-config.xml)
Пример
<!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
Пример
<!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>
基本用法
获取
Пример
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSession sqlSessionFactory = new SqlSessionBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
2. 执行查询
Пример
User user = session.selectOne("com.example.mapper.UserMapper.getUserById", 1);
// 方法 2: 通过 Mapper 接口
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.getUserById(1);
3. Выполнение вставки
Пример
newUser.setName("Zhang San");
newUser.setEmail("[email protected]");
int rows = mapper.insertUser(newUser);
session.commit(); // Зафиксировать транзакцию
Динамический SQL в MyBatis
MyBatis предоставляет множество элементов динамического SQL, которые могут динамически генерировать SQL-инструкции в зависимости от различных условий:
1. Элемент if
Пример
SELECT * FROM users
WHERE 1=1
<if test="name != null">
AND name = #{name}
</if>
<if test="email != null">
AND email = #{email}
</if>
</select>
2. Элементы choose/when/otherwise
Пример
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. Элемент foreach
Пример
SELECT * FROM users
WHERE id IN
<foreach item="id" collection="list" open="(" separator="," close=")">
#{id}
</foreach>
</select>
Ассоциативные запросы MyBatis
1. Ассоциация один-к-одному
Пример
<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. Ассоциация один-ко-многим
Пример
<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
1. Кэш первого уровня
Кэш первого уровня — это кэш уровня SqlSession, включённый по умолчанию. В рамках одной и той же SqlSession один и тот же запрос выполнит SQL только один раз.
Возможности:
Область видимости:
SqlSessionУровень (включён по умолчанию, отключить нельзя)Жизненный цикл: при
SqlSessionсоздании SqlSession он создаётся; приSqlSessionзакрытии SqlSession он уничтожается.Сценарии, вызывающие очистку:
Execute
INSERT/UPDATE/DELETEоперацииВызов
sqlSession.clearCache()Выполнить откат транзакции
Настроить другой
Statement ID(даже если SQL тот же)
Примечания:
Пример
User user1 = sqlSession.selectOne("getUserById", 1); // Выполнить SQL
User user2 = sqlSession.selectOne("getUserById", 1); // Получено из кэша
2. Кэш второго уровня
Кэш второго уровня — это кэш уровня Mapper, и несколько SqlSessions могут совместно использовать этот кэш. Его необходимо включить в файле конфигурации:
<settings>
<setting name="cacheEnabled" value="true"/> <!-- 默认true可省略 -->
</settings>
И настроить его в файле Mapper:
<cache eviction="LRU" <!-- 淘汰策略(默认LRU) --> flushInterval="60000" <!-- 刷新间隔(毫秒) --> size="512" <!-- 缓存对象数量 --> readOnly="true"/> <!-- 只读模式(性能更优) -->
Сравнение стратегий кэширования:
| Стратегия | Описание | Применимый сценарий |
|---|---|---|
| LRU | Наименее недавно использованный | Обычное использование |
| FIFO | Первым пришёл — первым ушёл | Доступ в фиксированном порядке |
| SOFT | Мягкая ссылка | Сценарии, чувствительные к памяти |
| WEAK | Слабая ссылка | Крайне чувствительно к памяти |
Интеграция MyBatis со Spring
1. Конфигурация зависимостей (рекомендуется для современного Spring Boot)
Пример
<dependencies>
<!-- Решение интеграции Spring Boot Starter (рекомендуется) -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<!-- Или используйте в традиционных проектах Spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>3.0.3</version>
</dependency>
<!-- Выберите драйвер базы данных в соответствии с фактической ситуацией -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
</dependency>
</dependencies>
2. Подходы к конфигурации (три основных способа)
Подход 1: Автоконфигурация Spring Boot (самый простой)
Пример
mybatis:
mapper-locations: classpath*:mapper/**/*.xml
type-aliases-package: com.example.model
configuration:
map-underscore-to-camel-case: true # Автоматическое преобразование в camel case
Подход 2: Полная конфигурация Java Config (тонкая настройка)
Пример
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");
// Пользовательская конфигурация (пример)
org.apache.ibatis.session.Configuration config = new Configuration();
config.setMapUnderscoreToCamelCase(true);
config.setDefaultFetchSize(100);
factory.setConfiguration(config);
// Конфигурация плагина (пример)
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); // Ограничить сканирование аннотаций
return scanner;
}
}
Подход 3: Традиционная конфигурация 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. Конфигурация управления транзакциями
Пример
@EnableTransactionManagement
public class TransactionConfig {
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
// Можно определить шаблон транзакции
@Bean
public TransactionTemplate transactionTemplate(PlatformTransactionManager manager) {
return new TransactionTemplate(manager);
}
}
4. Рекомендации по использованию и лучшие практики
Определение интерфейса Mapper:
Пример
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);
}
Пример сервисного слоя:
Пример
@Transactional(readOnly = true) // Только для чтения по умолчанию
public class UserService {
private final UserMapper userMapper;
@Autowired // Рекомендуется внедрение через конструктор
public UserService(UserMapper userMapper) {
this.userMapper = userMapper;
}
@Transactional // Для операций записи открывайте транзакции отдельно
public User createUser(String name) {
User user = new User();
user.setName(name);
userMapper.insert(user);
return userMapper.selectById(user.getId());
}
}
5. Интеграция расширенных функций
Конфигурация динамического источника данных:
Пример
@Primary
public DataSource dynamicDataSource() {
DynamicDataSource ds = new DynamicDataSource();
ds.setDefaultTargetDataSource(primaryDataSource());
ds.setTargetDataSources(Map.of(
"master", primaryDataSource(),
"slave", secondaryDataSource()
));
return ds;
}
Управление транзакциями с несколькими источниками данных:
Пример
public PlatformTransactionManager transactionManager() {
return new ChainedTransactionManager(
new JpaTransactionManager(entityManagerFactory()),
new DataSourceTransactionManager(dataSource())
);
}
Лучшие практики для MyBatis
- Используйте интерфейсы Mapper вместо прямого использования SqlSession: это делает код более типобезопасным и упрощает его сопровождение.
- Используйте динамический SQL надлежащим образом: избегайте рисков SQL-инъекций и сохраняйте читаемость SQL.
- Пакетные операции: для больших пакетных операций с данными используйте пакетную обработку для повышения производительности.
- Используйте кэширование надлежащим образом: настраивайте подходящие стратегии кэширования в зависимости от бизнес-требований.
- Оптимизация SQL: пишите эффективные SQL-запросы в Mapper XML.
MyBatis — это гибкий и мощный ORM-фреймворк. При правильном использовании он может значительно повысить эффективность разработки и производительность приложения. Надеюсь, эта статья поможет вам понять и использовать фреймворк MyBatis.
Другие расширения
Общие библиотеки классов Java