我就用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的性能优势!

相关推荐
程序员三明治2 小时前
SpringBoot YAML 配置读取机制 + 数据库自动初始化原理
数据库·spring boot·后端
flypwn4 小时前
TFCCTF 2025 WebLess题解
服务器·前端·数据库
n***i954 小时前
云原生数据库使用体验,与传统数据库差异
数据库·云原生
hygge9998 小时前
Spring Boot + MyBatis 整合与 MyBatis 原理全解析
java·开发语言·经验分享·spring boot·后端·mybatis
理想三旬11 小时前
关系数据库
数据库
无心水12 小时前
【分布式利器:RocketMQ】2、RocketMQ消息重复?3种幂等方案,彻底解决重复消费(附代码实操)
网络·数据库·rocketmq·java面试·消息幂等·重复消费·分布式利器
q***985213 小时前
基于人脸识别和 MySQL 的考勤管理系统实现
数据库·mysql
l1t13 小时前
用SQL求解advent of code 2024年23题
数据库·sql·算法
百***812714 小时前
Spring 中使用Mybatis,超详细
spring·tomcat·mybatis