[Megoldva] mysql_query("SET CHARACTER SET 'utf8'"); Java Servletben

Fórumok

Van egy adatbázis benne egy adattábla:

CREATE DATABASE siteDB DEFAULT CHARACTER SET utf8;

USE siteDB;

CREATE TABLE blog(
id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
created DATETIME DEFAULT '0000-00-00 00:00:00',
modified DATETIME DEFAULT '0000-00-00 00:00:00',
title VARCHAR(255) NOT NULL,
text TEXT NOT NULL
)DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

Készülget hozzá egy java EE-s alkalmazás. Minden fájl utf-8-ba mentve, mint látható a fentiből
az adatbázis is és az adattábla is utf-8-ban van. (igen a két szöveges mező is).

A problémám az, hogy a Mysql-be nem utf-8-ként mentődik, hanem az ékezetes betűk helyett mindenféle krix-krax van. Fontos tehát, hogy nem az adatbázisból való kiolvasással van a gond, hanem a beírással.

Mivel korábban foglalkoztam php-vel, így kipróbáltam, íme egy példa:
<?php
$link = mysql_connect('localhost','user','pass');
if (!$link) {
die('Could not connect to MySQL: ' . mysql_error());
}
echo 'Connection OK
';
$db = mysql_select_db("siteDB");
if ($db != true){
echo "Adatbázis kiválasztás sikertelen";
die();
}
echo "ok
";

$str="INSERT INTO blog (created, modified, title, text) VALUES(now(), now(),'éáő', 'éáőpé')";
//mysql_query("SET NAME 'utf8'");
mysql_query("SET CHARACTER SET 'utf8'"); // <- ha ez benne van, akkor oké

mysql_query($str);

mysql_close($link);
?>
A fenti példában a comment szerint ha beírom, a "mysql_query("SET CHARACTER SET 'utf8'");" sort, akkor jól mentődnek el az ékezetes karakterek, ha nem akkor a már ismertetett krix-kraxos történet jön elő.

Tehát valami mysql_query("SET CHARACTER SET 'utf8'");-hez hasonlót szeretnék javaban.

Ami megvan:
response.setContentType("text/html; charset=utf-8");
//request.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();

A html oldalak így generálódnak:

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

Amiket kipróbáltam, de nem segítettek:
1) google szerint, amikor csatlakozom a adatbázishoz, akkor paraméterként átadható az "encoding", tehát itt:
con = DriverManager.getConnection("jdbc:mysql://localhost/siteDB?IDE_JON_AZ_ENCODING",
"user", "pass");
Már nem emlékszem mi volt az IDE_JON_AZ_ENCODING, de kipróbáltam és nem működött. :)

2)Mint php-nél próbáltam egy query-t csinálni:

String sql = "INSERT INTO blog ....";
Connection con = null;
PreparedStatement ps = null;
Statement stmt = null;
try {
con = DriverManager.getConnection("jdbc:mysql://localhost/siteDB",
"user", "pass");

Statement st = con.createStatement();
st.executeQuery("SET NAMES 'utf8'");
st.executeQuery("SET CHARACTER SET 'utf8'");
st.executeUpdate(sql);

st.executeQuery("SET CHARACTER SET 'utf8'"); helyett próbáltam sima execute-ot -> semmi.
Továbbra is rosszul menti a karaktereket az adatbázisba.

3) my.cnf módosítása. Ez megtörtént, de sokra nem megyek vele, egyrészt mert nem javult meg ettől semmi, másrészt meg ahova majd feltölteném ott se tudom módosítani a my.cnf-et...

A kérdés tehát adott, valamiért az adattáblába rosszul mentődnek el a sorok,
A segítséget, ötletet előre is köszi!

Hozzászólások

szia!

pl

jdbc:mysql://host/database?useUnicode=true&characterEncoding=UTF-8

Ha programot irsz, fontos megerteni, mi miert tortenik. A mysql-nek teljesen mindegy, hogy mi a mezo enkodingja, vagy barmi, csak meg kell adni neki, hogy eppen mivel akarsz kommunikalni (SET NAMES - ezt a jdbc driver megcsinalja a fenti url parameterekkel), a tobbit atkonvertalja. Ebbol rengeteg problema szokott lenni, pl egy latin mezobe ha latinkent utf karaktereket kuldesz, azt eltarolhatja, mukodhet is jo darabig (ha beirva es kiolvasva is hibas set names-el van), de 1-2 dump/restore, mezo konverzio, stb utan akar visszaallithatatlanul truncatelodhet az informacio. Ezt csak azert irom, mert tenyleg fontos. Jelen esetben van egy olyan elkepzelesem, hogy a forraskodba irt stringedet nem menti jol el, milyen platformon dolgozol, mi a file.encoding? Vagy mast is rosszul insertal?

Azt hiszem most kezdem egy picit hülyének érezni magam. Szóval:
Eddig amit a Servletből akartam elmenteni azokat az adatokat nem a forrásfájlba írta be, hanem egy form-ból szedtem ki. Ha átírom fix szövegre a forrásfájlban akkor jól működik (mint a php-s példánál), de ha formból kapom az adatot, akkor áll fent a probléma, amiért nyitottam ezt a topicot.

1) A formból így szedem ki az adatot:
String title = request.getParameter("title");
És azt a "title"-t mentem el az adatbázisba (most az mindegy hogy nincs ellenőrzés és a title tartalma bármi lehet)
2) A form kiíratása:
out.print("

");
out.print("Cím:

");
out.print("Tartalom:
");
out.print("");
out.print("
");
out.print("

");
out.print("

");
out.print("

");

3) Részlet annak az oldalnak a forrásából, amiben a form van:

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

Tehát akkor gondolom azzal van gond, hogy a usetől nem utf8-ban kapom az adatot? Ezzel mit kezdjek?

Bár így ez (Jelen esetben van egy olyan elkepzelesem, hogy a forraskodba irt stringedet nem menti jol el, milyen platformon dolgozol, mi a file.encoding? Vagy mast is rosszul insertal?) már nem annyira érdekes, de leírom.
Linux (Slamd64), minden fájl utf-8-ba mentve, IDE: eclipse.

OK. Akkor a formból jön rosszul. Rossz iranyba indultunk :)

Valoszinuleg mar a kliens kuldi rosszul es nem kerul konvertalasra, vannak ilyen par soros servlet filterek mindenfele a google-ben erre a problemara. (Ha ez a problemad.)

Amugy miert csinalsz out.print() -el web alkalmazast? Ennyi erovel irhatnad C-ben is..

(A fentiben a form kiiratása persze nem így néz ki csak rosszul jelenik meg.)

"Amugy miert csinalsz out.print() -el web alkalmazast?"
Ez úgy néz ki, hogy minden oldal include-ol egy jsp-t:
response.setContentType("text/html; charset=utf-8");
PrintWriter out = response.getWriter();
request.getRequestDispatcher("/Menu.jsp").include(request, response);

Ez a Menu.jsp egy olyan jsp ami tartalmaz egy .css-t (< link rel='stylesheet' type='text/css' href='blog.css' / >),
majd div-ekkel elkezdi kirajzolni az oldalt: az oldal tetejét, a bal oldali menüt, majd kiirja a lényegi rész "nyitó" divjét, és nagyjából ennyi a Menu.jsp.
Tehát a tényleges Servletekben nem sok html-van (form például), 0 css, stb.

Mivel most ismerkedem a servletekkel és jsp-vel, nem tudom hogy jól csinálom-e ezt így. Ha csak ennyi miatt kell az out.print, akkor az még oké, vagy eleve rosszul állok a dologhoz? Ez esetben mit javasolnál hogyan?

Azt a filteres ötletet köszi, megpróbálok keresgélni. (lehet csak holnap ma már lefáradtam)
Köszönöm a segítséged, és bocsi, hogy először "átvertelek" és nem is az volt a hiba, mint amit írtam.

Senki nem programozik ma mar igy servlet-et. Onszopatas.

Probald ki a grails-t, ahol teljesen egyszeruen, ugyanakkor kurrens technologiakkal (hibernate, spring stb) lehet haladni. Egy kis pl. ORM tapasztalat 100x tobbet er, mint hogy ossze tudod-e reszelni servletben nativ JDBC-vel ezt a charset dolgot.

Köszi utána fogok nézni a grailsnak!
Az viszont igaz, hogy szeretem látni a dolgok mélyén mi van, ezért is nem bánom ha servletekkel, jsp-vel szívok. (Szívem szerint FastCGI-t tanulnám C/C++-ban írva, de félek nem sokra mennék vele a jövőben. :) )
Még egyszer, köszi a segítséget!

Na szóval, mint kiderült az volt a gond, hogy az adatokat a usertől kértem be form-on keresztül, azt viszont nem utf8-ban kaptam meg, így ha elmentettem egy adatbázisba konvertálás nélkül, akkor az hibásan mentődött el.
Megoldás:
String title = new String(request.getParameter("title").getBytes(), "UTF-8");
És ezt a "title"-t már el lehet menteni.

Szerk.:
Ez itt OFF, de hátha más is belefut:
javaból sokáig nem tudtam hozzáférni az adatbázishoz, konzolból, vagy php-vel igen.
A hiba abból eredt, hogy a Slackware-es (nálam: Slamd64-es) mysql rc script elég furán viselkedik, alapértelmezetten a beállító fájl egyik opcióját figyelmen kívül hagyja (felülírja):
Az rc.mysql-ben ezt a részt keresd:
###
# To allow outside connections to the database comment out the next line.
# If you don't need incoming network connections, then leave the line
# uncommented to improve system security.
SKIP="--skip-networking"

Írd át:
#SKIP="--skip-networking"-ra és JDBC-vel is eléred az adatbázisokat.
(Mire én erre rájöttem...)