Přidat otázku mezi oblíbenéZasílat nové odpovědi e-mailem Připojení dvou aplikací do jedné mysql databáze

Hoj,

potřebuji poradit.

Mám 2 aplikace:

a) Web app v hibernate
b) Destkop v javě

Aplikace a čte z databáze (pokaždé když někdo otevře stránku) a aplikace b do té databáze zapisuje (max 2x za den).

Jedná se o jednu tabulku do které obě aplikace přistupují. Obě přes stejný účet v mysql (přes roota).

Jak to vyřešit? Nemáte zkušenosti?

Díky za radu.

Předmět Autor Datum
A co na tom chceš řešit? To je naprosto normální, že se do databáze přistupuje z více míst.
Wikan 05.01.2016 15:30
Wikan
Problém je v tom, že když běží tomcat s webaplikací a a aplikace b chce zapsat data do databáze, tak…
MašinkaTomáš 05.01.2016 15:34
MašinkaTomáš
to bude nejspíše problém toho JAK do té databáze zapisuješ (kolik a kam), jak je postaven datový a r…
touchwood 05.01.2016 15:42
touchwood
Jelikož se s tím teprve učím, mám pouze jednu tabulku. Ukládám vždy 120 řádků. Používám DriverMana…
MašinkaTomáš 05.01.2016 15:54
MašinkaTomáš
insert do tabulky az taky problem nebude. skor to citanie. urobi zrejme table lock a uz mas problem.…
wam_Spider007 05.01.2016 16:06
wam_Spider007
O transakce se má starat servisní vrstva aplikace nezávisle na tom, co to je za DB. Do java kódu byc…
MaSo 05.01.2016 16:22
MaSo
To je v poriadku, ale na tej servisnej vrstve to musis riesit rovnako. Spravnym zamykanim zaznamov/t…
wam_Spider007 05.01.2016 17:21
wam_Spider007
Normálně se to dělá tak, že vytvoříš svoje backendové rozhraní pro práci s daty (třeba jako REST con…
MaSo 05.01.2016 15:42
MaSo
Používám hibernate. O zamykání nic nevím, tudíž by být žádné nemělo. Standardní uložení probíhá po…
MašinkaTomáš 05.01.2016 16:24
MašinkaTomáš
Co je to info_messageDao? EDIT: Mas to hodne zmatene napsane. Proc vytvaris EntityManager sam? Jake…
MaSo 05.01.2016 16:41
MaSo
Interface, přes který se ukládá objekt do db. Dědí od třídy @MappedSuperclass. Myslíš že bude prob…
MašinkaTomáš 05.01.2016 16:44
MašinkaTomáš
V hibernate mas mit jenom entitu, kterou chces ulozit. Je to trida, treba jako tato: @Entity @Table…
MaSo 05.01.2016 16:54
MaSo
O tom vím, děkuji, spring jsem nechtěl. O tom taky vím. @Transactional používám. EDIT: používám hi…
MašinkaTomáš 05.01.2016 17:03
MašinkaTomáš
Problem bude v jave ne v DB. Dej sem cely kod, jak pracujes s daty...
MaSo 05.01.2016 21:00
MaSo
Objekt, který ukládám do DB (+ dědění od základního BASEOBJECT): package org.donutek.domain; import… poslední
MašinkaTomáš 06.01.2016 08:57
MašinkaTomáš

Problém je v tom, že když běží tomcat s webaplikací a a aplikace b chce zapsat data do databáze, tak se kousne a prostě je nezapíše. (dodatek: na webové rozhraní v danou chvilku nikdo nelezl - tudíž tomcat neměl potřebu číst z db).

Testoval jsem to i s vypnutým tomcatem a když je vypnutý, normálně to funguje.

Myslel jsem, že to je problém.

Aplikace nemá žadný cyklus a nemůže se jen tak kousnout.

Pseudokód:

Vypiš startuji
Načti data
Vypiš data načtena
Vypiš ukládám do db
Ulož data
Vypiš uloženo

Kousne se po Vypiš ukládám do db a Vypiš uloženo už nevypíše a data v db nejsou.

S vypnutým tomcatem vše OK.

to bude nejspíše problém toho JAK do té databáze zapisuješ (kolik a kam), jak je postaven datový a relační model databáze a v neposlední řadě (možná) problém (ne)indexace polí, popř. nějaký obecnější problém se zamykáním tabulek.

jak máš postavený SQL dotaz pro ukládání dat?

Jelikož se s tím teprve učím, mám pouze jednu tabulku.

Ukládám vždy 120 řádků.

Používám DriverManager z java.sql.

conn = DriverManager.getConnection(jdbcUrl, userName, psw);

String    SQL_SERVER = "INSERT INTO " + table + " (" + CONST_SERVER_COUNTRY + ", " + CONST_SERVER_SPEED + "," + CONST_SERVER_PLAYDRS + "," + CONST_SERVER_START_BEFORE + ")" + " VALUES (?, ?, ?, ?)";
pr = conn.prepareStatement(SQL_SERVER);

for (int i = 0; i < tmpRow.size(); i++) {
     /*tmp je seznam objektu co taha string hodnoty*/
     pr.setString(1, tmpRow.get(i).a);
     pr.setString(2, tmpRow.get(i).b);
     pr.setString(3, tmpRow.get(i).c);
     pr.setString(4, tmpRow.get(i).d);
     pr.executeUpdate();
}


Tedy z kódu, dotaz je INSERT INTO NAZEVTABULKY (SLOUPEC1, SLOUPEC2, SLOUPEC3, SLOUPE4) VALUES (NECO, NECO, NECO, NECO);

insert do tabulky az taky problem nebude. skor to citanie. urobi zrejme table lock a uz mas problem.
ak pouzijes napriklad MyISAM engine, tak sa tomu vyhnes. pripadne urobis citanie bez zamknutia (co ma aj druhu stranku a to, ze budes citat aj necommitnute data).

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;
SELECT * FROM TABLE_NAME ;
COMMIT ;

Normálně se to dělá tak, že vytvoříš svoje backendové rozhraní pro práci s daty (třeba jako REST controllery) a toto rozhraní pak konzumuješ ve frontendových aplikacích.

My nevíme, jak v tomcatové aplikaci pracuješ s tou tabulkou, jak tam řešíš transakce (jestli tam třeba tu tabulku nezamykáš).

Používám hibernate.

O zamykání nic nevím, tudíž by být žádné nemělo.

Standardní uložení probíhá pomocí:

Vytvoření továrny při startu aplikace):

emf = Persistence.createEntityManagerFactory("neco");

Následný save do databáze:

        EntityManager em;

        em = emf.createEntityManager();
        info_messageDao.startTransaction(em);
        try {
            info_messageDao.save(info_message, em);
        } catch (Exception e) {
            info_messageDao.rollbackTransaction(em);
        }
        info_messageDao.commitTransaction(em);
        em.close();

Název tabulek a dat se může zde lišit, ve skutečné aplikaci je vše OK

persistence je:

<persistence-unit name="neco" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistencePr ovider</provider>

<properties>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema"/>

<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>

<property name="hibernate.connection.password" value=""/>
<property name="hibernate.connection.username" value="root"/>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/donutek_db"/>

<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/ >
<property name="hibernate.validator.apply_to_ddl" value="true" />

<property name="connection.provider_class" value="org.hibernate.connection.C3P0ConnectionProv ider"/>
<property name="hibernate.c3p0.min_size" value="5"/>
<property name="hibernate.c3p0.max_size" value="20"/>
<property name="hibernate.c3p0.timeout" value="300"/>
<property name="hibernate.c3p0.max_statements" value="50"/>
<property name="hibernate.c3p0.idle_test_period" value="300"/>

</properties>
</persistence-unit>

V hibernate mas mit jenom entitu, kterou chces ulozit. Je to trida, treba jako tato:

@Entity
@Table(name="EMPLOYEE")
public class Employee {
 
    @Id
    @GeneratedValue
    private Long id;
     
    @Column(name="firstname")
    private String firstname;
     
    @Column(name="lastname")
    private String lastname;
}

pak uz volas jenom em.persist(employee). Rizeni transkaci je dobre sverit nejake knihovne, treba Springu, at muzes pouzit anotaci @Transactional a nemusis pak furt psat begin, comit a rollback, kdyz exception.

O tom vím, děkuji, spring jsem nechtěl. O tom taky vím.

@Transactional používám.

EDIT: používám hibernate a JPA. Nepoužívám nic dalšího, protože nechci. Vím že to je.

EntityManager vytvarim z entity factory sám, protože je to ochrana proti vláknový práci.

Vím že to vypadá hrozně, ale teprve se to učím, pak přejdu výš na lepší knihovny.

Tohle asi ale nebude problém s DB, nebo myslíš že jo?

Objekt, který ukládám do DB (+ dědění od základního BASEOBJECT):

package org.donutek.domain;

import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;

@MappedSuperclass
public class BaseObject {

    private Long id;

    @Transient
    public boolean isNew() {
        return id == null;
    }

    @Id
    @GeneratedValue
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
package org.donutek.domain;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Table;

@Entity
@Table(name = "info_message")
public class info_message extends BaseObject implements Serializable {

    private String date, message;

    public info_message() {
    }

    public info_message(String date, String message) {
        this.date = date;
        this.message = message;
    }

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    @Override
    public String toString() {
        return "info_message{" + "date=" + date + ", message=" + message + '}';
    }

}

Konkrétní uložení:

  public void save_info_message(info_message info_message) {
        EntityManager em;

        em = emf.createEntityManager();
        info_messageDao.startTransaction(em);
        try {
            info_messageDao.save(info_message, em);
        } catch (Exception e) {
            info_messageDao.rollbackTransaction(em);
        }
        info_messageDao.commitTransaction(em);
        em.close();
    }

Kdy emf vytvářím při startu serveru takhle:

emf = Persistence.createEntityManagerFactory("neco");

Generické DAO (v interfacu jsou jen hlavičky metod):

package org.donutek.dao;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import org.donutek.domain.BaseObject;

public class GenericDaoJpa<T extends BaseObject> implements GenericDao<T> {

    protected EntityManagerFactory emf;
    private Class<T> persistedType;

    public GenericDaoJpa(EntityManagerFactory emf, Class<T> persistedType) {
        this.emf = emf;
        this.persistedType = persistedType;
    }

    @Override
    public T save(T value, EntityManager em) {
        if (value.isNew()) {
            em.persist(value);
            return value;
        } else {
            return em.merge(value);
        }
    }

    @Override
    public void remove(T toRemove, EntityManager em) {
        if (!toRemove.isNew()) {
            em.remove(toRemove);
        }
    }

    @Override
    public void startTransaction(EntityManager em) {
        em.getTransaction().begin();
    }

    @Override
    public void commitTransaction(EntityManager em) {
        em.getTransaction().commit();
    }

    @Override
    public void rollbackTransaction(EntityManager em) {
        em.getTransaction().rollback();
    }
}

Konkrétní DAO objektu se kterým pracuji dědí od generického:

package org.donutek.dao;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.NoResultException;
import javax.persistence.TypedQuery;
import org.donutek.domain.info_message;

public class info_messageDaoJpa extends GenericDaoJpa<info_message> implements info_messageDao {

    public info_messageDaoJpa(EntityManagerFactory emf) {
        super(emf, info_message.class);
    }

    @Override
    public info_message findLastMessage(EntityManager em) {
        TypedQuery<info_message> q = em.createQuery("SELECT t FROM info_message t ORDER BY t.id DESC", info_message.class);
        q.setMaxResults(1);
        try {
            return q.getSingleResult();
        } catch (NoResultException e) {
            return null;
        }
    }

}

Konkrétní výběr který posílám pak v REQUESTU je:

           EntityManager em;
        em = emf.createEntityManager();
        String date = daoRegister.getInfo_messageDao().findLastMessage(em).getDate(); //pristup do dao objektu
        em.close();

emf je pořád stejný objekt, který posílám tam kde je třeba.

Zpět do poradny Odpovědět na původní otázku Nahoru