mybatis操作mariadb駆動mysql一括挿入エラーjava.nio.BufferOverflowException:null
mybatis操作mariadb駆動mysql一括挿入エラーjava.nio.BufferOverflowException:null
ビジネスでは定期的にデータベースに統計データを書き込む必要があり、データ量が大きい.データベースへの書き込み中にバッファオーバーフロー異常が報告されることがあります.最後の例外スタックは次のとおりです.
Caused by: java.nio.BufferOverflowException: null at java.nio.HeapByteBuffer.put(HeapByteBuffer.java:189) at java.nio.ByteBuffer.put(ByteBuffer.java:859) at org.mariadb.jdbc.internal.packet.send.SendExecutePrepareStatementPacket.send(SendExecutePrepareStatementPacket.java:105) at org.mariadb.jdbc.internal.protocol.AbstractQueryProtocol.executePreparedQuery(AbstractQueryProtocol.java:578) at org.mariadb.jdbc.MariaDbServerPreparedStatement.executeInternal(MariaDbServerPreparedStatement.java:279) at org.mariadb.jdbc.MariaDbServerPreparedStatement.execute(MariaDbServerPreparedStatement.java:369) at com.alibaba.druid.pool.DruidPooledPreparedStatement.execute(DruidPooledPreparedStatement.java:493) … 31 common frames omitted
苦痛なソースコードの解読を経て、ついに異常な発生原因を見つけた.例外スタックのS e n d ExecutePrepareStatementPacketクラスのsendメソッドから言えば、ソースコードは次のとおりです.
ソースコードのnullBitsBuffer配列のサイズは、入力されたパラメータのデータ量によって決まります.buffer.buffer.put(nullBitsBuffer)文のbuffer.bufferは、次のコードで構成されています.
そのためnullBitsBufferサイズが1024を超えるとエラーが発生します.コミットするたびにデータベースのデータ量が大きすぎないことを確認する必要があります.
ビジネスでは定期的にデータベースに統計データを書き込む必要があり、データ量が大きい.データベースへの書き込み中にバッファオーバーフロー異常が報告されることがあります.最後の例外スタックは次のとおりです.
Caused by: java.nio.BufferOverflowException: null at java.nio.HeapByteBuffer.put(HeapByteBuffer.java:189) at java.nio.ByteBuffer.put(ByteBuffer.java:859) at org.mariadb.jdbc.internal.packet.send.SendExecutePrepareStatementPacket.send(SendExecutePrepareStatementPacket.java:105) at org.mariadb.jdbc.internal.protocol.AbstractQueryProtocol.executePreparedQuery(AbstractQueryProtocol.java:578) at org.mariadb.jdbc.MariaDbServerPreparedStatement.executeInternal(MariaDbServerPreparedStatement.java:279) at org.mariadb.jdbc.MariaDbServerPreparedStatement.execute(MariaDbServerPreparedStatement.java:369) at com.alibaba.druid.pool.DruidPooledPreparedStatement.execute(DruidPooledPreparedStatement.java:493) … 31 common frames omitted
苦痛なソースコードの解読を経て、ついに異常な発生原因を見つけた.例外スタックのS e n d ExecutePrepareStatementPacketクラスのsendメソッドから言えば、ソースコードは次のとおりです.
public int send(final OutputStream os) throws IOException {
PacketOutputStream buffer = (PacketOutputStream) os;
buffer.startPacket(0, true);
buffer.buffer.put((byte) 0x17);
buffer.buffer.putInt(statementId);
buffer.buffer.put((byte) 0x00); //CURSOR TYPE NO CURSOR TODO implement when using cursor
buffer.buffer.putInt(1); //Iteration count
//create null bitmap
if (parameterCount > 0) {
int nullCount = (parameterCount + 7) / 8;
byte[] nullBitsBuffer = new byte[nullCount];
for (int i = 0; i < parameterCount; i++) {
if (parameters[i] instanceof NullParameter) {
nullBitsBuffer[i / 8] |= (1 << (i % 8));
}
}
buffer.buffer.put(nullBitsBuffer);/*Null Bit Map*/
//check if parameters type (using setXXX) have change since previous request, and resend new header type if so
boolean mustSendHeaderType = false;
if (parameterTypeHeader[0] == null) {
mustSendHeaderType = true;
} else {
for (int i = 0; i < this.parameterCount; i++) {
if (!parameterTypeHeader[i].equals(parameters[i].getMariaDbType())) {
mustSendHeaderType = true;
break;
}
}
}
if (mustSendHeaderType) {
buffer.buffer.put((byte) 0x01);
//Store types of parameters in first in first package that is sent to the server.
for (int i = 0; i < this.parameterCount; i++) {
parameterTypeHeader[i] = parameters[i].getMariaDbType();
parameters[i].writeBufferType(buffer);
}
} else {
buffer.buffer.put((byte) 0x00);
}
}
for (int i = 0; i < parameterCount; i++) {
if (parameters[i] instanceof NotLongDataParameterHolder) {
((NotLongDataParameterHolder) parameters[i]).writeBinary(buffer);
}
}
buffer.finishPacket();
return 0;
}
ソースコードのnullBitsBuffer配列のサイズは、入力されたパラメータのデータ量によって決まります.buffer.buffer.put(nullBitsBuffer)文のbuffer.bufferは、次のコードで構成されています.
public PacketOutputStream(OutputStream outputStream) {
this.outputStream = outputStream;
buffer = ByteBuffer.allocate(1024).order(ByteOrder.LITTLE_ENDIAN);
this.seqNo = -1;
useCompression = false;
}
そのためnullBitsBufferサイズが1024を超えるとエラーが発生します.コミットするたびにデータベースのデータ量が大きすぎないことを確認する必要があります.