Как создавать транзакционные DAO с использованием JDBC - PullRequest
0 голосов
/ 06 июля 2019

Я сейчас работаю с JDBC и хочу создать отдельные слои для доступа к данным и бизнес-логики.Я создал несколько DAO для каждой сущности и несколько сервисов для моей бизнес-логики.Но я столкнулся с проблемой с транзакциями.В каждом DAO у меня есть CRUD, где я открываю соединение в каждой операции и после закрываю его.Но если мне нужно использовать несколько операций, как в транзакции, это не сработает.

Итак, я создаю одно соединение для всего DAO, но мне нужно открывать и закрывать соединение для каждой операции вне DAO.

Пример моего DAO

public class UserDAOImpl implements UserDAO {

    private Connection connection;

    public UserDAO(Connection connection) {
        this.connection = connection;
    }

    // CRUD operations
}

Абстрактная фабрика DAO

public abstract class DAOFactory {

    public abstract UserDAO getUserDAO();
    public abstract ItemDAO getItemDAO();
    public abstract OrderDAO getOrderDAO();
    public abstract RoleDAO getRoleDAO();

    public static DAOFactory getDAOFactory(Class<? extends DAOFactory> factoryClass) throws IllegalAccessException, InstantiationException {
        return factoryClass.newInstance();
    }
}

Пример реализации фабрики MySQL DAO

public class MySqlDAOFactory extends DAOFactory {

    private UserDAO userDAO;
    private ItemDAO itemDAO;
    private OrderDAO orderDAO;
    private RoleDAO roleDAO;

    @Override
    public UserDAO getUserDAO() {
        if (userDAO == null) {
            userDAO = new UserDAOImpl(getConnection());
        }
        return userDAO;
    }

    @Override
    public ItemDAO getItemDAO() {
        if (itemDAO == null) {
            itemDAO = new ItemDAOImpl(getConnection());
        }
        return itemDAO;
    }

    @Override
    public OrderDAO getOrderDAO() {
        if (orderDAO == null) {
            orderDAO = new OrderDAOImpl(getConnection());
        }
        return orderDAO;
    }

    @Override
    public RoleDAO getRoleDAO() {
        if (roleDAO == null) {
            roleDAO = new RoleDAOImpl(getConnection());
        }
        return roleDAO;
    }

    static {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection() {
        Connection connection = null;
        Context initCtx = null;
        try {
            initCtx = new InitialContext();
            Context envCtx = (Context) initCtx.lookup("java:comp/env");
            DataSource ds = (DataSource) envCtx.lookup("jdbc/mysql");
            connection = ds.getConnection();
        } catch (NamingException | SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }
}

Пример метода DAO

public Optional<User> findById(Long id) {
        User user = null;
        try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM shop.user WHERE id = ?", Statement.RETURN_GENERATED_KEYS)) {
            statement.setLong(1, id);
            ResultSet resultSet = statement.executeQuery();
            resultSet.next();
            user = userMapper.map(resultSet);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return Optional.ofNullable(user);
    }

Ответы [ 2 ]

1 голос
/ 06 июля 2019

Обычно вам не нужно иметь дело с транзакциями на уровне DAO.Лучше применять управление транзакциями на уровне обслуживания, поскольку это позволяет вам контролировать логику, когда вам не нужна транзакция, а также управлять другими аспектами, такими как политики отката и т. Д.

В вашем случаеВы можете взглянуть на документацию JTA.Этот API предоставляет аннотации и другие инструменты для простого управления транзакциями:)

0 голосов
/ 06 июля 2019

Теперь я создал класс для управления соединением между всеми моими DAO.Я изменил абстрактный класс DAOFactory для взаимодействия и создания абстрактного класса JdbcDaoFactory и расширяю свой DaoManager класс.

DAOFactory

public interface DAOFactory {

    UserDAO getUserDAO();
    ItemDAO getItemDAO();
    OrderDAO getOrderDAO();
    RoleDAO getRoleDAO();
}
public abstract class JdbcDaoFactory implements DAOFactory {

    protected Connection connection;

    private UserDAO userDAO;
    private ItemDAO itemDAO;
    private OrderDAO orderDAO;
    private RoleDAO roleDAO;

    protected JdbcDaoFactory(Connection connection) {
        this.connection = connection;
    }

    @Override
    public UserDAO getUserDAO() {
        if (userDAO == null) {
            userDAO = new UserDAOImpl(connection);
        }
        return userDAO;
    }

    @Override
    public ItemDAO getItemDAO() {
        if (itemDAO == null) {
            itemDAO = new ItemDAOImpl(connection);
        }
        return itemDAO;
    }

    @Override
    public OrderDAO getOrderDAO() {
        if (orderDAO == null) {
            orderDAO = new OrderDAOImpl(connection);
        }
        return orderDAO;
    }

    @Override
    public RoleDAO getRoleDAO() {
        if (roleDAO == null) {
            roleDAO = new RoleDAOImpl(connection);
        }
        return roleDAO;
    }
}
public class JdbcDaoManager extends JdbcDaoFactory implements AutoCloseable {

    public JdbcDaoManager() {
        super(DbHelper.getConnection());
    }

    public void beginTransaction() throws SQLException {
        connection.setAutoCommit(false);
    }

    public void commitTransaction() throws SQLException {
        connection.commit();
        connection.setAutoCommit(true);
    }

    public void rollbackTransaction() throws SQLException {
        connection.rollback();
        connection.setAutoCommit(true);
    }

    @Override
    public void close() throws SQLException {
        connection.close();
    }
}

Но я все еще не уверен, насколько правильным является это решение ... Это пример использования этого.

С транзакцией

try (JdbcDaoManager daoManager = new JdbcDaoManager()) {
    try {
        daoManager.beginTransaction();
        daoManager.getUserDAO().insert(new User("user1", "12345"));
        daoManager.getUserDAO().insert(new User("user2", "12345"));
        daoManager.getUserDAO().insert(new User("user3", "12345"));
        daoManager.commitTransaction();
    } catch (SQLException e) {
        daoManager.rollbackTransaction();
    }
} catch (SQLException e) {
    e.printStackTrace();
}

без транзакций

try (JdbcDaoManager daoManager = new JdbcDaoManager()) {
   daoManager.getUserDAO().insert(new User("user1", "12345"));
} catch (SQLException e) {
   e.printStackTrace();
}
...