JPA + Oracle + Blob
Estava precisando fazer um pequeno teste de campo blob com JPA no Oracle.
A atividade aparentemente é fácil, porém fiquei um dia inteiro pra fazê-la.
Segue os passos:
Tabela no oracle:
CREATE TABLE “TESTE_BLOB”
( “ID” NUMBER(6,0) NOT NULL ENABLE,
“IMAGEM” BLOB NOT NULL ENABLE,
“DESCRICAO” VARCHAR2(255 BYTE),
“NOME” VARCHAR2(50 BYTE),
CONSTRAINT “TESTE_BLOB_PK” PRIMARY KEY (“ID”) ENABLE
)
Entidade TesteBlob
@Entity(name = "TesteBlob")
@Table(name = "TESTE_BLOB")
public class TesteBlobTO {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(generator = "SequenceGenerator")
@SequenceGenerator(name = "SequenceGenerator", sequenceName = "SQ_TESTE_BLOB", initialValue = 1)
@Column(name = "ID")
private java.lang.Integer id;
@Column(name = "IMAGEM")
@Lob
@Basic(fetch=FetchType.LAZY)
private byte[] imagem;
@Column(name = "DESCRICAO")
private java.lang.String descricao;
@Column(name = "NOME")
private java.lang.String nome;
/* ... */
}
Até ai estava funcionando para arquivos de até 2kb. Quando tentava colocar um arquivo maior que isso ele dava os seguintes erros:
WARN [JDBCExceptionReporter] SQL Error: 17090, SQLState: null
ERROR [JDBCExceptionReporter] operação não permitida: streams type cannot be used in batching
ERROR [AbstractFlushingEventListener] Could not synchronize database state with session
Caused by: java.sql.SQLException: operação não permitida: streams type cannot be used in batching
Googlando por aí acabei achando uma solução, incluir no arquivo persistence.xml com a seguinte tag:
<property name=”hibernate.jdbc.batch_size”>0</property>
Ele aceitou arquivos com mais de 2k, mas quando tentava inserir arquivos com mais de 3kb ele dava um novo erro:
WARN [JDBCExceptionReporter] SQL Error: 1460, SQLState: 72000
ERROR [JDBCExceptionReporter] ORA-01460: unimplemented or unreasonable conversion requested
ERROR [AbstractFlushingEventListener] Could not synchronize database state with session
org.hibernate.exception.GenericJDBCException: could not insert: [testeblob.dataaccess.to.TesteBlobTO]
Caused by: java.sql.SQLException: ORA-01460: unimplemented or unreasonable conversion requested
Depois de ler caçar em vários lugares pela solução, vi um lugar sugerindo atualizar o driver da oracle. PErcebi que eu estava usando um driver antigo (ojdbc14.jar, mas vi gente usando um mais antigo ainda classes12.jar), troquei para
ojdbc5.jar (porque aqui ainda está com java 5, para java 6 tem o ojdbc6.jar) e tudo funcionou lindo e perfeitamente.
[]‘s
Quebrando páginas com JSF
Olá,
Essa semana passei pelo problema de ter que quebrar páginas com um conteúdo de um datatable. Tentei usar o style=”page-break-after: always;” dentro de um datatable e não deu certo de jeito nenhum, não sei porquei. Foi então que resolvi procurar outra forma de iteração dos dados. Só consegui usando o componente dataList do tomahawk:
<t:dataList id="dataTable1"
value="#{TesteQuebraPagina.lista}"
var="item">
<h:outputText style="page-break-after: always;"
value="#{item}" />
</t:dataList>
Na exibição da página ele não aparece quebrado, mas na hora de imprimir ou visualizar a impressão, ele vai colocar cada item em um página.
MySql Error 1005: Can’t create table (errno: 150) Problema Foreign Key
Achei essas dicas no site e achei interessante postar aqui também. Quando tentar criar uma foreign key no mysql e ele der a mensagem MySql Error 1005: Can’t create table (errno: 150), provavelmente o erro é algum desses itens:
* Os dois campos relacionados da Foreign Key não tem o mesmo tipo ou tamanho. Por exemplo, se um campo é INT(10) o campo da chave precisa ser INT(10) também, se for colocado INT(11) ou TINYINY já não serve. Você deve verificar esses dados usando a query “SHOW CREATE TABLE tblname;”. Também confirme se ambos os campos são ‘signed’ ou ‘unsigned’. Conclusão, os campos devem ser EXATAMENTE o mesmo!
* O campo do qual você deseja se referenciar em outra tabela não tem um índice (index) ou não é uma chave primária (primary key). Se um dos campos que você deseja criar a relação não for uma “primary key”, você deve criar um índice para ela.
* O nome da Foreign Key já existe em alguma chave. Confira se o nome de sua Foreign Key é única no seu banco de dados. Simplesmente adicione alguns caracteres aleatórios no fim do nome de sua key para testar essa condição.
* Uma ou ambas as tabelas são MyISAM. Para utilizar Foreign Key ambas as tabelas devem usar InnoDB. Normalmente quando ambas as tabelas são MyISAM o MySQL não apresenta nenhuma mensagem de erro, simplesmente não cria a chave.
* Você pode ter especificado “CASCADE ON DELETE SET NULL”, enquanto o campo é “NOT NULL”, esse é o erro mais comum.
* Se o seu script está funcionando perfeitamente em um server, mas não em outro, verifique o collate ou charset, eles podem dar problemas caso sejam diferentes.
* Você pode ter um valor default (ex. default=0) na sua coluna Foreign Key.
* O nome de sua Foreign Key excede o limite de no máximo 64 caracteres.
Fonte: http://diariodecodigos.info/2010/01/mysql-error-1005-can%E2%80%99t-create-table-errno-150/
Otimizando Javascript e CSS da aplicação
Andei pesquisando ultimamente sobre otimização de aplicações e web e encontrei algo que merece ser publicado, a redução do código Javascript e CSS. A idéia é transformar o código:
/*
Método que atualiza o valor de algum
atributo passado como parametro
*/
function updateField( field, value )
{
//arqui entraria um comentário
field.value = value;
window.close();
/* aqui vem outro
só que de bloco
*/
}
Para:
function updateField(b,a){b.value=a;window.close()};
Esse pequeno pedaço de código já mostra uma diferença significativa, imagina agora para aqueles arquivos javascript enormes com todas as funções do seu sistema?
Se parar para analisar, os javascript que são fornecidos para Ajax, JQuery e coisas do gênero também fazem isso.
O Yahoo disponibiliza um jar (http://yuilibrary.com/downloads/#yuicompressor) que faz isso automático. Basta executar a linha de comando: java -jar yuicompressor-x.y.z.jar “nomeDoArquvo.js”, assim ele vai gerar na saída padrão o código reduzido. Com o parâmetro -o você escolhe o nome do novo arquivo a ser gerado.
Um problema de fazer isso durante o desenvolvimento é que se você precisar dar manutenção no código, esquece. Para resolver esse novo problema, eu fiz uma manutenção na target do build.xml que gera o EAR da aplicação. Ele faz um backup dos javascript, reduz todos os códigos e depois de gerar o WAR ele restaura os javascripts anteriores.
<!-- fazer o backup dos javascripts -->
<echo message="Criando a pasta de backup dos javascripts" />
<mkdir dir="${web.root.dir}/javascriptBackup" />
<echo message="Copiando os javascripts" />
<copy todir="${web.root.dir}/javascriptBackup">
<fileset dir="${web.root.dir}/javascript/" />
</copy>
<!-- Minizando os javascripts -->
<echo message="Minimizando os javascripts" />
<taskdef name="for" classname="net.sf.antcontrib.logic.For" />
<for param="file">
<path>
<fileset dir="${web.root.dir}\javascript\" includes="*.js" />
</path>
<sequential>
<apply executable="java" parallel="false">
<fileset file="@{file}" />
<arg line="-jar" />
<arg line="ignorelib\yuicompressor-2.4.2.jar" />
<arg line="-o" />
<arg line="'@{file}'" />
<arg line="'@{file}'" />
</apply>
</sequential>
</for>
<!-- Gerando o WAR ou EAR -->
<jar destfile="${build.result.folder}/${full.name}">
<fileset dir="${web.root.dir}" includes="**/*.*" excludes="WEB-INF/classes/**/*.*" />
<fileset dir="${web.root.dir}/../temp.folder" includes="**" />
<manifest>
<attribute name="Class-Path" value="${manifest.classpath}" />
</manifest>
</jar>
<!-- Voltando o backup -->
<copy todir="${web.root.dir}/javascript" overwrite="true">
<fileset dir="${web.root.dir}/javascriptBackup/" />
</copy>
<!-- Apagando o backup -->
<delete dir="${web.root.dir}/javascriptBackup/" />
Aqui só citei o caso do javascript, mas o CSS é da mesma forma.
[]‘s
Comandos Oracle
Alguns comandos Oracle que volta e meia eu precisa dar uma googlada para encontrar:
Ver o código fonte de Views:
SELECT owner, text FROM all_views WHERE owner = ‘UWCLASS’ AND view_name = ‘PERSON_VIEW’;
ou
SELECT dbms_metadata.get_ddl(‘VIEW’, ‘PERSON_VIEW’) FROM dual;
Ver código fonte de Objetos:
SELECT * FROM user_source;
Ver objetos que estão inválidos no banco:
SELECT ‘alter ‘||object_type||’ ‘||object_name||’ compile;’ FROM user_objects WHERE status=’INVALID’;
Exportar o banco de dados:
EXP USERID=user/password FILE=C:\arquivo.DMP OWNER=user;
Importar um banco de dados: (lembrando que se foi feito por um usuário DBA, deve ser importado por um usuário DBA)
IMP USERID=user/password FILE=C:\dump.DMP FROMUSER=usuarioOrigem TOUSER=usuarioDestino FEEDBACK=5000 STATISTICS=NONE;
Depois junto mais e publico.
[]‘s
“A ordem das cláusulas altera o resultado”
Sempre acreditei que a ordem das cláusulas numa consulta comum não interfere em nada no resultado. Porém, passei um dia investigando uma consulta que estava dando erro. A correção veio como de uma simples alteração na ordem das cláusulas. Difícil acreditar, né?
Esse erro aconteceu no Oracle, ao chegar em casa fui testar em outro e banco e pimba, aconteceu novamente. No SqlServer aconteceu o erro, já no mysql não consegui retratar.
Chega de embromação e vamos ao erro.
Vamos criar um simples tabela.
CREATE TABLE [tabela] (
[TIPO] [varchar](1),
[valor] [varchar] (3)
)
Na primeira coluna armazenaremos o tipo de dado que tem na seguda.
insert into tabela1 (tipo, valor) values (‘N’, ’1′);
insert into tabela1 (tipo, valor) values (‘N’, ’2′);
insert into tabela1 (tipo, valor) values (‘A’, ‘A’);
insert into tabela1 (tipo, valor) values (‘A’, ‘B’);
Agora uma simples consulta do tipo:
select * from tabela1
where 1=1
and convert(numeric, valor) > 0
and tipo = ‘N’
Gera o seguinte resultado:
Server: Msg 8114, Level 16, State 5, Line 1
Error converting data type varchar to numeric.
Mas mudando a ordem para :
select * from tabela1
where 1=1
and tipo = ‘N’
and convert(numeric, valor) > 0
Obtemos:
TIPO valor
—- —–
N 1
N 2
(2 row(s) affected)
Ou no Oracle:
select * from tabela
where 1=1
and to_number(valor) > 0
and tipo = ‘N’
Detalhes: Isso aconteceu na versão do Oracle do trabalho e não na versão da minha casa.
Qual a possível explicação?
O mais perto que conseguimos acreditar, é no famoso curto circuito que estudamos em PD1. Ou seja, as cláusulas são avaliadas em algum sentido (no sqlserver de cima para baixo e no oracle de baixo para cima) e quando encontram alguma expressão que é falsa, ele já descarta o registro que está sendo avaliado. No nosso caso ele corre o risco de gerar um erro antes da primeira cláusula falsa, o que corre o risco de parar todo um processamento envolvido.
Soluções?
Fazer subconsultas para que não corra o risco de encontrar um erro, causa overhead mas não causa erro.
Outra coisa que aprendi sobre esse assunto, é que a ordem das tabelas no FROM da consulta também interfere em algumas consultas. Pelo menos no oracle ele olha as tabelas de trás para frente, então o ideal é colocar as tabelas com menos registros no final da lista, para que ele possa diminuir o trabalho de juntar tudo.
Estou a espera de melhores explicações e melhores soluções.
[]‘s
Hello Blog!
Agora tenho um blog. Grande merda. Pretendo colocar dicas e descobertas do mundo da programação (leia-se java) e outras coisas da computação.
[]‘s