在JPA項(xiàng)目啟動(dòng)時(shí)如何新增MySQL字段
前言
本來(lái)用了JPA,直接實(shí)體類加參數(shù)就可以新增字段了,但是架不住垃圾項(xiàng)目在啟動(dòng)項(xiàng)目時(shí)會(huì)加載數(shù)據(jù)庫(kù)SQL文件去插入數(shù)據(jù),那沒(méi)辦法了,只能再加一些弱智操作去修復(fù)一些弱智操作。
起因
項(xiàng)目啟動(dòng)的時(shí)候會(huì)先執(zhí)行schema.sql,再執(zhí)行data.sql,然后再執(zhí)行JPA建表新增字段等操作。然而在新版本中在配置表中加了某個(gè)字段,假設(shè)為status,并且在data.sql中對(duì)status進(jìn)行了賦值操作。此時(shí)舊版本升級(jí)新版本,啟動(dòng)時(shí)執(zhí)行了data.sql文件,就會(huì)報(bào)錯(cuò),報(bào)錯(cuò)信息,配置如下:
java.sql.SQLSyntaxErrorException: Unknown column 'status' in 'field list'
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
at com.mysql.cj.jdbc.StatementImpl.executeInternal(StatementImpl.java:764)
at com.mysql.cj.jdbc.StatementImpl.execute(StatementImpl.java:648)
at com.alibaba.druid.filter.FilterChainImpl.statement_execute(FilterChainImpl.java:2958)
at com.alibaba.druid.filter.FilterAdapter.statement_execute(FilterAdapter.java:2473)
at com.alibaba.druid.filter.FilterEventAdapter.statement_execute(FilterEventAdapter.java:188)
at com.alibaba.druid.filter.FilterChainImpl.statement_execute(FilterChainImpl.java:2956)
at com.alibaba.druid.wall.WallFilter.statement_execute(WallFilter.java:415)
at com.alibaba.druid.filter.FilterChainImpl.statement_execute(FilterChainImpl.java:2956)
at com.alibaba.druid.filter.FilterAdapter.statement_execute(FilterAdapter.java:2473)
at com.alibaba.druid.filter.FilterEventAdapter.statement_execute(FilterEventAdapter.java:188)
at com.alibaba.druid.filter.FilterChainImpl.statement_execute(FilterChainImpl.java:2956)
at com.alibaba.druid.proxy.jdbc.StatementProxyImpl.execute(StatementProxyImpl.java:147)
配置:
spring: datasource: # 工程啟動(dòng)加載數(shù)據(jù)庫(kù)結(jié)構(gòu)sql腳本 schema: - classpath:/mysql/schema.sql # 工程啟動(dòng)加載數(shù)據(jù)庫(kù)默認(rèn)數(shù)據(jù)sql腳本 data: - classpath:/mysql/data.sql
解決方案
如果要解決這個(gè)問(wèn)題,那么就需要在 schema.sql 中新增字段,下面是幾種解決方案:
方案1
方案說(shuō)明
在 schema.sql 刪除這個(gè)表,然后重新建表的時(shí)候帶上要新增的字段
SET FOREIGN_KEY_CHECKS=0; DROP TABLE IF EXISTS `your_table_name`; CREATE TABLE `hxj_report_template_index` ( `ID` bigint(20) NOT NULL AUTO_INCREMENT, `your_column_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`ID`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; SET FOREIGN_KEY_CHECKS=1;
應(yīng)用場(chǎng)景
該方案簡(jiǎn)單粗暴,僅限于這個(gè)表存的數(shù)據(jù)一直不變,不會(huì)被更新。
可能出現(xiàn)的問(wèn)題
如果該表被修改了,刪除再新增初始化會(huì)回到初始狀態(tài)。
方案2
方案說(shuō)明
在 schema.sql 判斷該字段是否存在,不存在則新增:
-- 替換 table_name 和 column_name 為實(shí)際的表名和列名 SET @table_name = 'your_table'; SET @column_name = 'new_column'; SET @column_definition = 'VARCHAR(255)'; -- 替換為你需要的列定義 -- 查詢列是否存在 SELECT COUNT(*) INTO @column_exists FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = @table_name AND column_name = @column_name; -- 根據(jù)查詢結(jié)果決定是否新增列 SET @sql = IF(@column_exists = 0, CONCAT('ALTER TABLE ', @table_name, ' ADD COLUMN ', @column_name, ' ', @column_definition), 'SELECT "Column already exists"'); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
應(yīng)用場(chǎng)景
沒(méi)遇到不適用的,評(píng)論區(qū)補(bǔ)充吧
可能出現(xiàn)的問(wèn)題
如果配置了阿里 Durid,那么Druid 連接池的 SQL 防火墻機(jī)制會(huì)阻止動(dòng)態(tài) SQL 語(yǔ)句 PREPARE stmt FROM @sql 的執(zhí)行。Druid 的 SQL 防火墻嚴(yán)格限制某些類型的 SQL 語(yǔ)句,以防止 SQL 注入攻擊。錯(cuò)誤如下(本來(lái)是一行的,我加下?lián)Q行方便查看):
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration':
Unsatisfied dependency expressed through constructor parameter 0;
nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'druidDataSource' defined in class path resource [com/xxx/config/DruidConfig.class]: Initialization of bean failed;
nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerInvoker':
Invocation of init method failed; nested exception is org.springframework.jdbc.datasource.init.ScriptStatementFailedException:
Failed to execute SQL script statement #26 of class path resource [mysql/schema.sql]: PREPARE stmt FROM @sql;
nested exception is java.sql.SQLException: sql injection violation, class com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPrepareStatement not allow : PREPARE stmt FROM @sql
主要看最后一行,如果確實(shí)需要使用 PREPARE 語(yǔ)句,可以考慮在 Druid 配置中放寬對(duì)該語(yǔ)句的限制。但這可能會(huì)帶來(lái)安全風(fēng)險(xiǎn),因此需要謹(jǐn)慎處理。
spring: datasource: druid: wall: config: update-allow: true delete-allow: true insert-allow: true select-allow: true truncate-allow: true replace-allow: true drop-allow: true create-table-allow: true alter-table-allow: true prepared-stmt-allow: true
方案3
方案說(shuō)明
搜索引擎結(jié)果表示在 MySQL8 有直接的語(yǔ)句可以判斷字段是否存在并新增
ALTER TABLE `your_table_name` ADD COLUMN IF NOT EXISTS `your_column_name` varchar(50);
應(yīng)用場(chǎng)景
適用于 MySQL8.0 以上版本(我在5.7.26和8.0.34版本都試過(guò),直接報(bào)錯(cuò)不知道什么原因)
可能出現(xiàn)的問(wèn)題
可能的問(wèn)題就是我試過(guò)我不行,沒(méi)時(shí)間去看為啥不行了,大佬可直接評(píng)論區(qū)說(shuō)一下,謝謝
總結(jié)
我用的方案1,如果你也是這種項(xiàng)目,那么我也推薦你用方案1,簡(jiǎn)單粗暴又方便;方案2是問(wèn)了chatgpt得出來(lái)的答案,感覺(jué)不錯(cuò),但是報(bào)錯(cuò)了又不想改;但是你需要知道為何會(huì)出現(xiàn)這種問(wèn)題,以及如何避免出現(xiàn)這種問(wèn)題,以下是我的理解:
- 不建議使用 schema.sql 和 data.sql 對(duì)數(shù)據(jù)庫(kù)結(jié)構(gòu)及數(shù)據(jù)進(jìn)行初始化,因?yàn)樵诿恳淮雾?xiàng)目啟動(dòng),這兩個(gè)文件都必須執(zhí)行一次,大大減慢了項(xiàng)目的啟動(dòng)速度,替代方案可以是使用 flyway 進(jìn)行數(shù)據(jù)庫(kù)版本控制。
- JPA 真的不是初學(xué)者快捷構(gòu)建項(xiàng)目的首選,如果沒(méi)有對(duì) JPA 有正確的理解,在遇到復(fù)雜場(chǎng)景時(shí)會(huì)手足無(wú)措,這邊還是建議使用 Mybatis 捏,初學(xué)者多寫(xiě)寫(xiě) SQL 語(yǔ)句有助于進(jìn)步捏,高手另說(shuō)哈。 感謝您的閱讀
到此這篇關(guān)于在JPA項(xiàng)目啟動(dòng)時(shí)新增MySQL字段的文章就介紹到這了,更多相關(guān)JPA啟動(dòng)新增MySQL字段內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- JPA之映射mysql text類型的問(wèn)題
- Springboot2.0配置JPA多數(shù)據(jù)源連接兩個(gè)mysql數(shù)據(jù)庫(kù)方式
- Spring boot基于JPA訪問(wèn)MySQL數(shù)據(jù)庫(kù)的實(shí)現(xiàn)
- 解決springboot的JPA在Mysql8新增記錄失敗的問(wèn)題
- Spring Data Jpa Mysql使用utf8mb4編碼的示例代碼
- springboot使用spring-data-jpa操作MySQL數(shù)據(jù)庫(kù)
- Spring-Data-JPA整合MySQL和配置的方法
- SpringBoot連接MYSQL數(shù)據(jù)庫(kù)并使用JPA進(jìn)行操作
- Spring Boot 添加MySQL數(shù)據(jù)庫(kù)及JPA實(shí)例
相關(guān)文章
Mysql經(jīng)典高逼格/命令行操作(速成)(推薦)
這篇文章主要介紹了Mysql命令行操作,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04MySQL 重裝MySQL后, mysql服務(wù)無(wú)法啟動(dòng)
把mysql程序卸載后, 重裝, 結(jié)果mysql服務(wù)啟動(dòng)不了,碰到這個(gè)問(wèn)題的朋友可以參考下。2011-08-08詳解MySQL的主從復(fù)制、讀寫(xiě)分離、備份恢復(fù)
本篇文章主要對(duì)MySQL的主從復(fù)制、讀寫(xiě)分離、備份恢復(fù)進(jìn)行詳細(xì)全面的講解,具有很好的參考價(jià)值,需要的朋友一起來(lái)看下吧2016-12-12詳解騰訊云CentOS7.0使用yum安裝mysql及使用遇到的問(wèn)題
本篇文章主要介紹了騰訊云CentOS7.0使用yum安裝mysql,詳細(xì)的介紹了使用yum安裝mysql及使用遇到的問(wèn)題,有興趣的可以了解一下。2017-01-01