2010-08-17 4 views
7

Ниже приведены методы, которые я имею в настоящее время в абстрактном классе DAO. Если есть одновременные вызовы, безопасны ли они, как они есть, или должна использоваться синхронизация? Я знаю, что синхронизация должна использоваться, если есть ссылка на атрибут вне области действия метода, но мне непонятно, как вещи должны обрабатываться внешним источником.Методы 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, поскольку это важно здесь.

+3

не использовать не одиночные списки для доступа к базе данных. –

+0

Я часто слышу это. Но какова альтернатива, когда вы работаете с простой Java? –

ответ

12

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

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

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

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

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

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

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

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 является основной ключ.

+2

Весна имеет достойную структуру DAO: http://static.springsource.org/spring/docs/2.5.x/reference/dao.html – Dave

+0

Более чем достойно. Это модель для подражания. – duffymo

+0

Спасибо за ответ duffymo. Я должен признать, что я немного борюсь, поскольку меня попросили не использовать фреймворк, такой как Spring. если у вас есть пример, который можно использовать в качестве шаблона, это было бы более чем приветствуется :). –

3

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

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

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

+0

Конкретные классы DAO работают так, как вы объяснили. Вышеупомянутые методы были просто идеей добавления некоторых методов утилиты в классе Asbtract, но, возможно, это плохой подход. Я, вероятно, еще не понял, как он должен взаимодействовать с JDBC и базой данных. –

3

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

При этом, если вы возвращаете другое соединение с каждым вызовом getCon(), то getPreparedStatement() не будет работать, если вы хотите, чтобы два вызова подготовленного оператора использовали одно и то же соединение (и такую ​​же транзакцию).

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

+0

«Соединение» - это просто интерфейс, независимо от того, реализованы ли потоки в потоковом режиме, не полностью ли используются драйвер JDBC –

+0

Хорошая точка. Я уточнил свой ответ, чтобы прояснить это. – Dave

0

Выглядит хорошо для меня. Эти функции являются потоковыми.

2

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

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

+0

Считаете ли вы, что я должен добавить какой-то поточный меканизм внутри DAO? –

+0

Это не ваш DAO, который не является потокобезопасным, это часть соединения. Как и @Bozho, если getCon() возвращает каждый раз конкретное соединение для каждого потока, тогда нет состояния гонки. –

+0

Хорошо, так что вы говорите, что я должен изолировать любые обращения к соединению. Я смотрел в синглтоне, и каждый раз он возвращает одно и то же соединение, поэтому это может быть проблемой. –

2

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

Определенно DAO не должен отвечать за подключение к базе данных, потому что вы захотите группировать несколько вызовов DAO в одной транзакции. Способом Spring является уровень сервиса, который получает свои транзакционные методы, завернутые в перехватчик, который вытягивает соединение из источника данных и помещает его в переменную threadlocal, где DAO могут ее найти.

Употребление вашего SQLException и возврат нулевого значения являются плохими. Как указывает duffymo, позволить PreparedStatement обойтись без уверенности, что он когда-нибудь будет закрыт, очень плохо. Кроме того, никто не должен использовать сырой JDBC больше, Ibatis или spring-jdbc - лучшие альтернативы.

+0

-1 для «никто больше не должен использовать необработанный JDBC». – GreenieMeanie

+0

-1 кажется немного суровым. Вы когда-нибудь использовали весну jdbc? Это почти сырой jdbc, где вы все равно будете манипулировать ps и rs (если хотите), но со всей обработкой исключений (и управлением ресурсами) и взаимодействием с tx. Таким образом, у вас есть преимущество необработанного доступа к данным с меньшим риском утечки. – Thierry

+0

Я думаю, что это защищаемая позиция, GreenieMeanie.Я бы предпочел, чтобы люди использовали Spring только для JDBC вместо отвратительного кода JDBC, который я вижу на SO. Я проголосовал за Натана Хьюза. – duffymo

Смежные вопросы