Базе података 1/Лаб 1 јануар 2021

Извор: SI Wiki
Пређи на навигацију Пређи на претрагу

Поставка

Банка путем својих филијала (прати се назив и адреса) у разним местима (прате се поштански број и назив) опслужује своје комитенте (прати се назив и адреса) који могу бити без места, а у тренутку првог појављивања у банци пријављују седиште у одређеном месту.

Сваки комитент може да има више рачуна у свакој од филијала (прате се статус, број ставки, дозвољени минус, и стање), а мора имати бар један рачун. Статус рачуна може бити активан, блокиран или угашен. Рачун постаје блокиран када пређе у недозвољени минус, а активира се када стање пређе у дозвољени минус.

Комитенти са својих рачуна врше трансакције путем ставки промета (прате се редни број, датум и време) које могу бити уплате (прати се основ и износ) или исплате (прате се износ и провизија), при чему је то могуће у било којој филијали.

ЕР дијаграм базе из поставке задатка.

Задатак

Написати програм који врши уплату за задати рачун. Функција као аргументе прима idFil, idRac и износ. Треба да се обавести корисник уколико је рачун након уплате променио статус, као и да ли је уплата била успешна. Функција је потребно да буде отпорна на грешке.

Решење Java

import java.sql.*;

public class Lab1Januar2021 {
    private Connection conn = null;

    //povezivanje na bazu
    public void connect() {
        //ako postoji neka konekcija od pre
        disconnect();
        try {
            Class.forName("org.sqlite.JDBC");
            conn = DriverManager.getConnection("jdbc:sqlite:Banka.db");
            System.out.println("Uspesna konekcija");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //diskoneckija sa baze
    public void disconnect() {
        if (conn == null) return;
        try {
            conn.close();
            conn = null;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
    private int dohvatiIdSta(){
        String racun = "SELECT COALESCE(MAX(IdSta), 0)+1 FROM Stavka";
        try (PreparedStatement ps = conn.prepareStatement(racun)) {
            ResultSet rs = ps.executeQuery();
            while(rs.next()){
                return rs.getInt(1);
            }

        }catch (SQLException e) {
            //
        }
        return -1;

    }
    private int dohvatiRedBr(int idfil, int idrac){
        String racun = "SELECT COALESCE(MAX(IdSta), 0)+1 FROM Stavka WHERE idFil = ? AND idRac = ?";
        try (PreparedStatement ps = conn.prepareStatement(racun)) {
            ps.setInt(1, idfil);
            ps.setInt(2, idrac);
            ResultSet rs = ps.executeQuery();
            while(rs.next()){
                return rs.getInt(1);
            }

        }catch (SQLException e) {
            e.printStackTrace();
        }
        return -1;
    }
    public String izvrsiUplatu(int idFil, int idRac, int iznos) {
        int idUneteStavke = -1;
        String staroStanje = "";
        int staroNovac = 0;
        boolean trebaDaSeMenja=false;
        boolean dosloJeDoPromeneStatusa=false;
        try {
            conn.setAutoCommit(false);

            //staro stanje
            String provera =  "SELECT * FROM Racun WHERE idFil = ? AND idRac = ?";
            try (PreparedStatement ps = conn.prepareStatement(provera)) {
                ps.setInt(1, idFil);
                ps.setInt(2, idRac);
                ResultSet rs = ps.executeQuery();


                staroStanje = rs.getString("Status");
                if(staroStanje.equals("U")){
                    return "Racun je ugasen!";
                }
                staroNovac = rs.getInt("Stanje");

                System.out.println("Provera obavljena. StaroStanje " + staroStanje + " staroNovac " + staroNovac);


            } catch (SQLException e) {
                e.printStackTrace();
            }
            if((staroNovac+iznos)>0 && staroStanje.equals("B")){
                dosloJeDoPromeneStatusa=true;
            }
            //uplati na racun
            String racun = "";
            if(dosloJeDoPromeneStatusa) racun=  "UPDATE racun SET stanje = stanje + ?, BrojStavki = BrojStavki + 1, Status = 'A' WHERE idFil = ? AND idRac = ?";
            else racun = "UPDATE racun SET stanje = stanje + ?, BrojStavki = BrojStavki + 1 WHERE idFil = ? AND idRac = ?";
            //stavljamo u try jer se radi automatsko zatvaranje
            try (PreparedStatement ps = conn.prepareStatement(racun)) {
                ps.setInt(1, iznos);
                ps.setInt(2, idFil);
                ps.setInt(3, idRac);
                if(ps.executeUpdate()==1){
                    System.out.println("uspeno upadte stanje" + racun);
                }else{
                    System.out.println("nije uspeno upadte stanje" +racun);
                }

            } catch (SQLException e) {
                e.printStackTrace();
            }
            //dodaj stavku
            String stavka = "INSERT INTO Stavka(IdSta, RedBroj, Datum, Vreme, Iznos, IdFil, IdRac) VALUES (?, ?, DATE('now'), TIME(), ?, ?, ?)";

            try (PreparedStatement ps = conn.prepareStatement(stavka)) {
                System.out.println(dohvatiIdSta() + "|" + dohvatiRedBr(idFil, idRac));
                ps.setInt(1, dohvatiIdSta());
                ps.setInt(2, dohvatiRedBr(idFil, idRac));
                ps.setInt(3, iznos);
                ps.setInt(4, idFil);
                ps.setInt(5, idRac);
                if (ps.executeUpdate() == 1) {
                    System.out.println("uspeno insert u stavke");
                    ResultSet keysRs = ps.getGeneratedKeys();
                    idUneteStavke = keysRs.getInt(1);

                }else{
                    System.out.println("nzm");
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            //unesi u uplatu
            String uplata = "INSERT INTO Uplata(IdSta, Osnov) VALUES (?, 'Uplata')";

            try (PreparedStatement ps = conn.prepareStatement(uplata)) {
                ps.setInt(1, idUneteStavke);
                ps.executeUpdate();

            } catch (SQLException e) {
                e.printStackTrace();
            }
            conn.commit();

        } catch (Exception e) {

        } finally {
            try {
                conn.setAutoCommit(true);
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        if(dosloJeDoPromeneStatusa)
            return "Doslo je do promene, racun je sada aktivan";
        else return "Nije doslo do promene";
    }
}

Решење C++

За решавање је потребна Banka.db база са странице предмета и SQLite C библиотека за комуникацију с базом. Оба су већ дата на лабораторијској вежби.

#include <iostream>
#include <string>
#include "sqlite3.h"

sqlite3 *otvoriBazu(const char *imeBaze) {
    sqlite3 *baza = nullptr;
    int kod = sqlite3_open(imeBaze, &baza);
    if (kod != SQLITE_OK) {
        throw std::string("Kod pri otvaranju: ") + std::to_string(kod);
    }
    return baza;
}

void zatvoriBazu(sqlite3 *baza) {
    int kod = sqlite3_close(baza);
    if (kod != SQLITE_OK) {
        throw std::string("Kod pri zatvaranju: ") + std::to_string(kod);
    }
}

void pripremi(sqlite3 *baza, const char *sql, sqlite3_stmt *&stmt) {
    int kod = sqlite3_prepare(baza, sql, -1, &stmt, nullptr);
    if (kod != SQLITE_OK) {
        std::string greska = std::string("Greška pri pripremanju upita: ") + sqlite3_errmsg(baza);
        sqlite3_finalize(stmt);
        throw greska;
    }
}

void izvrsiBezParametara(sqlite3 *baza, const char *sql, int (*callback)(void *, int, char **, char **) = nullptr) {
    char *errmsg = nullptr;
    int kod = sqlite3_exec(baza, sql, callback, nullptr, &errmsg);
    if (kod != SQLITE_OK) {
        std::string greska = std::string("Greška pri izvršavanju: ") + errmsg;
        sqlite3_free(errmsg);
        throw greska;
    }
}

void proknjiziUplatu(sqlite3 *baza) {
    const char *sql = "INSERT INTO Uplata (IdSta, Osnov) VALUES (?, 'Uplata')";
    sqlite3_stmt *stmt = nullptr;
    int kod;
    pripremi(baza, sql, stmt);
    sqlite3_bind_int(stmt, 1, sqlite3_last_insert_rowid(baza));
    kod = sqlite3_step(stmt);
    if (kod != SQLITE_DONE) {
        std::string greska = std::string("Greška pri proknjižavanju uplate: ") + sqlite3_errmsg(baza);
        sqlite3_finalize(stmt);
        throw greska;
    }
    sqlite3_finalize(stmt);
}

void proknjiziStavku(sqlite3 *baza, int iznos, int idFil, int idRac) {
    const char *sql = "INSERT INTO Stavka (RedBroj, Datum, Vreme, Iznos, IdFil, IdRac) "
        "SELECT COALESCE(MAX(Stavka.RedBroj), 0) + 1, DATE(), TIME(), ?, ?, ? "
        "FROM Stavka S "
        "WHERE S.IdRac = ?";
    sqlite3_stmt *stmt = nullptr;
    int kod;
    pripremi(baza, sql, stmt);
    sqlite3_bind_int(stmt, 1, iznos);
    sqlite3_bind_int(stmt, 2, idFil);
    sqlite3_bind_int(stmt, 3, idRac);
    sqlite3_bind_int(stmt, 4, idRac);
    izvrsiBezParametara(baza, "BEGIN TRANSACTION");
    kod = sqlite3_step(stmt);
    if (kod != SQLITE_DONE) {
        std::string greska = std::string("Greška pri proknjižavanju stavke: ") + sqlite3_errmsg(baza);
        sqlite3_finalize(stmt);
        throw greska;
    }
    sqlite3_finalize(stmt);
    proknjiziUplatu(baza);
    if (azurirajRacun(baza, idRac, iznos)) {
        std::cout << "Račun promenio status u aktivan. ";
    }
    izvrsiBezParametara(baza, "COMMIT TRANSACTION");
}

bool azurirajRacun(sqlite3 *baza, int idRac, int novIznos) {
    const char *sql1 = "SELECT Status, Stanje, DozvMinus FROM Racun"
        "WHERE IdRac = ?";
    const char *sql2 = "UPDATE Racun "
        "SET Status = ?1"
        "BrojStavki = (SELECT MAX(IdSta) FROM Stavka WHERE IdRac = ?2),"
        "Stanje = ?3"
        "WHERE IdRac = ?2";
    sqlite3_stmt *stmt = nullptr;
    int kod;
    pripremi(baza, sql1, stmt);
    sqlite3_bind_int(stmt,1,idRac);
    kod = sqlite3_step(stmt);
    if (kod != SQLITE_ROW) {
        std::string greska = std::string("Greška pri ažuriranju računa: ") + sqlite3_errmsg(baza);
        sqlite3_finalize(stmt);
        throw greska;
    }
    int staroStanje = sqlite3_column_int(stmt,1);
    int dMinus = sqlite3_column_int(stmt,2);
    const char *status = (const char*)sqlite3_column_text(stmt,0);
    sqlite3_finalize(stmt);

    stmt = nullptr;
    pripremi(baza, sql2, stmt);
    sqlite3_bind_text(stmt, 1, (staroStanje + novIznos > dMinus) ? "A" : status, 1, nullptr);
    sqlite3_bind_int(stmt, 2, idRac);
    sqlite3_bind_int(stmt, 3, staroStanje + novIznos);
    kod = sqlite3_step(stmt);
    if (kod != SQLITE_DONE) {
        std::string greska = std::string("Greška pri ažuriranju računa: ") + sqlite3_errmsg(baza);
        sqlite3_finalize(stmt);
        throw greska;
    }
    sqlite3_finalize(stmt);
    return staroStanje + novIznos > dMinus;
}

int main(void) {
    try {
        sqlite3 *baza = otvoriBazu("Banka.db");
        int idRac, idFil, iznos;
        std::cout << "Unesi ID računa: ";
        std::cin >> idRac;
        std::cout << "Unesi ID filijale: ";
        std::cin >> idFil;
        std::cout << "Unesi iznos: " ;
        std::cin >> iznos;
        proknjiziStavku(baza, iznos, idFil, idRac);
        std::cout << "Uspešno procesirana uplata. ";
        zatvoriBazu(baza);
    }
    catch (std::string &greska) {
        izvrsiBezParametara(baza, "ROLLBACK TRANSACTION");
        std::cout << "Desila se greška." << std::endl << greska << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}