一、mybatis
1.什么是
- 持久化框架。
- 通过XML或注解的方式将实体类和SQL语句进行映射,开发者快速进行CRUD操作。
2.核心组件
(1)SqlSessionFactory
- 创建SqlSession实例。
- 用于执行SQL操作 。
- 代码
java
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
(2)SqlSession
- 执行 SQL 语句、提交或回滚事务、获取映射器等。
- 代码
java
try (SqlSession session = sqlSessionFactory.openSession()) {
Blog blog = session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
}
(3)Mapper接口
- 定义数据库操作的接口,MyBatis会自动生成实现类。
- 可以通过XML文件或注解进行配置。
- 代码
java
public interface BlogMapper {
@Select("SELECT * FROM blog WHERE id = #{id}")
Blog selectBlog(int id);
}
(4)Mapper XML 文件
- 包含 SQL 语句和结果映射的配置文件。
- 代码
java
<?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="org.mybatis.example.BlogMapper">
<select id="selectBlog" resultType="org.mybatis.example.Blog">
SELECT * FROM blog WHERE id = #{id}
</select>
</mapper>
3.配置文件
mybatis-config.xml
- MyBatis 的全局配置文件,包含数据库连接信息、映射文件路径等配置。
- 代码
java
<?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.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="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
4.映射文件
(1)SQL语句
- 在 Mapper XML 文件中定义 SQL 语句。
- 代码
java
<select id="selectBlog" resultType="org.mybatis.example.Blog">
SELECT * FROM blog WHERE id = #{id}
</select>
(2)参数映射
- 通过 #{} 语法传递参数。
- 代码
java
<select id="selectBlog" resultType="org.mybatis.example.Blog">
SELECT * FROM blog WHERE id = #{id}
</select>
(3) 结果映射
- 将查询结果映射到 Java 对象。
- 代码
java
<resultMap id="blogResultMap" type="org.mybatis.example.Blog">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="author" column="author"/>
</resultMap>
<select id="selectBlog" resultMap="blogResultMap">
SELECT * FROM blog WHERE id = #{id}
</select>
5.动态SQL
(1)if:条件判断。
代码
java
<select id="findActiveBlogWithTitleLike" parameterType="map" resultType="Blog">
SELECT * FROM blog
WHERE state = 'ACTIVE'
<if test="title != null">
AND title like #{title}
</if>
</select>
(2)choose (when, otherwise):多条件选择。
代码
java
<select id="findActiveBlogLike" parameterType="map" resultType="Blog">
SELECT * FROM blog
WHERE state = 'ACTIVE'
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
(3)where:自动处理 AND 和 OR 关键字。
代码
java
<select id="findActiveBlogLike" parameterType="map" resultType="Blog">
SELECT * FROM blog
<where>
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</where>
</select>
(4)set:自动处理 SET 关键字。
代码
java
<update id="updateBlog" parameterType="map">
UPDATE blog
<set>
<if test="title != null">
title = #{title},
</if>
<if test="author != null">
author = #{author},
</if>
<if test="views != null">
views = #{views}
</if>
</set>
WHERE id = #{id}
</update>
(5)foreach:遍历集合。
代码
java
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT * FROM POST P
WHERE ID IN
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
6.缓存机制
(1)一级缓存
什么是
- SqlSession 级别的缓存,也就是说,同一个 SqlSession 在执行相同的 SQL 语句时,会首先从缓存中查找数据,如果缓存中有数据,则直接返回,不再访问数据库。一级缓存默认是开启的,且无法关闭。
代码
java
//UserMapper
public interface UserMapper {
User selectUserById(int id);
}
//UserMapper.xml
<?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="selectUserById" resultType="com.example.model.User">
SELECT * FROM user WHERE id = #{id}
</select>
</mapper>
//测试代码
public class MyBatisTest {
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 void main(String[] args) {
try (SqlSession session = sqlSessionFactory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
// 第一次查询
User user1 = mapper.selectUserById(1);
System.out.println(user1);
// 第二次查询,从一级缓存中获取
User user2 = mapper.selectUserById(1);
System.out.println(user2);
}
}
}
//结果输出
User{id=1, name='John Doe', email='john.doe@example.com'}
User{id=1, name='John Doe', email='john.doe@example.com'}
(2)二级缓存
什么是
- Mapper 级别的缓存,也就是说,多个 SqlSession 可以共享同一个 Mapper 的缓存。二级缓存是可选的,需要手动配置和开启。
代码
java
//mybatis-config.xml
<?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/mydb"/>
<property name="username" value="root"/>
<property name="password" value="password"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/example/mapper/UserMapper.xml"/>
</mappers>
</configuration>
//UserMapper.xml
<?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">
<!-- 开启二级缓存 -->
<cache/>
<select id="selectUserById" resultType="com.example.model.User">
SELECT * FROM user WHERE id = #{id}
</select>
</mapper>
//测试代码
public class MyBatisTest {
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 void main(String[] args) {
try (SqlSession session1 = sqlSessionFactory.openSession()) {
UserMapper mapper1 = session1.getMapper(UserMapper.class);
// 第一次查询
User user1 = mapper1.selectUserById(1);
System.out.println(user1);
}
try (SqlSession session2 = sqlSessionFactory.openSession()) {
UserMapper mapper2 = session2.getMapper(UserMapper.class);
// 第二次查询,从二级缓存中获取
User user2 = mapper2.selectUserById(1);
System.out.println(user2);
}
}
}
//结果输出
User{id=1, name='John Doe', email='john.doe@example.com'}
User{id=1, name='John Doe', email='john.doe@example.com'}
- 优点
- 简单易学:MyBatis 相对其他框架来说比较简单,易于上手,基于 SQL 编程,不需要花费精力处理其他繁琐过程。
- 减少代码量:与 JDBC 相比,MyBatis 可以减少 50%以上的代码量,消除了 JDBC 大量冗余的代码,不需要手动开关连接。
- 良好的数据库兼容性:MyBatis 很好的与各种数据库兼容,因为 MyBatis 使用 JDBC 来连接数据库,所以只要 JDBC 支持的数据库 MyBatis 都支持。
- 灵活:MyBatis 框架的优点还包括灵活,不会对应用程序或者数据库的现有设计强加任何影响,SQL 写在 XML 里,从程序代码中彻底分离,降低耦合度,便于统一管理和优化,可重用。
8.插件机制
什么是
- 允许开发者通过实现 Interceptor 接口来自定义插件,从而扩展框架的功能。
代码
java
//实现 Interceptor 接口
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})
public class MyInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 拦截逻辑
System.out.println("Before executing SQL");
Object result = invocation.proceed();
System.out.println("After executing SQL");
return result;
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
// 设置属性
}
}
//配置插件
<configuration>
<plugins>
<plugin interceptor="com.example.interceptor.MyInterceptor">
<property name="someProperty" value="100"/>
</plugin>
</plugins>
</configuration>
9.类型处理器
什么是
- 处理特殊数据类型的转换,如日期、枚举等。
代码
java
//实现TypeHandler接口
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class EnumTypeHandler extends BaseTypeHandler<MyEnum> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, MyEnum parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, parameter.getValue());
}
@Override
public MyEnum getNullableResult(ResultSet rs, String columnName) throws SQLException {
String value = rs.getString(columnName);
return MyEnum.fromValue(value);
}
@Override
public MyEnum getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String value = rs.getString(columnIndex);
return MyEnum.fromValue(value);
}
@Override
public MyEnum getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String value = cs.getString(columnIndex);
return MyEnum.fromValue(value);
}
}
//注册类型处理器
<typeHandlers>
<typeHandler javaType="com.example.MyEnum" jdbcType="VARCHAR" handler="com.example.handler.EnumTypeHandler"/>
</typeHandlers>
10.事务管理
什么是
- MyBatis 提供了简单的事务管理功能,可以方便地管理数据库事务
代码
java
try (SqlSession session = sqlSessionFactory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
// 开始事务
session.getConnection().setAutoCommit(false);
// 执行多个操作
mapper.insertUser(new User("John Doe", "john.doe@example.com"));
mapper.insertUser(new User("Jane Doe", "jane.doe@example.com"));
// 提交事务
session.commit();
} catch (Exception e) {
// 回滚事务
session.rollback();
e.printStackTrace();
}
二、mybatisplus
1.什么是
- MyBatis 的增强工具
- 简化操作,减少代码编写
- 提供了许多开箱即用的功能,如自动填充、分页查询、条件构造器等。
2.核心功能
(1) 自动填充
- 在插入或更新数据时,自动填充指定的字段。
- 代码
java
//配置
@Data
@TableName("user")
public class User {
private Long id;
private String name;
private String email;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
}
//处理器
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
this.strictInsertFill(metaObject, "updateTime", Date.class, new Date());
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
}
}
(2)分页查询
- 提供内置的分页查询方法。
- 代码
java
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
public List<User> getUsersByPage(int pageNum, int pageSize) {
Page<User> page = new Page<>(pageNum, pageSize);
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
IPage<User> userPage = userMapper.selectPage(page, queryWrapper);
return userPage.getRecords();
}
(3)条件构造器
- 条件构造器
- 代码
java
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
public List<User> getUsersByName(String name) {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", name);
return userMapper.selectList(queryWrapper);
}
(4)乐观锁
- 提供内置的乐观锁支持。
- 代码
java
//配置
@Data
@TableName("user")
public class User {
private Long id;
private String name;
private String email;
@Version
private Integer version;
}
//处理器
import com.baomidou.mybatisplus.annotation.Version;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import java.lang.reflect.Field;
import java.util.Map;
public class MyOptimisticLockerInterceptor extends OptimisticLockerInterceptor {
@Override
protected boolean isSupport(MappedStatement ms) {
return super.isSupport(ms) && ms.getSqlCommandType() == SqlCommandType.UPDATE;
}
@Override
protected AbstractMethod getMethod(TableInfo tableInfo) {
return new AbstractMethod(tableInfo, "updateByVersion") {
@Override
public String getSql() {
StringBuilder sql = new StringBuilder();
sql.append("<script>");
sql.append("UPDATE ").append(tableInfo.getTableName()).append(" SET ");
for (Map.Entry<String, Object> entry : tableInfo.getFieldMap().entrySet()) {
if (!entry.getKey().equals(tableInfo.getKeyColumn())) {
sql.append(entry.getKey()).append("=#{").append(entry.getValue()).append("},");
}
}
sql.append(tableInfo.getVersionColumn()).append("=#{").append(tableInfo.getVersionPropertyName()).append("+1},");
sql.append("WHERE ").append(tableInfo.getKeyColumn()).append("=#{").append(tableInfo.getKeyProperty()).append("} AND ");
sql.append(tableInfo.getVersionColumn()).append("=#{").append(tableInfo.getVersionPropertyName()).append("}</script>");
return sql.toString();
}
@Override
public KeyGenerator getKeyGenerator() {
return null;
}
};
}
}
- 配置
(1)Maven 依赖---引入 MyBatis-Plus 依赖
java
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
(2)配置文件---application.yml
java
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
mapper-locations: classpath*:mapper/*.xml
type-aliases-package: com.example.entity
(3)配置 MyBatis-Plus
java
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyBatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
- 常用注解
(1)@TableName---指定实体类对应的表名。
java
@Data
@TableName("user")
public class User {
private Long id;
private String name;
private String email;
}
(2)@TableField---指定实体类字段对应的表字段。
java
@Data
@TableName("user")
public class User {
private Long id;
@TableField("user_name")
private String name;
private String email;
}
(3)@TableId---指定主键字段。
java
@Data
@TableName("user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private String email;
}
(4)@Version---指定乐观锁版本字段。
java
@Data
@TableName("user")
public class User {
private Long id;
private String name;
private String email;
@Version
private Integer version;
}
(5)@TableLogic---指定逻辑删除字段。
java
@Data
@TableName("user")
public class User {
private Long id;
private String name;
private String email;
@TableLogic
private Integer deleted;
}
- 代码生成器
(1)什么是
- mybatisplus 提供了强大的代码生成器,可以自动生成实体类、Mapper 接口、XML 映射文件和 Service 层代码。
(2)代码
java
//添加依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
//编写代码生成器
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
public class CodeGenerator {
public static void main(String[] args) {
// 1. 全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("Your Name");
gc.setOpen(false);
// 2. 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/your_database?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("password");
// 3. 包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName("example");
pc.setParent("com.example");
// 4. 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
strategy.setInclude("user"); // 表名
// 5. 生成代码
new AutoGenerator().setGlobalConfig(gc)
.setDataSource(dsc)
.setPackageInfo(pc)
.setStrategy(strategy)
.execute();
}
}
- 性能优化
- 提供多种性能优化选项,如缓存、索引优化等。
- 代码
java
//启用二级缓存
mybatis-plus:
configuration:
cache-enabled: true
//自定义缓存实现
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
}
7.SQL 注入防护
- 提供 SQL 注入防护机制,防止恶意用户通过 SQL 注入攻击系统。
- 代码
java
//配置文件
mybatis-plus:
global-config:
db-config:
inject-bean: true
sql-injector: com.baomidou.mybatisplus.core.injector.DefaultSqlInjector
//自定义 SQL 注入器
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyBatisPlusConfig {
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
}
三、mybatis和mybatisplus区别
对比项 | MyBatis | MyBatis-Plus |
---|---|---|
框架定位 | 持久层框架,支持 SQL 映射和对象关系映射 | MyBatis 的增强工具,提供更高效的开发方式 |
核心功能 | 主要关注 SQL 语句的执行和映射 | 包括通用的 CRUD 操作、条件构造器、代码生成等功能 |
配置方式 | XML 配置文件结合注解 | 注解为主,XML 配置可选 |
代码生成 | 无内置代码生成 | 支持代码生成,可快速生成 Mapper、Model、Service 等代码 |
数据库操作 | 手动编写 SQL 语句 | 提供了更简洁的方法调用 |
性能 | 性能较好 | 性能损耗小,效率较高 |
扩展性 | 可通过扩展插件实现特定功能 | 扩展性强,提供了丰富的插件和功能 |
学习曲线 | 有一定学习成本 | 相对较简单,学习门槛较低 |