AutoTable, Hibernate自动建立表替代方案

news2024/11/18 4:37:15

痛点

之前一直使用JPA为主要ORM技术栈,主要是因为Mybatis没有实体逆向建表功能。虽然Mybatis有从数据库建立实体,但是实际应用却没那么美好:当实体变更时,往往不会单独再建立一个数据库重新生成表,然后把表再逆向为实体。最终的结果往往是维护一份数据库SQL,再同时维护一份实体对象,两者没有自动建立关联。

方案

如果能够自动建立表,并自动维护系统初始的数据,该有多方便啊。

笔者实际的经验,十年前已经实现Hibernate自动建表+DBUnit自动初始数据(包括图片和相对数据,可见笔者其它文章)。

然而世界在发展,痛点终究有大牛出来解决,在Mybatis领域,最近出现了一个的替代解决方案:MybatisPlusExt,简称MPE。其中的自动建表已被MPE作者单独一个项目处理,叫做AutoTableAuto Table)自动维护表结构icon-default.png?t=N7T8https://autotable.tangzc.com/

迁移步骤

配置文件

autotable也有springboot starter。重新建表的逻辑,也有JAP类似的参数,因此,很容易可以进行迁移,改动点如下:

JPA

spring:
  jpa:
    database-platform: ${app.dataSource.hibernateDialect}
    generate-ddl: false
    show-sql: false
    open-in-view: false
    properties:
      hibernate.jdbc.time_zone: ${app.timeZone:GMT+8}

以及config里的配置Bean:

	@Value("${app.init.mode:none}")
	private String initMode;
	
	@Bean
	@ConfigurationProperties(prefix = "spring.datasource")
	public JpaVendorAdapter jpaVendorAdapter() {
		return new HibernateJpaVendorAdapter();
	}

	@Bean
	public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter)
	{
	    LocalContainerEntityManagerFactoryBean bean=new LocalContainerEntityManagerFactoryBean();      
	    bean.setDataSource(dataSource);
	    bean.setPackagesToScan(new String[] {"org.ccframe.subsys.*.domain.entity"});
	    bean.setJpaVendorAdapter(jpaVendorAdapter);
	    bean.getJpaPropertyMap().put("hibernate.hbm2ddl.auto",initMode);
	    return bean;
	}

AutoTable

先导入starter依赖:


implementation ("com.tangzc:auto-table-spring-boot-starter:1.7.4") // 自动建表

然后书写格式:

auto-table:
  show-banner: false
  mode: ${app.init.mode}
  model-package: org.ccframe.subsys.*.domain.entity
  index-prefix: IDX_

Entity实体

以一个典型的带普通和Unique索引的实体User为例:

JPA

JPA+Hibernate方案

@Entity
@Table(name = "SYS_USER", indexes = {
	@Index(columnList = "USER_MOBILE"),
	@Index(columnList = "USER_EMAIL"),
}, uniqueConstraints = {
	@UniqueConstraint(columnNames = {"PLATFORM_ID","LOGIN_ID","USER_PSW"}),
})
@Getter
@Setter
@ToString
public class User extends BaseEntity{

	private static final long serialVersionUID = 6662916002685367792L;

	public static final String USER_ID = "userId";
	public static final String PLATFORM_ID = "platformId";
	public static final String LOGIN_ID = "loginId";
	public static final String USER_HEAD_PICT_ID = "userHeadPictId";
	public static final String USER_NAME = "userName";
	public static final String USER_PSW = "userPsw";
	public static final String USER_MOBILE = "userMobile";
	public static final String USER_EMAIL = "userEmail";
	public static final String USER_STATUS_CODE = "userStatusCode";
	public static final String IF_ADMIN = "ifAdmin";
	public static final String ROLE_CODE_STR = "roleCodeStr";

	@Id
	@GenericGenerator(name = "userId", strategy = "org.ccframe.commons.base.RedisIDGenerator")
	@GeneratedValue(generator = "userId")
    @Column(name = "USER_ID", nullable = false, length = 10)
	private Integer userId;

    @Column(name = "PLATFORM_ID", nullable = false, length = 10)
	private Integer platformId;

    @Column(name = "LOGIN_ID", nullable = false, length = 38)
    @Field(type = FieldType.Keyword)
	private String loginId;

    @Column(name = "USER_HEAD_PICT_ID", nullable = true, length = 10)
	private java.lang.Integer userHeadPictId;

    @Column(name = "USER_NAME", nullable = false, length = 32)
	private String userName;

    @Column(name = "USER_PSW", nullable = false, length = 128)
	private String userPsw;

    @Column(name = "USER_MOBILE", nullable = true, length = 17)
	private String userMobile;

    @Column(name = "USER_EMAIL", nullable = true, length = 70)
	private String userEmail;

    @Column(name = "IF_ADMIN", nullable = false, length = 2)
    @Field(type = FieldType.Keyword)
	private String ifAdmin;
    
    @Column(name = "USER_STATUS_CODE", nullable = false, length = 2)
	private String userStatusCode;

    @Column(name = "ROLE_CODE_STR", nullable = false, length = 80)
    private String roleCodeStr;
}

AutoTable

mybatis-plus + autotable的方案(原来platformId重新命名为规范的tenantId)

@TableName("SYS_USER")
@AutoTable("SYS_USER")
@TableIndex(name = "UK66q7srks5eylhocxej5gs68mb", type= IndexTypeEnum.UNIQUE, fields = {"tenantId","loginId","userPsw"})
@TableIndex(name = "IDXbby41q9neesp2i6hatmlud01b", fields = "userMobile")
@TableIndex(name = "IDXhjkdbn8wxvwcdp7ohh7dch6i1", fields = "userEmail")
@Getter
@Setter
@ToString
public class User extends BaseEntity{

	private static final long serialVersionUID = 6662916002685367792L;

	public static final String USER_ID = "userId";
	public static final String TENANT_ID = "tenantId";
	public static final String LOGIN_ID = "loginId";
	public static final String USER_AVATAR = "userAvatar";
	public static final String USER_NAME = "userName";
	public static final String USER_PSW = "userPsw";
	public static final String USER_MOBILE = "userMobile";
	public static final String USER_EMAIL = "userEmail";
	public static final String USER_STATUS_CODE = "userStatusCode";
	public static final String IF_ADMIN = "ifAdmin";
	public static final String ROLE_CODE_STR = "roleCodeStr";

	@TableId(type = IdType.ASSIGN_ID)
	private Long userId;

	@ColumnType(value = MysqlTypeConstant.VARCHAR, length = 38) @ColumnNotNull
    @Field(type = FieldType.Keyword)
	private String loginId;

	@ColumnType(value = MysqlTypeConstant.VARCHAR, length = 48) @ColumnNotNull
	private String userAvatar;

	@ColumnType(value = MysqlTypeConstant.VARCHAR, length = 32) @ColumnNotNull
	private String userName;

	@ColumnType(value = MysqlTypeConstant.VARCHAR, length = 128) @ColumnNotNull
	private String userPsw;

	@ColumnType(value = MysqlTypeConstant.VARCHAR, length = 17)
	private String userMobile;

	@ColumnType(value = MysqlTypeConstant.VARCHAR, length = 70)
	private String userEmail;

    @Field(type = FieldType.Keyword)
	@ColumnType(value = MysqlTypeConstant.CHAR, length = 1)
	private String ifAdmin;
    
	@ColumnType(value = MysqlTypeConstant.CHAR, length = 1)
	private String userStatusCode;

	@ColumnType(value = MysqlTypeConstant.VARCHAR, length = 80)
    private String roleCodeStr;
    
}

总结

AutoTable能够很好的兼容JPA的格式,实现自动建表的迁移。

但是有几个注意点:

1)索引需要进行命名,hibernate的是采用自动前缀+25位字符来自动实现索引的命名,我们不用去关心索引的名称。而迁移到AutoTable需要去起个不重复的名字。这个问题不大

2)hibernate采用方言的模式,可以兼容大部分数据库。而AutoTable的字段类型,需要指定数据库类型,如果要切换数据库,需要做实体代码定义的改动

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1664330.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

day07beef-xss之根据beef-xss获取cookies

1.安装 apt-get update apt-get install beef-xss 若报错运行不了尝试 apt remove ruby apt remove beef-xss apt-get install ruby apt-get install ruby-dev libpcap-dev gem install eventmachine apt-get install beef-xss 2.运行 beef-xss 运行成功会自动弹出浏览框。 攻…

CRF++ 中文NER

CLUENER数据准备 data [] with open("data/train.json", r) as f:for line in f.readlines():data.append(eval(line)) data特征提取 import jieba import jieba.posseg as psegdef process(text, labelsNone):words [i for i in text]words_flags pseg.cut(tex…

Linux进程——进程地址空间

前言:在讲完环境变量后,相信大家对Linux有更进一步的认识,而Linux进程概念到这也快接近尾声了,现在我们了解Linux进程中的地址空间! 本篇主要内容: 了解程序地址空间 理解进程地址空间 探究页表和虚拟地址空…

ChatGPT 即将登陆 iPhone;斯坦福推出 AI 辅助全息成像技术丨 RTE 开发者日报 Vol.202

开发者朋友们大家好: 这里是 「RTE 开发者日报」 ,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE(Real Time Engagement) 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

【优选算法】——Leetcode——LCR 179. 查找总价格为目标值的两个商品

1.题目 2. 解法⼀(暴⼒解法,会超时): 1.算法思路: 2.图解 3. 代码实现 3. 解法⼆(双指针-对撞指针): 1.算法思路: 2.图解 3.代码实现 1.C语言 2…

4G,5G执法记录仪人脸识别、人脸比对使用说明

4G/5G执法记录仪或4G/5G智能安全帽,做前端人脸识别、人脸比对,采用了上市公司的成熟的人脸识别算法,需要支付LICENSE给算法公司,理论上前端设备支持30K的人脸库(受设备运行内存限制)。 4G/5G执法记录仪侧要…

1.前端环境搭建

1.安装nodejs 因为我们开发Vue项目需要使用npm命令来创建和启动,安装node.js是为了获得这个命令,目前和使用node.js无关 下载地址:http://nodejs.cn/download/ 下载完之后安装,通过cmd查看是否安装成功 node --version2.创建项目…

使用./build.sh编译ORB_SLAM源码时出现报错:/usr/bin/ld:找不到 -lboost_serialization的解决办法

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、/usr/bin/ld:找不到 -lboost_serialization1.问题描述2.解决(1). 下载源码(2) . 编译安装 一、/usr/bin/ld:找不到 -lboost_serialization 1.问题描述 在安装…

KAN核心团队震撼力作!MIT华人用AI首次发现物理学全新方程 | 最新快讯

新智元报道 编辑:Aeneas 好困 刚刚提出了 KAN 的 MIT 物理学家 Max Tegmark 和北大校友刘子鸣,又有一项重磅研究问世了!团队发现,它们用 AI 发现了物理学中的新方程,从此,AI 很可能被引入物理学研究领域&am…

IPv6资产测绘哪家强?揭秘新一代网络空间资产测绘平台的独门秘籍

网络空间资产测绘,即通过一系列技术手段,对网络中的各类资产进行全面的发现、分类和定位,为各类用户提供精准的数据支撑和决策依据。网络空间资产测绘作为一门新兴的交叉学科,融合了计算机网络技术、数据挖掘、人工智能、信息安全…

Docker学习笔记(一)安装Docker、镜像操作、容器操作、数据卷操作

文章目录 1 Docker介绍1.1 Docker的优势1.1.1 应用部署的环境问题1.1.2 Docker解决依赖兼容问题1.1.3 Docker解决操作系统环境差异1.1.4 小结 1.2 Docker和虚拟机的区别1.3 Docker架构1.3.1 镜像和容器1.3.2 DockerHub1.3.3 Docker架构 1.4 安装Docker1.4.1 卸载旧版本Docker&a…

【微信开发】微信支付前期准备工作(申请及配置)

1、申请并配置公众号或微信小程序 1.1 账户申请 通过微信公众平台,根据指引申请微信小程序或公众号,申请时需要微信认证,申请流程不在赘述 1.2 信息配置 申请通过后,需进入小程序和公众号内进行信息配置 1.2.1 小程序信息配置…

小程序地理位置接口申请教程来啦4步学会

小程序地理位置接口有什么功能? 如果我们提审后驳回理由写了“当前提审小程序代码包中地理位置相关接口( chooseAddress、getLocation )暂未开通,建议完成接口开通后或移除接口相关内容后再进行后续版本提审”,如果你也碰到类似问题&#xff…

任务:单域,域树的搭建

一、单域: 搭建所需的系统:win2016 sever,win10 1.在创建域前,先设置静态ip 先查看win2016 sever的IP, ip:192.168.154.133 网关:192.168.154.2 DNS服务器:192.168.154.2 设置…

FPGA学习笔记(1)——Vivado和HLS

1 Vivado设计 1.1 FPGA基本知识 Xilinx Atrix-7使用6输入LUT结构(0-63)CLB:可配置逻辑块Slice:每个CLB包含2个Slice(包含查找表LUT和8位寄存器REG)布线池:围绕在CLB周围,衔接FPGA的资源调度I/O块&#xf…

conan2 基础入门(02)-安装

conan2 基础入门(02)-安装 文章目录 conan2 基础入门(02)-安装⭐前言⭐安装python安装安装包安装自行操作 ⭐验证配置环境变量命令行验证conan配置文件 END ⭐前言 Conan 2.0: C and C Open Source Package Manager 官方提供三种安装conan的方式。分别为: Recommen…

vuex核心概念-getters

除了state之外,有时我们还需要从state中派生出一些状态,这些状态是依赖state的,此时会用到getters。

鸿蒙内核源码分析(远程登录篇) | 内核如何接待远方的客人

什么是远程登录? 每个人都有上门做客的经历,抖音也一直在教我们做人,做客不要空手去,总得带点东西,而对中国人你就不能送钟,不能送梨,最好也别送鞋,因他们与 终 离 邪 谐音,犯忌讳. 这是人情世故,叫礼仪,是中华文明圈的共识,是相互交流信任的基础. 那互联网圈有没有这种共识呢…

光伏无人机巡检都有哪些功能?

随着光伏产业的快速发展,光伏电站的巡检工作变得越来越重要。然而,传统的人工巡检方式面临着效率低下、安全隐患大等问题。为了应对这些挑战,光伏无人机巡检应运而生,以其独特的优势在光伏巡检领域发挥着越来越重要的作用。本文将…

OpenCv中cv2.subtract(image,blurred)与(image-blurred)的区别

目录 一、cv2.subtract()函数二、cv2.subtract(image,blurred)和(image-blurred)处理效果对比2.1 代码2.2 输出结果 三、总结 一、cv2.subtract()函数 cv2.subtract是OpenCV库中的一个函数,用于进行图像减法运算。它可以很方便地进行两个图像…