Verständnisproblem mit Client/Server-Anwendung

Status
Nicht offen für weitere Antworten.

Alex_winf01

Top Contributor
Ich habe da ein kleines Verständnisproblem mit einer Client/Server-Anwendung:

Ich habe da eine kleine Applikation geschrieben, die eine Verbindung zur Datenbank H2 aufbaut. Derzeit liegt die Datenbank auf meinem localhost. Die auf einen Server zu installieren und dann der Anwendung zu sagen, wo die Datenbank liegt, ist kein Problem. Mein Problem ist nur folgendes:

Ich habe ja zwei Varianten, die Applikation zu installieren.

1. Ich installiere das Programm auf dem Client und über die Anwendung wird eine Verbindung zur Datenbank aufgebaut. Hier ist aber das Problem, dass ich nur eine Connection zur H2-Datenbank haben darf, ich aber mehrere Anwender gleichzeitig mit dem Programm auf ihrer lokalen Maschine auf die DB zugreifen.
2. Ich installiere auch das Programm auf dem Server und stelle es den Anwendern zur Verfügung.

Wie kann ich bei Punkt 1 sicherstellen, dass nur eine Connection zur Datenbank aufgebaut wird? Ich habe bei der H2-Datenbank die Möglichkeit, einen Server zu starten (siehe anderer Thread).

Wie kann ich Punkt 2 umsetzen? Ich weiss nicht, wie das dann mit RMI aussehen muss. Zur Info: Die Standardbeispiele mit einem Client und einem Server, die Strings austauschen oder die Chats habe ich schon gesehen. Nur wie muss das mit einer Datenbankanwendung aussehen? Ich habe nämlich mal gelesen, dass JDBC ein Problem mit RMI hat.

Noch mal zur Verdeutlichung meines Problems: Ich habe mehrere Anwender, die mit einer Software (die entweder lokal oder auf dem Server installiert ist???) sich mit einer Datenbank in Verbindung setzen.
 

HoaX

Top Contributor
Alex_winf01 hat gesagt.:
1. Ich installiere das Programm auf dem Client und über die Anwendung wird eine Verbindung zur Datenbank aufgebaut. Hier ist aber das Problem, dass ich nur eine Connection zur H2-Datenbank haben darf, ich aber mehrere Anwender gleichzeitig mit dem Programm auf ihrer lokalen Maschine auf die DB zugreifen.
wieso willst du nur eine verbindung zulassen? wenn du einen dbserver startest können damit gleichzeitig soviele kommunizieren wie wollen
 

Alex_winf01

Top Contributor
Also, mein Verständnisproblem:

Ich habe eine Klasse Login, in der ich die Connection regel.

Code:
/**********************************************************************

**********************************************************************/

//-------------------------------------------------------------------------------------

/** Die Login-Klasse ist dafür zuständig, den Anwender an der Datenbank anzumelden*/

//-------------------------------------------------------------------------------------


import java.awt.*;
import javax.swing.*;
import java.sql.*;
 

/** Die Klasse Login stellt die Verbindung zur Datenbank her.*/
public class Login
{
	// Variablendeklaration für die gesamte Klasse
	public static Connection connection;
  	public static String lese, lese_dokumentation, lese_icd1, lese_icd2, lese_icd3;
  	public static Statement stmt, stmt1, stmt2, stmt3, stmt4, stmt5;
  	public static ResultSet result, result_dokumentation, result_icd1, result_icd2, result_icd3, result_kh;
        	
              
   	/******************************************************************

	Anmeldedialog mit Benutzernamen, Passort und DB-Namen

	******************************************************************/
	
	private static void login()
	{
		String[] s_options = {"Anmelden", "Abbrechen"};
		
		JPanel pnl_main = new JPanel();
		pnl_main.setLayout(new GridLayout(3,3,10,10));

                JLabel lbl_username = new JLabel("Benutzername: ", JLabel.RIGHT);
		JTextField txt_username = new JTextField();

		JLabel lbl_password = new JLabel("Passwort: ", JLabel.RIGHT);
		JPasswordField txt_password = new JPasswordField();


		pnl_main.add(lbl_username,0);
		pnl_main.add(txt_username,1);

		pnl_main.add(lbl_password,2);
		pnl_main.add(txt_password,3);

                
		if(JOptionPane.showOptionDialog(null, pnl_main,
				"DB-Anmeldung",
				JOptionPane.OK_CANCEL_OPTION,
				JOptionPane.INFORMATION_MESSAGE,
				null, s_options,
				s_options[0]) != 0)
				{
    				System.exit(0);
				}
	}


	/******************************************************************
	main-Methode

	******************************************************************/
	public static void main(String[] args)
	{
		

        // Aufruf des Dialogs zur Identifikation
            
        login();
        try
        {
        	Class.forName("org.h2.Driver");
    		connection = DriverManager.getConnection("jdbc:h2:tcp:localhost/test", "sa", "");
    		
			
		}
	    catch(Exception e)
	    {
	    	JOptionPane.showMessageDialog(null, "Es ist folgender Fehler aufgetreten: " + e,
				"DB-Meldung", JOptionPane.ERROR_MESSAGE);
	    }
        
        StartFrame frm = new StartFrame("Mein Programm");
		frm.setVisible(true);
		frm.setSize(400,400);
		frm.pack();
	}
}

Da alle Clients diese Login haben und sich darüber anmelden und dann auf DIESELBE Datenbank und DIESELBEN Tabellen zugreifen, dachte ich, ich darf nur eine Connections haben. Was ich noch hab, ist eine .bat, in der ich den Server von H2 starte.

@ HoaX: Wenn ich Dich richtig verstehe, muss ich diese .bat einmal ausführen und dem Server ist es dann wurscht, ob da 2 Connections sind oder 5 oder 15?
 
T

tuxedo

Gast
Mehrere, kongruente Zugriffe auf ein und denselben Datensatz können zu einem inkonsitenten System führen. Ich wäre da vorsichtig. Nicht dass sich die Anwender gegenseitig ihre Änderungen überschreiben und am Ende gar nix mehr stimmt.


Mit RMI wird die Sache "besser" (aber nicht einfacher ;-) ):

Du bastelst dir einen Server. Dieser Server hat als einzigster Zugriff auf die DB. Clients verbinden sich mit dem Server. Will ein CLient einen Datensatz in der DB ändern, so muss er dafür eine Methode im Server aufrufen. Der Server merkt sich diesen Editiervorgang und blockt gleichzeitige Editieranfragen von anderen Nutzern.

Sind Server und Client bei dir dann im gleichen Netzwerk? Oder sind da Router/Firewalls dazwischen?

- Alex
 

Alex_winf01

Top Contributor
Ich programmiere das für verschiedene Kunden. Alle haben zumindestens eine Firewall. Einige setzen auch eine sog. Terminalserver ein.

Aber im Grundprinzip sollen Client und Server im gleichen Netzwerk liegen - bis auf die, die einen Terminalserver einsetzen.

Was mein Verständnisproblem ist: H2 kann ich bereits im Server-Modus laufen lassen. Wie muss ich diesen Server ansprechen?

Dass ich DB-mässig mich natürlich drum kümmern muss, dass weiss ich.

Aber ich glaub ich weiss, wass du meinst. Ich habe mal den Chat aus den FAQ genommen:

Der Server:

Code:
import java.net.*;
import java.io.*;
import java.util.*;

public class Server {

   private Hashtable clients;
   private int port;   
   
   public Server(int port) {
      this.port=port;
      clients = new Hashtable();
   }
   
   private void startServerListener() {
      ServerSocket ss ;
      try {
         ss = new ServerSocket(port);
         System.out.println("Server gestartet...");
         while (true)         
            new ServerBody(ss.accept(), this).start();   
      } catch (Exception e) {
         e.printStackTrace();
      }
   
   }   
   
   public void addClient(String name, ServerBody body) {
      clients.put(name, body);
   }
   
   public void removeClient(String name) {
      clients.remove(name);
   }
   
   public String getUsers() {
      String users;
      users="users|";
      for (Enumeration e = clients.keys();e.hasMoreElements();)
         users+=(String) e.nextElement() + "|";
      if (! users.equals("users|"))
         users = users.substring(0, users.length() - 1);
      return users;     
   }
   
   public void broadcast(String name, String msg) throws Exception {
      for (Enumeration e = clients.keys();e.hasMoreElements();)         
         ((ServerBody) clients.get((String) e.nextElement())).send(name + ": " + msg);     
   }
   
   public void send(String name, String targetname, String msg) throws Exception {
      ((ServerBody) clients.get(targetname)).send(name + ": " + msg);     
   }
   
   public boolean isClient(String name) {
      return clients.containsKey(name);
   }
   
   public static void main(String[] x) {   
      if (x.length != 1) {
         System.out.println("#java Server <port>");
         System.exit(0);
      }
      new Server(Integer.parseInt(x[0])).startServerListener();
   }
}


class ServerBody extends Thread {

   private Socket cs;
   private Server server;
   private PrintWriter out;

   public ServerBody(Socket cs, Server server) {
      this.cs=cs;
      this.server=server;
   }

   public void run() {
      BufferedReader in;
      StringTokenizer str;
      String name, msg, targetname;
      int n;
      try {
               
         in = new BufferedReader (new InputStreamReader(cs.getInputStream()));
         out = new PrintWriter(new DataOutputStream(cs.getOutputStream()));         
         name = in.readLine();         
         server.addClient(name, this);         
         server.broadcast(name, server.getUsers());
         System.out.println("+ Client " + name + " hat sich angemeldet!");         
         for (String buffer;(buffer = in.readLine()) != null;) {
            n = buffer.indexOf("|", 0);
            targetname = buffer.substring(0, n);
            msg = buffer.substring(n + 1, buffer.length());
            if (targetname.equals("all")) {
               server.broadcast(name, msg);
               System.out.println(">Client " + name + " schreibt an alle: " + msg);
            } else if (server.isClient(targetname)) {
               server.send(name, targetname, msg);
               System.out.println(">Client " + name + " schreibt an " + targetname + ": " + msg);
            } else
               this.send("Server: Client " + targetname + " existiert nicht!");
         }
         server.removeClient(name);
         System.out.println("- Client " + name + " hat sich abgemeldet!");
         in.close();
         out.close();               
      } catch (Exception e) {
         e.printStackTrace();
      }
   
   }

   public void send(String msg) throws Exception {
      out.println(msg);
      out.flush();
   }
}

Der Client:

Code:
import java.net.*;
import java.io.*;
import java.util.*;

public class Client {

   private String ip;
   private int port;

   public Client(String ip, int port) {
      this.ip=ip;
      this.port=port;
   }

   private void startClient() throws Exception {
      Socket s;
      String buffer, name, targetname, msg;
      PrintWriter out;
      BufferedReader in;
      int n;
      s = new Socket(ip, port);
      buffer = null;
      out = new PrintWriter(new DataOutputStream(s.getOutputStream()));     
      in = new BufferedReader(new InputStreamReader(System.in));           
      System.out.println("\n\nClient gestartet...\n\n");     
      name = null;     
      while (name == null || name.equals("")) {
         System.out.print("Client-Name eingeben: ");
         name = in.readLine();
         name = name.trim();
      }
      out.println(name);
      out.flush();
      new ClientBody(s.getInputStream()).start();           
      System.out.print("\nText eingeben -> <zielrechner> <message># ");     
      while (! (buffer = in.readLine().trim()).equals("stop")) {         
         if ((n = buffer.indexOf(" ", 0)) < 0) {
            System.out.print("\nUngueltige Eingabe! Text eingeben -> <zielrechner> <message># ");
            continue;
         }
         System.out.print("\nText eingeben -> <zielrechner> <message># ");         
         targetname = buffer.substring(0, n);
         msg = buffer.substring(n + 1, buffer.length());   
         out.println(targetname + "|" + msg);
         out.flush();   
      }
      System.out.println("\n\nClient gestoppt...\n\n");
      in.close();
      out.close();
   }

   public static void main(String[] x) throws Exception {
      if (x.length != 2) {
         System.out.println("#java Client <server-ip> <port>");
         System.exit(0);
      }     
      new Client(x[0], Integer.parseInt(x[1])).startClient();   
   }
}


class ClientBody extends Thread {
   private InputStream i;
   public ClientBody(InputStream i) {
      this.i=i;
   }

   public void run() {
      String buffer;
      BufferedReader in;
      int n;
      try {
         in = new BufferedReader(new InputStreamReader(i));
         while ((buffer = in.readLine()) != null) {           
            if ((n = buffer.indexOf("users|", 0)) > -1) {
               buffer = buffer.substring(n + "users|".length(), buffer.length());
               buffer = buffer.replace('|', ',');
               System.out.println("\n\n==>Angemeldete User: " + buffer);           
            } else
               System.out.println("\n\n==>Eingang von " + buffer);
            System.out.print("\nText eingeben -> <zielrechner> <message># ");     
         }
         
      } catch (Exception e) {}   
   }
}

Müsste hier dann auch die Connection über den Server laufen? Also folgender Part

Code:
try
        {
           Class.forName("org.h2.Driver");
          connection = DriverManager.getConnection("jdbc:h2:tcp:localhost/test", "sa", "");
          
         
      }

Dann der ganze Login und dann die verschiedenen Klassen für Einfügen.java, Loeschen.java und Update.java müssten dann über den Client laufen?

Also in der Klasse
Code:
public class Client
muss ich also z. B. die einzelnen Methoden zum Einfügen in der Klasse Einfügen.java aufrufen?
 

robertpic71

Bekanntes Mitglied
Alex_winf01 hat gesagt.:
Alle haben zumindestens eine Firewall.
Man müsste die Frage genauer Stellen: Hast du eine Firewall zwischen Client und Server?

Alex_winf01 hat gesagt.:
Aber im Grundprinzip sollen Client und Server im gleichen Netzwerk liegen - bis auf die, die einen Terminalserver einsetzen.
Wo die Clients bei einem Terminalserver (RDP, Citrix, X11) sind (innerhalb oder außerhalb der Firewall, VPN..) ist für dein Programm egal. Die Programme laufen direkt am Server, der Client erhält nur GUI Daten und liefert Maus- und Tastatureingaben zurück.

Um ein, am Terminalserver lauffähige Programme zu schreiben, muss man ein paar Sachen berücksichtigen. Die Programme laufen ja am gleichen System - nur an unterschiedlichen Desktop's. Da sind Resourcenkollisionen vorprogrammiert.

Alex_winf01 hat gesagt.:
Was mein Verständnisproblem ist: H2 kann ich bereits im Server-Modus laufen lassen. Wie muss ich diesen Server ansprechen?
Wie gehabt:

Code:
getConnection("jdbc:h2:tcp:localhost/test", "sa", "");

Wobei localhost durch die IP-Adresse des Servers zu ersetzen ist.

Zuerst solltest du dir einmal klar werden, ob du RMI-Funktionen oder einer Serverdatenbank arbeitest. Wenn du mit RMI arbeitest braucht die Datenbank nicht im Serverbetrieb zu arbeiten. Zu den konkurrierenden Zugriffen: Das ist tägliches Brot für die Datenbank und keine Grund nicht mit Datenbanken zu arbeiten. Auch beim Terminalserver hat man keine Vorteile RMI statt Datenbank: in beiden Fällen darf es nur einen Serverjob am System geben.

Im Falle einer Serveranwendung ist eine eigene Instanz (JVM) für die Datenbank zu empfehlen. Für Standaloneanwendungen würde ich mit "jdbc:h2:~/test" arbeiten. Wobei das "~" für das Arbeitsverzeichnis des Users steht, also bei Windows "Dokumente und Einstellungen\user\". Damit könnten auch auf einem Terminalserver mehrere Standalone-DB's laufen (1x je Benutzer).

/Robert
 

Alex_winf01

Top Contributor
@ robertpic71

vielen Dank schon mal für Deine Antwort. Ich wollte gerne die Datenbank im Server-Modus von H2 laufen lassen. Und da ist mir einfach noch nicht klar, wenn ich jetzt verschiedene Anwender habe und jeder über die Login.java eine Connections zur Datenbank aufbaut, ob das ein Problem darstellt und wie ich dann den Server von H2 ansteuern muss?

Wie sieht das denn aus, mit den Terminalservern? Wie muss ich das Problem lösen? Was ist da zu beachten?

Ach ja noch was: es ist natürlich nicht gewünscht, dass jeder Anwender eine eigene lokale DB hat. Es soll EINE DB sein mit mehreren Clients.
 
T

tuxedo

Gast
Nicht böse sein, aber mir scheint du hast im Moment keine richtigen Schimmer von der Sache?

Aaaalso. Setze den H2 DB-Server auf wie jeden anderen DB-Server auch. Sprich: Er muss für Clients im Netzwerk erreichbar sein. Dann kannst du mit deinen Clients im Netzwerk, welche jeweils JDBC benutzen, auf den DB-Server zugreifen. Dafür brauchst du die IP-Adresse/Hostnamem des Servers. Statt "127.0.0.1" wie bei einer lokalen Verbindung, benutzt du einfach die IP des Servers. Das war's schon.

So, und jetzt zu der Frage:

>> Und da ist mir einfach noch nicht klar, wenn ich jetzt verschiedene Anwender habe und jeder über die Login.java eine Connections zur Datenbank aufbaut, ob das ein Problem darstellt und wie ich dann den Server von H2 ansteuern muss?

Das WIE hab ich ja gerade erklärt.

Probleme gibts dann, wenn zwei oder mehr Clients auf ein und denselben Datensatz zugreifen. Nehmen wir mal an du hast eine Kundendatenbank mit dem Datensatz "Max Mustermann", und du hast 2 Clients.

So, Client 1 öffnet jetzt den Max Mustermann eintrag und ändert die Hausnummer von Musterstraße 1 auf Musterstraße 2. Er klickt aber noch nicht speichern, weil er sich schnell nen Kaffee holen geht oder Papier im Drucker nachfüllen muss um die Max Mustermann Kundenkarte auszudrucken.

So, jetzt kommt Client 2. Der sitzt am anderen Ende des Flur's in seinem Büro und hat keinen blassen schimmer was Client 1 gerade treibt. Er hat jedoch eine neue Emailadresse von Max Mustermann die er im System eintragen will. Also öffnet er den Eintrag von Max Mustermann, ändert die Emailadresse und klickt speicher.

Jetzt kommt Client 1 wieder zurück und will seine Änderung auch speichern. Was passiert jetzt? Genau: Client 1 überschreibt mit seinem Speicher-Vorgang die Emailadressenänderung die Client 2 gemacht hat...

DAS ist das Problem das ich weiter oben schon angesprochen hab.
Du solltest also, je nachdem was dein Programm im Detail macht, darauf achten, dass nicht 2 oder mehr Clients ein und denselben Datensatz gleichzeitig "zum schreiben" öffnen. Du solltest sicherstellen, dass wenn ein Client den Datendatz geöffnet hat, andere Clients den Datensatz nur "schreibgeschützt" öffnen können.

Das erreichst du, indem du vor die DB eine Serveranwendung platzierst und die Clients nur durch die Serveranwendung mit der DB kommunizieren (dann sollten die CLients mit dem Server z.B. über RMI sprechen und gar keine JDBC Verbindung zur DB selbst aufbauen). Die Serveranwendung ist dann diejenige die eine Verbindung zur DB unterhält.

ODER du du erweiterst deine Tabellen so, dass es überall eine Spalte "writeprotect" gibt welche auf "true"/"false" gesetzt werden kann. Öffnet ein Client nun einen Datensatz, muss er diese neue Spalte auf "true" setzen. Andere Cliients müssen dann vor dem öffnen darauf achten, wie der Wert dieser neuen Spalte ist, und ggf. den Eintrag nur "read-only" öffnen, d.h. keine speicher/update Funktion benutzen.

Sind jetzt alle klarheiten beseitigt ;-) ???

- Alex
 

Alex_winf01

Top Contributor
@ alex0801

Warum sollte ich Böse sein? Ich hab gelernt: Man kann noch so unwissend sein, man muss sich nur zu helfen wissen und sich das fehlende Wissen aneignen können. Und wenn es über fragen geht.

Danke schon mal auf jeden Fall für Deine Ausführung. Das hat mir auf jeden Fall geholfen.

Ich habe dann nur noch eine Frage: Was muss ich denn beachten, wenn das Programm auf einem Terminalserver läuft?
 
T

tuxedo

Gast
Was willst du denn mit dem Terminalserver bezwecken?

Sofern da immer noch mehrere Personen den Client gleichzeitig benutzen können, hast du nichts in Sachen Datenkonsistenz gewonnen.

Ob der Client auf einem Terminalserver läuft, oder ob er lokal installiert ist spielt dabei eigentlich keine Rolle, solange die Clients nicht alle versuchen ein und dieselbe lokale Ressource zu verwenden (bspw. öffnen eines lokalen Serverports für irgendein Callback oder so...).

Würde die Terminalserver-Sache weglassen.

a) bringt es dich nicht weiter
b) wird es dadurch nicht einfacher
c) hast du damit nicht wirklich weniger Probleme bei der Entwicklung

Ich würde mich an deiner Stelle ein wenig mit RMI befassen und den einzelnen CLients einen Server vorschalten, der als einziger eine direkte Verbindung zur DB hat. Damit hast du dann keine Probleme mit gleichzeitigen Zugriffen auf die DB (das kann ja der Server managen).

- Alex
 

ms

Top Contributor
alex0801 hat gesagt.:
Nicht böse sein, aber mir scheint du hast im Moment keine richtigen Schimmer von der Sache?
...

Das erreichst du, indem du vor die DB eine Serveranwendung platzierst und die Clients nur durch die Serveranwendung mit der DB kommunizieren (dann sollten die CLients mit dem Server z.B. über RMI sprechen und gar keine JDBC Verbindung zur DB selbst aufbauen). Die Serveranwendung ist dann diejenige die eine Verbindung zur DB unterhält.

ODER du du erweiterst deine Tabellen so, dass es überall eine Spalte "writeprotect" gibt welche auf "true"/"false" gesetzt werden kann. Öffnet ein Client nun einen Datensatz, muss er diese neue Spalte auf "true" setzen. Andere Cliients müssen dann vor dem öffnen darauf achten, wie der Wert dieser neuen Spalte ist, und ggf. den Eintrag nur "read-only" öffnen, d.h. keine speicher/update Funktion benutzen.
Es gibt sowas, dass nennt sich Transaktion.
Wurde das schon erwähnt?

ms
 
T

tuxedo

Gast
Ne, wurde noch nicht erwähnt. Hab ich auch noch nicht mit gearbeitet. Kannst du kurz 2..3 Sätze dazu schreiben (is vielleicht besser als wikipedia ...)? Würd mich auch interessieren.
 

Alex_winf01

Top Contributor
@ alex0801

Jetzt sei Du bitte nicht böse. Viele unserer Kunden arbeiten mit Terminalservern. Daher muss ich Rücksicht nehmen (wohl oder übel).

Zum Thema Transaktionen: Bei einer Transaktion werden mehrere Befehle so gebündelt, dass diese eine logische Einheit ergeben und zusammen ausgeführt wird. Entweder wird die ganze Transaktion erfolgreich durchgeführt oder es wird wieder der Ursprungszustand hergestellt.

Hier ist der Link zu Wikipedia:

de.wikipedia.org/wiki/Transaktion_%28Informatik%29

Könntest Du mir mit den Terminalservern helfen? Worauf muss ich achten?
 
T

tuxedo

Gast
Naja, hättest ja gleich sagen können dass es mit Terminalservern laufen MUSS, da Kundenvorgabe ... ;-)

Das hab ich zu Transaktionen auch gelesen. Ganz doof bin ich nicht ;-) Aber ich seh da noch keinen Zusammenhang zum DB Zugriff, vor allem nicht wenn mehrere Clients gleichzeitig dran arbeiten und die gefahr besteht dass der eine die Änderung des anderen überschreibt. . Vielleicht kann ms ja noch ein paar Worte dazu sagen.

Wie bereits schon 3 mal hier erwähnt wurde:

Ob das Client-Programm jetzt auf dem eigenen Rechner läuft, oder auf einem entfernten, der via Remote-Session ferngesteuert wird, ist prinzipiell wurscht. Du darfst nur nicht so Sachen machen wie "x mal ein und denselben lokale Serverport öffnen" oder "x mal parallel in ein und dieselbe Datei schreiben".

Also, erst lesen, dann denken, dann fragen ;-)
 

ms

Top Contributor
Der Vollständigkeit halber:
http://de.wikipedia.org/wiki/Transaktion_(Informatik)
http://www.h2database.com/h2.pdf

Ich sehe eigentlich auch kein spezielles Problem bei Terminalserver.
Aus Datenbanksicht ist es doch das selbe wie mehrere Rich Clients, oder?

ms
 
T

tuxedo

Gast
Entweder steh ich auf dem Schlauch oder ich seh das "Problem" aus einer ganz anderen Sicht:

Wenn ich eine Zeile aus einer Tabelle hole und diese "updaten" möchte, dann hole ich mir in der Regel erst die Zeile (SELECT xyz FROM abc WHERE def) um die Daten in der GUI anzuzeigen, dann ändert der User die Daten entsprechend und drückt auf speichern (UPDATE blablabla).

Wie soll ich jetzt mit Transaktionen verhindern, dass 2 Clients den gleichen Datensatz lesen und der eine speichern drückt, wobei der andere seine änderungen noch nicht eingecheckt hat? Kann mir das jemand erklären?

Table Locking ist mir bekannt. Aber ich will ja vielleicht nicht gleich die ganze Tabelle sperren ?!

- Alex
 

ms

Top Contributor
alex0801 hat gesagt.:
Wie soll ich jetzt mit Transaktionen verhindern, dass 2 Clients den gleichen Datensatz lesen und der eine speichern drückt, wobei der andere seine änderungen noch nicht eingecheckt hat?
Verhindern kannst du das nicht, aber zumindest sicherstellen, dass die Datenbank konsistent bleibt.
Das was du beschreibst fällt unter "pesimistic locking" - den Datensatz solange sperren, bis er geschrieben wurde. Das kann bei vielen gleichzeitigen Benutzern zu Problemen und einer schlechten Performance führen.
Optimistic Locking hingegen wäre, wenn du den Datensatz ohne Transaktion anzeigst und erst wenn der User auf Speichern klickt eine Transaktion gestartet wird. In dieser Transaktion wird das Update-Statement mit einer Where-Bedingung auf die alten Daten ausgeführt. Es wird also sichergestellt, dass wirklich nur der Datensatz mit den zuvor angezeigten Daten aktualisiert wird. Wenn diese aber in der Zwischenzeit von jemand anderem überschrieben wurden, dann liefert das Statement 0 zurück => es wurde kein Datensatz aktualisiert.
Dass Programm entscheidet dann was weiter passiert. Zb dem User anzeigen, dass der Datensatz mittlerweile von einem anderen User geändert wurde.

In Hibernate zB. gibt es dafür eine eigene Versions-Spalte, die man jeder Tabelle hinzufügen soll die bei jedem Update hochgezählt wird.
Tritt oben geschildeter Fall auf wird eine StaleObjectException geworfen.

ms
 
T

tuxedo

Gast
Ah, danke. Wieder was dazu gelernt. Ist ja recht easy zu bewerkstelligen. Muss man ja einfach im worst-case alle Spalte als Where-Bedingung stellen. Ist einfach und DB-unabhängig.

Der Transaktion (Informatik) Artikel bei Wikipedia beschreibt irgendwie was anderes. Passender fand ich Isolation (Datenbank) (Das hier ist auch gut)

Aber auch hier wird das einfache Verfahren mit der Where-Bedingung nicht aufgeführt. Okay, ist vielleicht auch nur für einfache Strukturen möglich, z.B. wenn ein Datensatz nur aus einer Zeile einer Tabelle besteht.

Einen einzelnen Datzsatz von der Serversoftware als "locked" zu markieren find ich jedoch noch performanter als gleich die ganze Tabelle zu "lock"en.

Gibts vielleicht irgendwas DMBS-seitiges (jetzt mal egal für welches DBMS, eben mal allgemein gefragt) für die Isolation bzw. das "lock"en eines einzelnen Datensatzes (nicht die ganze Tabelle)?

- Alex
 
T

Thomas Müller

Gast
Leider unterstützt H2 bisher kein Row Level Locking. Jedoch MVCC (Multi-Version Concurrency Control, allerdings im Moment Beta).

Für den angegebenen Fall würde ich allerdings auch kein Row Level Locking verwenden. Besser ist es wahrscheinlich, bei einer Spalte einen 'Update Counter' zu verwenden (z.B. einen Zähler, oder eine Sequenz). Ein Update könnte dann so aussehen:

update ... set ... where ... and modcount=40

Wenn jemand anderes den Datensatz verändert hat, ist der modcount geändert worden, und die Applikation merkts (weil updateCount 0 ist). Bin jetzt nicht sicher ob man das 'Optimistic Locking' nennt...
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
Thallius Verständnisproblem TLS Netzwerkprogrammierung 12
X Verständnisproblem bei AIO Netzwerkprogrammierung 7
S Verständnisproblem concurrent - iterativer Webserver Netzwerkprogrammierung 2
M Verständnisproblem Netzwerkprogrammierung 3
S Socket - Verständnisproblem Netzwerkprogrammierung 8
I Performanteste Kommunikationsmethode zwischen Client u. Server Netzwerkprogrammierung 4
L Socket Automatische Zuweisung von Server und Client Rolle Netzwerkprogrammierung 12
ExceptionOfExpectation Server/Client-Kommunikation Netzwerkprogrammierung 34
M Server-Client-System für Browsergame Netzwerkprogrammierung 5
B Axis2 Webservice mit Client Zertifikat Authentifizierung Netzwerkprogrammierung 3
Yonnig Threads mit Client/Server und GUI (laufend bis button-click) Netzwerkprogrammierung 9
T Jetty mit Client-Zertifikat nur bei spezifischer URL Netzwerkprogrammierung 1
J Einlesen von Servernachrichten von TCP-Client Netzwerkprogrammierung 17
J Client-Server und SOAP Netzwerkprogrammierung 23
L30nS RMI Aufruf einer Client-Methode von einem RMI-Server Netzwerkprogrammierung 3
T String von Client zu Server kommt nicht an Netzwerkprogrammierung 92
D WebSocket Server mit HTML Client und Java Server Netzwerkprogrammierung 5
D Server - Client Informationsaustausch, Möglichkeiten Netzwerkprogrammierung 3
H Socket Chat entwickeln mit Java Server Client Netzwerkprogrammierung 4
X Kann ich einen Client/Server verbindung hinkriegen die mir alle paar Sekunden die aktuellen Daten per Realtime zuschickt ? Netzwerkprogrammierung 9
T Client zu Client Kommunikation Netzwerkprogrammierung 2
D Slf4j - Logging - Client-Server Architektur Netzwerkprogrammierung 3
J client server mit nur einem PC Netzwerkprogrammierung 33
M Socket Nachricht von TCP-Client an Server schicken Netzwerkprogrammierung 12
M Socket Verbindung Matlab(Server) Java(Client) Netzwerkprogrammierung 1
R Socket FATAL EXCEPTION MAIN bei Socket based client/server app Netzwerkprogrammierung 2
G Server-Client IO Problem Netzwerkprogrammierung 6
ruutaiokwu ständig "sender address rejected: improper use of smtp" bei smtp-client Netzwerkprogrammierung 4
J HTTP [Java 9] Neuer HTTP Client - Tutorial Netzwerkprogrammierung 3
A Chatserver/-client - Code stoppt bei readUTF() Netzwerkprogrammierung 7
I Socket Das erste Server-Client Programm Netzwerkprogrammierung 16
L Zugriffprobleme Client - Webservice AspenTechnology Netzwerkprogrammierung 0
A Client Client Übertragung Netzwerkprogrammierung 12
M Socket Server antwortet dem Client nicht Netzwerkprogrammierung 6
K Socket Netty Client wirft Fehler! Netzwerkprogrammierung 3
I Client/Server Kommunikation bei einem Spiel Netzwerkprogrammierung 4
E Objekte versenden, Client-Server Netzwerkprogrammierung 25
C Mini Client-Server-Anwendung funktioniert nicht Netzwerkprogrammierung 8
U Client Soap Verbindung wieder schließen Netzwerkprogrammierung 0
U Socket Client mit hash authentifizieren Netzwerkprogrammierung 3
F HTTP HTTP Rest Client mit TLS1.2 und selbst signiertem Zertifikat Netzwerkprogrammierung 2
P Server als Client nutzen Netzwerkprogrammierung 8
D Socket Run Args Client/Server Socket Netzwerkprogrammierung 1
Cromewell Socket Multithreaded Server und Client Netzwerkprogrammierung 1
Y Client/Server/DB communication Netzwerkprogrammierung 3
JavaWolf165 Socket mit .writeUtf etwas vom Client zum Server schicken Netzwerkprogrammierung 13
J Client - Serversocket Netzwerkprogrammierung 1
P RMI Client Server Programm über Internet Netzwerkprogrammierung 2
brainless Client Server Kommunikation verschlüsseln Netzwerkprogrammierung 13
gamebreiti Socket Server / Client Anwendung Manipulation von Objekten durch Server Netzwerkprogrammierung 9
T Socket Server/Client Kommunikation Netzwerkprogrammierung 8
N Fragen zu Sockets Client Netzwerkprogrammierung 3
F Extasys TCp Client extends Funktion Netzwerkprogrammierung 0
F Server Client Anwendung mit UDP Netzwerkprogrammierung 2
O Client zwischen XML und JSON auswählen lassen Netzwerkprogrammierung 2
A RMI Wo treten Exceptions bei RMI Aufrufen auf? Auf Client oder auf Server? Netzwerkprogrammierung 3
A ByteBuffer - Client/Server Netzwerkprogrammierung 9
A Socket Wie ein einfacher Multithreads Service mit Telnet als Client mit Observable/Observer gelöst.... Netzwerkprogrammierung 0
K C# Server - Android Client Netzwerkprogrammierung 0
T Application Client NullPointerExc Netzwerkprogrammierung 7
V TCP Client funktioniert auf Emulator aber nicht auf Smartphone Netzwerkprogrammierung 5
H Machbarkeitsfrage: TCP/IP Client (z.B. Netty) für Java Web Applcation Netzwerkprogrammierung 1
P MIME-TYPE Erklaerung, Kommunikation zwischen Client und Server Netzwerkprogrammierung 3
H HTTP REST Jersey - PUT-Beispiel von Client senden Netzwerkprogrammierung 0
J Sichere Kommunikation bei Server Client Netzwerkprogrammierung 3
T Frage zu Client-Server Applikation Netzwerkprogrammierung 2
H Socket Client/Server Socket Programmieren Netzwerkprogrammierung 1
M Theoretische Frage zu Server - Client Netzwerkprogrammierung 2
P HTTP Server / Client Netzwerkprogrammierung 1
N FTP FTP Client invalid IPv6 address (Apache Commons Net API) Netzwerkprogrammierung 6
F TCP Client, verbindung aufrecht halten Netzwerkprogrammierung 0
X RMI: Woher kennt der Client das Schnittstellen-Interface? Netzwerkprogrammierung 2
E Thematik Client server Netzwerkprogrammierung 2
D UDP Client empfängt nichts Netzwerkprogrammierung 2
D Client/Server per Crossover Lan Kabel Netzwerkprogrammierung 1
S Client Server Connection Netzwerkprogrammierung 4
V erste Client - Server Anwendung, paar Fragen wie Socketverbindung checken usw. Netzwerkprogrammierung 4
S Client Anwendung mit zentraler SQL-Datenbank Netzwerkprogrammierung 3
N Client Identifikation eines Servers Netzwerkprogrammierung 1
S Sichere Server/Client Architektur Netzwerkprogrammierung 1
D Chat Server/mehre Client Netzwerkprogrammierung 9
I Server+Client Netzwerkprogrammierung 3
N Client am Server abmelden Netzwerkprogrammierung 0
F Server/Client Probleme Netzwerkprogrammierung 3
D SSH Client Netzwerkprogrammierung 7
U Socket Instant Messanger (Server Linux, Client Windows) Netzwerkprogrammierung 1
B TCP Client Android Netzwerkprogrammierung 3
Athena Grundsatzfragen zu Client-Server-Architektur / Matchmaking Netzwerkprogrammierung 1
A Problem beim Senden von Client zu Server Netzwerkprogrammierung 10
F Client Server DB Netzwerkprogrammierung 0
A Verständnisfrage Multi-Threaded Client/Server Netzwerkprogrammierung 5
F Tipps zum Thema Server/Client vie SOAP Netzwerkprogrammierung 0
OnDemand Ist Client noch angemeldet? Netzwerkprogrammierung 7
F Socket Java - Server/Client simple Netzwerkprogrammierung 1
D Socket UDP Client reagiert nicht auf spontane Meldungen Netzwerkprogrammierung 5
R Zeitliche Syncronisation Server - Client Netzwerkprogrammierung 0
S Server-Client: Image senden Netzwerkprogrammierung 2
C Multithreading Client / Server erklärt Netzwerkprogrammierung 11
M Client sendet nur, wenn das Socket geschlossen wird Netzwerkprogrammierung 53
P server - client verbindung (anfänger) Netzwerkprogrammierung 8

Ähnliche Java Themen


Oben