Mybatis 是一个优秀的持久层框架,支持定制化 SQL、存储过程以及高级映射,能够将业务逻辑与数据库访问逻辑分离。它通过 XML 或注解的方式将 SQL 语句和 Java 方法进行映射,适用于多种数据库平台。Mybatis 提供了灵活的 SQL 执行能力和良好的可维护性。本文将详细介绍 Mybatis 持久层框架资料,包括其安装配置、核心概念、基本使用方法以及高级特性。
Mybatis简介Mybatis 是一个优秀的持久层框架,支持定制化 SQL、存储过程以及高级映射。Mybatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取返回结果集的工作。Mybatis 通过 XML 或注解的方式将 SQL 语句和 Java 方法进行映射,从而将业务逻辑与数据库访问逻辑分离,使得程序结构更加清晰。
Mybatis 是一款优秀的持久层框架,基于 Java 的持久化框架,与 Hibernate 类似,Mybatis 也是对象关系映射(ORM)框架。它并没有完全替代 JDBC 的所有功能,而是作为 JDBC 的封装层,可以与任何主流数据库产品一起使用。Mybatis 通过简单的 XML 或注解进行配置和原始映射,将接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)映射成数据库中的记录。
优势:
应用场景:
为了使用 Mybatis,需要在项目中添加 Mybatis 依赖。以 Maven 项目为例,展示如何在 pom.xml
文件中添加 Mybatis 依赖:
<dependencies> <!-- Mybatis核心依赖 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.6</version> </dependency> <!-- MySQL数据库驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.23</version> </dependency> <!-- C3P0数据库连接池 --> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.4</version> </dependency> </dependencies>
在配置好依赖后,需要创建 Mybatis 的配置文件 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> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mydatabase"/> <property name="username" value="root"/> <property name="password" value="password"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/example/dao/UserMapper.xml"/> </mappers> </configuration>
接下来,创建数据库表和对应的 Java 类。这里以一个简单的用户表为例:
CREATE TABLE users ( id int(11) NOT NULL AUTO_INCREMENT, username varchar(255) NOT NULL, password varchar(255) NOT NULL, PRIMARY KEY (id) );
Java 类定义如下:
public class User { private int id; private String username; private String password; // Getters and Setters }
最后,需要创建 Mybatis 的 Mapper XML 文件,编写相关的 SQL 语句:
<?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.UserMapper"> <select id="selectUserById" resultType="com.example.User"> SELECT * FROM users WHERE id = #{id} </select> </mapper>
至此,Mybatis 的安装和环境搭建已经完成。
Mybatis的核心概念Mybatis 的核心概念包括 SqlSession、SqlSessionFactory、Mapper、Mapper 接口和 Mybatis 的配置文件。
SqlSession 是 Mybatis 中最重要的接口之一,是执行数据库操作的载体,可以理解为一个会话(session),它是线程不安全的。通过 SqlSession,可以执行 CRUD 操作、提交或回滚事务。
SqlSessionFactory 是一个工厂接口,用于创建 SqlSession。SqlSessionFactory 是线程安全的,可以通过 Mybatis 的配置文件创建 SqlSessionFactory。
下面是一个创建 SqlSessionFactory 的示例:
// 创建 SqlSessionFactory SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml")); // 通过 SqlSessionFactory 创建 SqlSession SqlSession session = factory.openSession();
Mapper 是 Mybatis 中专门用于处理数据库操作的接口。通过 Mapper 接口,可以简化 SQL 语句的编写。Mapper 接口中的方法对应于 SQL 语句,可以通过注解或 XML 文件来定义这些 SQL 语句。
Mapper 接口通常定义如下:
public interface UserMapper { User selectUserById(int id); }
相应的 Mapper XML 文件定义如下:
<mapper namespace="com.example.dao.UserMapper"> <select id="selectUserById" resultType="com.example.User"> SELECT * FROM users WHERE id = #{id} </select> </mapper>
Mybatis 的配置文件 mybatis-config.xml
包含了数据库连接信息、事务管理器配置、环境配置等重要信息。以下是配置文件的部分示例:
<configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mydatabase"/> <property name="username" value="root"/> <property name="password" value="password"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/example/dao/UserMapper.xml"/> </mappers> </configuration>
其中 <environments>
标签用于配置数据库环境,<transactionManager>
标签用于配置事务管理器,<dataSource>
标签用于配置数据源,<mappers>
标签用于配置 Mapper 文件。
Mybatis 的基本使用包括 CRUD 操作、结果集映射和动态 SQL 的编写。这些内容是 Mybatis 使用中最基础和常见的部分。
CRUD 是指创建(Create)、读取(Read)、更新(Update)和删除(Delete)操作。下面通过一个简单的例子来展示如何使用 Mybatis 进行 CRUD 操作。
首先,定义一个 User
类:
public class User { private int id; private String username; private String password; // Getters and Setters }
接下来定义 UserMapper
接口:
public interface UserMapper { User selectUserById(int id); List<User> selectAllUsers(); int insertUser(User user); int updateUser(User user); int deleteUser(int id); }
对应的 Mapper XML 文件:
<mapper namespace="com.example.dao.UserMapper"> <select id="selectUserById" resultType="com.example.User"> SELECT * FROM users WHERE id = #{id} </select> <select id="selectAllUsers" resultType="com.example.User"> SELECT * FROM users </select> <insert id="insertUser"> INSERT INTO users (username, password) VALUES (#{username}, #{password}) </insert> <update id="updateUser"> UPDATE users SET username = #{username}, password = #{password} WHERE id = #{id} </update> <delete id="deleteUser"> DELETE FROM users WHERE id = #{id} </delete> </mapper>
在实际的项目中,还需要编写 Mybatis 的配置文件 mybatis-config.xml
:
<configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mydatabase"/> <property name="username" value="root"/> <property name="password" value="password"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/example/dao/UserMapper.xml"/> </mappers> </configuration>
接下来编写测试代码:
public class MybatisTest { public static void main(String[] args) { SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml")); SqlSession session = factory.openSession(); UserMapper mapper = session.getMapper(UserMapper.class); // 添加用户 User user = new User(); user.setUsername("testUser"); user.setPassword("testPassword"); mapper.insertUser(user); session.commit(); // 查询用户 User userById = mapper.selectUserById(1); System.out.println(userById); // 查询所有用户 List<User> allUsers = mapper.selectAllUsers(); System.out.println(allUsers); // 更新用户 user.setUsername("updatedUser"); mapper.updateUser(user); session.commit(); // 删除用户 mapper.deleteUser(1); session.commit(); session.close(); } }
Mybatis 通过 ResultMap 来映射数据库中的字段到 Java 对象的属性。ResultMap 定义了列和属性之间的映射关系,支持一对一和一对多的映射。
下面通过一个简单的例子来展示如何使用 ResultMap。假设有一个用户表 users
和一个订单表 orders
,用户表中有用户信息,订单表中有订单信息。每个用户可以有多个订单。
首先,定义 User
类和 Order
类:
public class User { private int id; private String username; private String password; private List<Order> orders; // Getters and Setters } public class Order { private int id; private int userId; private String orderName; private Date orderDate; // Getters and Setters }
对应的 Mapper XML 文件:
<mapper namespace="com.example.dao.UserMapper"> <resultMap id="UserResultMap" type="com.example.User"> <id property="id" column="id"/> <result property="username" column="username"/> <result property="password" column="password"/> <collection property="orders" ofType="com.example.Order" select="selectOrders" column="id" /> </resultMap> <select id="selectUserById" resultMap="UserResultMap"> SELECT * FROM users WHERE id = #{id} </select> <select id="selectOrders" resultType="com.example.Order"> SELECT * FROM orders WHERE user_id = #{userId} </select> </mapper>
在上面的配置中,<resultMap>
标签定义了用户和订单之间的映射关系,selectOrders
是一个调用另一个 SQL 语句的方法,通过 column
属性传递参数。
Mybatis 动态 SQL 用于根据不同的条件生成不同的 SQL 语句。常用的动态 SQL 标签有 <if>
、<choose>
、<when>
、<otherwise>
、<foreach>
、<set>
等。
下面通过一个例子来展示如何使用动态 SQL。假设需要一个查询语句,可以根据不同的参数条件查询用户。
<select id="selectUserByCondition" resultType="com.example.User"> SELECT * FROM users <where> <if test="username != null"> AND username = #{username} </if> <if test="password != null"> AND password = #{password} </if> </where> </select>
在上面的配置中,<where>
标签用于生成 SQL 的 WHERE 子句,<if>
标签用于根据条件生成 SQL。
Mybatis 的高级特性包括一级和二级缓存、分页查询、插件开发与拦截器和类型处理器。
Mybatis 支持一级缓存和二级缓存。
一级缓存:
一级缓存是 SqlSession 级别的缓存,每个 SqlSession 都有一个本地缓存,当执行 SQL 语句时,结果会先被缓存起来。一级缓存默认开启,不需要额外的配置。
二级缓存:
二级缓存是基于 Mapper 的缓存,同一个 Mapper 的所有 SqlSession 都可以共享这个缓存。二级缓存默认是关闭的,需要在 Mapper XML 文件中进行配置。
示例配置:
<cache />
默认情况下,二级缓存会为每个 Mapper 创建一个缓存实例。也可以自定义缓存策略和实现:
<cache eviction="FIFO" <!-- 启用缓存的策略,默认是 LRU --> flushInterval="60000" <!-- 缓存刷新间隔,默认是未指定 --> size="100" <!-- 缓存的最大容量,默认是 1024 --> readOnly="true" <!-- 是否只读缓存,默认是 false --> />
Mybatis 提供了分页查询的支持,可以通过插件或在 SQL 语句中使用动态 SQL 来实现分页。
通过插件实现分页:
Mybatis 提供了插件机制可以实现分页插件。下面是一个简单的分页插件示例:
public class PaginationPlugin extends Interceptor { @Override public Object intercept(Invocation invocation) { Object target = invocation.getTarget(); Method method = invocation.getMethod(); if (method.getName().equals("select")) { MappedStatement mappedStatement = (MappedStatement) target; Configuration configuration = mappedStatement.getConfiguration(); // 获取原 SQL 语句 String originalSql = mappedStatement.getSqlSource().getOriginalSql(); // 获取参数 Object[] args = invocation.getArgs(); // 分页参数 int pageSize = (Integer) args[1]; int skip = (Integer) args[2]; // 构造新的 SQL 语句 String newSql = originalSql + " limit " + skip + ", " + pageSize; // 构造新的 MappedStatement MappedStatement newMappedStatement = configuration.newMappedStatement( mappedStatement.getId(), new SqlSource(originalSql) { @Override public BoundSql getBoundSql(Object parameterObject) { return new BoundSql(configuration, newSql, parameterObject); } }, mappedStatement.getSqlCommandType(), mappedStatement.getSqlId(), mappedStatement.getParameters(), mappedStatement.getKeyProperty(), mappedStatement.getKeyColumns(), mappedStatement.getKeyResultSet(), mappedStatement.getResultMap(), mappedStatement.getKeyResultType(), mappedStatement.getKeyResultHandler(), mappedStatement.getKeyResultMaps(), mappedStatement.getKeyResultSetType(), mappedStatement.getKeyResultSetHandler(), mappedStatement.getKeyResultMapType(), mappedStatement.getKeyResultHandlerType() ); // 调用新的 MappedStatement return invocation.proceed(new Object[]{newMappedStatement, args[0]}); } return invocation.proceed(); } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { // 设置属性 } }
通过动态 SQL 实现分页:
在 Mapper XML 文件中使用动态 SQL 实现分页:
<select id="selectUserByPage" resultType="com.example.User"> SELECT * FROM users <if test="skip != null"> LIMIT #{skip}, #{pageSize} </if> </select>
Mybatis 提供了插件机制,可以通过插件来扩展 Mybatis 的功能。插件通过实现 org.apache.ibatis.plugin.Interceptor
接口来实现。
下面是一个简单的插件示例,用于拦截所有的 SQL 语句并打印出来:
public class LoggingPlugin implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { Object target = invocation.getTarget(); Method method = invocation.getMethod(); Object[] args = invocation.getArgs(); System.out.println("Intercepting method: " + method.getName()); System.out.println("Target: " + target); System.out.println("Arguments: " + Arrays.toString(args)); Object result = invocation.proceed(); System.out.println("Result: " + result); return result; } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { // 设置属性 } }
插件配置需要在 mybatis-config.xml
中进行:
<plugins> <plugin interceptor="com.example.plugin.LoggingPlugin"> <!-- 设置插件的属性 --> </plugin> </plugins>
Mybatis 提供了类型处理器(TypeHandler)来处理 Java 类型和数据库类型之间的转换。默认情况下,Mybatis 会使用一些常见的类型处理器,如 IntegerTypeHandler
、StringTypeHandler
等。可以通过实现 org.apache.ibatis.type.TypeHandler
接口来创建自定义的类型处理器。
下面是一个简单的自定义类型处理器示例,用于处理 Java 的 Date
类型和数据库的 VARCHAR
类型之间的转换:
public class CustomDateTypeHandler implements TypeHandler<Date> { @Override public void setParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType) throws SQLException { if (parameter == null) { ps.setNull(i, Types.VARCHAR); } else { ps.setString(i, new SimpleDateFormat("yyyy-MM-dd").format(parameter)); } } @Override public Date getResult(ResultSet rs, String columnName) throws SQLException { String dateStr = rs.getString(columnName); if (dateStr == null) { return null; } return new SimpleDateFormat("yyyy-MM-dd").parse(dateStr); } @Override public Date getResult(ResultSet rs, int columnIndex) throws SQLException { String dateStr = rs.getString(columnIndex); if (dateStr == null) { return null; } return new SimpleDateFormat("yyyy-MM-dd").parse(dateStr); } @Override public Date getResult(Statement rs, int columnIndex) throws SQLException { String dateStr = rs.getString(columnIndex); if (dateStr == null) { return null; } return new SimpleDateFormat("yyyy-MM-dd").parse(dateStr); } }
在配置文件中注册自定义类型处理器:
<typeHandlers> <typeHandler handler="com.example.handler.CustomDateTypeHandler" javaType="java.util.Date" jdbcType="VARCHAR"/> </typeHandlers>Mybatis与Spring集成
Mybatis 与 Spring 集成可以让 Mybatis 更加方便地使用。Spring 提供了 MybatisTemplate
和 SqlSessionTemplate
支持 Mybatis 的事务管理。同时,Spring 也提供了 @Mapper
注解和 Mapper 接口扫描功能。
为了使用 Mybatis 和 Spring 的集成功能,需要在项目中引入 Mybatis-Spring 的依赖:
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.6</version> </dependency>
@Mapper
注解用于标记 Mapper 接口,Spring 会自动扫描并创建 Mapper 接口的实例。
例如:
@Mapper public interface UserMapper { User selectUserById(int id); }
@MapperScan
注解用于扫描 Mapper 接口所在的包,例如:
@Configuration @MapperScan("com.example.mapper") public class MybatisConfig { // Mybatis 配置 }
Spring 提供了声明式事务管理和编程式事务管理。可以通过 @Transactional
注解来声明式地管理事务。
@Service public class UserService { @Autowired private UserMapper userMapper; @Transactional public void addUser(User user) { userMapper.insertUser(user); } }
在 Spring 配置文件中,可以通过 DataSourceTransactionManager
来配置事务管理器:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean>Mybatis调试与优化
Mybatis 提供了日志工具的支持,可以通过日志来查看 SQL 语句和参数等信息。下面是使用 log4j 配置 Mybatis 日志的示例:
<configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <logger name="com.example" level="debug" /> <logger name="org.apache.ibatis" level="debug" /> <root level="info"> <appender-ref ref="STDOUT" /> </root> </configuration>
<cache /> <cache eviction="FIFO" flushInterval="60000" size="100" readOnly="true" />
<dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mydatabase"/> <property name="username" value="root"/> <property name="password" value="password"/> </dataSource>
CREATE INDEX idx_username ON users(username);
SELECT * FROM users WHERE username = 'testUser';
<property name="url" value="jdbc:mysql://localhost:3306/mydatabase"/>
@Transactional public void addUser(User user) { userMapper.insertUser(user); }
通过本文的介绍,你应该已经掌握了 Mybatis 的基本概念、使用方法和高级特性。希望这些内容能够帮助你在实际项目中更有效地使用 Mybatis。