首页 > 其他分享 >Mybatis-flex代替繁琐的JPA

Mybatis-flex代替繁琐的JPA

时间:2024-10-06 14:10:53浏览次数:7  
标签:columnConfig flex JPA eq 查询 Mybatis globalConfig 生成

1. 前言

最近在新的SpringBoot项目中采用JPA来作为数据库的持久层。刚开始得益于Spring框架自带,IDEA也有丰富的支持;可以自行匹配数据库字段,接口中方法可以直接提示,支持JPQL,原生SQL等方式。写起来也是非常顺手。但是当业务中有一些复杂一点的需求,在JPA中实现就非常麻烦,且不直观。

本文不是批判JPA和Mybatis-plus的不足,也不会来对比他们的写法优劣。主要是介绍从编码生产力方面解决我日常写代码的一些问题和带来哪些便利。

2. 使用痛点

2.1. JpaRepository(优点)

JPA的Mapper操作类是通过继承JpaRepository来进行CRUD操作,同时有一个非常便捷的操作,我们只需要在接口中通过一定的规则定义方法名称,我们就可以执行对应的SQL。

interface AppRealtimeRecordRepository: JpaRepository<AppRealtimeRecord, Int> {

    fun findByCardNo(cardNo: String?): AppRealtimeRecord?

    @Query("select count(1) from AppRealtimeRecord arr where " +
            "arr.deviceSn = :#{#orderQueryRequest.deviceSn} AND " +
            "arr.createTime BETWEEN COALESCE(:#{#orderQueryRequest.payStartTime}, arr.createTime) AND " +
            "COALESCE(:#{#orderQueryRequest.payEndTime}, arr.createTime)"
    )
    fun summaryQuery(orderQueryRequest: OrderQueryRequest): Long
}

 

 

findByCardNo可以直接生成通过卡号查询实体的语句,非常方便。但是如果我们查询条件比较多,用这种方式就会生成非常长的方法名称,这个时候就需要通过@Query进行参数指定查询。

2.2. 条件查询

经常有一个需求,需要判断某一个字段存在时,在进行SQL查询。但是这种情况使用JPA会感觉非常麻烦。无论是用JPQL还是原生的SQL感觉很难比较好的实现。

上面提供了一个示例是判断开始时间和结束时间是否为空,在进行比较判断。利用的数据库的判空逻辑来进行实现,感觉非常不直观,也不利于SQL调试。

2.2.1. Mybatis-Flex

我们Mybatis-Flex中就非常优雅的可以实现。像写SQL一样非常直观的实现SQL的编写。

QueryWrapper query = QueryWrapper.create()
        .where(EMPLOYEE.LAST_NAME.like(searchWord)) //条件为null时自动忽略
        .and(EMPLOYEE.GENDER.eq(1))
        .and(EMPLOYEE.AGE.gt(24));
List<Employee> employees = employeeMapper.selectListByQuery(query);

 

 

不需要判断条件,默认条件为空时,自动忽略。

2.3. 查询部分字段

这个又是JPA一个比较麻烦的点,JPA是以对象的形式来操作的SQL,所以每次都是查询出来全部的数据。有两种方式可以解决。

  • 查询出数据集,用List<Object[]>数组来接收,在转化成对应我们需要的部分数据。

  • 重新构建一个Model数据,里面只放置我们需要的数据字段,通过new Model(ParamA, ParamB)的方式来解决。

无论哪一种方式都会感觉非常别扭,只是一个很简单的需求。实现起来异常的麻烦。

2.3.1. Mybatis-Flex

在Mybatis-Flex中实现非常简单。使用select方法即可,不传参数值就是查询所有字段。可以定义自己想要查询的字段即可。

// 查询所有数据
QueryWrapper queryWrapper = QueryWrapper.create()
        .select()
        .where(ACCOUNT.AGE.eq(18));
Account account = accountMapper.selectOneByQuery(queryWrapper);

// 查询部分字段,也可以使用Lambda表达式
select(QueryColumn("id"), QueryColumn("name"), QueryColumn("category_id"))

 

 

2.4. kotlin支持

我同步也有一个Kotlin的项目用的JPA,我也一起改成了flex版本。花了不多时间就改造完成,感觉代码整个都看起来非常优雅。

2.4.1. 分页查询
fun detailList(fairyDetailParam: FairyDetailParam): List<FairyDetail> {
    val paginateWith = paginate<FairyDetail>(pageNumber = fairyDetailParam.current,
        pageSize = fairyDetailParam.size,
        init = {
            select(QueryColumn("id"), QueryColumn("name"), QueryColumn("category_id"))
            whereWith {
                FairyDetail::categoryId eq fairyDetailParam.categoryId
            }
        }
    )

    return paginateWith.records
}

 

 

定义分页对象和查询条件即可,init参数传入的是QueryScope,可以自由匹配需要查询的参数。flex有一个特别好的点是,写代码和写SQL的感觉保持一致性。先写select,再写where,orderBy这些。

// 无需注册Mapper与APT/KSP即可查询操作
val accountList: List<Account> = query {
    select(Account::id, Account::userName)
    whereWith {
        Account::age.isNotNull and (Account::age ge 17)
    }
    orderBy(-Account::id)
}

 

 
2.4.2. 更新用户
// 更新用户头像和昵称
update<User> {
    User::avatarUrl set user.avatarUrl
    whereWith {
        User::openId eq user.openId
    }
}

 

 

更新用户头像地址,通过OpenId。写起来非常丝滑。

2.5. 代码自动生成

Gradle中需要添加annotationProcessor 'com.mybatis-flex:mybatis-flex-processor:1.9.3'注解来进行代码生成。Maven的用户可以自行在官网查询如何配置。

目前我做的是半自动的数据生成。先手动创建实体类,在通过实体类生成对应的操作对象。

2.5.1. 创建实体
package cn.db101.jcc.entity;

import java.io.Serializable;
import java.util.Date;

import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import lombok.Data;

/**
 * 
 * @TableName t_banner
 */
@Table("t_banner")
@Data
public class Banner {
    /**
     * 
     */
    @Id(keyType = KeyType.Auto)
    private Integer id;

    /**
     * 
     */
    private String url;

    /**
     * 排序,越小越靠前
     */
    private Integer sort;

    /**
     * 
     */
    private Date createTime;

}

 

 
2.5.2. 编译项目

会在target或者build目录中生成对应的实体互操作类。

默认生成的实体类和字段都是大写来进行体现。

/**
 * 通过用户查询收藏列表
 * @param userId
 * @return
 */
public List<Lineup> lineUpList(int userId) {
    // 查询收藏的Id
    List<Favorites> favoritesList = favoritesMapper.selectListByQuery(QueryWrapper.create()
            .select(Favorites::getLineupId)
            .from(Favorites.class)
            .where(FAVORITES.USER_ID.eq(userId)));

    return lineupService.listFromId(favoritesList.stream().map(Favorites::getLineupId).collect(Collectors.toList()));
}

/**
 * 删除收藏
 * @param favorites
 */
public void deleteFavorites(Favorites favorites) {

    favoritesMapper.deleteByQuery(QueryWrapper.create()
            .where(FAVORITES.USER_ID.eq(favorites.getUserId()))
            .and(FAVORITES.LINEUP_ID.eq(favorites.getLineupId())));
}

public Favorites selectOne(Favorites favorites) {

    return favoritesMapper.selectOneByQuery(QueryWrapper.create()
            .where(FAVORITES.USER_ID.eq(favorites.getUserId()))
            .and(FAVORITES.LINEUP_ID.eq(favorites.getLineupId())));
}

 

 
2.5.3. 全自动生成

通过连接数据库查询对应的表生成对应的实体,实体互操作 类,Mapper,Controller等。

public class Codegen {

    public static void main(String[] args) {
        //配置数据源
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/your-database?characterEncoding=utf-8");
        dataSource.setUsername("root");
        dataSource.setPassword("******");

        //创建配置内容,两种风格都可以。
        GlobalConfig globalConfig = createGlobalConfigUseStyle1();
        //GlobalConfig globalConfig = createGlobalConfigUseStyle2();

        //通过 datasource 和 globalConfig 创建代码生成器
        Generator generator = new Generator(dataSource, globalConfig);

        //生成代码
        generator.generate();
    }

    public static GlobalConfig createGlobalConfigUseStyle1() {
        //创建配置内容
        GlobalConfig globalConfig = new GlobalConfig();

        //设置根包
        globalConfig.setBasePackage("com.test");

        //设置表前缀和只生成哪些表
        globalConfig.setTablePrefix("tb_");
        globalConfig.setGenerateTable("tb_account", "tb_account_session");

        //设置生成 entity 并启用 Lombok
        globalConfig.setEntityGenerateEnable(true);
        globalConfig.setEntityWithLombok(true);
        //设置项目的JDK版本,项目的JDK为14及以上时建议设置该项,小于14则可以不设置
        globalConfig.setJdkVersion(17);

        //设置生成 mapper
        globalConfig.setMapperGenerateEnable(true);

        //可以单独配置某个列
        ColumnConfig columnConfig = new ColumnConfig();
        columnConfig.setColumnName("tenant_id");
        columnConfig.setLarge(true);
        columnConfig.setVersion(true);
        globalConfig.setColumnConfig("tb_account", columnConfig);

        return globalConfig;
    }

    public static GlobalConfig createGlobalConfigUseStyle2() {
        //创建配置内容
        GlobalConfig globalConfig = new GlobalConfig();

        //设置根包
        globalConfig.getPackageConfig()
                .setBasePackage("com.test");

        //设置表前缀和只生成哪些表,setGenerateTable 未配置时,生成所有表
        globalConfig.getStrategyConfig()
                .setTablePrefix("tb_")
                .setGenerateTable("tb_account", "tb_account_session");

        //设置生成 entity 并启用 Lombok
        globalConfig.enableEntity()
                .setWithLombok(true)
                .setJdkVersion(17);

        //设置生成 mapper
        globalConfig.enableMapper();

        //可以单独配置某个列
        ColumnConfig columnConfig = new ColumnConfig();
        columnConfig.setColumnName("tenant_id");
        columnConfig.setLarge(true);
        columnConfig.setVersion(true);
        globalConfig.getStrategyConfig()
                .setColumnConfig("tb_account", columnConfig);

        return globalConfig;
    }
}

 

 

Copy记录仅供自己下次使用方便

 

标签:columnConfig,flex,JPA,eq,查询,Mybatis,globalConfig,生成
From: https://www.cnblogs.com/zhangxuetao/p/18449032

相关文章

  • 【2024计算机毕业设计】基于jsp+mysql+Spring+mybatis的SSM药品进货销售仓储信息管理
    运行环境:最好是javajdk1.8,我在这个平台上运行的。其他版本理论上也可以。IDE环境:Eclipse,Myeclipse,IDEA或者SpringToolSuite都可以,如果编译器的版本太低,需要升级下编译器,不要弄太低的版本tomcat服务器环境:Tomcat7.x,8.x,9.x版本均可操作系统环境:WindowsXP/7......
  • MyBatis快速入门
    一、简介MyBatis是一个优秀的基于ORM的半自动轻量级持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码ORM(ObjectRelationalMap......
  • CSS display: flex布局
    CSSdisplay:flex布局来源https://zhuanlan.zhihu.com/p/646436119前言早期CSS布局依赖display属性+position属性+float属性。它对特殊的布局非常不方便,如,垂直居中。于是,W3C在2009年提出了一种新的方案——Flex方案,可以简便、完整、响应式地实现各种页面布局。目前,它已......
  • CSS display属性 inline-block flex grid
    CSSdisplayinline-block flexgrid=======================================CSS的display属性是一个核心属性,用于控制元素如何在页面布局中显示,包括其盒模型的行为。以下是display属性的一些常见值及其示例代码:1.block   说明:将元素变为块级元素,独占一行,可以设置宽高、......
  • 第二百六十节 JPA教程 - JPA查询命名参数示例
    JPA教程-JPA查询命名参数示例JPQL支持两种类型的参数绑定语法。第一种是位置绑定,其中参数在查询字符串中通过问号后面跟随参数号来指示。执行查询时,开发人员指定应替换的参数编号。SELECTeFROMEmployeeeWHEREe.department=?1ANDe.salary>?2命名参数......
  • mybatis xml里的 resultMap、resultOrdered、resultSets、resultSetType、resultType
    在MyBatis中,映射结果集是一项重要的功能,用于将数据库查询结果映射到Java对象中。为了实现这一功能,MyBatis提供了多个配置选项,如resultMap、resultOrdered、resultSets、resultSetType和resultType。以下是这些配置选项的详细解释及示例:1.resultTyperesultType是最简单的结......
  • CSS弹性盒子(display:flex)使用技巧
    1.弹性盒模型简介FlexibleBox(伸缩盒模型,又称:弹性盒子)是W3C在2009年提出的一种新的盒子模型。通过display:flex;可以开启伸缩盒模型,将元素设置为伸缩容器,可以轻松的对元素进行布局。2.主轴与侧轴开启display:flex;的元素内的子元素会沿着主轴排列,主轴默认水平方向,......
  • 七,MyBatis-Plus 扩展功能:乐观锁,代码生成器,执行SQL分析打印(实操详细使用)
    七,MyBatis-Plus扩展功能:乐观锁,代码生成器,执行SQL分析打印(实操详细使用)@目录七,MyBatis-Plus扩展功能:乐观锁,代码生成器,执行SQL分析打印(实操详细使用)1.乐观锁2.代码生成器3.执行SQL分析打印4.总结:5.最后:1.乐观锁首先我们需要先了解开发中的一个常见场景,叫做并发请求。并......
  • 828华为云征文 | 华为云Flexus X实例在混合云环境中的应用与实践
    目录前言1.混合云环境的优势与挑战1.1混合云的优势1.2混合云的挑战2.FlexusX实例的配置与集成2.1FlexusX实例简介2.2FlexusX实例的混合云部署2.3配置步骤与措施3.数据迁移与同步策略3.1数据迁移方案3.2数据同步措施4.安全性与合规性管理4.1混合云......
  • MyBatis-plus 3.5之前版本 处理存储json数据
    MyBatis-plus3.6之后支持集合泛型,不需要自定义TypeHandler当前使用的是MyBatis-plus3.5.2版本一:如果是支持对象,直接用MP内置的Handler,JacksonTypeHandler或FastjsonTypeHandler@TableField(typeHandler=FastjsonTypeHandler.class)//@TableField(typeHandler=JacksonTypeHa......