Базе података 1/Лаб 1 јануар 2021 — разлика између измена
м (→Решење: fix) |
(resenje java) |
||
| (Нису приказане 3 међуизмене 2 корисника) | |||
| Ред 8: | Ред 8: | ||
Комитенти са својих рачуна врше трансакције путем ставки промета (прате се редни број, датум и време) које могу бити уплате (прати се основ и износ) или исплате (прате се износ и провизија), при чему је то могуће у било којој филијали. | Комитенти са својих рачуна врше трансакције путем ставки промета (прате се редни број, датум и време) које могу бити уплате (прати се основ и износ) или исплате (прате се износ и провизија), при чему је то могуће у било којој филијали. | ||
[[Датотека:BP1 Lab 1 semestralni dijagram. | [[Датотека:BP1 Lab 1 semestralni dijagram.svg|frame|center|ЕР дијаграм базе из поставке задатка.]] | ||
== Задатак == | == Задатак == | ||
Написати програм који врши уплату за задати рачун. Функција као аргументе прима idFil, idRac и износ. Треба да се обавести корисник уколико је рачун након уплате променио статус, као и да ли је уплата била успешна. Функција је потребно да буде отпорна на грешке. | Написати програм који врши уплату за задати рачун. Функција као аргументе прима idFil, idRac и износ. Треба да се обавести корисник уколико је рачун након уплате променио статус, као и да ли је уплата била успешна. Функција је потребно да буде отпорна на грешке. | ||
== Решење == | == Решење Java == | ||
<syntaxhighlight lang="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"; | |||
} | |||
} | |||
</syntaxhighlight> | |||
== Решење C++== | |||
За решавање је потребна [https://rti.etf.bg.ac.rs/rti/bp1/materijali/vezbe/Banka.db Banka.db] база са странице предмета и [https://sqlite.org/download.html SQLite C библиотека] за комуникацију с базом. Оба су већ дата на лабораторијској вежби. | За решавање је потребна [https://rti.etf.bg.ac.rs/rti/bp1/materijali/vezbe/Banka.db Banka.db] база са странице предмета и [https://sqlite.org/download.html SQLite C библиотека] за комуникацију с базом. Оба су већ дата на лабораторијској вежби. | ||
| Ред 160: | Ред 320: | ||
[[Категорија:Базе података 1]] | [[Категорија:Базе података 1]] | ||
[[Категорија:Лабораторијске вежбе]] | |||
Тренутна верзија на датум 22. децембар 2022. у 22:21
Поставка
Банка путем својих филијала (прати се назив и адреса) у разним местима (прате се поштански број и назив) опслужује своје комитенте (прати се назив и адреса) који могу бити без места, а у тренутку првог појављивања у банци пријављују седиште у одређеном месту.
Сваки комитент може да има више рачуна у свакој од филијала (прате се статус, број ставки, дозвољени минус, и стање), а мора имати бар један рачун. Статус рачуна може бити активан, блокиран или угашен. Рачун постаје блокиран када пређе у недозвољени минус, а активира се када стање пређе у дозвољени минус.
Комитенти са својих рачуна врше трансакције путем ставки промета (прате се редни број, датум и време) које могу бити уплате (прати се основ и износ) или исплате (прате се износ и провизија), при чему је то могуће у било којој филијали.
Задатак
Написати програм који врши уплату за задати рачун. Функција као аргументе прима 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;
}