Verständnisproblem mit Get und Set und lesendem Zugriff

MrSnoop

Neues Mitglied
Hallo Forum,

als ganz neues Mitglied habe ich gleich mal ein Problem, das aus einem massiven Verständnisproblem meinerseits zu resultieren scheint.
Folgende Situation: Ich habe eine hibernate-Klasse namens User und in dieser Klasse ein Attribut namens password.
Grundsätzlich funktioniert erstmal alles, ich kann über ein Objekt meiner Klasse Daten in der Datenbank speichern und auch wieder abrufen. Das Problem begann damit, dass ich nun mein password als md5 Hash in der Datenbank speichern wollte und mir gedacht habe, dass könnte man doch super in die Setter-Methode integrieren, nämlich so:

Java:
public class User {
	private String password;

	public String getpassword() { return password; }

	public void setpassword(String password) { 		
		StringBuffer stringBuffer = new StringBuffer(32);
		try {
			MessageDigest md5 = MessageDigest.getInstance("MD5");
			md5.update(password.getBytes());
			Formatter f = new Formatter(stringBuffer);
			for (byte b :md5.digest()) {
				f.format("%02x", b);
			}
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		
		password = stringBuffer.toString();
	}

}

Soweit so gut, das Kennwort wird beim anlegen eines neuen Users nun als MD5 Hasch in der Datenbank abgelegt, alles prächtig. Nun kam ich aber irgendwann an den Punkt, dass ich über den bekannten Benutzernamen die zugehörige ID aus der DB holen wollte. Das mache ich so:

Java:
		    Session session = SessionFactoryUtil.getInstance().getCurrentSession();
		    Transaction transaction = null;
		    transaction = session.beginTransaction();
				 
		    Query q = session.createQuery("from User u where u.login = :login");
		    q.setString("login", username); // den username habe ich an dieser Stelle aus der Session
			     
		    java.util.List User = q.list();
		    transaction.commit();
		    for (Iterator iter = User.iterator(); iter.hasNext();) {
		    	User element = (User) iter.next();
		    	res = element.getUSERID(); 
		    }

Auch das funktioniert prächtig. Nun habe ich aber gerade festgestellt, dass bei genau diesem Zugriff der md5 Hash des Kennworts aus der Datenbank gelesen wird, erneut durch die md5 Maschine läuft und dann irgendwann doppelt und dreifach gehasht in der DB steht.

Das ich das Problem relativ leicht lösen könnte, indem ich den Hash an einer anderen Stelle erzeuge, ist mir klar, mir geht es nun aber ums Verständnis! Was mir völlig unklar ist: Warum wird überhaupt irgendwas in die DB zurück geschrieben. An der Stelle möchte ich ja eigentlich nur lesend auf die Datenbank zugreifen! Und ein session.save(user) steht da ja nicht. ???:L
Wird denn jedes Mal, wenn ich auf diese Weise zugreife etwas in die DB zurück geschrieben oder liegt das nur daran, dass sich ja mein password quasi geändert hat? Aber selbst dann sollte das doch ein rein lesender Zugriff sein?

So, nun hoffe ich, dass ich mich verständlich ausgedrückt habe und dass Ihr Licht meine Umnachtung bringen könnt.
Ich wünsche Euch ein schönes Wochenende!
 
S

SlaterB

Gast
Hibernate macht das einfach so, Ende der Diskussion ;)
Stichwort Dirty Checking
Hibernate Tutorial | Automatic Dirty Checking

kann man bestimmt irgendwie konfigurieren/ abschalten, wobei du hier das Objekt per setter schon änderst bevor du selber nach der Query drankommst, das ist ziemlich eng,
dieses schreckliche set umzubauen ist wirklich dringend zu raten


----------

ansonsten ist für read-only am sichersten, gar nicht erst User-Objekte zu laden,
auch wenn das der Objektorientierung und dem Komfort nicht gerade entgegen kommt,

drei Möglichkeiten dazu:
mit
> select x from User u where u.login = :login
liest du eine List<String, List<Integer> oder was immer der Typ von x ist

mit
> select x, y from User u where u.login = :login
liest du eine List<Object[]>, hier sieht dann fast wie im simplen JDBC aus

nett ist
> select new package.UserRO(x, y) from User u where u.login = :login
wenn es eine entsprechende Klasse mit passendem Konstruktor gibt, UserRO ist fast wie User,
Änderungen in UserRO können nie versehentlich in die DB kommen, nur über expliziten Code
saveAsUser(userRO)

Nachteil wie gesagt der Verzicht auf die schon schön modellierte User-Klasse,
evtl. kann man da mit Vererbung etwas Verdopplung sparen, zwei Klassen wären aber nicht zu vermeiden
 

MrSnoop

Neues Mitglied
Guten Morgen!

Erstmal vielen Dank für die Antwort!

Hibernate macht das einfach so, Ende der Diskussion ;)
Stichwort Dirty Checking
Hibernate Tutorial | Automatic Dirty Checking

Und vielen Dank für den Link. Das klärt mein Verständnisproblem dann auch soweit. Mir war bisher nicht bewusst, dass

Java:
BallPlayer p = (BallPlayer)session.get(BallPlayer.class, 1L);
p.setNickname("Bambino");
transaction.commit();  //new nickname is synch’ed and committed here
session.close();

das Objekt auch synchronisiert. Ich hätte da noch ein session.update(p); eingefügt. Dazu noch die Frage, ob session.update(p); an dieser Stelle überhaupt irgendwas bewirken würde. Ich hab das in meinem Code an zahlreichen Stellen so drin; ist es ratsam die Zeile jeweils raus zu nehmen (performance?) oder ist das einfach egal?

kann man bestimmt irgendwie konfigurieren/ abschalten, wobei du hier das Objekt per setter schon änderst bevor du selber nach der Query drankommst, das ist ziemlich eng,
dieses schreckliche set umzubauen ist wirklich dringend zu raten

An dieser Stelle irgendwas abzuschalten oder umzukonfigurieren habe ich absolut nicht vor. Ich denke, das würde viele Stunden Forschungsarbeit bedeuten und die Vorteile wären dann auch fraglich. Ich hab die Hash-Funktion nun letztendlich ausgelagert und rufe diese explizit auf, wenn ich das Passwort speichern möchte. Das passiert ja ohnehin nur an ganz bestimmten Stellen und ist insofern auch sinnvoll. Ich hatte das nur so angelegt, weil ich es aus verschiedenen Delphi-Umgebungen gewohnt war, dass solche Funktionalitäten im Setter realisiert werden.

Soweit also vielen Dank und viel Freude beim Programmieren bei diesen schweißtreibenden Temperaturen! ;(

Viele Grüße!
 
S

SlaterB

Gast
> ist es ratsam die Zeile jeweils raus zu nehmen (performance?) oder ist das einfach egal?

an Performance würde ich da nicht denken, wenn dann an Code-Lesbarkeit,
falls der Befehl garantiert nix bringt, dann ruhig entfernen, letztlich aber doch überwiegend egal, meiner Meinung nach
 

Ähnliche Java Themen


Oben