{"id":10072,"date":"2011-12-16T20:11:51","date_gmt":"2011-12-16T19:11:51","guid":{"rendered":"http:\/\/cogito-ergo-blog.de\/blog\/?p=10072"},"modified":"2011-12-16T20:11:51","modified_gmt":"2011-12-16T19:11:51","slug":"cassandra-cql-mit-jdbc-driver","status":"publish","type":"post","link":"https:\/\/cogito-ergo-blog.de\/blog\/2011\/12\/16\/cassandra-cql-mit-jdbc-driver\/","title":{"rendered":"Cassandra CQL mit JDBC-Driver"},"content":{"rendered":"<p>Hatte endlich mal Gelegenheit mich mit einer NoSQL Datenbank zu besch\u00e4ftigen: Cassandra von Apache. Allerdings f\u00fchlte ich mich aus Anwender &#8211; in meinem Fall also Anwendungsprogrammierer &#8211; in die Steinzeit der Datenbankprogrammierung zur\u00fcckversetzt: es gibt nur\u00a0propriet\u00e4re\u00a0Schnittstellen und die sind auch nicht abgek\u00fcndigt (Thrift). Selbst Apache\u00a0empfiehlt\u00a0auf ein abstrakteres API wie zum Bespiel Hector zu setzen.<\/p>\n<p>Leider f\u00fchlt sich auch Hector in keiner Weise so an wie man es von konventioneller Datenbank-Programmierung gewohnt ist. Das Java-API ist nach meinem Geschmack &#8220;gew\u00f6hnungsbed\u00fcrftig&#8221; um es einmal diplomatisch auszudr\u00fccken.<\/p>\n<p>Dabei gibt mit Spring-JDBC (oder neuerdings mit Spring-Data) l\u00e4ngst gute Beispiele wie man es gut machen kann. Jetzt kann man nat\u00fcrlich einwenden, dass diese &#8220;alten&#8221; Ans\u00e4tze f\u00fcr SQL-Datenbanken gemacht sind und sich daher nicht f\u00fcr NoSQL L\u00f6sungen eignen, aber wenn man zweimal hinsieht, dann merkt man schnell, dass das gar nicht stimmt.<\/p>\n<p><!--more-->Der Unterschied bei der Sicht auf die Daten besteht meiner Meinung nach im Wesentlichen im Datenmodell, oder in der Art wie man zum Datenmodell kommt: entweder klassisch relational und normalisiert, oder Abfrage-Orientiert und\u00a0de-normalisiert.<\/p>\n<p>Wenn das Datenmodell aber steht, lie\u00dfe sich mit den Daten eigentlich genauso arbeiten wie mit SQL-Datenbanken: \u00fcber eine Abfrage-Sprache. Im Falle von Cassandra ist das CQL. Parallelen gibt es mit Keyspace = Database, ColumnFamily = Tabelle, und Column \/ Row genug. Die Einschr\u00e4nkungen \/ Erweiterungen con CQL sind eben der Datenbank geschuldet (z.B. kein Join) und st\u00f6ren erst mal nicht, wenn man sich f\u00fcr das NoSQL Modell entschieden hat.<\/p>\n<p>Jetzt gibt es mit Cassandra-JDBC sogar einen JDBC-Treiber f\u00fcr Cassandra, der auch CQL \u00fcber JDBC in jeder Java-Anwendung verf\u00fcgbar macht. Man sollte also meinen alles Handwerkzeug in H\u00e4nden zu halten, um &#8220;vern\u00fcnftig&#8221; arbeiten zu k\u00f6nnen.<\/p>\n<p>Leider ist dem im aktuellen Release 1.0.5 (Dez 2011) von Cassandra nicht so.<\/p>\n<p>Die Umsetzung ist etwas l\u00fcckenhaft, so dass praktisch bei jeder anderen Anwendung (au\u00dfer &#8220;Hello World&#8221;) Probleme auftreten.<\/p>\n<p><strong>Spalten sind nicht l\u00f6schbar<\/strong><\/p>\n<p>Will man eine Spalte l\u00f6schen, dann wird man im normalen SQL ein UPDATE &#8230; Feldname = NULL verwenden, was aber beide Spaltenorientierten Cassandra mit CQL nicht funktioniert. Dort muss stattdessen die Spalte selbst gel\u00f6scht werden mit DELETE Column(s) FROM ColumnFamily WHERE &#8230;<\/p>\n<p>Unn\u00f6tig umst\u00e4ndlich wie ich finde. Man ist gezwungen UPDATES auf Rows in ein UPDATE und ein DELETE Statement aufzuspalten, wenn man einen Teil der Spalten l\u00f6schen will. Gerade weil Cassandra aber kein festes Schema mit beliebig vielen Spalten, die auch nicht notwendigerweise gef\u00fcllt sein m\u00fcssen, unterst\u00fctzt, ist dies doppelt \u00e4rgerlich.<\/p>\n<p><strong>Selects auf NULL-Spalten funktionieren nicht<\/strong><\/p>\n<p>Wie schon erw\u00e4hnt wird man in einer Cassandra Persistenz sicher h\u00e4ufig auf Rows treffen, bei der nicht alle Spalten mit Werten belegt sind. Statt bei einer CQL Anfrage dann aber NULL, oder zumindest in der JDBC Darstellung NULL bzw. den passenden Default zu liefern, stolpert man \u00fcber eine Exception. Man kann gar keine Spalten abfragen, die nicht gesetzt sind.<\/p>\n<p><strong>Unzureichende Expression-Language<\/strong><\/p>\n<p>Cassandra kennt zwar bestimmte Typen Spalten. Allerdings liefert CQL kaum ausreichen Ausdrucksm\u00f6glichkeiten mit diesen Typen umzugehen. Man kann nicht einmal einen Timestamp erzeugen, ausser den nackten Long-Wert direkt einzugeben, um nur ein Beispiel zu geben. Dies erschwert die Formulierung von Abfragen wiederum unn\u00f6tig. Man h\u00e4tte leicht bestehende Implementierungen von ELs adaptieren k\u00f6nnen, um halbwegs verwendbare Ausdr\u00fccke in CQL einsetzen zu k\u00f6nnen.<\/p>\n<p><strong>PreparedStatements funktionieren nicht<\/strong><\/p>\n<p>In JDBC ist es eigentlich der Normalfall PreparedStatements zu nutzen. Nicht nur weil man dem Server Gelegenheit gibt, die Anfragen zu optimieren, auch Injection wird damit wirkungsvoll verhindert. Leider unterst\u00fctzt Cassandra 1.0.5 solche Anfragen bislang nicht. Der JDBC-Treiber bietet sie dennoch an.<\/p>\n<p>Wie man in der Beschreibung und im Quellcode nachlesen kann, werden die Bindings jedoch schon auf der Clientseite aufgel\u00f6st und dann zum Server geschickt. Damit k\u00f6nnte man leben, wenn das wenigstens funktionieren w\u00fcrde. Leider ist auch hier die Implementierung fehlerhaft, sodass oft genug die Bindung schlicht falsch ist und der Server die Anfrage mit einem Fehler quittiert.<\/p>\n<p><strong>Fazit<\/strong><\/p>\n<p>Will man Cassandra einsetzen, hat man sich so an das eine oder andere zu gew\u00f6hnen (oder wieder zu gew\u00f6hnen). Und damit meine ich nicht in erster Linie die Art der Datenmodellierung. Ich jedenfalls f\u00fchlte mich in mancher Hinsicht um eine paar Jahre in die Vergangenheit zur\u00fcck versetzt, als man mit Oracle noch per Oracle Call Interface (OCI) sprechen musste. Aber wenns denn Cassandra sein muss &#8230;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hatte endlich mal Gelegenheit mich mit einer NoSQL Datenbank zu besch\u00e4ftigen: Cassandra von Apache. Allerdings f\u00fchlte ich mich aus Anwender &#8211; in meinem Fall also Anwendungsprogrammierer &#8211; in die Steinzeit der Datenbankprogrammierung zur\u00fcckversetzt: es gibt nur\u00a0propriet\u00e4re\u00a0Schnittstellen und die sind auch &hellip; <a href=\"https:\/\/cogito-ergo-blog.de\/blog\/2011\/12\/16\/cassandra-cql-mit-jdbc-driver\/\">Weiterlesen <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[],"_links":{"self":[{"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/posts\/10072"}],"collection":[{"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/comments?post=10072"}],"version-history":[{"count":3,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/posts\/10072\/revisions"}],"predecessor-version":[{"id":10079,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/posts\/10072\/revisions\/10079"}],"wp:attachment":[{"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/media?parent=10072"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/categories?post=10072"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/tags?post=10072"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}