Eu tenho um aplicativo que usa anotações Hibernate 3.1 e JPA. Possui alguns objetos com atributos byte [] (1k - 200k de tamanho). Ele usa a anotação JPA @Lob, e o hibernate 3.1 pode lê-los perfeitamente em todos os principais bancos de dados - parece ocultar as peculiaridades do fornecedor do JDBC Blob (como deveria).
@Entity
public class ConfigAttribute {
@Lob
public byte[] getValueBuffer() {
return m_valueBuffer;
}
}
Tivemos que atualizar para 3.5, quando descobrimos que o hibernate 3.5 quebra (e não corrige) essa combinação de anotação no postgresql (sem solução alternativa). Não encontrei uma correção clara até agora, mas notei que se eu apenas remover o @Lob, ele usa o tipo bytea do postgresql (que funciona, mas apenas no postgres).
annotation postgres oracle works on
-------------------------------------------------------------
byte[] + @Lob oid blob oracle
byte[] bytea raw(255) postgresql
byte[] + @Type(PBA) oid blob oracle
byte[] + @Type(BT) bytea blob postgresql
once you use @Type, @Lob seems to not be relevant
note: oracle seems to have deprecated the "raw" type since 8i.
Estou procurando uma maneira de ter uma única classe anotada (com uma propriedade blob) que seja portátil entre os principais bancos de dados.
- Qual é a maneira portátil de anotar uma propriedade byte []?
- Isso foi corrigido em alguma versão recente do hibernate?
Atualização: Depois de ler este blog , finalmente descobri qual era a solução alternativa original para o problema do JIRA: Aparentemente, você deve remover @Lob e anotar a propriedade como:
@Type(type="org.hibernate.type.PrimitiveByteArrayBlobType")
byte[] getValueBuffer() {...
No entanto, isso não funciona para mim - ainda recebo OIDs em vez de bytea; no entanto, funcionou para o autor da edição do JIRA, que parecia querer oid.
Após a resposta de A. Garcia, tentei esta combinação, que na verdade funciona no postgresql, mas não no oracle.
@Type(type="org.hibernate.type.BinaryType")
byte[] getValueBuffer() {...
O que eu realmente preciso fazer é controlar para qual @ org.hibernate.annotations.Type a combinação (@Lob + byte [] é mapeada) (no postgresql).
Aqui está o snippet de 3.5.5.Final de MaterializedBlobType (sql type Blob). De acordo com o blog de Steve, postgresql deseja que você use Streams para bytea (não me pergunte por quê) e o tipo de Blob personalizado do postgresql para oids. Observe também que o uso de setBytes () em JDBC também serve para bytea (por experiência anterior). Portanto, isso explica por que usar-streams não tem efeito, ambos assumem 'bytea'.
public void set(PreparedStatement st, Object value, int index) {
byte[] internalValue = toInternalFormat( value );
if ( Environment.useStreamsForBinary() ) {
// use streams = true
st.setBinaryStream( index,
new ByteArrayInputStream( internalValue ), internalValue.length );
}
else {
// use streams = false
st.setBytes( index, internalValue );
}
}
Isto resulta em:
ERROR: column "signature" is of type oid but expression is of type bytea
Atualizar A próxima pergunta lógica é: "por que não mudar as definições da tabela manualmente para bytea" e manter o (@Lob + byte [])? Isso faz o trabalho, ATÉ tentar armazenar um byte nulo []. Que o driver postgreSQL pensa que é uma expressão de tipo OID e o tipo de coluna é bytea - isso ocorre porque hibernate (corretamente) chama JDBC.setNull () em vez de JDBC.setBytes (null) que o driver PG espera.
ERROR: column "signature" is of type bytea but expression is of type oid
O sistema de tipo no hibernate é atualmente um 'trabalho em andamento' (de acordo com o comentário de depreciação 3.5.5). Na verdade, grande parte do código 3.5.5 está obsoleto, é difícil saber o que olhar ao subclassificar o PostgreSQLDialect).
AFAKT, Types.BLOB / 'oid' no postgresql deve ser mapeado para algum tipo personalizado que usa o acesso JDBC do estilo OID (ou seja, objeto PostgresqlBlobType e NOT MaterializedBlobType). Na verdade, nunca usei o Blobs com o postgresql com sucesso, mas sei que o bytea simplesmente funciona como um / seria de esperar.
No momento, estou olhando para BatchUpdateException - é possível que o driver não ofereça suporte ao envio em lote.
Excelente citação de 2004: "Para resumir minhas divagações, eu diria que devemos esperar que o driver JDBC faça os LOBs corretamente antes de alterar o Hibernate."
Referências:
- https://forum.hibernate.org/viewtopic.php?p=2393203
- https://forum.hibernate.org/viewtopic.php?p=2435174
- http://hibernate.atlassian.net/browse/HHH-4617
- http://postgresql.1045698.n5.nabble.com/Migration-to-Hibernate-3-5-final-td2175339.html
- https://jira.springframework.org/browse/SPR-2318
- https://forums.hibernate.org/viewtopic.php?p=2203382&sid=b526a17d9cf60a80f13d40cf8082aafd
- http://virgo47.wordpress.com/2008/06/13/jpa-postgresql-and-bytea-vs-oid-type/
Respostas:
Depende do que você quer. JPA pode persistir um não anotado
byte[]
. Da especificação JPA 2.0:E o Hibernate irá mapeá-lo "por padrão" para um SQL
VARBINARY
(ou um SQLLONGVARBINARY
dependendo doColumn
tamanho?) Que o PostgreSQL manipula com umbytea
.Mas se você quiser que o
byte[]
seja armazenado em um objeto grande, você deve usar a@Lob
. Da especificação:E o Hibernate irá mapeá-lo para um SQL
BLOB
que o PostgreSQL manipula com umoid
.Bem, o problema é que não sei exatamente qual é o problema. Mas posso pelo menos dizer que nada mudou desde 3.5.0-Beta-2 (que é onde uma mudança foi introduzida) no branch 3.5.x.
Mas meu entendimento de questões como HHH-4876 , HHH-4617 e de PostgreSQL e BLOBs (mencionados no javadoc do
PostgreSQLDialect
) é que você deve definir a seguinte propriedadese quiser usar o
oid
iebyte[]
com@Lob
(que é meu entendimento jáVARBINARY
que não é o que você quer com o Oracle). Você tentou isso?Como alternativa, o HHH-4876 sugere o uso do obsoleto
PrimitiveByteArrayBlobType
para obter o comportamento antigo (pré Hibernate 3.5).Referências
Recursos
fonte
hibernate.jdbc.use_streams_for_binary=false
também? (vou verificar o que Steve disse agora).Aqui vai o que O'reilly Enterprise JavaBeans 3.0 diz
Aqui vai o código-fonte do PostgreSQLDialect
Então o que você pode fazer
Substitua PostgreSQLDialect da seguinte maneira
Agora é só definir seu dialeto personalizado
E use sua anotação JPA @Lob portátil
ATUALIZAR
Aqui foi extraído aqui
...
que pode ser explicado aqui
...
Interessante é porque quando ele mapeia Types.BOLB como bytea (Veja CustomPostgreSQLDialect), ele obtém
ao inserir ou atualizar
fonte
Estou usando o Hibernate 4.2.7.SP1 com Postgres 9.3 e o seguinte funciona para mim:
já que o Oracle não tem problemas com isso, e para Postgres estou usando um dialeto personalizado:
considero a vantagem desta solução, que posso manter os potes de hibernação intocados.
Para mais problemas de compatibilidade do Postgres / Oracle com o Hibernate, veja minha postagem no blog .
fonte
Eu finalmente consegui fazer isso funcionar. Ele expande a solução de A. Garcia, no entanto, como o problema está no tipo de hibernação MaterializedBlob, apenas o mapeamento de Blob> bytea não é suficiente, precisamos de uma substituição para MaterializedBlobType que funciona com o suporte de blob quebrado do hibernação. Essa implementação só funciona com bytea, mas talvez o cara do problema do JIRA que queria OID pudesse contribuir com uma implementação de OID.
Infelizmente, substituir esses tipos em tempo de execução é uma dor, pois eles deveriam fazer parte do dialeto. Se este aprimoramento do JIRA chegar ao 3.6, isso seria possível.
Muito disso provavelmente pode ser estático (getBinder () realmente precisa de uma nova instância?), Mas eu realmente não entendo a hibernação interna, então isso é principalmente copiar + colar + modificar.
fonte
Corrigi meu problema adicionando a anotação de @Lob que criará o byte [] no oracle como blob, mas essa anotação criará o campo como oid que não funciona corretamente. postgres como abaixo
Também é necessário substituir o parâmetro para o dialeto
spring.jpa.properties.hibernate.dialect = com.ntg.common.DBCompatibilityHelper.PostgreSQLDialectCustom
mais dicas podem ser encontradas nela: https://dzone.com/articles/postgres-and-oracle
fonte
Consegui funcionar substituindo a anotação por arquivo XML para Postgres. A anotação é mantida para Oracle. Em minha opinião, neste caso, seria melhor substituir o mapeamento desta entidade problemática com mapeamento xml. Podemos substituir entidades únicas / múltiplas com mapeamento xml. Portanto, usaríamos anotações para nosso banco de dados com suporte principal e um arquivo xml para cada banco de dados.
Nota: só precisamos substituir uma única classe, então não é um grande problema. Leia mais no meu exemplo de exemplo para substituir a anotação com XML
fonte
No Postgres @Lob está quebrando para byte [] ao tentar salvá-lo como oid, e para String também ocorre o mesmo problema. O código abaixo está quebrando no postgres que está funcionando bem no oracle.
e
A fim de corrigir acima no postgres, escrevemos abaixo hibernate.dialect personalizado
Agora configure o dialeto personalizado em hibernação
XYZ é o nome do pacote.
Agora está funcionando bem. NOTA- Minha versão Hibernate - 5.2.8.Final Postgres version- 9.6.3
fonte
Obrigado Justin, Pascal por me guiar na direção certa. Eu também estava enfrentando o mesmo problema com o Hibernate 3.5.3. Sua pesquisa e dicas para as aulas certas me ajudaram a identificar o problema e a consertar.
Para o benefício de quem ainda está preso ao Hibernate 3.5 e usando a combinação oid + byte [] + @LoB, a seguir está o que eu fiz para corrigir o problema.
Eu criei um BlobType customizado estendendo MaterializedBlobType e substituindo os métodos set e get com o acesso de estilo oid.
Registre o CustomBlobType com Hibernate. A seguir está o que eu fiz para conseguir isso.
fonte