Методы DAO и синхронизированы - PullRequest
8 голосов
/ 18 августа 2010

Ниже приведены методы, которые в настоящее время используются в классе Abstract DAO. Если есть одновременные вызовы, безопасны ли они, как они есть, или следует использовать синхронизацию? Я знаю, что синхронизацию следует использовать, если есть ссылка на атрибут вне области действия метода, но мне неясно, как следует обращаться с внешним ресурсом.

public Connection getConnection() {
    // Call to singleton handling JDBC stuff
    return Database.getInstance().getCon();
}

public boolean isConnectionAvailable(){     
    if( getConnection() != null ){
        return true;
    }

    return false;
}

public PreparedStatement getPreparedStatement( String sqlStatement ){
    Connection connection = getConnection();
    PreparedStatement pS = null;

    if( connection != null ){
        try {
            pS = connection.prepareStatement( sqlStatement );
        } catch (SQLException e) {
            return null;
        }
    }

    return pS;
}

Редактировать: Я мог бы переформулировать этот вопрос, включив в него информацию о написании DAO, поскольку это важно здесь.

Ответы [ 6 ]

13 голосов
/ 18 августа 2010

Я совсем не согласен с этой реализацией.

Во-первых, DAO следует предоставлять информацию о подключении службам, которые владеют единицами работы и транзакций.

Во-вторых, я не вижу интерфейса.

В-третьих, я не вижу объекты модели или домена.

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

В-пятых, передача подготовленного утверждения из объекта делает ответственность за его закрытие и очистку гораздо менее ясной. Ваш DAO умрет в результате утечки ресурса.

Вот интерфейс для общего DAO. Вы заметите, что это все операции CRUD, без упоминания о соединениях или каких-либо интерфейсах из пакета java.sql:

package persistence;

import java.io.Serializable;
import java.util.List;

public interface GenericDao<T, K extends Serializable>
{
    T find(K id);
    List<T> find();
    List<T> find(T example);
    List<T> find(String queryName, String [] paramNames, Object [] bindValues);

    K save(T instance);
    void update(T instance);
    void delete(T instance);
}

Вы можете пройти долгий путь с этим. Это лучшая абстракция. T - это тип вашего бизнес-объекта, а K - это первичный ключ.

3 голосов
/ 18 августа 2010

Класс JDBC Connection не гарантированно является потокобезопасным. Если ваш метод Database.getInstance (). GetCon () всегда возвращает одно и то же соединение, вы столкнетесь с проблемами. Однако, если он использует пул так, что каждый вызов getInstance (). GetCon () возвращает другое соединение, у вас все будет в порядке.

Тем не менее, если вы возвращаете разные соединения с каждым вызовом getCon (), то getPreparedStatement () не будет работать, если вы хотите, чтобы два вызова Prepared Statement использовали одно и то же соединение (и одну и ту же транзакцию).

Мне нравится класс Spring JDBCTemplate в качестве основы для моих классов DAO.

3 голосов
/ 18 августа 2010

Если getCon() возвращает новый Connection каждый раз, когда он вызывается, или возвращает ThreadLocal соединение, то вы в безопасности, и нет необходимости использовать synchronized

Если вы вернетесьодно и то же соединение со всеми, кого вы можете сохранить с точки зрения синхронизации, потому что в соединении нет изменяемого состояния (в вашем текущем коде).Но вы должны избегать этой практики.Вместо этого рассмотрим пул соединений.

И несколько замечаний по общим принципам проектирования.DAO образуют отдельный слой.Каждый слой существует по какой-то причине, а не просто ради классных имен.Уровень DAO существует для того, чтобы абстрагировать или, другими словами, скрыть доступ к базе данных от сервисов, которые используют объекты DAO.Чтобы представить это более четко - DAO должен быть написан так, что если завтра вы решите переключиться с хранилища RDBMD (через JDBC) на хранилище XML, вы сможете сделать это, изменив only объекты DAO и ничего больше.

2 голосов
/ 18 августа 2010

Посмотрите, как Spring это делает, они уже разобрались со всем этим, и нет необходимости заново его изобретать.Посмотрите пример кода для petclinic, который поставляется вместе с полным дистрибутивом Spring, или (для подхода, отличного от Spring) прочитайте главу DAO в книге Bauer / King Hibernate.

Определенно, DAO не должен отвечать за соединение с базой данных, потому что вы захотите сгруппировать несколько вызовов DAO в одну транзакцию.Как это делает Spring, есть сервисный уровень, который заключает свои транзакционные методы в перехватчик, который извлекает соединение из источника данных и помещает его в переменную локального потока, где DAO может его найти.возвращать ноль плохо.Как указывает Даффимо, пропускать PreparedStatement без уверенности, что он когда-либо закроется, очень плохо.Кроме того, никто не должен больше использовать сырой JDBC, Ibatis или spring-jdbc являются лучшими альтернативами.

2 голосов
/ 18 августа 2010

Вы не должны использовать одно и то же соединение в каждом потоке.Драйверы JDBC не должны быть потокобезопасными.Если вам нужен потокобезопасный код, вы должны создать одно соединение для каждого потока.

Остальная часть кода кажется безопасной.

0 голосов
/ 18 августа 2010

выглядит хорошо для меня. Функции являются поточно-безопасными.

...