Merge remote-tracking branch 'origin/master'
This commit is contained in:
@ -1,30 +1,26 @@
|
||||
---
|
||||
layout: pattern
|
||||
title: Transaction script
|
||||
title: Transaction Script
|
||||
folder: transaction-script
|
||||
permalink: /patterns/transaction-script/
|
||||
categories: Domain logic
|
||||
categories: Behavioral
|
||||
tags:
|
||||
- Data access
|
||||
---
|
||||
|
||||
## Intent
|
||||
Transaction script(TS) is mainly used in small applications where nothing complex is done and bigger architecture's are not needed.
|
||||
Transaction Script organizes business logic by procedures where each procedure handles a single request from the presentation.
|
||||
|
||||
## Explanation
|
||||
Real world example
|
||||
> Your need is to be able to book a hotel room and also be able to cancel that booking.
|
||||
>
|
||||
> You need to create a hotel room booking system. Since the requirements are quite simple we intend to use the Transaction Script pattern here.
|
||||
|
||||
In plain words
|
||||
> All logic related to booking a hotel room like checking room availability,
|
||||
> calculate rates and update the database is done inside a single transaction script.
|
||||
> Similar procedure is also needed for cancelling a room booking and all
|
||||
> that logic will be in another transaction script.
|
||||
> Transaction Script organizes business logic into transactions that the system needs to carry out.
|
||||
|
||||
Programmatic example
|
||||
|
||||
The Hotel class takes care of booking and cancelling a room in a hotel.
|
||||
The `Hotel` class takes care of booking and cancelling room reservations.
|
||||
|
||||
```java
|
||||
public class Hotel {
|
||||
@ -76,7 +72,7 @@ public class Hotel {
|
||||
}
|
||||
```
|
||||
|
||||
This class has two methods, one for booking and cancelling a room respectively.
|
||||
The `Hotel` class has two methods, one for booking and cancelling a room respectively. Each one of them handles a single transaction in the system, making `Hotel` implement the Transaction Script pattern.
|
||||
|
||||
```
|
||||
public void bookRoom(int roomNumber);
|
||||
@ -94,8 +90,7 @@ if booked then calculates the refund amount and updates the database using the D
|
||||

|
||||
|
||||
## Applicability
|
||||
Use the transaction script model when the application has only a small amount of logic and that
|
||||
logic won't be extended in the future.
|
||||
Use the Transaction Script pattern when the application has only a small amount of logic and that logic won't be extended in the future.
|
||||
|
||||
## Consequences
|
||||
* As the business logic gets more complicated,
|
@ -23,7 +23,6 @@
|
||||
|
||||
package com.ashishtrivedi16.transactionscript;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import javax.sql.DataSource;
|
||||
import org.h2.jdbcx.JdbcDataSource;
|
||||
@ -51,8 +50,8 @@ public class TransactionScriptApp {
|
||||
addRooms(dao);
|
||||
|
||||
getRoomStatus(dao);
|
||||
|
||||
Hotel hotel = new Hotel(dao);
|
||||
|
||||
var hotel = new Hotel(dao);
|
||||
|
||||
hotel.bookRoom(1);
|
||||
hotel.bookRoom(2);
|
||||
@ -77,7 +76,7 @@ public class TransactionScriptApp {
|
||||
}
|
||||
}
|
||||
|
||||
private static void deleteSchema(DataSource dataSource) throws SQLException {
|
||||
private static void deleteSchema(DataSource dataSource) throws java.sql.SQLException {
|
||||
try (var connection = dataSource.getConnection();
|
||||
var statement = connection.createStatement()) {
|
||||
statement.execute(RoomSchemaSql.DELETE_SCHEMA_SQL);
|
||||
@ -89,7 +88,7 @@ public class TransactionScriptApp {
|
||||
var statement = connection.createStatement()) {
|
||||
statement.execute(RoomSchemaSql.CREATE_SCHEMA_SQL);
|
||||
} catch (Exception e) {
|
||||
throw new CustomException(e.getMessage(), e);
|
||||
throw new SqlException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,7 +98,7 @@ public class TransactionScriptApp {
|
||||
* @return h2 datasource
|
||||
*/
|
||||
private static DataSource createDataSource() {
|
||||
JdbcDataSource dataSource = new JdbcDataSource();
|
||||
var dataSource = new JdbcDataSource();
|
||||
dataSource.setUrl(H2_DB_URL);
|
||||
return dataSource;
|
||||
}
|
@ -30,7 +30,7 @@ import org.slf4j.LoggerFactory;
|
||||
public class Hotel {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(TransactionScriptApp.class);
|
||||
|
||||
private HotelDaoImpl hotelDao;
|
||||
private final HotelDaoImpl hotelDao;
|
||||
|
||||
public Hotel(HotelDaoImpl hotelDao) {
|
||||
this.hotelDao = hotelDao;
|
||||
@ -44,7 +44,7 @@ public class Hotel {
|
||||
*/
|
||||
public void bookRoom(int roomNumber) throws Exception {
|
||||
|
||||
Optional<Room> room = hotelDao.getById(roomNumber);
|
||||
var room = hotelDao.getById(roomNumber);
|
||||
|
||||
if (room.isEmpty()) {
|
||||
throw new Exception("Room number: " + roomNumber + " does not exist");
|
||||
@ -52,7 +52,7 @@ public class Hotel {
|
||||
if (room.get().isBooked()) {
|
||||
throw new Exception("Room already booked!");
|
||||
} else {
|
||||
Room updateRoomBooking = room.get();
|
||||
var updateRoomBooking = room.get();
|
||||
updateRoomBooking.setBooked(true);
|
||||
hotelDao.update(updateRoomBooking);
|
||||
}
|
||||
@ -66,14 +66,14 @@ public class Hotel {
|
||||
* @throws Exception if any error
|
||||
*/
|
||||
public void cancelRoomBooking(int roomNumber) throws Exception {
|
||||
|
||||
Optional<Room> room = hotelDao.getById(roomNumber);
|
||||
|
||||
var room = hotelDao.getById(roomNumber);
|
||||
|
||||
if (room.isEmpty()) {
|
||||
throw new Exception("Room number: " + roomNumber + " does not exist");
|
||||
} else {
|
||||
if (room.get().isBooked()) {
|
||||
Room updateRoomBooking = room.get();
|
||||
var updateRoomBooking = room.get();
|
||||
updateRoomBooking.setBooked(false);
|
||||
int refundAmount = updateRoomBooking.getPrice();
|
||||
hotelDao.update(updateRoomBooking);
|
||||
|
@ -26,7 +26,6 @@ package com.ashishtrivedi16.transactionscript;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Optional;
|
||||
import java.util.Spliterator;
|
||||
import java.util.Spliterators;
|
||||
@ -48,7 +47,7 @@ public class HotelDaoImpl implements HotelDao {
|
||||
try {
|
||||
var connection = getConnection();
|
||||
var statement = connection.prepareStatement("SELECT * FROM ROOMS");
|
||||
ResultSet resultSet = statement.executeQuery(); // NOSONAR
|
||||
var resultSet = statement.executeQuery(); // NOSONAR
|
||||
return StreamSupport.stream(new Spliterators.AbstractSpliterator<Room>(Long.MAX_VALUE,
|
||||
Spliterator.ORDERED) {
|
||||
|
||||
@ -60,7 +59,7 @@ public class HotelDaoImpl implements HotelDao {
|
||||
}
|
||||
action.accept(createRoom(resultSet));
|
||||
return true;
|
||||
} catch (SQLException e) {
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e); // NOSONAR
|
||||
}
|
||||
}
|
||||
@ -71,8 +70,8 @@ public class HotelDaoImpl implements HotelDao {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
} catch (SQLException e) {
|
||||
throw new CustomException(e.getMessage(), e);
|
||||
} catch (Exception e) {
|
||||
throw new SqlException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,8 +89,8 @@ public class HotelDaoImpl implements HotelDao {
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
throw new CustomException(ex.getMessage(), ex);
|
||||
} catch (Exception ex) {
|
||||
throw new SqlException(ex.getMessage(), ex);
|
||||
} finally {
|
||||
if (resultSet != null) {
|
||||
resultSet.close();
|
||||
@ -113,8 +112,8 @@ public class HotelDaoImpl implements HotelDao {
|
||||
statement.setBoolean(4, room.isBooked());
|
||||
statement.execute();
|
||||
return true;
|
||||
} catch (SQLException ex) {
|
||||
throw new CustomException(ex.getMessage(), ex);
|
||||
} catch (Exception ex) {
|
||||
throw new SqlException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,8 +129,8 @@ public class HotelDaoImpl implements HotelDao {
|
||||
statement.setBoolean(3, room.isBooked());
|
||||
statement.setInt(4, room.getId());
|
||||
return statement.executeUpdate() > 0;
|
||||
} catch (SQLException ex) {
|
||||
throw new CustomException(ex.getMessage(), ex);
|
||||
} catch (Exception ex) {
|
||||
throw new SqlException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -141,12 +140,12 @@ public class HotelDaoImpl implements HotelDao {
|
||||
var statement = connection.prepareStatement("DELETE FROM ROOMS WHERE ID = ?")) {
|
||||
statement.setInt(1, room.getId());
|
||||
return statement.executeUpdate() > 0;
|
||||
} catch (SQLException ex) {
|
||||
throw new CustomException(ex.getMessage(), ex);
|
||||
} catch (Exception ex) {
|
||||
throw new SqlException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private Connection getConnection() throws SQLException {
|
||||
private Connection getConnection() throws Exception {
|
||||
return dataSource.getConnection();
|
||||
}
|
||||
|
||||
@ -156,12 +155,12 @@ public class HotelDaoImpl implements HotelDao {
|
||||
resultSet.close();
|
||||
statement.close();
|
||||
connection.close();
|
||||
} catch (SQLException e) {
|
||||
throw new CustomException(e.getMessage(), e);
|
||||
} catch (Exception e) {
|
||||
throw new SqlException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private Room createRoom(ResultSet resultSet) throws SQLException {
|
||||
private Room createRoom(ResultSet resultSet) throws Exception {
|
||||
return new Room(resultSet.getInt("ID"),
|
||||
resultSet.getString("ROOM_TYPE"),
|
||||
resultSet.getInt("PRICE"),
|
||||
|
@ -26,18 +26,18 @@ package com.ashishtrivedi16.transactionscript;
|
||||
/**
|
||||
* Custom exception.
|
||||
*/
|
||||
public class CustomException extends Exception {
|
||||
public class SqlException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public CustomException() {
|
||||
public SqlException() {
|
||||
}
|
||||
|
||||
public CustomException(String message) {
|
||||
public SqlException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public CustomException(String message, Throwable cause) {
|
||||
public SqlException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
@ -28,7 +28,6 @@ import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
@ -103,7 +102,7 @@ public class HotelTest {
|
||||
}
|
||||
|
||||
|
||||
private static void deleteSchema(DataSource dataSource) throws SQLException {
|
||||
private static void deleteSchema(DataSource dataSource) throws java.sql.SQLException {
|
||||
try (var connection = dataSource.getConnection();
|
||||
var statement = connection.createStatement()) {
|
||||
statement.execute(RoomSchemaSql.DELETE_SCHEMA_SQL);
|
||||
@ -115,7 +114,7 @@ public class HotelTest {
|
||||
var statement = connection.createStatement()) {
|
||||
statement.execute(RoomSchemaSql.CREATE_SCHEMA_SQL);
|
||||
} catch (Exception e) {
|
||||
throw new CustomException(e.getMessage(), e);
|
||||
throw new SqlException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user