MyBatis简介和工程搭建

MyBatis是Java中使用最广泛的持久层ORM框架之一,它的主要功能是根据参数组装SQL语句,以及将SQL执行的结果映射到Java对象。
MyBatis和JPA/Hibernate不同,JPA映射的是Java对象和数据库表,SQL语句则是全自动生成的;而MyBatis则是一个半自动的ORM框架,开发人员需要手写SQL语句并手动配置映射关系。MyBatis虽然写法稍显麻烦,但它在性能和易用性之间选择了一个绝佳的平衡点,MyBatis能够使开发人员更灵活的使用SQL以及更多的利用数据库的功能,如各种数据库的专有特性等,而又不至于陷入直接使用JDBC的繁琐代码中。
官方Github仓库:https://github.com/mybatis/mybatis-3
MyBatis简单使用
下面例子中,我们在一个普通的Java工程里使用MyBatis框架并实现一个查询功能,以此了解MyBatis的使用方法。
引入Maven依赖
首先在Maven的pom.xml中编写配置信息,引入我们需要的MyBatis依赖,此外还需要引入数据库驱动,我这里使用的数据库是MySQL。
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.13</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.1.0</version>
</dependency>
配置文件中,我们引入了MyBatis框架和MySQL驱动。注意由于我这里使用的是最新版本MySQL8.1数据库,它的驱动包<artifactId>发生了变化,老版本中为mysql-connector-java,截至目前实际开发中可能还是老版本MySQL居多。
表和实体类
数据库中,我们按如下SQL语句建表。
create table netstore.t_user (
user_id bigint auto_increment primary key,
username varchar(20) not null,
password varchar(255) not null
);
Java代码中,我们的实体类定义如下。
package com.gacfox.demomb.model;
import lombok.Data;
@Data
public class User {
private Long userId;
private String username;
private String password;
}
mybatis-config.xml
mybatis-config.xml是MyBatis的配置文件,具体内容见代码中的注释。
<?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>
<!--为类全名定义一个别名方便在Mapper文件中使用-->
<typeAliases>
<typeAlias alias="User" type="com.gacfox.demomb.model.User"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<!--使用MyBatis自带的连接池-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/netstore"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--映射文件位置-->
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
配置中,连接池里需要指定MySQL的驱动类,我这里使用的是最新版的MySQL和驱动,因此包名为com.mysql.cj.jdbc.Driver,在较早的版本中包名可能为com.mysql.jdbc.Driver,截至目前实际项目中还是以老版本使用居多。
UserMapper.xml
UserMapper.xml是MyBatis框架中需要我们编写的映射文件。
<?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.gacfox.demomb.mapper.UserMapper">
<select id="selectAll" resultType="User">
select user_id as userId, username, password
from t_user
</select>
</mapper>
注意我们这里的数据库查询结果字段名和用户实体类对应的字段名是一样的,这保证了Mapper映射文件中能够不需要其他设置,直接将SQL返回的结果映射到Java对象上(Mapper文件中使用了resultType进行指定,User是之前配置的com.gacfox.demomb.model.User的别名,该别名在之前的typeAlias配置中进行过声明)。
有关Mapper相关的其它配置和用法将在后续章节继续详细介绍。
调用MyBatis框架
下面例子中,我们调用MyBatis框架查询数据。
Main.java
package com.gacfox.demomb;
import com.gacfox.demomb.model.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.Reader;
import java.util.List;
public class Main {
public static void main(String[] args) {
try {
//加载MyBatis配置文件生成SqlSessionFactory
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
reader.close();
//通过SqlSessionFactory获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//执行Mapper中定义的任务,selectAll是select标签的id
List<User> userList = sqlSession.selectList("selectAll");
for (User u : userList) {
System.out.println(u);
}
sqlSession.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
代码中,我们先创建了MyBatis的SqlSessionFactory对象,然后调用sqlSessionFactory.openSession()打开数据库连接并调用执行SQL命令的方法。此时就可以正常查询到数据了。
SpringBoot工程集成MyBatis
MyBatis提供了SpringBoot起步依赖,直接将其引入即可,使用起来非常简单。
pom.xml
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
此外还需要在工程配置文件中对数据源和扫描路径等进行配置。
application.properties
# 数据库驱动类
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 数据源名称
spring.datasource.name=defaultDataSource
# 数据库连接URL
spring.datasource.url=jdbc:mysql://localhost:3306/netstore?useSSL=false&serverTimezone=GMT%2B8
# 数据库用户名
spring.datasource.username=root
# 数据库密码
spring.datasource.password=root
# MyBatis的Mapper文件路径
mybatis.mapper-locations=classpath:mappers/*.xml
# MyBatis的实体类扫描路径
mybatis.type-aliases-package=com.gacfox.demomb.model
配置中,mybatis.mapper-locations指定了Mapper的XML文件路径,如果未指定该配置,默认值为类路径和Java接口同包名路径下(即Maven结构的src/main/resources/<Mapper接口同样的java包路径>/xxxMapper.xml),这样写起来比较麻烦,因此建议配置mybatis.mapper-locations值。mybatis.type-aliases-package指定实体类包扫描,如果未指定该配置也可以写类全限定名映射,但一般都推荐配置包名较为简便。
如上配置后,我们还需要配置Mapper接口的包扫描。SpringBoot中,我们需要为MyBatis的映射配置创建一个Mapper接口,但不必编写实现类,MyBatis将根据接口和XML映射配置自动创建实现类,然后我们便可以基于Mapper接口类型进行依赖注入了,但为了让MyBatis能通过反射找到这些Mapper接口我们还需要额外配置,这其实有两种方式实现:
- 在SpringBoot启动类上标注
@MapperScan接口,指定Mapper接口的包路径 - 在Mapper接口上标注
@Mapper注解
注:Mybatis的起步依赖没有对Mapper接口包扫描设置默认值,我们需要手动设置,否则会在注入Mapper时报错找不到对应的SpringBean。
package com.gacfox.demomb.mapper;
import com.gacfox.demomb.model.Role;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface RoleMapper {
List<Role> selectAll();
}
配置完成后,我们就可以直接在SpringBean中依赖注入Mapper并调用相关方法了。
@Resource
private RoleMapper roleMapper;
老式Spring工程集成MyBatis
在手动搭建的Spring工程中使用MyBatis比较麻烦,首先我们要引入MyBatis框架和MySQL驱动的依赖,这部分和前面普通Java工程中相同。此外还需要在applicationContext.xml中对相关的Bean进行装配,下面是一个例子配置。
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 业务层注解扫描-->
<context:component-scan base-package="com.gacfox.mbdemo.service"/>
<!-- 配置数据源使用C3P0数据库连接池-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<!-- 数据库驱动-->
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<!-- 数据库连接URL-->
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/netstore"/>
<!-- 用户名-->
<property name="user" value="root"/>
<!-- 密码-->
<property name="password" value="root"/>
<!-- 连接池最小维持连接数-->
<property name="minPoolSize" value="10"/>
<!-- 连接池最大维持连接数-->
<property name="maxPoolSize" value="100"/>
<!-- 连接池初始连接数-->
<property name="initialPoolSize" value="10"/>
<!-- 连接最大空闲时间-->
<property name="maxIdleTime" value="300"/>
<!-- 数据源已加载预编译SQL语句最大数量-->
<property name="maxStatements" value="1000"/>
<!-- 空闲连接检查时间间隔-->
<property name="idleConnectionTestPeriod" value="60"/>
<!--获取新连接失败时的重试次数-->
<property name="acquireRetryAttempts" value="30"/>
</bean>
<!--配置MyBatis的SqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--数据源-->
<property name="dataSource" ref="dataSource"/>
<!--mybatis-config.xml文件位置-->
<property name="configLocation" value="classpath:mybatis-config.xml" />
<!--mapper.xml文件位置-->
<property name="mapperLocations">
<array>
<value>classpath:mappers/*.xml</value>
</array>
</property>
<!--该包下所有的类使用类名作为类全名的别名-->
<property name="typeAliasesPackage" value="com.gacfox.demomb.model"/>
</bean>
<!-- 配置Mapper扫描器 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--扫描的包名-->
<property name="basePackage" value="com.gacfox.demomb.mapper"/>
<!--上面配置的bean名,注意这个配置比较怪,参数是bean名字符串,而不是引用-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
</bean>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 注解驱动的事务支持-->
<tx:annotation-driven transaction-manager="txManager"/>
</beans>
上面配置中,我们主要配置了数据源,以及适用于MyBatis的SqlSessionFactory。配置完成后,使用方法同SpringBoot工程。