Archiv der Kategorie: MySQL

MySQL – Den richtigen (Daten)typ kennen

Am Wochenende sah ich mir ein Script eines anderen Programmierers an … der Webmaster des Scriptes hatte eine Frage und zur Beantwortung benötigte ich Zugang zum Script. Nach langen Erklärungen, was denn genau passieren soll und was denn aktuell wirklich passiert, stieß ich auf einige Besonderheiten im Script.

Nun, den Fehler konnte ich beseitigen und der Webbi bat mich dann gleich mal, ob ich denn mal über den Code an sich sehen könnte, “ob man da noch was rausholen kann, so, Geschwindigkeitstechnisch”. “Immer”, denke ich mir und sehe mir das ganze so.

Okay, optimal war der Code nicht, eher genau das Gegenteil. Mein Kommentar war dann, dass, wenn der Webbi das ganze schnell haben will, er sich doch bitte einen _guten_ Programmierer holen soll, der das ganze mal neu macht. Der alte Code wäre dafür nicht geeignet. Der Webbi war nachher froh, dass der alte Code das macht, was er wollte und damit ist die Geschichte erstmal beendet.

Warum schreibe ich das ganze?
Nun, im Code fiel mir auf, dass ziemlich viele Variablen gegen die Datenbank geprüft wurden, nur für den Zweck, ob in einem Datenbankfeld – sinngemäß – ja oder nein steht. Dieses ja-oder-nein wurde dann aber in einem Zahlenfeld in mySQL gespeichert – soweit, so gut – nur eben ein INT(1).

Und nun zum Sinn dieses Postings: Lieber Programmierer, du brauchst in der DB einen Platz um “ja” oder “nein” zu speichern? Dann minimiere “ja” zu 1 und “nein” zu 0, soweit kamst du ja schon. Nun noch die Auswahl des geeigneten DB-Typen und da hast du gepatzt.

Ein INT(1) speichert eben NICHT nur eine Zahl mit der Länge 1 (also 0 bis 9), sondern einen 4 Byte großen Integer Wert, den du mittels “ZEROFILL” dann auf die in den Klammern angegebene Zahl mit 0 auffüllen kannst. Habe ich ein INT(3) Feld und speichere dort die Zahl 4 rein, dann steht da 004; in ein INT(3) kann ich aber auch die Zahl 123456 schreiben und habe kein Problem damit, da ein 4-Byte INT Zahlen von 0 bis 4294967295 (UNSIGNED) oder von –2147483648 bis 2147483647 (SIGNED) speichern kann, egal was in Klammern steht.

Um Speicherplatz zu sparen nimm bitte den Datentyp TINYINT, der speichert nur 1 Byte große Zahlen, also von 0 bis 255 (UNSIGNED) oder –128 bis 127 (SIGNED).

Zur weiteren Info lies dir die folgenden beiden Links durch:
http://dev.mysql.com/doc/refman/5.1/de/numeric-types.html
http://dev.mysql.com/doc/refman/5.1/de/storage-requirements.html

Java MySQL Tutorial

In Sachen Java und Datenbank bin ich ein totaler Neuling. Allerdings hält man sich ja gern fit in solchen Sachen und da wir hier firmenintern ein neues Desktop-Tool brauchen, bot sich Java an. Für mich die einzige Schwierigkeit: Die Verbindung von Java zur MySQL-Datenbank.

Lange habe ich gesucht, lange herumprobiert und getippt und gelesen und wieder getippt. Am Ende habe ich es dann geschafft, mit ganz einfachen Mitteln eine Verbindung herzustellen.

Die Anforderungen waren:

  • Connect zur MySQL Datenbank
  • Ausführen eines SELECT´s
  • Auswerten der Antwort
  • Schließen der Datenbank

Das ganze aber ohne Frameworks wie Hibernate oder sowas, sondern nur mit Bordmitteln, die Java mitliefert. Betrachtet man das Ergebnis, ist es doch sehr einfach, aber man muss es ja auch erstmal wissen. Ich will es euch nicht vorenthalten. Dazu habe ich mal eine Beispiel – Konsolen Anwendung mit NetBeans erstellt, der Code läßt sich aber problemlos in große Projekte übernehmen.

Schritt 0: Benötigte imports

Folgendes import wird benötigt

import java.sql.*;

Vor den ganzen Code setzt man noch folgende Merker:

Statement stmt;       
ResultSet rs;

Die Funktion von ResultSet und Statement erkläre ich später.

Schritt 1: Treiber einbinden

(Alles ab hier sollte in einen try…catch Block)
Den Treiber für MySQL muss man mit 2 Schritten einbinden, in Netbeans geht das ziemlich einfach.
a) Rechtsklick auf das Projekt, Properties, dann Libraries, dann bei „Compile“ und „Run“ die „MySQL JDBC Driver“ mit „Add Library“ auswählen und bestätigen.
b) Den Code

Class.forName("com.mysql.jdbc.Driver");

hinzufügen.

Schritt 2: Verbindung zur MySQL-Datenbank herstellen

Die Verbindung zur Datenbank wird wie folgt hergestellt


String url     = "jdbc:mysql://localhost:3306/meinDatenbankSchema";
Connection con = DriverManager.getConnection(url,"benutzername", "benutzerpasswort");
stmt = con.createStatement();

Zeile 1 definiert das Datenbankziel, Zeile 2 stellt die eigentliche Verbindung her. Nicht vergessen, die Daten für „meinDatenbankSchema„, „benutzername“ und „benutzerpasswort“ anzupassen.
Zeile 3 erzeugt ein sogenanntes „Statement“ Objekt, mit welchem wir Anfragen an die Datenbank stellen können (Querys).

Schritt 3: Querys zur Datenbank senden

SQL-Querys sendet man mit Hilfe des Statement-Objektes zur Datenbank und wertet das ganze mit dem ResultSet-Objekt wieder aus.
SELECT-Beispiel, absenden des SQL, return-typ ist ResultSet:

rs = stmt.executeQuery("SELECT vorname, nachname FROM users");

UPDATE-Beipiel, absenden des SQL, return-typ ist integer:

int anzahlZeilen = stmt.executeQuery("UPDATE users SET vorname = 'Harry' WHERE vorname='Larry' ");
Schritt 4: Auswerten eines SELECT Ergebnisses

Bei einer SELECT Anfrage bekommt man ein ResultSet Objekt zurück, dieses kann man wie folgt auswerten:

while (rs.next())       
{
    String  vorname = rs.getString("vorname");
    String  nachname = rs.getString("nachname");
    System.out.println("Vorname: "+vorname+" | Nachname: "+nachname);
}
Schritt 5: Auswerten eines UPDATE Ergebnisses

Einfach den integer auswerten, er gibt die Anzahl der sogenannten „betroffenen Zeilen“ an.

Schritt 6: Verbindung zur MySQL-Datenbank schließen

Geht ganz einfach und sollte in jedem Fall gemacht werden (im Gegensatz zu PHP, wo das leider noch ein kann ist, ist es bei Java ein muss).

con.close();

So, ich hoffe, ihr könnt damit was anfangen – im wahrsten Sinne des Wortes. Mir jedenfalls wird es sehr helfen, meine ersten Datenbankabhängigen Servlets, JSP’s oder Java-Anwendungen zu schreiben.

SQL-Injection sichere MySQL-Query Funktion

Immer wieder ein Thema: SQL-Injections in Webseiten. Nicht zuletzt, seit es immer mehr große Zeitschriften sich zum Thema machen, das Prinzip ‚Wie führe ich eine SQL-Injection durch‘ auch für die ganz … naja, sagen wir mal lernfaulen … auf zu schreiben, wird das Thema doch immer beliebter.

Deshalb stelle ich nun mal – im kleinen Rahmen natürlich – meine Funktion vor, mit deren Hilfe es mir gelang, meine Projekte bis dato SQL-Injection safe laufen zu lassen.

Die Funktion, wie ich sie hier vorstelle, ist nur ein Auszug aus der echten Funktion. Die Funktion selbst liegt bei mir auch innerhalb einer Klasse. Abgerundet mit vielen Features – wie z.B. logging der SQL-Strings, logging der Dauer einzelner und aller Abfragen usw., hat mir diese Klasse über die Jahre sehr gute Dienste geleistet, was eine schnelle, saubere und vor allem sichere Erstellung von Webprojekten angeht.

Okay, genug geschwafelt, hier der Code:

public function myquery()
{
   $args    = func_get_args();
   $query   = array_shift($args);
   $args    = array_map(‚mysql_real_escape_string‘, $args);
   // echo vsprintf($query, $args).“
\n“;
   return mysql_query(vsprintf($query, $args));
}
 

Der Experte sieht gleich, was hier passiert, allen anderen erkläre ich es gern. Die Funktion nimmt sich alle Argumente, benutzt das erste Argument als SQL-Query-String und alle folgenden als Argumente zu diesem String. Alle Argumente werden mit der Funktion mysql_real_escape_string behandelt, welche alle für mySQL gefährlichen Zeichen entsprechend ungefährlich macht (mal salopp ausgedrückt).

Dannach werden die Argumente mittels printf-Funktion in den Query gebracht und dann wird das ganze ausgeführt. Zurück bekommt ihr den Rückgabewert von mysql_query, mit dem ihr dann ganz normal weiterarbeiten könnt.

Ein Beispiel-Aufruf:

$sql = „SELECT userid FROM tblUser WHERE username=’%s‘ AND password=MD5(‚%s‘)“;
$_ressource = mysql_query_safe($sql,$_POST[„username“],$_POST[„password“]);

Hier wird – in einer sonst sehr gefährlichen Umgebung – die UserID nach einem Login anhand von Username und Passwort ermittelt, die der User eingegeben hat.

Die einzelnen Tags, also wann kommt ein %s, wann ein %u usw., das lest ihr am besten direkt bei der Funktion sprintf nach.

Verbesserungsvorschläge nehme ich natürlich gern entgegen.

Import von großen mySQL-Dumps

Ich habe hier einen mySQL Dump der Größe 173 MB.
Das ist wirklich eine Menge.
Dazu kommt, dass es Zeilen gibt, die über 1 Mio Zeichen lang sind. Dies sind INSERT INTO Kommandos, die direkt auf einer Zeile 10.000 Datensätze importieren (siehe Doku zu INSERT INTO). Hauptproblem an der Sache war, dass es phpMyAdmin nicht hinbekam, die Datei
a) hochzuladen
b) zu verarbeiten
Auch der mySQL Query Browser flog mir bei der Menge von Daten einfach mal davon.

Außerdem: Es muss doch einen einfachen Weg geben, die ganzen Daten problemfrei auf einen Rutsch zu importieren. Gesucht, gelesen, getan.

Die Lösung: Man öffne die Kommandozeile und gehe zum Verzeichnis der mySQL Installation. Man benötigt das ‘mysql’ Programm, dies liegt meist im ‘bin’ Verzeichnis der Installation.

Nun benutzt man folgendes Kommando:

mysql –u [USERNAME] –p[PASSWORT] [DATENBANKNAME] < [SQLDATEI]
  • [USERNAME] = Dein Username, z.b. root
  • [PASSWORT] = Klar, oder? Bitte KEIN Leerzeichen zwischen –p und dem Passwort. Wenn ihr einen Account ohne PW habt, dann einfach nix hinschreiben.
  • [DATENBANKNAME] = Die DB muss existieren, dann einfach hier angeben.
  • [SQLDATEI] = Voller Pfad zur SQL Datei

Beispiel: mysql –u sascha –pMeinPW SaschasDatenbank < “c:/sqldumps/meinedatenbank.sql”

Einmal ENTER drücken und warten. Meine 173 MB waren in sagenhaften 30 sek. importiert, komplett und ohne Fehler. *wow*

Viel Erfolg weiterhin …

Disqualifiziert: Meine Suchmaschine

Ich habe eine Suchmaschine geschrieben. Nicht so was wie Google und Co, eine Suchmaschine für Produkte ist es. Und – wie ich selbst meine – eine gute Suchmaschine.

Ich habe lange an meiner SuMa gearbeitet, habe verbessert und optimiert. Nun war es so, dass meine SuMa „in die Welt“ musste, damit ich auch mal Feedback bekomme. Feedback im Sinne von „Wer sucht was“ und wenn jemand etwas sucht „wer klickt was, wenn er was gesucht hat“. Solche Fragen kannst du nicht allein beantworten, dazu muss deine Seite – deine SuMa – „live“ sein.
Eine Domain hatte ich noch, ein Design war schnell besorgt, auch wenn es dazu nötig war einen Copyright-Hinweis einzublenden; nicht schön, aber hauptsache die Seite geht ins Internet.

Nun noch schnell alle Scripte hochladen, die DB erstellen und nun – tata – die Produktdaten hochladen. Das dauerte … und dauerte … und dauerte. Irgendwann hatte ich dann mal knappe 500.000 Produkte in der Online-DB drin, da vertagte ich den Rest auf morgen. Ich war einfach zu müde.

Am nächsten Tag starte ich meinen Rechner, meinen Browser und HALT – da stimmt was nicht. Meine SuMa ist meine Startseite, ich weiß genau, was mich erwartet, aber das, was nun kam, sah nicht aus wie grün, weiß mit Wolken am oberen Rand, dass war eine Fehlerseite. Genauer gesagt, eine Seite, die mir anzeigte, dass die Domain „disabled“ war. Häh?

Na gut, Mailprogramm auf und siehe da, eine Mail meines Hosters. Meine Domain ist „temporär gesperrt“, weil ich mit meinem Verhalten auf der DB alle anderen Kunden beeinflussen würde. Das war wohl das hochladen der Produktdaten. Weiterhin wäre der Betrieb einer SuMa auf einem normalen Hosting-Server wohl „nicht möglich“.Möglich ist es schon, wie meine Webseite zeigt, das Problem ist wohl, dass ich mit dem Upload und den Aktualisierungen – die ich ja eigentlich täglich durchführen müsste – wohl den Regelbetrieb so sehr störe, dass ich gesperrt wurde.

Naja, ein Kniefall und das Versprechen, dass ich erstmal eine Uploads mehr durchführe später ist meine Webseite nun wieder online und kann zumindest wieder indiziert werden.

Leider bräuchte ich für den Normalbetrieb der SuMa einen root-Server. Der aber kostet zu viel Geld. Ziel der SuMa war es ja, ein wenig Geld ein zu bringen, nicht jeden Monat Geld rein zu pumpen. Derzeit wirft die SuMa nichts ab, was aber klar ist, da die SuMa
a. noch recht neu ist und
b. gerade mal 10% meiner Ideen verwirklicht sind.

Ich habe noch 3 Dutzend Ideen für das Projekt. Dumm nur, dass ich an einem normalen Tag gerade mal 20 Minuten Zeit habe, etwas davon zu realisieren. Die Motivation wäre bestimmt höher, wenn mal jemand meine SuMa benutzen würde.

Ist schon frustrierend. Da willst du eine zu studienzwecken eine SuMa für Produkte bauen und dabei was über SEO, SuMa, PHP, DB, usw. lernen und nebenbei etwas Geld verdienen, damit du studieren kannst, kommst aber nicht dazu, weil du dir keinen root-Server leisten kannst, weil die SuMa nicht genug Geld abwirft … was sie nur dann kann, wenn sie auf einem root-Server liegt … was nicht geht, weil die SuMa kein Geld abwirft … und so weiter.

So, hab nun erstmal meinen gröbsten Frust abgeladen.
Mal schauen, wie es weitergeht…

MySQL Suchfeld für Firefox

Nachdem mir mein PHP-Suchfeld sehr gut Dienste leistet, habe ich nun noch ein weiteres Suchfeld für MySQL gebaut. Dort kann ich nun sehr bequem nach der Syntax für MySQL-Kommandos suchen.

Die Vorgehensweise ist die gleiche wie beim PHP-Suchfeld, anbei noch der Inhalt der Datei; viel Spaß damit 🙂

— mysql-suche.xml —————————————————————–

MySQL Suche
Suche nach MySQL-Funktionen mit Firefox
UTF-8
data:image/x-icon;base64,AAABAAEAEBAQAAAAAABoAwAAFgAAACgAAAAQAAAAIAAAAAEAGAAAAAAAAAMAABILAAASCwAAAAAAAAAAAAD////////////////////////////////////////////////////////////////////////////////////////////////////////////////////Vwpzeyqz///////////////////////////////////////////////////+0nVru1r3/////////////////////////////////+v//8v//////////////+v/eyqzNoWLmyqz///////////////////+9oWL24s3Vwpz////////////////////e0rTewov/+v/////////////////uzrTmyqykhTH////////////////25t60mVr23s3////////////////////////ewov/+vbmyqz///////////////+9oWL/+v/////////////////////////////Vwpz/////////////////////7u7NtoP////////////////////////////////24s3m2sX////////////////NsnP27ub////////////////////////////////Vsnv////////////////25t69qnP////////////////////////////////27ubmyqz/+v//////////+va0nVr////////////////////////////////////evpz/8v/u1r3////23s20mVr/+v/////////////////////////////////26t7Vwpz/8u7NuovFoWLNupT////////////////////////////////////////uzrTFqnPNqnP/9vb///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//



————————————————————————————–