如何使用JDBC创建事务DAO

时间:2019-07-05 21:49:34

标签: java jdbc transactions dao

我现在正在使用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 个答案:

答案 0 :(得分:1)

通常,您不必处理DAO级别的事务。最好在服务层应用事务管理,因为这样可以控制何时需要事务或不需要事务时的逻辑,还可以控制回滚策略等其他方面。

根据您的情况,您可以查看JTA文档。该API提供了批注和其他工具,可轻松管理您的交易:)

答案 1 :(得分:0)

现在,我已经创建了用于管理所有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();
}