Java DAO模式多表原子事务

时间:2017-02-17 20:09:54

标签: java database jdbc dao

我正在尝试使用DAO模式插入两个具有一对一关系的表。我有customeraddress个表格。每个customer都有一个address_id字段,该字段引用address表的ID。

我想要做的是将客户地址插入address表并获取生成的address_id并使用该地址将客户插入customer表。如果这些任务中的任何一个失败,则数据库保持不变。

我没有使用像spring或hibernate这样的任何框架,只使用带有DAO模式的普通JDBC。

这是代码。在Application.java中,首先插入地址,然后插入客户。如果客户插入失败,则地址仍保留在数据库中。

我可以关闭数据库连接的自动提交并将地址和客户插入合并到一个数据库连接中,但这是否与DAO模式相对应?

Customer.java:

package com.example.model;

public class Customer {

   private long id;
   private String firstName;
   private String lastName;
   private String email;
   private byte[] salt;
   private byte[] digest;
   private Address address;

   // getters and setters
}

Address.java:

package com.example.model;

public class Address {

    private long id;
    private String address;
    private String postalCode;
    private String phone;

    // getters and setters
}

AddressDAO.java:

package com.example.dao;

import com.example.model.Address;

public interface AddressDAO {

    void create(Address address);
}

AddressDAOImpl.java:

package com.example.dao;

import com.example.model.Address;
import com.example.util.DatabaseUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class AddressDAOImpl implements AddressDAO {

    private static final Logger LOG = LoggerFactory.getLogger(AddressDAOImpl.class);

    @Override
    public void create(Address address) {
        String sql = "INSERT INTO address (address, postal_code, phone) VALUES (?, ?, ?)";
        try (PreparedStatement ps = DatabaseUtil.getConnection()
                .prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS)) {
            ps.setString(1, address.getAddress());
            ps.setString(2, address.getPostalCode());
            ps.setString(3, address.getPhone());
            ps.executeUpdate();
            try (ResultSet rs = ps.getGeneratedKeys()) {
                if (rs.next()) {
                    address.setId(rs.getShort(1));
                }
            }
        } catch (SQLException e) {
            LOG.error(e.getMessage(), e);
        }
    }
}

CustomerDAO.java:

package com.example.dao;

import com.example.model.Customer;

public interface CustomerDAO {

    void create(Customer customer);
}

CustomerDOAImpl.java:

package com.example.dao;

import com.example.model.Customer;
import com.example.util.DatabaseUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class CustomerDAOImpl implements CustomerDAO {

    private static final Logger LOG = LoggerFactory.getLogger(CustomerDAOImpl.class);

    @Override
    public void create(Customer customer) {
        String sql = "INSERT INTO customer (first_name, last_name, email, address_id, salt, digest) " +
            "VALUES (?, ?, ?, ?, ?, ?)";
        try (PreparedStatement ps = DatabaseUtil.getConnection()
                .prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS)){
            ps.setString(1, customer.getFirstName());
            ps.setString(2, customer.getLastName());
            ps.setString(3, customer.getEmail());
            ps.setLong(4, customer.getAddress().getId());
            ps.setBytes(5, customer.getSalt());
            ps.setBytes(6, customer.getDigest());
            ps.executeUpdate();
            try (ResultSet rs = ps.getGeneratedKeys()) {
                if (rs.next()) {
                    customer.setId(rs.getLong(1));
                }
            }
        } catch (SQLException e) {
            LOG.error(e.getMessage(), e);
        }
    }
}

Application.java:

package com.example;

import com.example.dao.AddressDAO;
import com.example.dao.AddressDAOImpl;
import com.example.dao.CustomerDAO;
import com.example.dao.CustomerDAOImpl;
import com.example.model.Address;
import com.example.model.Customer;

public class Application {

    public static void main(String[] args) {
        Customer customer = new Customer();
        Address address = new Address();
        CustomerDAO customerDAO = new CustomerDAOImpl();
        AddressDAO addressDAO = new AddressDAOImpl();

        address.setAddress("Address");
        address.setPostalCode("123456789");
        address.setPhone("987654321");

        customer.setFirstName("John");
        customer.setLastName("Doe");
        customer.setEmail("john.doe@mail.com");
        customer.setAddress(address);

        addressDAO.create(customer.getAddress());
        customerDAO.create(customer);

        System.out.println(customer.getId());
    }
}

1 个答案:

答案 0 :(得分:0)

由于这是一对一的关系并且假设您不会自己创建地址,我只想在CustomerDAOImpl中创建Address。稍后,如果有必要,您可以稍后在AddressDAO中公开Address对象的检索。地址的更新也可以通过相同的CustomerDAOImpl类来处理。

如果您将来转换到JPA / Hibernate,并且框架会表现出相同的行为,那么从长远来看,这种方法会更好。此外,这可以防止您必须在DAO类之间进行自己的事务/连接管理。