Postgresql动态分区和Hibernate插入无法通过返回NULL的before Insert触发器工作
Postgresql动态分区和Hibernate插入无法通过触发器工作 我有一个图形和节点表。图通过Node_id与节点表有一对一的关系,而节点表通过parent_id与自身有一个递归关系。每个节点表和图表都有租户名称,在多租户表中,我希望使用动态分区,如中所述 因此,我:Postgresql动态分区和Hibernate插入无法通过返回NULL的before Insert触发器工作,hibernate,database-partitioning,hibernate-5.x,postgresql-12,Hibernate,Database Partitioning,Hibernate 5.x,Postgresql 12,Postgresql动态分区和Hibernate插入无法通过触发器工作 我有一个图形和节点表。图通过Node_id与节点表有一对一的关系,而节点表通过parent_id与自身有一个递归关系。每个节点表和图表都有租户名称,在多租户表中,我希望使用动态分区,如中所述 因此,我: CREATE TABLE IF NOT EXISTS graph ( id SERIAL NOT NULL, name character varying(255) NOT NULL, opt_lock_vers
CREATE TABLE IF NOT EXISTS graph
(
id SERIAL NOT NULL,
name character varying(255) NOT NULL,
opt_lock_version int NOT NUll default 1,
type character varying(255) NOT NULL,
tenant_name character varying(255) NOT NULL,
node_id int,
CONSTRAINT graph_pkey PRIMARY KEY (id),
CONSTRAINT graph_node_fk FOREIGN KEY (node_id)
REFERENCES node (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT graph_node_id_uk UNIQUE (node_id)
);
CREATE TABLE IF NOT EXISTS node
(
id SERIAL NOT NULL,
pending_removal boolean,
tenant_name character varying(255) NOT NULL,
name character varying(255) NOT NULL,
type character varying(255) NOT NULL,
parent_id int,
CONSTRAINT node_pkey PRIMARY KEY (id),
CONSTRAINT node_parent_id_fk FOREIGN KEY (parent_id)
REFERENCES node (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
);
我已经存储了创建动态表的函数,并在动态创建的动态表中插入了一行(它可以正常工作):
现在的问题是Hibernate Insert用于图形表,由于store函数返回NULL,它返回“Insert 0”。Hibernate失败,批处理更新从更新[0]返回的意外行数为1;实际行数:0;预期:1;语句已执行。记录已插入到动态表中,但主表中的0行受到影响。我不想在主图表表中复制数据(它应该是空的),只有动态表才会有记录
如何伪造“插入0 1”或如何指示数据已插入休眠
更新:
我可以通过更改hibernate internalorg.hibernate.jdbc.Expectations类来伪造插入,该类检查受影响的记录,并通过threadlocal变量count将其iff设置为TRUE:唯一的问题是现在更新和删除语句没有tenant\u name,否则它不能满表扩展只需对租户进行分区,这样更新/删除速度就会很慢
/**
* Holds various often used {@link Expectation} definitions.
*
* @author Steve Ebersole
*/
public class Expectations {
**public static final ThreadLocal<Boolean> count_zero = new ThreadLocal<Boolean>();**
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( Expectations.class );
private static SqlExceptionHelper sqlExceptionHelper = new SqlExceptionHelper( false );
public static final int USUAL_EXPECTED_COUNT = 1;
public static final int USUAL_PARAM_POSITION = 1;
// Base Expectation impls ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public static class BasicExpectation implements Expectation {
private final int expectedRowCount;
protected BasicExpectation(int expectedRowCount) {
this.expectedRowCount = expectedRowCount;
if ( expectedRowCount < 0 ) {
throw new IllegalArgumentException( "Expected row count must be greater than zero" );
}
}
public final void verifyOutcome(int rowCount, PreparedStatement statement, int batchPosition) {
rowCount = determineRowCount( rowCount, statement );
if ( batchPosition < 0 ) {
checkNonBatched( rowCount, statement );
}
else {
checkBatched( rowCount, batchPosition, statement );
}
}
private void checkBatched(int rowCount, int batchPosition, PreparedStatement statement) {
if ( rowCount == -2 ) {
LOG.debugf( "Success of batch update unknown: %s", batchPosition );
}
else if ( rowCount == -3 ) {
throw new BatchFailedException( "Batch update failed: " + batchPosition );
}
else {
if ( expectedRowCount > rowCount ) {
**if(count_zero.get() == null || count_zero.get()) {**
throw new StaleStateException(
"Batch update returned unexpected row count from update ["
+ batchPosition + "]; actual row count: " + rowCount
+ "; expected: " + expectedRowCount + "; statement executed: "
+ statement
);
}
}
if ( expectedRowCount < rowCount ) {
**if(count_zero.get() == null || count_zero.get()) {**
String msg = "Batch update returned unexpected row count from update [" +
batchPosition + "]; actual row count: " + rowCount +
"; expected: " + expectedRowCount;
throw new BatchedTooManyRowsAffectedException(msg, expectedRowCount, rowCount, batchPosition);
}
}
}
}
private void checkNonBatched(int rowCount, PreparedStatement statement) {
if ( expectedRowCount > rowCount ) {
**if(count_zero.get() == null || count_zero.get()) {**
throw new StaleStateException(
"Unexpected row count: " + rowCount + "; expected: " + expectedRowCount
+ "; statement executed: " + statement
);
}
}
if ( expectedRowCount < rowCount ) {
**if(count_zero.get() == null || count_zero.get()) {**
String msg = "Unexpected row count: " + rowCount + "; expected: " + expectedRowCount;
throw new TooManyRowsAffectedException(msg, expectedRowCount, rowCount);
}
}
}
public int prepare(PreparedStatement statement) throws SQLException, HibernateException {
return 0;
}
public boolean canBeBatched() {
return true;
}
protected int determineRowCount(int reportedRowCount, PreparedStatement statement) {
return reportedRowCount;
}
}
public static class BasicParamExpectation extends BasicExpectation {
private final int parameterPosition;
protected BasicParamExpectation(int expectedRowCount, int parameterPosition) {
super( expectedRowCount );
this.parameterPosition = parameterPosition;
}
@Override
public int prepare(PreparedStatement statement) throws SQLException, HibernateException {
toCallableStatement( statement ).registerOutParameter( parameterPosition, Types.NUMERIC );
return 1;
}
@Override
public boolean canBeBatched() {
return false;
}
@Override
protected int determineRowCount(int reportedRowCount, PreparedStatement statement) {
try {
return toCallableStatement( statement ).getInt( parameterPosition );
}
catch (SQLException sqle) {
sqlExceptionHelper.logExceptions( sqle, "could not extract row counts from CallableStatement" );
throw new GenericJDBCException( "could not extract row counts from CallableStatement", sqle );
}
}
private CallableStatement toCallableStatement(PreparedStatement statement) {
if ( !CallableStatement.class.isInstance( statement ) ) {
throw new HibernateException(
"BasicParamExpectation operates exclusively on CallableStatements : " + statement.getClass()
);
}
return (CallableStatement) statement;
}
}
// Various Expectation instances ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public static final Expectation NONE = new Expectation() {
public void verifyOutcome(int rowCount, PreparedStatement statement, int batchPosition) {
// explicitly doAfterTransactionCompletion no checking...
}
public int prepare(PreparedStatement statement) {
return 0;
}
public boolean canBeBatched() {
return true;
}
};
public static final Expectation BASIC = new BasicExpectation( USUAL_EXPECTED_COUNT );
public static final Expectation PARAM = new BasicParamExpectation( USUAL_EXPECTED_COUNT, USUAL_PARAM_POSITION );
public static Expectation appropriateExpectation(ExecuteUpdateResultCheckStyle style) {
if ( style == ExecuteUpdateResultCheckStyle.NONE ) {
return NONE;
}
else if ( style == ExecuteUpdateResultCheckStyle.COUNT ) {
return BASIC;
}
else if ( style == ExecuteUpdateResultCheckStyle.PARAM ) {
return PARAM;
}
else {
throw new HibernateException( "unknown check style : " + style );
}
}
private Expectations() {
}
}
/**
*保存各种常用的{@link expection}定义。
*
*@作者史蒂夫·埃伯索尔
*/
公众阶级的期望{
**public static final ThreadLocal count_zero=new ThreadLocal()**
私有静态最终CoreMessageLogger日志=CoreLogging.messageLogger(Expectations.class);
私有静态SqlExceptionHelper SqlExceptionHelper=新SqlExceptionHelper(false);
公共静态最终整数通常\预期\计数=1;
公共静态最终int通常参数位置=1;
//基本期望~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
公共静态类BasicExpection实现了预期{
私人最终int expectedRowCount;
受保护的基本预期(int-expectedRowCount){
this.expectedRowCount=expectedRowCount;
如果(预期的rowCount<0){
抛出新的IllegalArgumentException(“预期行计数必须大于零”);
}
}
公开最终无效验证结果(整数行数、预处理语句、整数批位置){
rowCount=determineRowCount(rowCount,语句);
if(批位置<0){
checkNonBatched(行计数、语句);
}
否则{
checkBatched(行计数、batchPosition、语句);
}
}
私有void checkbatch(int rowCount、int batchPosition、PreparedStatement语句){
如果(行计数==-2){
LOG.debugf(“批更新成功未知:%s”,batchPosition);
}
else if(行计数==-3){
抛出新的BatchFailedException(“批更新失败:+batchPosition”);
}
否则{
如果(expectedRowCount>rowCount){
**if(count_zero.get()==null | | count_zero.get()){**
抛出新的StaleStateException(
“批处理更新从更新[]返回了意外的行数”
+batchPosition+“];实际行计数:“+rowCount”
+应执行“+expectedRowCount+”语句:
+声明
);
}
}
如果(预期的行数<行数){
**if(count_zero.get()==null | | count_zero.get()){**
String msg=“批处理更新从更新返回意外的行数[”+
batchPosition+“];实际行计数:“+rowCount”+
“预期:”+expectedRowCount;
抛出新的BatchedTooManyRowsAffectedException(msg、expectedRowCount、rowCount、batchPosition);
}
}
}
}
私有void checknonbatch(int行计数、PreparedStatement语句){
如果(expectedRowCount>rowCount){
**if(count_zero.get()==null | | count_zero.get()){**
抛出新的StaleStateException(
意外的行计数:“+rowCount+”;应为:“+expectedRowCount”
+“已执行语句:”+语句
);
}
}
如果(预期的行数<行数){
**if(count_zero.get()==null | | count_zero.get()){**
字符串msg=“意外的行数:”+rowCount+”;预期:“+expectedRowCount;
抛出新的ToomAnyRowAffectedException(msg、expectedRowCount、rowCount);
}
}
}
public int prepare(PreparedStatement语句)抛出SQLException、HibernateeException{
返回0;
}
公共布尔值可批处理(){
返回true;
}
受保护的int determinerRowCount(int reportedRowCount,PreparedStatement语句){
返回reportedRowCount;
}
}
公共静态类BasicParamExpection扩展了BasicExpection{
私有最终int参数位置;
受保护的BasicParamExpection(int expect
/**
* Holds various often used {@link Expectation} definitions.
*
* @author Steve Ebersole
*/
public class Expectations {
**public static final ThreadLocal<Boolean> count_zero = new ThreadLocal<Boolean>();**
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( Expectations.class );
private static SqlExceptionHelper sqlExceptionHelper = new SqlExceptionHelper( false );
public static final int USUAL_EXPECTED_COUNT = 1;
public static final int USUAL_PARAM_POSITION = 1;
// Base Expectation impls ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public static class BasicExpectation implements Expectation {
private final int expectedRowCount;
protected BasicExpectation(int expectedRowCount) {
this.expectedRowCount = expectedRowCount;
if ( expectedRowCount < 0 ) {
throw new IllegalArgumentException( "Expected row count must be greater than zero" );
}
}
public final void verifyOutcome(int rowCount, PreparedStatement statement, int batchPosition) {
rowCount = determineRowCount( rowCount, statement );
if ( batchPosition < 0 ) {
checkNonBatched( rowCount, statement );
}
else {
checkBatched( rowCount, batchPosition, statement );
}
}
private void checkBatched(int rowCount, int batchPosition, PreparedStatement statement) {
if ( rowCount == -2 ) {
LOG.debugf( "Success of batch update unknown: %s", batchPosition );
}
else if ( rowCount == -3 ) {
throw new BatchFailedException( "Batch update failed: " + batchPosition );
}
else {
if ( expectedRowCount > rowCount ) {
**if(count_zero.get() == null || count_zero.get()) {**
throw new StaleStateException(
"Batch update returned unexpected row count from update ["
+ batchPosition + "]; actual row count: " + rowCount
+ "; expected: " + expectedRowCount + "; statement executed: "
+ statement
);
}
}
if ( expectedRowCount < rowCount ) {
**if(count_zero.get() == null || count_zero.get()) {**
String msg = "Batch update returned unexpected row count from update [" +
batchPosition + "]; actual row count: " + rowCount +
"; expected: " + expectedRowCount;
throw new BatchedTooManyRowsAffectedException(msg, expectedRowCount, rowCount, batchPosition);
}
}
}
}
private void checkNonBatched(int rowCount, PreparedStatement statement) {
if ( expectedRowCount > rowCount ) {
**if(count_zero.get() == null || count_zero.get()) {**
throw new StaleStateException(
"Unexpected row count: " + rowCount + "; expected: " + expectedRowCount
+ "; statement executed: " + statement
);
}
}
if ( expectedRowCount < rowCount ) {
**if(count_zero.get() == null || count_zero.get()) {**
String msg = "Unexpected row count: " + rowCount + "; expected: " + expectedRowCount;
throw new TooManyRowsAffectedException(msg, expectedRowCount, rowCount);
}
}
}
public int prepare(PreparedStatement statement) throws SQLException, HibernateException {
return 0;
}
public boolean canBeBatched() {
return true;
}
protected int determineRowCount(int reportedRowCount, PreparedStatement statement) {
return reportedRowCount;
}
}
public static class BasicParamExpectation extends BasicExpectation {
private final int parameterPosition;
protected BasicParamExpectation(int expectedRowCount, int parameterPosition) {
super( expectedRowCount );
this.parameterPosition = parameterPosition;
}
@Override
public int prepare(PreparedStatement statement) throws SQLException, HibernateException {
toCallableStatement( statement ).registerOutParameter( parameterPosition, Types.NUMERIC );
return 1;
}
@Override
public boolean canBeBatched() {
return false;
}
@Override
protected int determineRowCount(int reportedRowCount, PreparedStatement statement) {
try {
return toCallableStatement( statement ).getInt( parameterPosition );
}
catch (SQLException sqle) {
sqlExceptionHelper.logExceptions( sqle, "could not extract row counts from CallableStatement" );
throw new GenericJDBCException( "could not extract row counts from CallableStatement", sqle );
}
}
private CallableStatement toCallableStatement(PreparedStatement statement) {
if ( !CallableStatement.class.isInstance( statement ) ) {
throw new HibernateException(
"BasicParamExpectation operates exclusively on CallableStatements : " + statement.getClass()
);
}
return (CallableStatement) statement;
}
}
// Various Expectation instances ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public static final Expectation NONE = new Expectation() {
public void verifyOutcome(int rowCount, PreparedStatement statement, int batchPosition) {
// explicitly doAfterTransactionCompletion no checking...
}
public int prepare(PreparedStatement statement) {
return 0;
}
public boolean canBeBatched() {
return true;
}
};
public static final Expectation BASIC = new BasicExpectation( USUAL_EXPECTED_COUNT );
public static final Expectation PARAM = new BasicParamExpectation( USUAL_EXPECTED_COUNT, USUAL_PARAM_POSITION );
public static Expectation appropriateExpectation(ExecuteUpdateResultCheckStyle style) {
if ( style == ExecuteUpdateResultCheckStyle.NONE ) {
return NONE;
}
else if ( style == ExecuteUpdateResultCheckStyle.COUNT ) {
return BASIC;
}
else if ( style == ExecuteUpdateResultCheckStyle.PARAM ) {
return PARAM;
}
else {
throw new HibernateException( "unknown check style : " + style );
}
}
private Expectations() {
}
}