我正在尝试在我的JPA import.sql文件中定义一些PostgreSQL函数和触发器。我使用Hibernate 5.x作为基础JPA提供程序。由于我的import.sql文件包含多行命令,因此我在persistence.xml文件中设置了以下属性:
import.sql
persistence.xml
<property name="hibernate.hbm2ddl.import_files_sql_extractor" value="org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor" />
从那里,我试图在中定义函数import.sql。他们看起来像这样:
DROP FUNCTION IF EXISTS update_total_feedback_count() CASCADE; CREATE FUNCTION update_total_feedback_count() RETURNS TRIGGER AS $$ DECLARE application_version_id BIGINT := 0; app_version_metadata_id BIGINT:= 0; application_id BIGINT := 0; app_metadata_id BIGINT := 0; BEGIN IF (TG_OP = 'INSERT') THEN SELECT INTO application_version_id tbl_application_version.id FROM tbl_application_version INNER JOIN tbl_feedback ON tbl_feedback.application_version_id = tbl_application_version.id WHERE tbl_feedback.id = NEW.id; SELECT INTO app_version_metadata_id tbl_application_version.application_version_metadata_id FROM tbl_application_version WHERE id = application_version_id; SELECT INTO app_metadata_id registered_application_metadata_id FROM tbl_registered_application INNER JOIN tbl_application_version ON tbl_application_version.registered_application_id = tbl_registered_application.id WHERE tbl_application_version.id = application_version_id; UPDATE tbl_registered_application_metadata SET feedbackcount = (feedbackcount + 1), lastfeedbackdate = NEW.createddate WHERE id = app_metadata_id; UPDATE tbl_application_version_metadata SET feedbackcount = (feedbackcount + 1), lastfeedbackdate = NEW.createddate WHERE id = app_version_metadata_id; RETURN NEW; ELSIF (TG_OP = 'DELETE') THEN -- IMPLEMENT THIS TRIGGER RETURN NULL; END IF; END; $$ LANGUAGE 'plpgsql'; ALTER FUNCTION update_total_feedback_count() OWNER TO feedback_tracker;
但是,当我部署WAR文件时,出现如下错误:
无终止的美元报价从SQL中的位置65开始创建函数my_function()以T的形式返回触发器
因此,很明显,它依赖$$于我的函数声明中。有没有解决的办法?我应该以不同的方式声明我的功能/触发吗?我可以在persistence.xml文件中设置可以解决此问题的属性吗?
$$
hibernate的默认SqlStatementParser实现的问题,该实现在多行sql命令提取器中使用。
如果查看语法定义hibernate-core/src/main/antlr/sql-stmt.g ,则有语句结尾的定义:
hibernate-core/src/main/antlr/sql-stmt.g
STMT_END : ';' ( '\t' | ' ' | '\r' | '\n' )* ; NOT_STMT_END : ~( ';' ) ;
这表明语句结尾是分号符号,后跟“空格”,“制表符”,“回车符”或“换行”符号。
因此:在Hibernate中的默认实施不支持美元报价。
如果您不想实现自定义的hibernate解析器,则可以使用简单的'引用重写所有函数而无需使用美元引用。但是您将需要小心逃脱'字符。
'
更新:您可以创建自定义 ImportSqlCommandExtractor。例如:使用以下命令分隔命令--******(在注释中使用6个星号,只是为了使您的文件成为正确的SQL文件,而在注释中使用自定义命令分隔,或者选择您喜欢的任何疯狂组合),然后在简单实现中将它们分开
ImportSqlCommandExtractor
--******
public class ImportSqlCE implements ImportSqlCommandExtractor { private static final Logger log = LoggerFactory.getLogger(ImportSqlCE.class); @Override public String[] extractCommands(Reader reader) { try { String allCommands = IOUtils.toString(reader); return allCommands.split("--******"); } catch (IOException e) { log.error("error reading import commands", e); log.info("sengind default empty command set"); return new String[0]; } } }
然后配置hibernate以使用它 <property name="hibernate.hbm2ddl.import_files_sql_extractor" value="example.ImportSqlCE" />
<property name="hibernate.hbm2ddl.import_files_sql_extractor" value="example.ImportSqlCE" />
有了这个,您的import.sql将支持美元报价(即它将简单地忽略任何SQL对正在发生的事情的了解。)