我就用mybatis作为与数据库交互,但我想用orm,最好的实现方案是啥

明白了!你想用 MyBatis 作为主要数据库交互工具 ,但同时享受 ORM 的便利性。最好的方案是:

方案:MyBatis-Plus + 代码生成器(最主流)

1. 项目结构

复制代码
src/main/java/
├── entity/              # 实体类(ORM核心)
├── mapper/             # Mapper接口
├── service/           # 业务层
└── controller/        # 控制层

2. 依赖配置

xml 复制代码
<dependencies>
    <!-- MyBatis-Plus Starter -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.4.1</version>
    </dependency>
    
    <!-- 代码生成器 -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-generator</artifactId>
        <version>3.5.4.1</version>
    </dependency>
    
    <!-- 模板引擎 -->
    <dependency>
        <groupId>org.freemarker</groupId>
        <artifactId>freemarker</artifactId>
        <version>2.3.32</version>
    </dependency>
</dependencies>

3. 基础实体类(ORM核心)

java 复制代码
@Data
public class BasePO {
    @TableId(type = IdType.AUTO)
    private Long id;
    
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    
    @TableField(fill = FieldFill.INSERT)
    private Long createUser;
    
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;
}

4. 自动生成影视实体类

java 复制代码
// Movie.java - 电影实体
@Data
@TableName("movie")
@EqualsAndHashCode(callSuper = true)
public class Movie extends BasePO {
    private String title;
    private String originalTitle;
    private Integer releaseYear;
    private Integer duration;
    private BigDecimal rating;
    private String description;
    private String posterUrl;
    private String country;
    private String language;
    private Long directorId;
    
    // 关联字段(不映射到数据库)
    @TableField(exist = false)
    private String directorName;
    
    @TableField(exist = false)
    private List<Actor> actors;
}

// Actor.java - 演员实体
@Data
@TableName("actor")
@EqualsAndHashCode(callSuper = true)
public class Actor extends BasePO {
    private String name;
    private String englishName;
    private Integer gender;
    private LocalDate birthday;
    private String country;
    private String biography;
    private String avatarUrl;
}

5. 自动生成 Mapper

java 复制代码
// 自动生成的基础Mapper
@Mapper
public interface MovieMapper extends BaseMapper<Movie> {
    // 继承后自动拥有:
    // insert, deleteById, updateById, selectById, selectList, selectPage 等方法
}

@Mapper  
public interface ActorMapper extends BaseMapper<Actor> {
    // 基础CRUD方法自动实现
}

6. 自定义复杂查询(手写SQL)

java 复制代码
@Mapper
public interface MovieMapper extends BaseMapper<Movie> {
    
    // 复杂查询:电影详情(包含导演和演员)
    @Select("SELECT m.*, d.name as director_name " +
            "FROM movie m " +
            "LEFT JOIN director d ON m.director_id = d.id " +
            "WHERE m.id = #{movieId}")
    Movie selectMovieDetail(@Param("movieId") Long movieId);
    
    // 复杂查询:分页搜索
    @Select("<script>" +
            "SELECT m.*, d.name as director_name " +
            "FROM movie m " +
            "LEFT JOIN director d ON m.director_id = d.id " +
            "WHERE 1=1 " +
            "<if test='title != null'> AND m.title LIKE CONCAT('%', #{title}, '%') </if>" +
            "<if test='minRating != null'> AND m.rating >= #{minRating} </if>" +
            "<if test='startYear != null'> AND m.release_year >= #{startYear} </if>" +
            "<if test='endYear != null'> AND m.release_year <= #{endYear} </if>" +
            "ORDER BY m.rating DESC " +
            "LIMIT #{offset}, #{limit}" +
            "</script>")
    List<Movie> searchMovies(@Param("title") String title,
                            @Param("minRating") BigDecimal minRating,
                            @Param("startYear") Integer startYear,
                            @Param("endYear") Integer endYear,
                            @Param("offset") Long offset,
                            @Param("limit") Integer limit);
}

7. 服务层使用(享受ORM便利)

java 复制代码
@Service
public class MovieService {
    
    @Autowired
    private MovieMapper movieMapper;
    
    @Autowired
    private ActorMapper actorMapper;
    
    /**
     * 简单CRUD - 像ORM一样使用
     */
    public void addMovie(Movie movie) {
        movieMapper.insert(movie);  // 自动填充createTime等字段
    }
    
    public Movie getMovie(Long id) {
        return movieMapper.selectById(id);  // 自动映射到实体
    }
    
    public void updateMovie(Movie movie) {
        movieMapper.updateById(movie);  // 自动填充updateTime
    }
    
    public void deleteMovie(Long id) {
        movieMapper.deleteById(id);  // 简单删除
    }
    
    public List<Movie> listMovies() {
        return movieMapper.selectList(null);  // 查询所有
    }
    
    /**
     * 复杂业务 - 使用自定义SQL
     */
    public List<Movie> searchHighRatedMovies(String keyword) {
        return movieMapper.searchMovies(keyword, 
            new BigDecimal("8.0"), 2020, 2024, 0L, 20);
    }
    
    /**
     * 关联查询
     */
    public Movie getMovieWithActors(Long movieId) {
        Movie movie = movieMapper.selectMovieDetail(movieId);
        if (movie != null) {
            // 查询关联的演员
            List<Actor> actors = actorMapper.selectActorsByMovieId(movieId);
            movie.setActors(actors);
        }
        return movie;
    }
}

8. 自动填充配置

java 复制代码
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    
    @Override
    public void insertFill(MetaObject metaObject) {
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject, "createUser", Long.class, getCurrentUserId());
        this.strictInsertFill(metaObject, "updateUser", Long.class, getCurrentUserId());
    }
    
    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
        this.strictUpdateFill(metaObject, "updateUser", Long.class, getCurrentUserId());
    }
    
    private Long getCurrentUserId() {
        // 从安全上下文获取当前用户ID
        return 1L; // 实际项目中从登录信息获取
    }
}

优势总结

✅ 真正的ORM体验 :实体类操作,自动映射

✅ 性能可控 :复杂查询手写SQL优化

✅ 开发效率 :代码生成器快速生成基础代码

✅ 灵活性 :既享受ORM便利,又保持SQL灵活性

✅ 主流方案:大厂广泛使用,社区活跃

这就是 MyBatis-Plus 的"半ORM"方案 - 既享受了ORM的开发效率,又保持了MyBatis的性能优势!

相关推荐
Henry-SAP1 小时前
SAP PP模块全景概览
数据库
喜欢吃豆1 小时前
Better Auth 深度解析:从用户认证到企业级身份基础设施
数据库·架构·权限·多租户
其实防守也摸鱼2 小时前
Cylab在线靶场——CTF中的通用技能
linux·数据库·学习·算法·靶场·ctf·学习网络安全
吹什么轩2 小时前
MySQL:数据库基础
数据库·mysql
内存漫游2 小时前
Undo、Redo 与事务回滚
数据库
FluxDB2 小时前
用 Rust + GPUI 重做数据库客户端
数据库·mysql
烬羽3 小时前
PostgreSQL:AI 时代原生的"隐型"向量数据库 — 用 pgvector 给消息表加上长期记忆
数据库·人工智能·程序员
Yyyyyy~3 小时前
【Mysql】增删查改操作
数据库·mysql
钱栈up3 小时前
前端改了三页、后端也动了,用户说「完全没变化」——我在 116 库上找到的三个真凶
css·数据库
这个DBA有点耶4 小时前
索引建了查询却更慢——优化器选错索引与Index Merge的隐藏代价
数据库·架构·代码规范