MyBatis 是一个基于 Java 的优秀持久层框架,在软件开发中发挥着重要作用。它最初是 Apache 的开源项目 iBatis,后更名为 MyBatis。
MyBatis 具有诸多显著特点。首先,它支持定制化 SQL,开发人员可以根据具体需求编写灵活的 SQL 语句,满足不同业务场景下的数据查询和操作需求。对于存储过程的支持,使得复杂的数据库操作可以封装在存储过程中,提高了执行效率和代码的可维护性。同时,高级映射功能允许将接口和 Java 的普通对象(POJOs)映射成数据库中的记录,实现了对象关系映射(ORM),方便了 Java 应用与数据库之间的数据交互。
MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集的繁琐过程。通过简单的 XML 或注解来配置和映射原生信息,大大降低了开发人员的工作量,提高了开发效率。例如,使用 XML 配置文件可以将 SQL 语句与 Java 代码分离,便于统一管理和优化。同时,提供映射标签,支持对象与数据库的 ORM 字段关系映射、对象关系组建维护以及编写动态 SQL,增强了框架的灵活性和可扩展性。
当前,最新版本是 MyBatis 3.5.7,其发布时间是 2021 年 4 月 21 日。每个 MyBatis 应用程序主要都是使用 SqlSessionFactory 实例的,一个 SqlSessionFactory 实例可以通过 SqlSessionFactoryBuilder 获得。SqlSessionFactoryBuilder 可以从一个 xml 配置文件或者一个预定义的配置类的实例获得。用 xml 文件构建 SqlSessionFactory 实例非常简单,推荐在这个配置中使用类路径资源,但也可以使用任何 Reader 实例,包括用文件路径或 file:// 开头的 url 创建的实例。MyBatis 还有一个实用类 Resources,它有很多方法,可以方便地从类路径及其它位置加载资源。
MyBatis 的配置和注解方式十分简单。它没有复杂的依赖关系,只需要引入相应的库文件即可开始使用。对于开发人员来说,学习成本较低,可以快速上手。例如,通过简单的 XML 配置文件或者注解,就可以轻松地完成数据库表与 Java 对象之间的映射。开发人员只需要关注业务逻辑,而无需过多地关心底层数据库操作的细节,大大提高了开发效率。
MyBatis 提供了极为灵活的 SQL 映射配置。开发人员可以根据不同的业务需求,编写复杂的 SQL 查询语句,而不会对应用程序的整体架构或者数据库的设计造成影响。例如,使用 MyBatis 的动态 SQL 功能,可以根据不同的条件动态生成 SQL 语句,满足各种复杂的查询需求。此外,MyBatis 还支持自定义类型处理器、注解和插件等功能,进一步增强了框架的灵活性。
MyBatis 通过使用动态 SQL 语句和一级缓存等技术,显著提高了数据库操作的性能。动态 SQL 语句可以根据具体的查询条件进行优化,减少不必要的数据库查询操作。而一级缓存机制可以将频繁查询的数据缓存起来,下次查询时直接从缓存中获取,避免了重复的数据库查询,大大提高了查询效率。据统计,在一些高并发的应用场景下,MyBatis 的性能优势尤为明显,可以有效降低数据库的负载,提高系统的响应速度。
MyBatis 可以与 Spring、Spring Boot 等流行的 Java 框架无缝集成。这使得开发人员可以在这些框架的基础上,更加方便地使用 MyBatis 进行数据库操作。例如,在 Spring 框架中,可以通过配置 MyBatis 的 SqlSessionFactory 和 SqlSessionTemplate 等 bean,轻松地将 MyBatis 集成到项目中。与 Spring Boot 的集成更加便捷,只需要引入相应的 starter 依赖,就可以自动配置 MyBatis,无需进行繁琐的配置工作。这种易于集成的特性,使得开发人员可以更加专注于业务逻辑的实现,提高开发效率。
相对于其他 ORM 框架,如 Hibernate,MyBatis 的学习成本确实较高。开发人员不仅需要掌握 SQL 语句的编写,还需要熟悉 MyBatis 的配置方式。MyBatis 的配置文件相对复杂,包括各种 XML 标签和属性的设置,对于初学者来说可能会感到困惑。例如,在配置文件中需要设置数据库连接信息、映射关系、SQL 语句等,每个部分都有特定的语法和规则。而且,MyBatis 的文档和社区支持相对较弱,当开发人员遇到问题时,可能需要花费更多的时间去查找解决方案。据统计,学习 MyBatis 的时间可能是学习其他一些简单 ORM 框架的两倍甚至更多。
与一些自动化程度较高的框架相比,MyBatis 需要开发人员手写 SQL 语句。对于不熟悉 SQL 的开发者来说,这无疑增加了开发的难度。编写复杂的 SQL 语句需要对数据库的结构和查询语言有深入的了解,否则容易出现语法错误和性能问题。例如,当涉及到多表关联查询、复杂的条件判断和聚合函数时,SQL 语句的编写可能会变得非常复杂。而且,手写 SQL 语句容易出现安全问题,如 SQL 注入攻击。开发人员需要格外小心,对用户输入的数据进行严格的验证和过滤,以防止 SQL 注入。
MyBatis 的配置文件较为繁琐,需要编写大量的 XML 配置文件。这些配置文件包括数据库连接信息、映射关系、SQL 语句等,每个部分都需要仔细配置,否则容易出现错误。例如,在编写映射文件时,需要为每个数据库表和 Java 对象之间的映射关系进行详细的配置,包括字段名、属性名、数据类型等。而且,当数据库结构发生变化时,需要相应地修改配置文件,这增加了维护的工作量。据统计,一个中等规模的项目可能需要编写数百行甚至上千行的 XML 配置文件,这对于开发人员来说是一个不小的负担。
MyBatis 通过多种方式加载配置文件,例如使用sqlSessionFactory的mapperLocations进行加载,或者使用MapperScannerConfigurer进行扫描,还可以在mybatis的配置文件中配置<mappers>节点。在加载配置文件的过程中,会解析全局配置文件和映射文件,将这些信息保存到Configuration的单例实例中,并初始化以下内容:properties 全局参数、settings 设置、typeAliases 别名、ObjectFactory 类型处理器、plugin 插件、environment 环境、DatabaseIdProvider 数据库标识、Mapper 映射器等。
加载配置文件时会涉及到ClassLoader类加载器加载配置文件,通过类名.class获取Class对象,然后获取类加载器去加载配置文件返回InputStream。例如,以下代码展示了如何通过ClassLoader加载配置文件:
//1、读取配置文件
InputStream is = Demo2.class.getClassLoader().getResourceAsStream("db.properties");
//2、创建 Properties 对象
Properties pro = new Properties();
//3、装载
pro.load(is);
//4、解析
String driver = pro.getProperty("driver");
String url = pro.getProperty("url");
String user = pro.getProperty("user");
String password = pro.getProperty("password");
//5、注册驱动获取连接
Class.forName(driver);
Connection conn = DriverManager.getConnection(url, user, password);
加载配置文件后,会生成Configuration对象和一个个MappedStatement,MappedStatement包括了参数映射配置、动态 SQL 语句、结果映射配置等,其对应着<select | update | delete | insert>标签项。
有了Configuration对象后,创建SqlSessionFactory就变得相对简单。通过SqlSessionFactoryBuilder根据Configuration对象来构建SqlSessionFactory。SqlSessionFactory是一个接口,其默认的实现类是org.apache.ibatis.session.defaults.DefaultSqlSessionFactory。一般情况下我们都没有必要自己创建新的SqlSessionFactory实现类。
例如,以下代码展示了创建SqlSessionFactory的过程:
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
通过SqlSessionFactory的openSession方法创建SqlSession,它是与数据库交互的核心对象。SqlSession有两个实现类,分别是DefaultSqlSession和SqlSessionManager。SqlSession通过内部存放的执行器(Executor)来对数据进行 CRUD。
通过SqlSession的方法执行 SQL,例如调用selectOne、insert、update、delete等方法。在执行 SQL 时,会借助MappedStatement进行解析和执行。Executor接口将根据SqlSession传递的参数动态地生成需要执行的 SQL 语句,同时负责查询缓存的维护。
例如,当执行查询操作时,SqlSession会通过Statement ID找到对应的MappedStatement对象,然后通过Executor将MappedStatement对象进行解析,包括 sql 参数转化、动态 sql 拼接,生成jdbc Statement对象,最后执行 SQL 并借助MappedStatement中的结果映射关系,将返回结果转化成HashMap、JavaBean等存储结构并返回。
使用完SqlSession后,需要关闭它以释放与数据库的连接等资源。通常在finally块中完成关闭操作,确保即使出现异常也能正常关闭资源。关闭SqlSession可以避免资源泄漏,提高系统的稳定性和性能。
在使用 Maven 创建项目时,首先需要在项目的 pom.xml 文件中添加 MyBatis 的依赖。以下是一个示例的依赖配置:
<!--MyBatis 及 插件依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.2.1</version>
</dependency>
这样就可以将 MyBatis 引入到项目中。创建好 Maven 项目结构后,可以方便地管理项目的依赖和构建过程。
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="username" value="root"/>
<property name="password" value="password"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/example/mapper/UserMapper.xml"/>
</mappers>
</configuration>
<mapper namespace="com.example.mapper.UserMapper">
<select id="selectUser" parameterType="int" resultType="com.example.domain.User">
SELECT * FROM users WHERE id = #{id}
</select>
<insert id="insertUser" parameterType="com.example.domain.User">
INSERT INTO users(name, email) VALUES(#{name}, #{email})
</insert>
</mapper>
MyBatis 的动态 SQL 功能非常强大,可以根据条件生成不同的 SQL 语句。例如:
<select id="findUsers" resultType="com.example.domain.User">
SELECT * FROM users
<where>
<if test="name!= null">
AND name = #{name}
</if>
<if test="email!= null">
AND email = #{email}
</if>
</where>
</select>
在这个例子中,根据传入的参数name和email的值,动态地生成 SQL 语句中的条件部分。如果name不为空,则添加AND name = #{name}条件;如果email不为空,则添加AND email = #{email}条件。
try (SqlSession session = sqlSessionFactory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
User user1 = mapper.selectUser(1);
User user2 = mapper.selectUser(1);
// 从缓存中读取
}
<configuration>
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
<mapper namespace="com.example.mapper.UserMapper">
<cache/>
<select id="selectUser" parameterType="int" resultType="com.example.domain.User">
SELECT * FROM users WHERE id = #{id}
</select>
</mapper>
</configuration>
通过mybatis-spring-boot-starter可以实现 MyBatis 与 Spring Boot 的无缝整合。首先,在项目的 pom.xml 文件中添加以下依赖:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
然后,在 application.properties 或 application.yml 文件中配置数据库连接信息和 MyBatis 的相关参数。例如:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mydb
username: root
password: password
mybatis:
mapper-locations: classpath*:com/example/mapper/*.xml
这样就可以在 Spring Boot 项目中方便地使用 MyBatis 进行数据库操作。
使用 PageHelper 分页插件可以实现分页查询。首先,在项目的 pom.xml 文件中添加 PageHelper 的依赖:
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.2.1</version>
</dependency>
然后,在项目中配置 PageHelper:
@Bean
public SqlSessionFactory sqlSessionFactoryBean(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setTypeAliasesPackage(MODEL_PACKAGE);
//配置分页插件,详情请查阅官方文档
PageHelper pageHelper = new PageHelper();
Properties properties = new Properties();
properties.setProperty("pageSizeZero", "true");//分页尺寸为0时查询所有纪录不再执行分页
properties.setProperty("reasonable", "true");//页码<=0 查询第一页,页码>=总页数查询最后一页
properties.setProperty("supportMethodsArguments", "true");//支持通过 Mapper 接口参数来传递分页参数
pageHelper.setProperties(properties);
//添加插件
factory.setPlugins(new Interceptor[]{pageHelper});
//添加XML目录
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
factory.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));
return factory.getObject();
}
导入 MyBatis 的核心 Jar 包是使用 MyBatis 的第一步,确保项目能够正确识别和使用 MyBatis 的功能。
# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
在业务相关的包中创建 XML 映射文件,模板如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.mybatis.example.BlogMapper">
<select id="selectBlog" resultType="Blog">select * from Blog where id = #{id}</select>
</mapper>
Java 类中使用 MyBatis 分为如下步骤:
String resource = "mybatis_config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
//构建映射文件中映射的位置(ID)
Customer customer = sqlSession.selectOne("com.itheima.mapper" + ".CustomerMapper.findCustomerById", 1);
sqlSession.close();
依次点击 File->Other Settings->Default Settings。搜索 “Template”,找到 “File and Code Templates”。点击加号新建文件格式,输入名字和后缀,点击 “Enable Live Templates”,Apply。
以 MyBaits 映射文件为例,在 Name 项中填写模板名称,Extension 项中填写文件类型。下面空白处填写模板内容。最关键的是一定要把【Enable Live Templates】前面的对勾打上,否则模板可能无法在新建菜单中看到。最后点击 Apply 应用 OK,保存模板。
例如创建 mybatis-config.xml 核心配置文件模板如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--引入外部配置文件,注意 xml 标签中的顺序-->
<properties resource="jdbc.properties"/>
<typeAliases>
<!--这种方式扫描实体类的包,它的默认别名就为这个类的类名,首字母小写!-->
<package name=""/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!--每一个 Mapper.xml 都需要在 Mybatis 核心配置文件中注册!-->
<mappers>
<package name=""/>
</mappers>
</configuration>
对于创建 MyBatis 映射文件,以 MyBatis Mapper 文件为例,在 Name 项中填写模板名称为 “MyBatis Mapper”,Extension 项中填写 “xml”。下面空白处填写模板内容:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="${NAMESPACE}"></mapper>
最关键的是一定要把【Enable Live Templates】前面的对勾打上,否则模板可能无法在新建菜单中看到。最后点击 Apply 应用 OK,保存模板。
这样,在新建文件时可以看到自定义的模板 MyBatis Mapper。由于在创建模板的时候添加了参数【${NAMESPACE}】,所以在创建文件的时候,除了文件名称,还可以传递参数。
MyBatis 起源于 Apache 的开源项目 iBatis,经过不断发展,如今已成为 Java 领域中广泛使用的持久层框架。它主要解决了传统 JDBC 开发中代码繁琐、数据库连接管理复杂、结果集封装麻烦等问题。通过提供定制化 SQL、存储过程支持以及高级映射功能,MyBatis 让开发者能够更加灵活地操作数据库,同时避免了几乎所有的 JDBC 底层代码编写工作。
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
public class User {
private Integer id;
private String username;
private String password;
// 省略 getter 和 setter 方法
}
public interface IUserMapper {
List<User> findAll();
}
<?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.dao.IUserMapper">
<select id="findAll" resultType="com.example.entity.User">
select * from user
</select>
</mapper>
创建一个名为MyBatisUtil的工具类,用于方便地获取SqlSession对象。
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.InputStream;
public class MyBatisUtil {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession();
}
}
传统的 Dao 开发方式需要编写 Dao 接口的实现类,在实现类中通过SqlSession对象执行数据库操作。这种方式的优点是比较直观,容易理解。缺点是代码较为繁琐,需要手动编写大量的数据库操作代码。例如:
import com.example.entity.User;
import org.apache.ibatis.session.SqlSession;
import java.util.List;
public class UserDaoImpl implements IUserMapper {
@Override
public List<User> findAll() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
try {
return sqlSession.selectList("com.example.dao.IUserMapper.findAll");
} finally {
sqlSession.close();
}
}
}
Mapper 动态代理方式无需程序员手动实现 Dao 接口,MyBatis 会根据 Dao 接口自动生成动态代理实现。这种方式的优点是代码简洁,开发效率高。只需要编写 Dao 接口,MyBatis 会根据接口定义和对应的映射文件自动生成代理对象。例如:
import com.example.entity.User;
import org.apache.ibatis.session.SqlSession;
import java.util.List;
public class MapperDynamicProxyTest {
public static void main(String[] args) {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
IUserMapper userMapper = sqlSession.getMapper(IUserMapper.class);
List<User> users = userMapper.findAll();
for (User user : users) {
System.out.println(user);
}
sqlSession.close();
}
}
因篇幅问题不能全部显示,请点此查看更多更全内容